-
Notifications
You must be signed in to change notification settings - Fork 162
Expand file tree
/
Copy pathHeading.tsx
More file actions
90 lines (75 loc) · 2.33 KB
/
Heading.tsx
File metadata and controls
90 lines (75 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { type ComponentPropsWithoutRef, type ElementType, useContext, useEffect } from 'react'
import { useInView } from 'react-intersection-observer'
import { classNames, ExperimentalButton } from '@edgeandnode/gds'
import { Link as LinkIcon } from '@edgeandnode/gds/icons'
import { useI18n } from '@/i18n'
import { MDXContentContext } from '@/layout'
interface HeadingProps extends ComponentPropsWithoutRef<'h1'> {
as?: ElementType
}
const BaseHeading = ({ as: Element = 'h1', id, className, children, ...props }: HeadingProps) => {
const { markHeading } = useContext(MDXContentContext)!
const { t } = useI18n()
const { ref, inView: inOrAboveView } = useInView({
rootMargin: '99999px 0px -60% 0px', // consider it "in or above view" if it's above 60% from the bottom of the viewport
})
useEffect(
() => {
if (!id) return
markHeading(id, inOrAboveView)
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[id, inOrAboveView],
)
return (
<Element ref={ref} id={id} className={classNames(['group/heading', className])} {...props}>
{children}
{id ? (
<span
className={`
absolute end-[calc(100%+theme(spacing[2.5]))] top-0 flex h-[1lh] items-center opacity-0 transition
group-hover/heading:opacity-100
group-has-focus-visible/heading:opacity-100
max-md:hidden
`}
>
<ExperimentalButton
variant="naked"
size="large"
href={`#${id}`}
className="+:**:text-[1em] +:nested-icon:prop-size-[0.85em]"
>
<LinkIcon alt={t('global.page.linkToThisSection')} />
</ExperimentalButton>
</span>
) : null}
</Element>
)
}
const H1 = (props: HeadingProps) => {
return <BaseHeading as="h1" {...props} />
}
const H2 = (props: HeadingProps) => {
return <BaseHeading as="h2" {...props} />
}
const H3 = (props: HeadingProps) => {
return <BaseHeading as="h3" {...props} />
}
const H4 = (props: HeadingProps) => {
return <BaseHeading as="h4" {...props} />
}
const H5 = (props: HeadingProps) => {
return <BaseHeading as="h5" {...props} />
}
const H6 = (props: HeadingProps) => {
return <BaseHeading as="h6" {...props} />
}
const Heading = Object.assign({}, BaseHeading, {
H1,
H2,
H3,
H4,
H5,
H6,
})
export { Heading }