A design system in a box. hip-ui.tngl.io/docs/introduction
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

factor out heading link

+189 -57
+77
apps/docs/src/components/typography/index.tsx
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 + import { LinkIcon } from "lucide-react"; 2 3 import { 3 4 createContext, 4 5 use, ··· 9 10 } from "react"; 10 11 11 12 import { CopyToClipboardButton } from "../copy-to-clipboard-button"; 13 + import { Flex } from "../flex"; 12 14 import { LinkContext } from "../link/link-context"; 15 + import { animationDuration } from "../theme/animations.stylex"; 13 16 import { uiColor } from "../theme/color.stylex"; 14 17 import { mediaQueries } from "../theme/media-queries.stylex"; 15 18 import { radius } from "../theme/radius.stylex"; ··· 100 103 overflow: "hidden", 101 104 textOverflow: "ellipsis", 102 105 whiteSpace: "nowrap", 106 + }, 107 + linkedHeadingLink: { 108 + color: "inherit", 109 + textDecoration: "none", 110 + }, 111 + linkedHeadingLinkButton: { 112 + opacity: { 113 + default: 0, 114 + ":is([data-heading-link]:hover *)": 1, 115 + ":is([data-focus-visible])": 1, 116 + }, 117 + transitionDuration: animationDuration.fast, 118 + transitionProperty: { 119 + default: "opacity", 120 + "@media (prefers-reduced-motion: reduce)": "none", 121 + }, 122 + transitionTimingFunction: "ease-in-out", 103 123 }, 104 124 }); 105 125 ··· 371 391 /> 372 392 ); 373 393 }; 394 + 395 + /** 396 + * Props for the LinkedHeading component. 397 + */ 398 + export interface LinkedHeadingProps { 399 + /** 400 + * The ID of the heading, used to create the anchor link. 401 + * If not provided, the component will just render the children. 402 + */ 403 + id?: string; 404 + /** 405 + * The heading content to display. 406 + */ 407 + children: React.ReactNode; 408 + /** 409 + * Optional style to apply to the container. 410 + */ 411 + style?: stylex.StyleXStyles; 412 + } 413 + 414 + /** 415 + * A wrapper component for headings that adds a link and copy-to-clipboard button. 416 + * The link allows users to jump to the heading, and the button copies the full URL 417 + * with the anchor to the clipboard. 418 + */ 419 + export const LinkedHeading = ({ 420 + id, 421 + children, 422 + style, 423 + }: LinkedHeadingProps) => { 424 + if (!id) { 425 + return <>{children}</>; 426 + } 427 + 428 + const url = typeof window !== "undefined" 429 + ? `${window.location.origin}${window.location.pathname}#${id}` 430 + : `#${id}`; 431 + 432 + return ( 433 + <Flex 434 + direction="row" 435 + gap="2" 436 + align="center" 437 + data-heading-link={true} 438 + style={style} 439 + > 440 + <a href={`#${id}`} {...stylex.props(styles.linkedHeadingLink)}> 441 + {children} 442 + </a> 443 + <CopyToClipboardButton 444 + text={url} 445 + icon={<LinkIcon />} 446 + style={styles.linkedHeadingLinkButton} 447 + /> 448 + </Flex> 449 + ); 450 + };
+8 -1
apps/docs/src/docs/components/content/typography.mdx
··· 17 17 import { Typeramp } from '../../../examples/typography/typeramp' 18 18 import { BlockquoteExample } from '../../../examples/typography/blockquote' 19 19 import { InlineCodeExample } from '../../../examples/typography/inline-code' 20 + import { LinkedHeadingExample } from '../../../examples/typography/linked-heading' 20 21 import { PreExample } from '../../../examples/typography/pre' 21 22 22 23 <Example src={Typeramp} /> ··· 33 34 34 35 This is a custom component collection built for typography. 35 36 36 - <PropDocs components={["Heading1", "Heading2", "Heading3", "Heading4", "Heading5", "Body", "SmallBody", "LabelText", "SubLabel", "Blockquote", "UnorderedList", "OrderedList", "ListItem", "InlineCode", "Pre"]} /> 37 + <PropDocs components={["Heading1", "Heading2", "Heading3", "Heading4", "Heading5", "Body", "SmallBody", "LabelText", "SubLabel", "Blockquote", "UnorderedList", "OrderedList", "ListItem", "InlineCode", "Pre", "LinkedHeading"]} /> 37 38 38 39 ## Typeramp 39 40 ··· 85 86 Typography also includes a pre component. 86 87 87 88 <Example src={PreExample} /> 89 + 90 + ### Linked Heading 91 + 92 + Typography also includes a linked heading component that adds anchor links and copy-to-clipboard functionality to headings. 93 + 94 + <Example src={LinkedHeadingExample} /> 88 95 89 96 ## Related Components 90 97
+26
apps/docs/src/examples/typography/linked-heading.tsx
··· 1 + import { 2 + Heading2, 3 + Heading3, 4 + Heading4, 5 + LinkedHeading, 6 + } from "@/components/typography"; 7 + 8 + export function LinkedHeadingExample() { 9 + return ( 10 + <div> 11 + <LinkedHeading id="section-1"> 12 + <Heading2>Section 1</Heading2> 13 + </LinkedHeading> 14 + <LinkedHeading id="subsection-1-1"> 15 + <Heading3>Subsection 1.1</Heading3> 16 + </LinkedHeading> 17 + <LinkedHeading id="subsection-1-2"> 18 + <Heading3>Subsection 1.2</Heading3> 19 + </LinkedHeading> 20 + <LinkedHeading id="detail-1-2-1"> 21 + <Heading4>Detail 1.2.1</Heading4> 22 + </LinkedHeading> 23 + </div> 24 + ); 25 + } 26 +
+4 -56
apps/docs/src/routes/docs.$.tsx
··· 18 18 19 19 import * as stylex from "@stylexjs/stylex"; 20 20 import { allDocs } from "content-collections"; 21 - import { LinkIcon } from "lucide-react"; 22 21 import { Suspense } from "react"; 23 22 import { modules, pages } from "virtual:content"; 24 23 ··· 33 32 Heading4, 34 33 Heading5, 35 34 InlineCode, 35 + LinkedHeading, 36 36 ListItem, 37 37 OrderedList, 38 38 Pre, ··· 40 40 } from "@/components/typography"; 41 41 import { Text } from "@/components/typography/text"; 42 42 import { TableOfContents } from "@/components/table-of-contents"; 43 - import { CopyToClipboardButton } from "@/components/copy-to-clipboard-button"; 44 43 45 - import { animationDuration } from "../components/theme/animations.stylex"; 46 44 import { spacing } from "../components/theme/spacing.stylex"; 47 45 import { Content } from "@/components/content"; 48 46 import { containerBreakpoints } from "../components/theme/media-queries.stylex"; ··· 65 63 header: { 66 64 marginBottom: spacing["12"], 67 65 }, 68 - linkedHeadingLink: { 69 - color: "inherit", 70 - textDecoration: "none", 71 - }, 72 - linkedHeadingLinkButton: { 73 - opacity: { 74 - default: 0, 75 - ":is([data-heading-link]:hover *)": 1, 76 - ":is([data-focus-visible])": 1, 77 - }, 78 - transitionDuration: animationDuration.fast, 79 - transitionProperty: { 80 - default: "opacity", 81 - "@media (prefers-reduced-motion: reduce)": "none", 82 - }, 83 - transitionTimingFunction: "ease-in-out", 84 - }, 85 66 tableOfContents: { 86 67 display: { 87 68 default: "none", ··· 90 71 }, 91 72 }); 92 73 93 - function LinkedHeading({ 94 - id, 95 - children, 96 - style, 97 - }: { 98 - id?: string; 99 - children: React.ReactNode; 100 - style?: stylex.StyleXStyles; 101 - }) { 102 - const location = useLocation(); 103 - 104 - if (!id) { 105 - return children; 106 - } 107 - 108 - return ( 109 - <Flex 110 - direction="row" 111 - gap="2" 112 - align="center" 113 - data-heading-link={true} 114 - style={[style]} 115 - > 116 - <a href={`#${id}`} {...stylex.props(styles.linkedHeadingLink)}> 117 - {children} 118 - </a> 119 - <CopyToClipboardButton 120 - text={`${location.url}#${id}`} 121 - icon={<LinkIcon />} 122 - style={styles.linkedHeadingLinkButton} 123 - /> 124 - </Flex> 125 - ); 126 - } 127 - 128 74 function Link({ href, ...props }: LinkProps) { 129 75 if (href && href.startsWith("/")) { 130 76 const splat = href.split("/").slice(2).join("/"); ··· 179 125 li: ({ className: _className, style: _style, ...props }) => ( 180 126 <ListItem {...props} /> 181 127 ), 182 - pre: Pre, 128 + pre: ({ className: _className, style: _style, ...props }) => ( 129 + <Pre {...props} /> 130 + ), 183 131 code: ({ className: _className, style: _style, ...props }) => ( 184 132 <InlineCode {...props} /> 185 133 ),
+74
packages/hip-ui/src/components/typography/index.tsx
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 + import { LinkIcon } from "lucide-react"; 2 3 import { 3 4 createContext, 4 5 use, ··· 9 10 } from "react"; 10 11 11 12 import { CopyToClipboardButton } from "../copy-to-clipboard-button"; 13 + import { Flex } from "../flex"; 12 14 import { LinkContext } from "../link/link-context"; 15 + import { animationDuration } from "../theme/animations.stylex"; 13 16 import { uiColor } from "../theme/color.stylex"; 14 17 import { mediaQueries } from "../theme/media-queries.stylex"; 15 18 import { radius } from "../theme/radius.stylex"; ··· 100 103 overflow: "hidden", 101 104 textOverflow: "ellipsis", 102 105 whiteSpace: "nowrap", 106 + }, 107 + linkedHeadingLink: { 108 + textDecoration: "none", 109 + color: "inherit", 110 + }, 111 + linkedHeadingLinkButton: { 112 + opacity: { 113 + default: 0, 114 + ":is([data-focus-visible])": 1, 115 + ":is([data-heading-link]:hover *)": 1, 116 + }, 117 + transitionDuration: animationDuration.fast, 118 + transitionProperty: { 119 + default: "opacity", 120 + "@media (prefers-reduced-motion: reduce)": "none", 121 + }, 122 + transitionTimingFunction: "ease-in-out", 103 123 }, 104 124 }); 105 125 ··· 371 391 /> 372 392 ); 373 393 }; 394 + 395 + /** 396 + * Props for the LinkedHeading component. 397 + */ 398 + export interface LinkedHeadingProps { 399 + /** 400 + * The ID of the heading, used to create the anchor link. 401 + * If not provided, the component will just render the children. 402 + */ 403 + id?: string; 404 + /** 405 + * The heading content to display. 406 + */ 407 + children: React.ReactNode; 408 + /** 409 + * Optional style to apply to the container. 410 + */ 411 + style?: stylex.StyleXStyles; 412 + } 413 + 414 + /** 415 + * A wrapper component for headings that adds a link and copy-to-clipboard button. 416 + * The link allows users to jump to the heading, and the button copies the full URL 417 + * with the anchor to the clipboard. 418 + */ 419 + export const LinkedHeading = ({ id, children, style }: LinkedHeadingProps) => { 420 + if (!id) { 421 + return <>{children}</>; 422 + } 423 + 424 + const url = 425 + globalThis.window === undefined 426 + ? `#${id}` 427 + : `${globalThis.location.origin}${globalThis.location.pathname}#${id}`; 428 + 429 + return ( 430 + <Flex 431 + direction="row" 432 + gap="2" 433 + align="center" 434 + data-heading-link={true} 435 + style={style} 436 + > 437 + <a href={`#${id}`} {...stylex.props(styles.linkedHeadingLink)}> 438 + {children} 439 + </a> 440 + <CopyToClipboardButton 441 + text={url} 442 + icon={<LinkIcon />} 443 + style={styles.linkedHeadingLinkButton} 444 + /> 445 + </Flex> 446 + ); 447 + };