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.

typography overhaul

+371 -129
+4 -17
apps/docs/src/components/aspect-ratio/index.tsx
··· 2 2 3 3 import type { StyleXComponentProps } from "../theme/types"; 4 4 5 - import { mediaQueries } from "../theme/media-queries.stylex"; 6 5 import { radius } from "../theme/radius.stylex"; 7 6 8 7 const styles = stylex.create({ ··· 15 14 }, 16 15 rounded: { 17 16 cornerShape: "squircle", 18 - borderBottomLeftRadius: { 19 - default: radius.md, 20 - [mediaQueries.supportsSquircle]: radius["3xl"], 21 - }, 22 - borderBottomRightRadius: { 23 - default: radius.md, 24 - [mediaQueries.supportsSquircle]: radius["3xl"], 25 - }, 26 - borderTopLeftRadius: { 27 - default: radius.md, 28 - [mediaQueries.supportsSquircle]: radius["3xl"], 29 - }, 30 - borderTopRightRadius: { 31 - default: radius.md, 32 - [mediaQueries.supportsSquircle]: radius["3xl"], 33 - }, 17 + borderBottomLeftRadius: radius.lg, 18 + borderBottomRightRadius: radius.lg, 19 + borderTopLeftRadius: radius.lg, 20 + borderTopRightRadius: radius.lg, 34 21 }, 35 22 imageContainer: { 36 23 inset: 0,
+4
apps/docs/src/components/button/index.tsx
··· 15 15 16 16 const styles = stylex.create({ 17 17 content: { 18 + // eslint-disable-next-line @stylexjs/valid-styles 19 + textBoxEdge: "cap alphabetic", 20 + // eslint-disable-next-line @stylexjs/valid-styles 21 + textBoxTrim: "trim-both", 18 22 gap: spacing["2"], 19 23 alignItems: "center", 20 24 display: "flex",
+27 -13
apps/docs/src/components/card/index.tsx
··· 25 25 borderWidth: 1, 26 26 27 27 cornerShape: "squircle", 28 - gap: "var(--card-gap)", 29 28 overflow: "hidden", 30 29 boxShadow: shadow["sm"], 31 30 display: "flex", ··· 33 32 fontFamily: fontFamily["sans"], 34 33 35 34 "--card-gap": { 36 - ":is([data-card-size=lg])": spacing["9"], 37 - ":is([data-card-size=md])": spacing["6"], 38 - ":is([data-card-size=sm])": spacing["2"], 35 + ":is([data-card-size=lg])": spacing["4"], 36 + ":is([data-card-size=md])": spacing["4"], 37 + ":is([data-card-size=sm])": spacing["1"], 39 38 }, 40 39 "--card-x-padding": { 41 - ":is([data-card-size=lg])": spacing["9"], 40 + ":is([data-card-size=lg])": spacing["8"], 42 41 ":is([data-card-size=md])": spacing["6"], 43 - ":is([data-card-size=sm])": spacing["2"], 42 + ":is([data-card-size=sm])": spacing["3"], 44 43 }, 45 44 "--card-y-padding": { 46 - ":is([data-card-size=lg])": spacing["10"], 47 - ":is([data-card-size=md])": spacing["7"], 48 - ":is([data-card-size=sm])": spacing["2"], 45 + ":is([data-card-size=lg])": spacing["8"], 46 + ":is([data-card-size=md])": spacing["6"], 47 + ":is([data-card-size=sm])": spacing["3"], 49 48 }, 50 49 }, 51 50 cardSection: { 52 51 boxSizing: "border-box", 53 - paddingBottom: { ":last-child": "var(--card-y-padding)" }, 52 + paddingBottom: { 53 + default: "var(--card-gap)", 54 + ":last-child": "var(--card-y-padding)", 55 + }, 54 56 paddingLeft: "var(--card-x-padding)", 55 57 paddingRight: "var(--card-x-padding)", 56 58 paddingTop: { ":first-child": "var(--card-y-padding)" }, ··· 63 65 'description action' 64 66 `, 65 67 }, 66 - gap: "calc(var(--card-gap) * 0.25)", 68 + gap: "calc(var(--card-gap) * 0.5)", 67 69 alignItems: "center", 68 70 display: "grid", 69 71 }, ··· 80 82 justifyContent: "flex-end", 81 83 }, 82 84 cardTitle: { 85 + // eslint-disable-next-line @stylexjs/valid-styles 86 + textBoxEdge: "cap alphabetic", 87 + // eslint-disable-next-line @stylexjs/valid-styles 88 + textBoxTrim: "trim-both", 83 89 gridArea: "title", 84 90 gap: spacing["3"], 85 91 alignItems: "center", ··· 87 93 fontSize: { 88 94 ":is([data-card-size='lg'] *)": fontSize["2xl"], 89 95 ":is([data-card-size='md'] *)": fontSize["xl"], 90 - ":is([data-card-size='sm'] *)": fontSize["lg"], 96 + ":is([data-card-size='sm'] *)": fontSize["base"], 91 97 }, 92 98 fontWeight: fontWeight["bold"], 93 99 }, ··· 99 105 lineHeight: lineHeight["sm"], 100 106 }, 101 107 cardBody: { 108 + // eslint-disable-next-line @stylexjs/valid-styles 109 + textBoxEdge: "cap alphabetic", 110 + // eslint-disable-next-line @stylexjs/valid-styles 111 + textBoxTrim: "trim-both", 102 112 gap: "calc(var(--card-gap) * 0.5)", 103 113 display: "flex", 104 114 flexDirection: "column", 105 - lineHeight: lineHeight["lg"], 115 + fontSize: { 116 + ":is([data-card-size='lg'] *)": fontSize["lg"], 117 + ":is([data-card-size='sm'] *)": fontSize["xs"], 118 + }, 106 119 }, 107 120 cardFooter: { 108 121 gap: spacing["2"], ··· 115 128 borderBottomRightRadius: { default: 0, ":last-child": radius.md }, 116 129 borderTopLeftRadius: { default: 0, ":first-child": radius.md }, 117 130 borderTopRightRadius: { default: 0, ":first-child": radius.md }, 131 + marginBottom: "var(--card-y-padding)", 118 132 }, 119 133 }); 120 134
+1
apps/docs/src/components/combobox/index.tsx
··· 38 38 39 39 const styles = stylex.create({ 40 40 matchWidth: { 41 + minWidth: 180, 41 42 width: "var(--trigger-width)", 42 43 }, 43 44 emptyState: {
+5 -2
apps/docs/src/components/dialog/index.tsx
··· 24 24 const styles = stylex.create({ 25 25 dialog: { 26 26 overflow: "auto", 27 - paddingBottom: spacing["2"], 28 27 }, 29 28 header: { 30 29 gap: spacing["2"], ··· 63 62 gap: spacing["2"], 64 63 display: "flex", 65 64 justifyContent: "flex-end", 66 - paddingBottom: spacing["2"], 65 + paddingBottom: spacing["4"], 67 66 paddingLeft: spacing["4"], 68 67 paddingRight: spacing["4"], 69 68 paddingTop: spacing["4"], 69 + position: "sticky", 70 + bottom: 0, 71 + zIndex: 1, 72 + backgroundColor: uiColor.bg, 70 73 71 74 borderTopColor: uiColor.border1, 72 75 borderTopStyle: "solid",
+5 -3
apps/docs/src/components/listbox/index.tsx
··· 7 7 8 8 import * as stylex from "@stylexjs/stylex"; 9 9 import { Check } from "lucide-react"; 10 - import { createContext, use } from "react"; 10 + import { createContext, use, useContext, useRef } from "react"; 11 11 import { 12 12 ListBox as AriaListBox, 13 13 ListBoxItem as AriaListBoxItem, ··· 83 83 }: ListBoxProps<T>) { 84 84 const { trigger } = useHaptics(); 85 85 const size = sizeProp || use(SizeContext); 86 - 86 + const innerRef = useRef<HTMLDivElement>(null); 87 + const context = useContext(ListStateContext); 87 88 const handleSelectionChange = ( 88 89 keys: Parameters<NonNullable<typeof onSelectionChange>>[0], 89 90 ) => { ··· 99 100 const listbox = ( 100 101 <AriaListBox 101 102 {...props} 103 + ref={innerRef} 102 104 onSelectionChange={handleSelectionChange} 103 - onAction={handleAction} 105 + onAction={context ? undefined : handleAction} 104 106 {...stylex.props(styles.listBox, style)} 105 107 /> 106 108 );
+4
apps/docs/src/components/menubar/index.tsx
··· 39 39 position: "relative", 40 40 }, 41 41 button: { 42 + // eslint-disable-next-line @stylexjs/valid-styles 43 + textBoxEdge: "cap alphabetic", 44 + // eslint-disable-next-line @stylexjs/valid-styles 45 + textBoxTrim: "trim-both", 42 46 borderColor: "transparent", 43 47 borderRadius: radius.lg, 44 48 borderStyle: "solid",
+16 -2
apps/docs/src/components/segmented-control/index.tsx
··· 27 27 const styles = stylex.create({ 28 28 group: { 29 29 padding: spacing["1"], 30 - borderRadius: radius.xl, 31 30 32 31 cornerShape: "squircle", 33 32 gap: spacing["2"], ··· 42 41 ":is([data-size=sm])": spacing["7"], 43 42 }, 44 43 }, 44 + small: { 45 + borderRadius: radius.xl, 46 + }, 47 + large: { 48 + borderRadius: radius.lg, 49 + }, 45 50 item: { 51 + // eslint-disable-next-line @stylexjs/valid-styles 52 + textBoxEdge: "cap alphabetic", 53 + // eslint-disable-next-line @stylexjs/valid-styles 54 + textBoxTrim: "trim-both", 46 55 borderRadius: radius.lg, 47 56 borderWidth: 0, 48 57 ··· 56 65 ":is([data-selected])": uiColor.text2, 57 66 }, 58 67 display: "flex", 68 + gap: spacing["1"], 59 69 flexGrow: 1, 60 70 justifyContent: "center", 61 71 position: "relative", ··· 131 141 data-size={size} 132 142 onSelectionChange={handleSelectionChange} 133 143 {...props} 134 - {...stylex.props(styles.group, style)} 144 + {...stylex.props( 145 + styles.group, 146 + size === "sm" ? styles.small : styles.large, 147 + style, 148 + )} 135 149 > 136 150 {children} 137 151 </AriaToggleButtonGroup>
+9 -1
apps/docs/src/components/tag-group/index.tsx
··· 98 98 height: spacing["4"], 99 99 width: spacing["4"], 100 100 }, 101 + tagText: { 102 + // eslint-disable-next-line @stylexjs/valid-styles 103 + textBoxEdge: "cap alphabetic", 104 + // eslint-disable-next-line @stylexjs/valid-styles 105 + textBoxTrim: "trim-both", 106 + paddingBottom: spacing["0.5"], 107 + paddingTop: spacing["0.5"], 108 + }, 101 109 }); 102 110 103 111 interface TagGroupBaseProps<T> ··· 154 162 > 155 163 {({ allowsRemoving }) => ( 156 164 <> 157 - {children} 165 + <span {...stylex.props(styles.tagText)}>{children}</span> 158 166 {allowsRemoving && ( 159 167 <Button slot="remove" {...stylex.props(styles.removeButton)}> 160 168 <X size={12} />
+43 -6
apps/docs/src/components/theme/typography.stylex.tsx
··· 4 4 import { spacing } from "./spacing.stylex"; 5 5 6 6 export const fontFamily = stylex.defineVars({ 7 + title: "'Inter', sans-serif", 7 8 sans: "'Inter', sans-serif", 8 9 serif: "Georgia, serif", 9 10 mono: "Monaco, monospace", ··· 41 42 none: "1", 42 43 xs: "0.8", 43 44 sm: "1.25", 44 - base: "1.75", 45 + base: "1.65", 45 46 lg: "2", 46 47 xl: "2.5", 47 48 "2xl": "3", ··· 60 61 // eslint-disable-next-line @stylexjs/enforce-extension 61 62 export const typeramp = stylex.create({ 62 63 heading1: { 64 + // eslint-disable-next-line @stylexjs/valid-styles 65 + textBoxEdge: "cap alphabetic", 66 + // eslint-disable-next-line @stylexjs/valid-styles 67 + textBoxTrim: "trim-both", 63 68 margin: 0, 64 69 // eslint-disable-next-line @stylexjs/valid-styles 65 - fontFamily: fontFamily["sans"], 70 + fontFamily: fontFamily["title"], 66 71 fontSize: { 67 72 default: fontSize["4xl"], 68 73 [breakpoints.md]: fontSize["5xl"], ··· 74 79 scrollMarginBlockStart: spacing["20"], 75 80 }, 76 81 heading2: { 82 + // eslint-disable-next-line @stylexjs/valid-styles 83 + textBoxEdge: "cap alphabetic", 84 + // eslint-disable-next-line @stylexjs/valid-styles 85 + textBoxTrim: "trim-both", 77 86 margin: 0, 78 87 // eslint-disable-next-line @stylexjs/valid-styles 79 - fontFamily: fontFamily["sans"], 88 + fontFamily: fontFamily["title"], 80 89 fontSize: { 81 90 default: fontSize["3xl"], 82 91 [breakpoints.md]: fontSize["4xl"], ··· 89 98 borderBottomWidth: 1, 90 99 }, 91 100 heading3: { 101 + // eslint-disable-next-line @stylexjs/valid-styles 102 + textBoxEdge: "cap alphabetic", 103 + // eslint-disable-next-line @stylexjs/valid-styles 104 + textBoxTrim: "trim-both", 92 105 margin: 0, 93 106 // eslint-disable-next-line @stylexjs/valid-styles 94 - fontFamily: fontFamily["sans"], 107 + fontFamily: fontFamily["title"], 95 108 fontSize: { default: fontSize["2xl"] }, 96 109 // eslint-disable-next-line @stylexjs/valid-styles 97 110 fontWeight: fontWeight["semibold"], ··· 100 113 scrollMarginBlockStart: spacing["20"], 101 114 }, 102 115 heading4: { 116 + // eslint-disable-next-line @stylexjs/valid-styles 117 + textBoxEdge: "cap alphabetic", 118 + // eslint-disable-next-line @stylexjs/valid-styles 119 + textBoxTrim: "trim-both", 103 120 margin: 0, 104 121 // eslint-disable-next-line @stylexjs/valid-styles 105 - fontFamily: fontFamily["sans"], 122 + fontFamily: fontFamily["title"], 106 123 fontSize: { default: fontSize["xl"] }, 107 124 // eslint-disable-next-line @stylexjs/valid-styles 108 125 fontWeight: fontWeight["semibold"], ··· 111 128 scrollMarginBlockStart: spacing["20"], 112 129 }, 113 130 heading5: { 131 + // eslint-disable-next-line @stylexjs/valid-styles 132 + textBoxEdge: "cap alphabetic", 133 + // eslint-disable-next-line @stylexjs/valid-styles 134 + textBoxTrim: "trim-both", 114 135 margin: 0, 115 136 // eslint-disable-next-line @stylexjs/valid-styles 116 - fontFamily: fontFamily["sans"], 137 + fontFamily: fontFamily["title"], 117 138 fontSize: { default: fontSize["lg"] }, 118 139 // eslint-disable-next-line @stylexjs/valid-styles 119 140 fontWeight: fontWeight["semibold"], ··· 122 143 scrollMarginBlockStart: spacing["20"], 123 144 }, 124 145 body: { 146 + // eslint-disable-next-line @stylexjs/valid-styles 147 + textBoxEdge: "cap alphabetic", 148 + // eslint-disable-next-line @stylexjs/valid-styles 149 + textBoxTrim: "trim-both", 125 150 margin: 0, 126 151 // eslint-disable-next-line @stylexjs/valid-styles 127 152 fontFamily: fontFamily["sans"], ··· 129 154 lineHeight: lineHeight.base, 130 155 }, 131 156 smallBody: { 157 + // eslint-disable-next-line @stylexjs/valid-styles 158 + textBoxEdge: "cap alphabetic", 159 + // eslint-disable-next-line @stylexjs/valid-styles 160 + textBoxTrim: "trim-both", 132 161 margin: 0, 133 162 // eslint-disable-next-line @stylexjs/valid-styles 134 163 fontFamily: fontFamily["sans"], ··· 136 165 lineHeight: lineHeight.base, 137 166 }, 138 167 label: { 168 + // eslint-disable-next-line @stylexjs/valid-styles 169 + textBoxEdge: "cap alphabetic", 170 + // eslint-disable-next-line @stylexjs/valid-styles 171 + textBoxTrim: "trim-both", 139 172 margin: 0, 140 173 // eslint-disable-next-line @stylexjs/valid-styles 141 174 fontFamily: fontFamily["sans"], ··· 146 179 lineHeight: lineHeight.sm, 147 180 }, 148 181 sublabel: { 182 + // eslint-disable-next-line @stylexjs/valid-styles 183 + textBoxEdge: "cap alphabetic", 184 + // eslint-disable-next-line @stylexjs/valid-styles 185 + textBoxTrim: "trim-both", 149 186 margin: 0, 150 187 // eslint-disable-next-line @stylexjs/valid-styles 151 188 fontFamily: fontFamily["sans"],
+8 -4
apps/docs/src/components/theme/useButtonStyles.ts
··· 9 9 import { SizeContext } from "../context"; 10 10 import { animationDuration } from "./animations.stylex"; 11 11 import { uiColor } from "./color.stylex"; 12 - import { mediaQueries } from "./media-queries.stylex"; 13 12 import { radius } from "./radius.stylex"; 14 13 import { critical, primary, ui } from "./semantic-color.stylex"; 15 14 import { shadow } from "./shadow.stylex"; ··· 21 20 boxShadow: shadow["xs"], 22 21 }, 23 22 base: { 23 + // eslint-disable-next-line @stylexjs/valid-styles 24 + textBoxEdge: "cap alphabetic", 25 + // eslint-disable-next-line @stylexjs/valid-styles 26 + textBoxTrim: "trim-both", 27 + 24 28 borderRadius: radius.lg, 25 29 borderStyle: "solid", 26 30 borderWidth: 1, ··· 102 106 }, 103 107 secondary: { 104 108 borderColor: { 105 - default: uiColor.component1, 106 - ":is([data-hovered])": uiColor.component2, 107 - ":is([data-pressed])": uiColor.component3, 109 + default: uiColor.border1, 110 + ":is([data-hovered])": uiColor.border2, 111 + ":is([data-pressed])": uiColor.border3, 108 112 }, 109 113 }, 110 114 tertiary: {
+4 -1
apps/docs/src/components/theme/useListBoxItemStyles.ts
··· 14 14 } from "../theme/typography.stylex"; 15 15 import { animationDuration } from "./animations.stylex"; 16 16 import { criticalColor, primaryColor, uiColor } from "./color.stylex"; 17 - import { mediaQueries } from "./media-queries.stylex"; 18 17 19 18 const styles = stylex.create({ 20 19 item: { ··· 103 102 }, 104 103 }, 105 104 label: { 105 + // eslint-disable-next-line @stylexjs/valid-styles 106 + textBoxEdge: "cap alphabetic", 107 + // eslint-disable-next-line @stylexjs/valid-styles 108 + textBoxTrim: "trim-both", 106 109 gap: spacing["1.5"], 107 110 display: "flex", 108 111 flexDirection: "column",
-1
apps/docs/src/components/tree/index.tsx
··· 22 22 import { SizeContext } from "../context"; 23 23 import { animationDuration } from "../theme/animations.stylex"; 24 24 import { primaryColor } from "../theme/color.stylex"; 25 - import { mediaQueries } from "../theme/media-queries.stylex"; 26 25 import { radius } from "../theme/radius.stylex"; 27 26 import { ui } from "../theme/semantic-color.stylex"; 28 27 import { spacing } from "../theme/spacing.stylex";
+7
apps/docs/src/docs/components/overlays/dialog.mdx
··· 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/dialog/basic"; 9 9 import { DialogForm } from "../../../examples/dialog/form"; 10 + import { LongContentDialog } from "../../../examples/dialog/long-content"; 10 11 import { DialogSizes } from "../../../examples/dialog/sizes"; 11 12 12 13 <Example src={Basic} /> 14 + 15 + ### Long Content 16 + 17 + Dialogs can handle long-form content inside the body while keeping the surrounding chrome usable. 18 + 19 + <Example src={LongContentDialog} /> 13 20 14 21 ## Installation 15 22
+26 -11
apps/docs/src/examples/card/sizes.tsx
··· 1 - import { Card, CardBody, CardHeader, CardTitle } from "@/components/card"; 1 + import { 2 + Card, 3 + CardBody, 4 + CardHeader, 5 + CardImage, 6 + CardTitle, 7 + } from "@/components/card"; 2 8 import { Flex } from "@/components/flex"; 3 9 4 10 export function CardSizes() { 5 11 return ( 6 - <Flex gap="4" wrap> 12 + <Flex gap="4" wrap align="start"> 7 13 <Card size="sm"> 14 + <CardImage 15 + src="https://images.unsplash.com/photo-1602293589930-45aad59ba3ab?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=272&h=272&q=80&crop=entropy" 16 + alt="Beautiful landscape" 17 + aspectRatio={16 / 9} 18 + /> 8 19 <CardHeader> 9 20 <CardTitle>Small Card</CardTitle> 10 21 </CardHeader> 11 - <CardBody> 12 - <p>Small card content</p> 13 - </CardBody> 22 + <CardBody>Small card content</CardBody> 14 23 </Card> 15 24 <Card size="md"> 25 + <CardImage 26 + src="https://images.unsplash.com/photo-1602293589930-45aad59ba3ab?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=272&h=272&q=80&crop=entropy" 27 + alt="Beautiful landscape" 28 + aspectRatio={16 / 9} 29 + /> 16 30 <CardHeader> 17 31 <CardTitle>Medium Card</CardTitle> 18 32 </CardHeader> 19 - <CardBody> 20 - <p>Medium card content</p> 21 - </CardBody> 33 + <CardBody>Medium card content</CardBody> 22 34 </Card> 23 35 <Card size="lg"> 36 + <CardImage 37 + src="https://images.unsplash.com/photo-1602293589930-45aad59ba3ab?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=272&h=272&q=80&crop=entropy" 38 + alt="Beautiful landscape" 39 + aspectRatio={16 / 9} 40 + /> 24 41 <CardHeader> 25 42 <CardTitle>Large Card</CardTitle> 26 43 </CardHeader> 27 - <CardBody> 28 - <p>Large card content</p> 29 - </CardBody> 44 + <CardBody>Large card content</CardBody> 30 45 </Card> 31 46 </Flex> 32 47 );
+1
apps/docs/src/examples/combobox/basic.tsx
··· 12 12 label="Choose an option" 13 13 placeholder="Type to search..." 14 14 items={options} 15 + allowsCustomValue 15 16 > 16 17 {(item) => ( 17 18 <ComboBoxItem key={item.id} id={item.id}>
+41
apps/docs/src/examples/dialog/long-content.tsx
··· 1 + import { Button } from "@/components/button"; 2 + import { 3 + Dialog, 4 + DialogBody, 5 + DialogFooter, 6 + DialogHeader, 7 + } from "@/components/dialog"; 8 + import { Flex } from "@/components/flex"; 9 + import { Body } from "@/components/typography"; 10 + 11 + const paragraphs = [ 12 + "This example is intentionally long so you can verify that the dialog body scrolls independently while the header and footer remain easy to reach.", 13 + "Longer dialogs are useful for policies, onboarding steps, release notes, audit details, or any workflow where users need to review a lot of content before taking action.", 14 + "Keeping the content inside the dialog body also prevents the overall page from jumping unexpectedly when the modal opens on smaller screens.", 15 + "The header stays visible so the user always knows which task they are in, and the footer stays close at hand so the primary and secondary actions remain accessible.", 16 + "If your dialog contains a form, this same pattern helps users scroll through guidance, field groups, and validation messages without losing the submit actions.", 17 + "You can also combine long-form text with lists, media, tables, or sections as long as the core interaction still fits comfortably inside a modal experience.", 18 + "When content grows beyond a simple confirmation, it is usually a good idea to keep the title concise and let the body carry the detailed explanation.", 19 + "For especially dense content, consider splitting the experience into sections or steps so the modal does not feel overwhelming even when it needs to be comprehensive.", 20 + "This sample keeps the copy simple, but the important part is that the content is long enough to exercise overflow behavior in a realistic layout.", 21 + "After reviewing the content, the user can cancel or continue without needing to scroll all the way back to the top of the dialog.", 22 + ]; 23 + 24 + export function LongContentDialog() { 25 + return ( 26 + <Dialog trigger={<Button>Open Long Content Dialog</Button>}> 27 + <DialogHeader>Review Details</DialogHeader> 28 + <DialogBody> 29 + <Flex direction="column" gap="4"> 30 + {paragraphs.map((paragraph) => ( 31 + <Body key={paragraph}>{paragraph}</Body> 32 + ))} 33 + </Flex> 34 + </DialogBody> 35 + <DialogFooter> 36 + <Button variant="secondary">Close</Button> 37 + <Button>Continue</Button> 38 + </DialogFooter> 39 + </Dialog> 40 + ); 41 + }
+36 -18
apps/docs/src/routes/docs.$.tsx
··· 51 51 header: { 52 52 marginBottom: spacing["12"], 53 53 }, 54 + defaultMargin: { 55 + marginBottom: spacing["6"], 56 + marginTop: spacing["6"], 57 + }, 58 + h2: { 59 + marginBottom: spacing["8"], 60 + marginTop: spacing["12"], 61 + }, 62 + h3: { 63 + marginBottom: spacing["5"], 64 + marginTop: spacing["8"], 65 + }, 66 + h4: { 67 + marginBottom: spacing["8"], 68 + marginTop: spacing["8"], 69 + }, 70 + h5: { 71 + marginBottom: spacing["8"], 72 + marginTop: spacing["8"], 73 + }, 54 74 }); 55 75 56 76 function Link({ href, ...props }: LinkProps) { ··· 73 93 <Heading1 {...props} /> 74 94 ), 75 95 h2: ({ className: _className, style: _style, ...props }) => ( 76 - <LinkedHeading id={props.id}> 96 + <LinkedHeading id={props.id} style={styles.h2}> 77 97 <Heading2 {...props} /> 78 98 </LinkedHeading> 79 99 ), 80 100 h3: ({ className: _className, style: _style, ...props }) => ( 81 - <LinkedHeading id={props.id}> 101 + <LinkedHeading id={props.id} style={styles.h3}> 82 102 <Heading3 {...props} /> 83 103 </LinkedHeading> 84 104 ), 85 105 h4: ({ className: _className, style: _style, ...props }) => ( 86 - <LinkedHeading id={props.id}> 106 + <LinkedHeading id={props.id} style={styles.h4}> 87 107 <Heading4 {...props} /> 88 108 </LinkedHeading> 89 109 ), 90 110 h5: ({ className: _className, style: _style, ...props }) => ( 91 - <LinkedHeading id={props.id}> 111 + <LinkedHeading id={props.id} style={styles.h5}> 92 112 <Heading5 {...props} /> 93 113 </LinkedHeading> 94 114 ), 95 115 p: ({ className: _className, style: _style, ...props }) => ( 96 - <Body {...props} /> 116 + <Body {...props} style={styles.defaultMargin} /> 97 117 ), 98 118 a: ({ className: _className, style: _style, ...props }) => ( 99 119 <Link {...(props as LinkProps)} /> 100 120 ), 101 121 ul: ({ className: _className, style: _style, ...props }) => ( 102 - <UnorderedList {...props} /> 122 + <UnorderedList {...props} style={styles.defaultMargin} /> 103 123 ), 104 124 ol: ({ className: _className, style: _style, ...props }) => ( 105 - <OrderedList {...props} /> 125 + <OrderedList {...props} style={styles.defaultMargin} /> 106 126 ), 107 127 li: ({ className: _className, style: _style, ...props }) => ( 108 128 <ListItem {...props} /> 109 129 ), 110 130 pre: ({ className: _className, style: _style, ...props }) => ( 111 - <Pre {...props} /> 131 + <Pre {...props} style={styles.defaultMargin} /> 112 132 ), 113 133 code: ({ className: _className, style: _style, ...props }) => ( 114 134 <InlineCode {...props} /> 115 135 ), 116 136 blockquote: ({ className: _className, style: _style, ...props }) => ( 117 - <Blockquote {...props} /> 137 + <Blockquote {...props} style={styles.defaultMargin} /> 118 138 ), 119 139 }; 120 140 ··· 154 174 return ( 155 175 <> 156 176 <SidebarLayout.Page> 157 - <Content> 158 - <Flex direction="column" gap="4" style={styles.header}> 159 - <Heading1>{doc.title}</Heading1> 160 - <Text size="xl" variant="secondary"> 161 - {doc.description} 162 - </Text> 163 - </Flex> 164 - <Page components={components} /> 165 - </Content> 177 + <Flex direction="column" gap="6" style={styles.header}> 178 + <Heading1>{doc.title}</Heading1> 179 + <Text size="xl" variant="secondary"> 180 + {doc.description} 181 + </Text> 182 + </Flex> 183 + <Page components={components} /> 166 184 </SidebarLayout.Page> 167 185 168 186 {toc && (
+4 -17
packages/hip-ui/src/components/aspect-ratio/index.tsx
··· 2 2 3 3 import type { StyleXComponentProps } from "../theme/types"; 4 4 5 - import { mediaQueries } from "../theme/media-queries.stylex"; 6 5 import { radius } from "../theme/radius.stylex"; 7 6 8 7 const styles = stylex.create({ ··· 15 14 }, 16 15 rounded: { 17 16 cornerShape: "squircle", 18 - borderBottomLeftRadius: { 19 - default: radius.md, 20 - [mediaQueries.supportsSquircle]: radius["3xl"], 21 - }, 22 - borderBottomRightRadius: { 23 - default: radius.md, 24 - [mediaQueries.supportsSquircle]: radius["3xl"], 25 - }, 26 - borderTopLeftRadius: { 27 - default: radius.md, 28 - [mediaQueries.supportsSquircle]: radius["3xl"], 29 - }, 30 - borderTopRightRadius: { 31 - default: radius.md, 32 - [mediaQueries.supportsSquircle]: radius["3xl"], 33 - }, 17 + borderBottomLeftRadius: radius.lg, 18 + borderBottomRightRadius: radius.lg, 19 + borderTopLeftRadius: radius.lg, 20 + borderTopRightRadius: radius.lg, 34 21 }, 35 22 imageContainer: { 36 23 inset: 0,
+4
packages/hip-ui/src/components/button/index.tsx
··· 15 15 16 16 const styles = stylex.create({ 17 17 content: { 18 + // eslint-disable-next-line @stylexjs/valid-styles 19 + textBoxEdge: "cap alphabetic", 20 + // eslint-disable-next-line @stylexjs/valid-styles 21 + textBoxTrim: "trim-both", 18 22 gap: spacing["2"], 19 23 alignItems: "center", 20 24 display: "flex",
+27 -13
packages/hip-ui/src/components/card/index.tsx
··· 25 25 borderWidth: 1, 26 26 27 27 cornerShape: "squircle", 28 - gap: "var(--card-gap)", 29 28 overflow: "hidden", 30 29 boxShadow: shadow["sm"], 31 30 display: "flex", ··· 33 32 fontFamily: fontFamily["sans"], 34 33 35 34 "--card-gap": { 36 - ":is([data-card-size=lg])": spacing["9"], 37 - ":is([data-card-size=md])": spacing["6"], 38 - ":is([data-card-size=sm])": spacing["2"], 35 + ":is([data-card-size=lg])": spacing["4"], 36 + ":is([data-card-size=md])": spacing["4"], 37 + ":is([data-card-size=sm])": spacing["1"], 39 38 }, 40 39 "--card-x-padding": { 41 - ":is([data-card-size=lg])": spacing["9"], 40 + ":is([data-card-size=lg])": spacing["8"], 42 41 ":is([data-card-size=md])": spacing["6"], 43 - ":is([data-card-size=sm])": spacing["2"], 42 + ":is([data-card-size=sm])": spacing["3"], 44 43 }, 45 44 "--card-y-padding": { 46 - ":is([data-card-size=lg])": spacing["10"], 47 - ":is([data-card-size=md])": spacing["7"], 48 - ":is([data-card-size=sm])": spacing["2"], 45 + ":is([data-card-size=lg])": spacing["8"], 46 + ":is([data-card-size=md])": spacing["6"], 47 + ":is([data-card-size=sm])": spacing["3"], 49 48 }, 50 49 }, 51 50 cardSection: { 52 51 boxSizing: "border-box", 53 - paddingBottom: { ":last-child": "var(--card-y-padding)" }, 52 + paddingBottom: { 53 + default: "var(--card-gap)", 54 + ":last-child": "var(--card-y-padding)", 55 + }, 54 56 paddingLeft: "var(--card-x-padding)", 55 57 paddingRight: "var(--card-x-padding)", 56 58 paddingTop: { ":first-child": "var(--card-y-padding)" }, ··· 63 65 'description action' 64 66 `, 65 67 }, 66 - gap: "calc(var(--card-gap) * 0.25)", 68 + gap: "calc(var(--card-gap) * 0.5)", 67 69 alignItems: "center", 68 70 display: "grid", 69 71 }, ··· 80 82 justifyContent: "flex-end", 81 83 }, 82 84 cardTitle: { 85 + // eslint-disable-next-line @stylexjs/valid-styles 86 + textBoxEdge: "cap alphabetic", 87 + // eslint-disable-next-line @stylexjs/valid-styles 88 + textBoxTrim: "trim-both", 83 89 gridArea: "title", 84 90 gap: spacing["3"], 85 91 alignItems: "center", ··· 87 93 fontSize: { 88 94 ":is([data-card-size='lg'] *)": fontSize["2xl"], 89 95 ":is([data-card-size='md'] *)": fontSize["xl"], 90 - ":is([data-card-size='sm'] *)": fontSize["lg"], 96 + ":is([data-card-size='sm'] *)": fontSize["base"], 91 97 }, 92 98 fontWeight: fontWeight["bold"], 93 99 }, ··· 99 105 lineHeight: lineHeight["sm"], 100 106 }, 101 107 cardBody: { 108 + // eslint-disable-next-line @stylexjs/valid-styles 109 + textBoxEdge: "cap alphabetic", 110 + // eslint-disable-next-line @stylexjs/valid-styles 111 + textBoxTrim: "trim-both", 102 112 gap: "calc(var(--card-gap) * 0.5)", 103 113 display: "flex", 104 114 flexDirection: "column", 105 - lineHeight: lineHeight["lg"], 115 + fontSize: { 116 + ":is([data-card-size='lg'] *)": fontSize["lg"], 117 + ":is([data-card-size='sm'] *)": fontSize["xs"], 118 + }, 106 119 }, 107 120 cardFooter: { 108 121 gap: spacing["2"], ··· 115 128 borderBottomRightRadius: { default: 0, ":last-child": radius.md }, 116 129 borderTopLeftRadius: { default: 0, ":first-child": radius.md }, 117 130 borderTopRightRadius: { default: 0, ":first-child": radius.md }, 131 + marginBottom: "var(--card-y-padding)", 118 132 }, 119 133 }); 120 134
+1
packages/hip-ui/src/components/combobox/index.tsx
··· 38 38 39 39 const styles = stylex.create({ 40 40 matchWidth: { 41 + minWidth: 180, 41 42 width: "var(--trigger-width)", 42 43 }, 43 44 emptyState: {
+5 -2
packages/hip-ui/src/components/dialog/index.tsx
··· 24 24 const styles = stylex.create({ 25 25 dialog: { 26 26 overflow: "auto", 27 - paddingBottom: spacing["2"], 28 27 }, 29 28 header: { 30 29 gap: spacing["2"], ··· 63 62 gap: spacing["2"], 64 63 display: "flex", 65 64 justifyContent: "flex-end", 66 - paddingBottom: spacing["2"], 65 + paddingBottom: spacing["4"], 67 66 paddingLeft: spacing["4"], 68 67 paddingRight: spacing["4"], 69 68 paddingTop: spacing["4"], 69 + position: "sticky", 70 + bottom: 0, 71 + zIndex: 1, 72 + backgroundColor: uiColor.bg, 70 73 71 74 borderTopColor: uiColor.border1, 72 75 borderTopStyle: "solid",
+5 -3
packages/hip-ui/src/components/listbox/index.tsx
··· 7 7 8 8 import * as stylex from "@stylexjs/stylex"; 9 9 import { Check } from "lucide-react"; 10 - import { createContext, use } from "react"; 10 + import { createContext, use, useContext, useRef } from "react"; 11 11 import { 12 12 ListBox as AriaListBox, 13 13 ListBoxItem as AriaListBoxItem, ··· 83 83 }: ListBoxProps<T>) { 84 84 const { trigger } = useHaptics(); 85 85 const size = sizeProp || use(SizeContext); 86 - 86 + const innerRef = useRef<HTMLDivElement>(null); 87 + const context = useContext(ListStateContext); 87 88 const handleSelectionChange = ( 88 89 keys: Parameters<NonNullable<typeof onSelectionChange>>[0], 89 90 ) => { ··· 99 100 const listbox = ( 100 101 <AriaListBox 101 102 {...props} 103 + ref={innerRef} 102 104 onSelectionChange={handleSelectionChange} 103 - onAction={handleAction} 105 + onAction={context ? undefined : handleAction} 104 106 {...stylex.props(styles.listBox, style)} 105 107 /> 106 108 );
+4
packages/hip-ui/src/components/menubar/index.tsx
··· 39 39 position: "relative", 40 40 }, 41 41 button: { 42 + // eslint-disable-next-line @stylexjs/valid-styles 43 + textBoxEdge: "cap alphabetic", 44 + // eslint-disable-next-line @stylexjs/valid-styles 45 + textBoxTrim: "trim-both", 42 46 borderColor: "transparent", 43 47 borderRadius: radius.lg, 44 48 borderStyle: "solid",
+16 -2
packages/hip-ui/src/components/segmented-control/index.tsx
··· 27 27 const styles = stylex.create({ 28 28 group: { 29 29 padding: spacing["1"], 30 - borderRadius: radius.xl, 31 30 32 31 cornerShape: "squircle", 33 32 gap: spacing["2"], ··· 42 41 ":is([data-size=sm])": spacing["7"], 43 42 }, 44 43 }, 44 + small: { 45 + borderRadius: radius.xl, 46 + }, 47 + large: { 48 + borderRadius: radius.lg, 49 + }, 45 50 item: { 51 + // eslint-disable-next-line @stylexjs/valid-styles 52 + textBoxEdge: "cap alphabetic", 53 + // eslint-disable-next-line @stylexjs/valid-styles 54 + textBoxTrim: "trim-both", 46 55 borderRadius: radius.lg, 47 56 borderWidth: 0, 48 57 ··· 56 65 ":is([data-selected])": uiColor.text2, 57 66 }, 58 67 display: "flex", 68 + gap: spacing["1"], 59 69 flexGrow: 1, 60 70 justifyContent: "center", 61 71 position: "relative", ··· 131 141 data-size={size} 132 142 onSelectionChange={handleSelectionChange} 133 143 {...props} 134 - {...stylex.props(styles.group, style)} 144 + {...stylex.props( 145 + styles.group, 146 + size === "sm" ? styles.small : styles.large, 147 + style, 148 + )} 135 149 > 136 150 {children} 137 151 </AriaToggleButtonGroup>
+9 -1
packages/hip-ui/src/components/tag-group/index.tsx
··· 98 98 height: spacing["4"], 99 99 width: spacing["4"], 100 100 }, 101 + tagText: { 102 + // eslint-disable-next-line @stylexjs/valid-styles 103 + textBoxEdge: "cap alphabetic", 104 + // eslint-disable-next-line @stylexjs/valid-styles 105 + textBoxTrim: "trim-both", 106 + paddingBottom: spacing["0.5"], 107 + paddingTop: spacing["0.5"], 108 + }, 101 109 }); 102 110 103 111 interface TagGroupBaseProps<T> ··· 154 162 > 155 163 {({ allowsRemoving }) => ( 156 164 <> 157 - {children} 165 + <span {...stylex.props(styles.tagText)}>{children}</span> 158 166 {allowsRemoving && ( 159 167 <Button slot="remove" {...stylex.props(styles.removeButton)}> 160 168 <X size={12} />
+43 -6
packages/hip-ui/src/components/theme/typography.stylex.tsx
··· 4 4 import { spacing } from "./spacing.stylex"; 5 5 6 6 export const fontFamily = stylex.defineVars({ 7 + title: "'Inter', sans-serif", 7 8 sans: "'Inter', sans-serif", 8 9 serif: "Georgia, serif", 9 10 mono: "Monaco, monospace", ··· 41 42 none: "1", 42 43 xs: "0.8", 43 44 sm: "1.25", 44 - base: "1.75", 45 + base: "1.65", 45 46 lg: "2", 46 47 xl: "2.5", 47 48 "2xl": "3", ··· 60 61 // eslint-disable-next-line @stylexjs/enforce-extension 61 62 export const typeramp = stylex.create({ 62 63 heading1: { 64 + // eslint-disable-next-line @stylexjs/valid-styles 65 + textBoxEdge: "cap alphabetic", 66 + // eslint-disable-next-line @stylexjs/valid-styles 67 + textBoxTrim: "trim-both", 63 68 margin: 0, 64 69 // eslint-disable-next-line @stylexjs/valid-styles 65 - fontFamily: fontFamily["sans"], 70 + fontFamily: fontFamily["title"], 66 71 fontSize: { 67 72 default: fontSize["4xl"], 68 73 [breakpoints.md]: fontSize["5xl"], ··· 74 79 scrollMarginBlockStart: spacing["20"], 75 80 }, 76 81 heading2: { 82 + // eslint-disable-next-line @stylexjs/valid-styles 83 + textBoxEdge: "cap alphabetic", 84 + // eslint-disable-next-line @stylexjs/valid-styles 85 + textBoxTrim: "trim-both", 77 86 margin: 0, 78 87 // eslint-disable-next-line @stylexjs/valid-styles 79 - fontFamily: fontFamily["sans"], 88 + fontFamily: fontFamily["title"], 80 89 fontSize: { 81 90 default: fontSize["3xl"], 82 91 [breakpoints.md]: fontSize["4xl"], ··· 89 98 borderBottomWidth: 1, 90 99 }, 91 100 heading3: { 101 + // eslint-disable-next-line @stylexjs/valid-styles 102 + textBoxEdge: "cap alphabetic", 103 + // eslint-disable-next-line @stylexjs/valid-styles 104 + textBoxTrim: "trim-both", 92 105 margin: 0, 93 106 // eslint-disable-next-line @stylexjs/valid-styles 94 - fontFamily: fontFamily["sans"], 107 + fontFamily: fontFamily["title"], 95 108 fontSize: { default: fontSize["2xl"] }, 96 109 // eslint-disable-next-line @stylexjs/valid-styles 97 110 fontWeight: fontWeight["semibold"], ··· 100 113 scrollMarginBlockStart: spacing["20"], 101 114 }, 102 115 heading4: { 116 + // eslint-disable-next-line @stylexjs/valid-styles 117 + textBoxEdge: "cap alphabetic", 118 + // eslint-disable-next-line @stylexjs/valid-styles 119 + textBoxTrim: "trim-both", 103 120 margin: 0, 104 121 // eslint-disable-next-line @stylexjs/valid-styles 105 - fontFamily: fontFamily["sans"], 122 + fontFamily: fontFamily["title"], 106 123 fontSize: { default: fontSize["xl"] }, 107 124 // eslint-disable-next-line @stylexjs/valid-styles 108 125 fontWeight: fontWeight["semibold"], ··· 111 128 scrollMarginBlockStart: spacing["20"], 112 129 }, 113 130 heading5: { 131 + // eslint-disable-next-line @stylexjs/valid-styles 132 + textBoxEdge: "cap alphabetic", 133 + // eslint-disable-next-line @stylexjs/valid-styles 134 + textBoxTrim: "trim-both", 114 135 margin: 0, 115 136 // eslint-disable-next-line @stylexjs/valid-styles 116 - fontFamily: fontFamily["sans"], 137 + fontFamily: fontFamily["title"], 117 138 fontSize: { default: fontSize["lg"] }, 118 139 // eslint-disable-next-line @stylexjs/valid-styles 119 140 fontWeight: fontWeight["semibold"], ··· 122 143 scrollMarginBlockStart: spacing["20"], 123 144 }, 124 145 body: { 146 + // eslint-disable-next-line @stylexjs/valid-styles 147 + textBoxEdge: "cap alphabetic", 148 + // eslint-disable-next-line @stylexjs/valid-styles 149 + textBoxTrim: "trim-both", 125 150 margin: 0, 126 151 // eslint-disable-next-line @stylexjs/valid-styles 127 152 fontFamily: fontFamily["sans"], ··· 129 154 lineHeight: lineHeight.base, 130 155 }, 131 156 smallBody: { 157 + // eslint-disable-next-line @stylexjs/valid-styles 158 + textBoxEdge: "cap alphabetic", 159 + // eslint-disable-next-line @stylexjs/valid-styles 160 + textBoxTrim: "trim-both", 132 161 margin: 0, 133 162 // eslint-disable-next-line @stylexjs/valid-styles 134 163 fontFamily: fontFamily["sans"], ··· 136 165 lineHeight: lineHeight.base, 137 166 }, 138 167 label: { 168 + // eslint-disable-next-line @stylexjs/valid-styles 169 + textBoxEdge: "cap alphabetic", 170 + // eslint-disable-next-line @stylexjs/valid-styles 171 + textBoxTrim: "trim-both", 139 172 margin: 0, 140 173 // eslint-disable-next-line @stylexjs/valid-styles 141 174 fontFamily: fontFamily["sans"], ··· 146 179 lineHeight: lineHeight.sm, 147 180 }, 148 181 sublabel: { 182 + // eslint-disable-next-line @stylexjs/valid-styles 183 + textBoxEdge: "cap alphabetic", 184 + // eslint-disable-next-line @stylexjs/valid-styles 185 + textBoxTrim: "trim-both", 149 186 margin: 0, 150 187 // eslint-disable-next-line @stylexjs/valid-styles 151 188 fontFamily: fontFamily["sans"],
+8 -4
packages/hip-ui/src/components/theme/useButtonStyles.ts
··· 9 9 import { SizeContext } from "../context"; 10 10 import { animationDuration } from "./animations.stylex"; 11 11 import { uiColor } from "./color.stylex"; 12 - import { mediaQueries } from "./media-queries.stylex"; 13 12 import { radius } from "./radius.stylex"; 14 13 import { critical, primary, ui } from "./semantic-color.stylex"; 15 14 import { shadow } from "./shadow.stylex"; ··· 21 20 boxShadow: shadow["xs"], 22 21 }, 23 22 base: { 23 + // eslint-disable-next-line @stylexjs/valid-styles 24 + textBoxEdge: "cap alphabetic", 25 + // eslint-disable-next-line @stylexjs/valid-styles 26 + textBoxTrim: "trim-both", 27 + 24 28 borderRadius: radius.lg, 25 29 borderStyle: "solid", 26 30 borderWidth: 1, ··· 102 106 }, 103 107 secondary: { 104 108 borderColor: { 105 - default: uiColor.component1, 106 - ":is([data-hovered])": uiColor.component2, 107 - ":is([data-pressed])": uiColor.component3, 109 + default: uiColor.border1, 110 + ":is([data-hovered])": uiColor.border2, 111 + ":is([data-pressed])": uiColor.border3, 108 112 }, 109 113 }, 110 114 tertiary: {
+4 -1
packages/hip-ui/src/components/theme/useListBoxItemStyles.ts
··· 14 14 } from "../theme/typography.stylex"; 15 15 import { animationDuration } from "./animations.stylex"; 16 16 import { criticalColor, primaryColor, uiColor } from "./color.stylex"; 17 - import { mediaQueries } from "./media-queries.stylex"; 18 17 19 18 const styles = stylex.create({ 20 19 item: { ··· 103 102 }, 104 103 }, 105 104 label: { 105 + // eslint-disable-next-line @stylexjs/valid-styles 106 + textBoxEdge: "cap alphabetic", 107 + // eslint-disable-next-line @stylexjs/valid-styles 108 + textBoxTrim: "trim-both", 106 109 gap: spacing["1.5"], 107 110 display: "flex", 108 111 flexDirection: "column",
-1
packages/hip-ui/src/components/tree/index.tsx
··· 22 22 import { SizeContext } from "../context"; 23 23 import { animationDuration } from "../theme/animations.stylex"; 24 24 import { primaryColor } from "../theme/color.stylex"; 25 - import { mediaQueries } from "../theme/media-queries.stylex"; 26 25 import { radius } from "../theme/radius.stylex"; 27 26 import { ui } from "../theme/semantic-color.stylex"; 28 27 import { spacing } from "../theme/spacing.stylex";