xref: /expo/docs/components/Permalink.tsx (revision 46b58c59)
15b6cd93dSBartosz Kaszubowskiimport { css } from '@emotion/react';
2f4b1168bSBartosz Kaszubowskiimport { LinkBase } from '@expo/styleguide';
3586106d6SBartłomiej Klocekimport * as React from 'react';
4586106d6SBartłomiej Klocek
5586106d6SBartłomiej Klocekimport { AdditionalProps } from '~/common/headingManager';
652aab7caSKeith Kurakimport PermalinkIcon from '~/components/icons/Permalink';
71f61a071SBartosz Kaszubowskiimport withHeadingManager, {
81f61a071SBartosz Kaszubowski  HeadingManagerProps,
91f61a071SBartosz Kaszubowski} from '~/components/page-higher-order/withHeadingManager';
10586106d6SBartłomiej Klocek
111f61a071SBartosz Kaszubowskitype BaseProps = React.PropsWithChildren<{
12586106d6SBartłomiej Klocek  component: any;
13586106d6SBartłomiej Klocek  className?: string;
143c9a6b96SBartosz Kaszubowski  style?: React.CSSProperties;
151f61a071SBartosz Kaszubowski}>;
16586106d6SBartłomiej Klocek
171f61a071SBartosz Kaszubowskitype EnhancedProps = React.PropsWithChildren<{
18cb5b8d03SBartosz Kaszubowski  // Sidebar heading level override
19586106d6SBartłomiej Klocek  nestingLevel?: number;
20586106d6SBartłomiej Klocek  additionalProps?: AdditionalProps;
21586106d6SBartłomiej Klocek  id?: string;
221f61a071SBartosz Kaszubowski}>;
23586106d6SBartłomiej Klocek
24929e0953SCedric van Puttenconst STYLES_PERMALINK_TARGET = css`
25929e0953SCedric van Putten  display: block;
26929e0953SCedric van Putten  position: absolute;
27b5ea8c8fSBartosz Kaszubowski  top: -46px;
28929e0953SCedric van Putten  visibility: hidden;
29929e0953SCedric van Putten`;
30929e0953SCedric van Putten
31929e0953SCedric van Puttenconst STYLES_PERMALINK_LINK = css`
32b5ea8c8fSBartosz Kaszubowski  position: relative;
33929e0953SCedric van Putten  color: inherit;
34cb5b8d03SBartosz Kaszubowski  text-decoration: none !important;
35929e0953SCedric van Putten
36929e0953SCedric van Putten  /* Disable link when used in collapsible, to allow expand on click */
37929e0953SCedric van Putten  details & {
38929e0953SCedric van Putten    pointer-events: none;
39929e0953SCedric van Putten  }
40929e0953SCedric van Putten`;
41929e0953SCedric van Putten
42929e0953SCedric van Puttenconst STYLED_PERMALINK_CONTENT = css`
439e30a8beSCedric van Putten  display: inline;
44929e0953SCedric van Putten`;
45929e0953SCedric van Putten
46929e0953SCedric van Puttenconst STYLES_PERMALINK_ICON = css`
47929e0953SCedric van Putten  cursor: pointer;
48f4b1168bSBartosz Kaszubowski  vertical-align: middle;
49929e0953SCedric van Putten  display: inline-block;
50929e0953SCedric van Putten  width: 1.2em;
51f4b1168bSBartosz Kaszubowski  height: 1em;
52929e0953SCedric van Putten  padding: 0 0.2em;
53929e0953SCedric van Putten  visibility: hidden;
54929e0953SCedric van Putten
558c97fc97SBartosz Kaszubowski  a:hover &,
568c97fc97SBartosz Kaszubowski  a:focus-visible & {
57929e0953SCedric van Putten    visibility: visible;
58929e0953SCedric van Putten  }
59929e0953SCedric van Putten
60929e0953SCedric van Putten  svg {
61929e0953SCedric van Putten    width: 100%;
62929e0953SCedric van Putten    height: auto;
63929e0953SCedric van Putten  }
64929e0953SCedric van Putten`;
65929e0953SCedric van Putten
661f61a071SBartosz Kaszubowskiconst PermalinkBase = ({ component, children, className, ...rest }: BaseProps) =>
67929e0953SCedric van Putten  React.cloneElement(
68586106d6SBartłomiej Klocek    component,
69586106d6SBartłomiej Klocek    {
70586106d6SBartłomiej Klocek      className: [className, component.props.className || ''].join(' '),
71586106d6SBartłomiej Klocek      ...rest,
72586106d6SBartłomiej Klocek    },
73586106d6SBartłomiej Klocek    children
74586106d6SBartłomiej Klocek  );
75586106d6SBartłomiej Klocek
761f61a071SBartosz Kaszubowskiconst Permalink: React.FC<EnhancedProps> = withHeadingManager(
771f61a071SBartosz Kaszubowski  (props: EnhancedProps & HeadingManagerProps) => {
78586106d6SBartłomiej Klocek    // NOTE(jim): Not the greatest way to generate permalinks.
79586106d6SBartłomiej Klocek    // for now I've shortened the length of permalinks.
80586106d6SBartłomiej Klocek    const component = props.children as JSX.Element;
81586106d6SBartłomiej Klocek    const children = component.props.children || '';
82586106d6SBartłomiej Klocek
83df72b035SBartosz Kaszubowski    if (!props.nestingLevel) {
84df72b035SBartosz Kaszubowski      return children;
85df72b035SBartosz Kaszubowski    }
86df72b035SBartosz Kaszubowski
87df72b035SBartosz Kaszubowski    const heading = props.headingManager.addHeading(
88fccf9c8cSCedric van Putten      children,
89fccf9c8cSCedric van Putten      props.nestingLevel,
90fccf9c8cSCedric van Putten      props.additionalProps,
91b5ea8c8fSBartosz Kaszubowski      props.id
92df72b035SBartosz Kaszubowski    );
93586106d6SBartłomiej Klocek
94586106d6SBartłomiej Klocek    return (
9524f68907SBartosz Kaszubowski      <PermalinkBase component={component} style={props.additionalProps?.style}>
96df72b035SBartosz Kaszubowski        <LinkBase css={STYLES_PERMALINK_LINK} href={'#' + heading.slug} ref={heading.ref}>
97df72b035SBartosz Kaszubowski          <span css={STYLES_PERMALINK_TARGET} id={heading.slug} />
98929e0953SCedric van Putten          <span css={STYLED_PERMALINK_CONTENT}>{children}</span>
99*46b58c59SKeith Kurak          <span css={STYLES_PERMALINK_ICON}>
100*46b58c59SKeith Kurak            <PermalinkIcon />
101*46b58c59SKeith Kurak          </span>
102cb5b8d03SBartosz Kaszubowski        </LinkBase>
103929e0953SCedric van Putten      </PermalinkBase>
104586106d6SBartłomiej Klocek    );
1051f61a071SBartosz Kaszubowski  }
1061f61a071SBartosz Kaszubowski);
107929e0953SCedric van Putten
108929e0953SCedric van Puttenexport default Permalink;
109