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.

disclosure

+520 -3
+2 -1
.cursor/rules/hip-component.mdc
··· 15 15 7. Run `pnpm hip install --all` in the apps/docs dir 16 16 8. Generate and .mdx page with example in apps/docs 17 17 18 - ## Rules 18 + ## Rules for Components 19 19 20 20 - Prefer using packages/hip-ui/src/components/flex and packages/hip-ui/src/components/grid over css for things layout related 21 21 - Use icon from lucide-react 22 22 - Prefer re-using existing component rather than redefining them 23 + - For composite components use the size prop only on the root element. otherwise use css to stylex for different sizes
+2 -2
README.md
··· 35 35 - [ ] Drawer 36 36 - [ ] Sheet 37 37 38 - - [ ] Disclosure 39 38 - [ ] Disclosure Group 40 39 - [ ] Form 41 40 - [ ] Grid List 42 41 - [ ] Menubar 43 42 - [ ] Navigation Menu 44 - - [ ] Spinner 45 43 - [ ] Tabs 46 44 - [ ] Toolbar 47 45 - [ ] Toast ··· 53 51 54 52 ### Done 55 53 54 + - [x] Disclosure 55 + - [x] Spinner 56 56 - [x] Input Group 57 57 - [x] Breadcrumb 58 58 - [x] Range Date Picker
+171
apps/docs/src/components/disclosure/index.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + import { ChevronDown, PanelBottom } from "lucide-react"; 3 + import { use } from "react"; 4 + import { 5 + Disclosure as AriaDisclosure, 6 + DisclosureProps as AriaDisclosureProps, 7 + DisclosurePanel as AriaDisclosurePanel, 8 + DisclosurePanelProps as AriaDisclosurePanelProps, 9 + Button, 10 + ButtonProps as AriaButtonProps, 11 + } from "react-aria-components"; 12 + 13 + import { SizeContext } from "../context"; 14 + import { animationDuration } from "../theme/animations.stylex"; 15 + import { mediaQueries } from "../theme/media-queries.stylex"; 16 + import { radius } from "../theme/radius.stylex"; 17 + import { uiColor } from "../theme/semantic-color.stylex"; 18 + import { spacing } from "../theme/spacing.stylex"; 19 + import { Size, StyleXComponentProps } from "../theme/types"; 20 + import { fontFamily, fontSize, fontWeight } from "../theme/typography.stylex"; 21 + 22 + const styles = stylex.create({ 23 + disclosure: { 24 + display: "flex", 25 + flexDirection: "column", 26 + }, 27 + title: { 28 + alignItems: "center", 29 + backgroundColor: { 30 + default: "transparent", 31 + ":is([data-hovered=true])": uiColor.component2, 32 + ":is([data-pressed=true])": uiColor.component3, 33 + }, 34 + borderRadius: radius["md"], 35 + borderWidth: 0, 36 + color: uiColor.text1, 37 + cursor: "pointer", 38 + display: "flex", 39 + fontFamily: fontFamily["sans"], 40 + fontSize: { 41 + ":is([data-size=sm] *)": fontSize["sm"], 42 + ":is([data-size=md] *)": fontSize["base"], 43 + ":is([data-size=lg] *)": fontSize["lg"], 44 + }, 45 + fontWeight: fontWeight["medium"], 46 + gap: spacing["2"], 47 + justifyContent: "space-between", 48 + padding: { 49 + ":is([data-size=sm] *)": `${spacing["2"]} ${spacing["3"]}`, 50 + ":is([data-size=md] *)": `${spacing["3"]} ${spacing["4"]}`, 51 + ":is([data-size=lg] *)": `${spacing["4"]} ${spacing["5"]}`, 52 + }, 53 + textAlign: "left", 54 + transitionDuration: animationDuration.fast, 55 + transitionProperty: { 56 + default: "background-color", 57 + [mediaQueries.reducedMotion]: "none", 58 + }, 59 + transitionTimingFunction: "ease-in-out", 60 + width: "100%", 61 + }, 62 + titleDisabled: { 63 + opacity: 0.5, 64 + pointerEvents: "none", 65 + }, 66 + chevron: { 67 + color: uiColor.text2, 68 + flexShrink: 0, 69 + rotate: { 70 + default: "0deg", 71 + ":is([aria-expanded=true] *)": "180deg", 72 + }, 73 + transition: { 74 + default: "rotate 200ms ease-in-out", 75 + [mediaQueries.reducedMotion]: "none", 76 + }, 77 + }, 78 + panel: { 79 + fontSize: { 80 + ":is([data-size=sm] *)": fontSize["sm"], 81 + ":is([data-size=md] *)": fontSize["base"], 82 + ":is([data-size=lg] *)": fontSize["lg"], 83 + }, 84 + height: "var(--disclosure-panel-height)", 85 + overflow: "clip", 86 + transitionDuration: { 87 + default: animationDuration.default, 88 + [mediaQueries.reducedMotion]: 0, 89 + }, 90 + transitionProperty: "height", 91 + transitionTimingFunction: "ease-in-out", 92 + }, 93 + panelContent: { 94 + padding: { 95 + ":is([data-size=sm] *)": `${spacing["2"]} ${spacing["3"]}`, 96 + ":is([data-size=md] *)": `${spacing["3"]} ${spacing["4"]}`, 97 + ":is([data-size=lg] *)": `${spacing["4"]} ${spacing["5"]}`, 98 + }, 99 + }, 100 + }); 101 + 102 + export interface DisclosureProps 103 + extends StyleXComponentProps<Omit<AriaDisclosureProps, "children">> { 104 + children: React.ReactNode; 105 + size?: Size; 106 + } 107 + 108 + export function Disclosure({ 109 + children, 110 + style, 111 + size: sizeProp, 112 + ...props 113 + }: DisclosureProps) { 114 + const size = sizeProp || use(SizeContext); 115 + 116 + return ( 117 + <SizeContext value={size}> 118 + <AriaDisclosure 119 + {...props} 120 + data-size={size} 121 + {...stylex.props(styles.disclosure, style)} 122 + > 123 + {children} 124 + </AriaDisclosure> 125 + </SizeContext> 126 + ); 127 + } 128 + 129 + export interface DisclosureTitleProps 130 + extends StyleXComponentProps<Omit<AriaButtonProps, "slot" | "children">> { 131 + children: React.ReactNode; 132 + } 133 + 134 + export function DisclosureTitle({ 135 + children, 136 + style, 137 + ...props 138 + }: DisclosureTitleProps) { 139 + return ( 140 + <Button 141 + {...props} 142 + slot="trigger" 143 + {...stylex.props( 144 + styles.title, 145 + props.isDisabled && styles.titleDisabled, 146 + style, 147 + )} 148 + > 149 + {children} 150 + <ChevronDown size={16} {...stylex.props(styles.chevron)} /> 151 + </Button> 152 + ); 153 + } 154 + 155 + export interface DisclosurePanelProps 156 + extends StyleXComponentProps<Omit<AriaDisclosurePanelProps, "children">> { 157 + children: React.ReactNode; 158 + isQuiet?: boolean; 159 + } 160 + 161 + export function DisclosurePanel({ 162 + children, 163 + style, 164 + ...props 165 + }: DisclosurePanelProps) { 166 + return ( 167 + <AriaDisclosurePanel {...props} {...stylex.props(styles.panel, style)}> 168 + <div {...stylex.props(styles.panelContent)}>{children}</div> 169 + </AriaDisclosurePanel> 170 + ); 171 + }
+55
apps/docs/src/docs/components/disclosure.mdx
··· 1 + --- 2 + title: Disclosure 3 + description: A collapsible section of content composed of a heading that expands and collapses a panel. 4 + --- 5 + 6 + import { PropDocs } from '../../lib/PropDocs' 7 + import { Example } from '../../lib/Example' 8 + import { Basic } from '../../examples/disclosure/basic' 9 + import { Expanded } from '../../examples/disclosure/expanded' 10 + import { Disabled } from '../../examples/disclosure/disabled' 11 + import { Sizes } from '../../examples/disclosure/sizes' 12 + 13 + <Example src={Basic} /> 14 + 15 + ## Installation 16 + 17 + Run the following command to add the disclosure component to your project. 18 + 19 + ```bash 20 + pnpm hip install disclosure 21 + ``` 22 + 23 + ## Props 24 + 25 + This component is built using the [React Aria Disclosure](https://react-spectrum.adobe.com/react-aria/Disclosure.html). 26 + 27 + <PropDocs components={["Disclosure", "DisclosureTitle", "DisclosurePanel"]} /> 28 + 29 + ## Features 30 + 31 + ### Expanded 32 + 33 + Disclosure can be expanded by default using the `defaultExpanded` prop. 34 + 35 + <Example src={Expanded} /> 36 + 37 + ### Disabled State 38 + 39 + Disclosure can be disabled to prevent interaction. 40 + 41 + <Example src={Disabled} /> 42 + 43 + 44 + ### Sizes 45 + 46 + Disclosure supports three different sizes: small, medium, and large. 47 + 48 + <Example src={Sizes} /> 49 + 50 + ## Related Components 51 + 52 + - [Accordion](/docs/components/accordion) - For multiple collapsible sections 53 + - [Dialog](/docs/components/dialog) - For modal content 54 + - [Popover](/docs/components/popover) - For overlay content 55 +
+25
apps/docs/src/examples/disclosure/basic.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + import { 4 + Disclosure, 5 + DisclosurePanel, 6 + DisclosureTitle, 7 + } from "@/components/disclosure"; 8 + 9 + const styles = stylex.create({ 10 + root: { 11 + width: "100%", 12 + }, 13 + }); 14 + 15 + export function Basic() { 16 + return ( 17 + <Disclosure style={styles.root}> 18 + <DisclosureTitle>System Requirements</DisclosureTitle> 19 + <DisclosurePanel> 20 + Details about system requirements here. Minimum system requirements 21 + include Windows 10 or macOS 10.15 or later. 22 + </DisclosurePanel> 23 + </Disclosure> 24 + ); 25 + }
+14
apps/docs/src/examples/disclosure/disabled.tsx
··· 1 + import { Disclosure, DisclosurePanel, DisclosureTitle } from "@/components/disclosure"; 2 + 3 + export function Disabled() { 4 + return ( 5 + <Disclosure> 6 + <DisclosureTitle isDisabled>System Requirements</DisclosureTitle> 7 + <DisclosurePanel> 8 + Details about system requirements here. 9 + Minimum system requirements include Windows 10 or macOS 10.15 or later. 10 + </DisclosurePanel> 11 + </Disclosure> 12 + ); 13 + } 14 +
+14
apps/docs/src/examples/disclosure/expanded.tsx
··· 1 + import { Disclosure, DisclosurePanel, DisclosureTitle } from "@/components/disclosure"; 2 + 3 + export function Expanded() { 4 + return ( 5 + <Disclosure defaultExpanded> 6 + <DisclosureTitle>System Requirements</DisclosureTitle> 7 + <DisclosurePanel> 8 + Details about system requirements here. 9 + Minimum system requirements include Windows 10 or macOS 10.15 or later. 10 + </DisclosurePanel> 11 + </Disclosure> 12 + ); 13 + } 14 +
+44
apps/docs/src/examples/disclosure/sizes.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + import { 4 + Disclosure, 5 + DisclosurePanel, 6 + DisclosureTitle, 7 + } from "@/components/disclosure"; 8 + import { Flex } from "@/components/flex"; 9 + 10 + const styles = stylex.create({ 11 + root: { 12 + width: "100%", 13 + }, 14 + }); 15 + 16 + export function Sizes() { 17 + return ( 18 + <Flex direction="column" gap="4" style={styles.root}> 19 + <Disclosure size="sm"> 20 + <DisclosureTitle>Small Disclosure</DisclosureTitle> 21 + <DisclosurePanel> 22 + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, 23 + quos. 24 + </DisclosurePanel> 25 + </Disclosure> 26 + 27 + <Disclosure size="md"> 28 + <DisclosureTitle>Medium Disclosure</DisclosureTitle> 29 + <DisclosurePanel> 30 + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, 31 + quos. 32 + </DisclosurePanel> 33 + </Disclosure> 34 + 35 + <Disclosure size="lg"> 36 + <DisclosureTitle>Large Disclosure</DisclosureTitle> 37 + <DisclosurePanel> 38 + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, 39 + quos. 40 + </DisclosurePanel> 41 + </Disclosure> 42 + </Flex> 43 + ); 44 + }
+2
packages/hip-ui/src/cli/install.tsx
··· 32 32 import { datePickerConfig } from "../components/date-picker/date-picker-config.js"; 33 33 import { dateRangePickerConfig } from "../components/date-range-picker/date-range-picker-config.js"; 34 34 import { dialogConfig } from "../components/dialog/dialog-config.js"; 35 + import { disclosureConfig } from "../components/disclosure/disclosure-config.js"; 35 36 import { fileDropZoneConfig } from "../components/file-drop-zone/file-drop-zone-config.js"; 36 37 import { flexConfig } from "../components/flex/flex-config.js"; 37 38 import { gridConfig } from "../components/grid/grid-config.js"; ··· 106 107 commandMenuConfig, 107 108 alertDialogConfig, 108 109 dialogConfig, 110 + disclosureConfig, 109 111 avatarConfig, 110 112 badgeConfig, 111 113 breadcrumbsConfig,
+20
packages/hip-ui/src/components/disclosure/disclosure-config.ts
··· 1 + import { ComponentConfig } from "../../types"; 2 + 3 + export const disclosureConfig: ComponentConfig = { 4 + name: "disclosure", 5 + filepath: "./index.tsx", 6 + hipDependencies: [ 7 + "../theme/semantic-color.stylex.tsx", 8 + "../theme/spacing.stylex.tsx", 9 + "../theme/typography.stylex.tsx", 10 + "../theme/radius.stylex.tsx", 11 + "../theme/animations.stylex.tsx", 12 + "../theme/media-queries.stylex.tsx", 13 + "../context.ts", 14 + ], 15 + dependencies: { 16 + "react-aria-components": "^1.13.0", 17 + "lucide-react": "^0.263.1", 18 + }, 19 + }; 20 +
+171
packages/hip-ui/src/components/disclosure/index.tsx
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + import { ChevronDown, PanelBottom } from "lucide-react"; 3 + import { use } from "react"; 4 + import { 5 + Disclosure as AriaDisclosure, 6 + DisclosureProps as AriaDisclosureProps, 7 + DisclosurePanel as AriaDisclosurePanel, 8 + DisclosurePanelProps as AriaDisclosurePanelProps, 9 + Button, 10 + ButtonProps as AriaButtonProps, 11 + } from "react-aria-components"; 12 + 13 + import { SizeContext } from "../context"; 14 + import { animationDuration } from "../theme/animations.stylex"; 15 + import { mediaQueries } from "../theme/media-queries.stylex"; 16 + import { radius } from "../theme/radius.stylex"; 17 + import { uiColor } from "../theme/semantic-color.stylex"; 18 + import { spacing } from "../theme/spacing.stylex"; 19 + import { Size, StyleXComponentProps } from "../theme/types"; 20 + import { fontFamily, fontSize, fontWeight } from "../theme/typography.stylex"; 21 + 22 + const styles = stylex.create({ 23 + disclosure: { 24 + display: "flex", 25 + flexDirection: "column", 26 + }, 27 + title: { 28 + alignItems: "center", 29 + backgroundColor: { 30 + default: "transparent", 31 + ":is([data-hovered=true])": uiColor.component2, 32 + ":is([data-pressed=true])": uiColor.component3, 33 + }, 34 + borderRadius: radius["md"], 35 + borderWidth: 0, 36 + color: uiColor.text1, 37 + cursor: "pointer", 38 + display: "flex", 39 + fontFamily: fontFamily["sans"], 40 + fontSize: { 41 + ":is([data-size=sm] *)": fontSize["sm"], 42 + ":is([data-size=md] *)": fontSize["base"], 43 + ":is([data-size=lg] *)": fontSize["lg"], 44 + }, 45 + fontWeight: fontWeight["medium"], 46 + gap: spacing["2"], 47 + justifyContent: "space-between", 48 + padding: { 49 + ":is([data-size=sm] *)": `${spacing["2"]} ${spacing["3"]}`, 50 + ":is([data-size=md] *)": `${spacing["3"]} ${spacing["4"]}`, 51 + ":is([data-size=lg] *)": `${spacing["4"]} ${spacing["5"]}`, 52 + }, 53 + textAlign: "left", 54 + transitionDuration: animationDuration.fast, 55 + transitionProperty: { 56 + default: "background-color", 57 + [mediaQueries.reducedMotion]: "none", 58 + }, 59 + transitionTimingFunction: "ease-in-out", 60 + width: "100%", 61 + }, 62 + titleDisabled: { 63 + opacity: 0.5, 64 + pointerEvents: "none", 65 + }, 66 + chevron: { 67 + color: uiColor.text2, 68 + flexShrink: 0, 69 + rotate: { 70 + default: "0deg", 71 + ":is([aria-expanded=true] *)": "180deg", 72 + }, 73 + transition: { 74 + default: "rotate 200ms ease-in-out", 75 + [mediaQueries.reducedMotion]: "none", 76 + }, 77 + }, 78 + panel: { 79 + fontSize: { 80 + ":is([data-size=sm] *)": fontSize["sm"], 81 + ":is([data-size=md] *)": fontSize["base"], 82 + ":is([data-size=lg] *)": fontSize["lg"], 83 + }, 84 + height: "var(--disclosure-panel-height)", 85 + overflow: "clip", 86 + transitionDuration: { 87 + default: animationDuration.default, 88 + [mediaQueries.reducedMotion]: 0, 89 + }, 90 + transitionProperty: "height", 91 + transitionTimingFunction: "ease-in-out", 92 + }, 93 + panelContent: { 94 + padding: { 95 + ":is([data-size=sm] *)": `${spacing["2"]} ${spacing["3"]}`, 96 + ":is([data-size=md] *)": `${spacing["3"]} ${spacing["4"]}`, 97 + ":is([data-size=lg] *)": `${spacing["4"]} ${spacing["5"]}`, 98 + }, 99 + }, 100 + }); 101 + 102 + export interface DisclosureProps 103 + extends StyleXComponentProps<Omit<AriaDisclosureProps, "children">> { 104 + children: React.ReactNode; 105 + size?: Size; 106 + } 107 + 108 + export function Disclosure({ 109 + children, 110 + style, 111 + size: sizeProp, 112 + ...props 113 + }: DisclosureProps) { 114 + const size = sizeProp || use(SizeContext); 115 + 116 + return ( 117 + <SizeContext value={size}> 118 + <AriaDisclosure 119 + {...props} 120 + data-size={size} 121 + {...stylex.props(styles.disclosure, style)} 122 + > 123 + {children} 124 + </AriaDisclosure> 125 + </SizeContext> 126 + ); 127 + } 128 + 129 + export interface DisclosureTitleProps 130 + extends StyleXComponentProps<Omit<AriaButtonProps, "slot" | "children">> { 131 + children: React.ReactNode; 132 + } 133 + 134 + export function DisclosureTitle({ 135 + children, 136 + style, 137 + ...props 138 + }: DisclosureTitleProps) { 139 + return ( 140 + <Button 141 + {...props} 142 + slot="trigger" 143 + {...stylex.props( 144 + styles.title, 145 + props.isDisabled && styles.titleDisabled, 146 + style, 147 + )} 148 + > 149 + {children} 150 + <ChevronDown size={16} {...stylex.props(styles.chevron)} /> 151 + </Button> 152 + ); 153 + } 154 + 155 + export interface DisclosurePanelProps 156 + extends StyleXComponentProps<Omit<AriaDisclosurePanelProps, "children">> { 157 + children: React.ReactNode; 158 + isQuiet?: boolean; 159 + } 160 + 161 + export function DisclosurePanel({ 162 + children, 163 + style, 164 + ...props 165 + }: DisclosurePanelProps) { 166 + return ( 167 + <AriaDisclosurePanel {...props} {...stylex.props(styles.panel, style)}> 168 + <div {...stylex.props(styles.panelContent)}>{children}</div> 169 + </AriaDisclosurePanel> 170 + ); 171 + }