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.

share input and popover code

+910 -702
+88 -125
README.md
··· 1 - # Turborepo starter 1 + # hip 2 2 3 - This Turborepo starter is maintained by the Turborepo core team. 3 + ## TODO 4 4 5 - ## Using this example 5 + ### Components 6 6 7 - Run the following command: 7 + ## Maybe 8 8 9 - ```sh 10 - npx create-turbo@latest 11 - ``` 9 + - [ ] Chart 12 10 13 - ## What's inside? 11 + #### Custom 14 12 15 - This Turborepo includes the following packages/apps: 13 + - [ ] Alert / Callout 14 + - [ ] Aspect Ratio 15 + - [ ] Avatar 16 + - [ ] Badge 17 + - [ ] Carousel 18 + - [ ] Empty 19 + - [ ] Grid 20 + - [ ] Input Group 21 + - [ ] Input OTP 22 + - [ ] Kbd 23 + - [ ] Pagination 24 + - [ ] Resizable 25 + - [ ] Sidebar 26 + - [ ] Skeleton 16 27 17 - ### Apps and Packages 28 + #### react-aria wrappers 18 29 19 - - `docs`: a [Next.js](https://nextjs.org/) app 20 - - `web`: another [Next.js](https://nextjs.org/) app 21 - - `@repo/ui`: a stub React component library shared by both `web` and `docs` applications 22 - - `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) 23 - - `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo 24 - 25 - Each package/app is 100% [TypeScript](https://www.typescriptlang.org/). 30 + - [ ] Alert Dialog 31 + - [ ] Breadcrumb 32 + - [ ] Calendar 33 + - [ ] Combobox 34 + - [ ] Color Area 35 + - [ ] Color Field 36 + - [ ] Color Picker 37 + - [ ] Color Swatch 38 + - [ ] Color Swatch Picker 39 + - [ ] Color Wheel 40 + - [ ] Command 41 + - [ ] Data Table 42 + - [ ] Date Field 43 + - [ ] Date Picker 44 + - [ ] Dialog 45 + - [ ] Disclosure 46 + - [ ] Disclosure Group 47 + - [ ] Drawer 48 + - [ ] File Trigger 49 + - [ ] File Drop zone 50 + - [ ] Field 51 + - [ ] Form 52 + - [ ] Grid List 53 + - [ ] Hover Card 54 + - [ ] Item 55 + - [ ] Meter 56 + - [ ] Menubar 57 + - [ ] Navigation Menu 58 + - [ ] Number Field 59 + - [ ] Progress 60 + - [ ] Range Date Picker 61 + - [ ] Segmented Control 62 + - [ ] Search Field 63 + - [ ] Sheet 64 + - [ ] Slider 65 + - [ ] Spinner 66 + - [ ] Switch 67 + - [ ] Table 68 + - [ ] Tabs 69 + - [ ] Tag Group 70 + - [ ] Timefield 71 + - [ ] Toolbar 72 + - [ ] Toast 73 + - [x] Button 74 + - [x] Button Group 75 + - [x] Card 76 + - [x] Checkbox 77 + - [x] Context Menu 78 + - [x] Dropdown Menu 79 + - [x] Flez 80 + - [x] Icon Button 81 + - [x] Label 82 + - [x] Link 83 + - [x] Listbox 84 + - [x] Popover 85 + - [x] Radio Group 86 + - [x] Select 87 + - [x] Separator 88 + - [x] Text Field 89 + - [x] Textarea 90 + - [x] Toggle 91 + - [x] Toggle Group 92 + - [x] Tooltip 93 + - [x] Tree 94 + - [x] Typography 26 95 27 - ### Utilities 96 + ### Imprrovements 28 97 29 - This Turborepo has some additional tools already setup for you: 30 - 31 - - [TypeScript](https://www.typescriptlang.org/) for static type checking 32 - - [ESLint](https://eslint.org/) for code linting 33 - - [Prettier](https://prettier.io) for code formatting 34 - 35 - ### Build 36 - 37 - To build all apps and packages, run the following command: 38 - 39 - ``` 40 - cd my-turborepo 41 - 42 - # With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended) 43 - turbo build 44 - 45 - # Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager 46 - npx turbo build 47 - yarn dlx turbo build 48 - pnpm exec turbo build 49 - ``` 50 - 51 - You can build a specific package by using a [filter](https://turborepo.com/docs/crafting-your-repository/running-tasks#using-filters): 52 - 53 - ``` 54 - # With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended) 55 - turbo build --filter=docs 56 - 57 - # Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager 58 - npx turbo build --filter=docs 59 - yarn exec turbo build --filter=docs 60 - pnpm exec turbo build --filter=docs 61 - ``` 62 - 63 - ### Develop 64 - 65 - To develop all apps and packages, run the following command: 66 - 67 - ``` 68 - cd my-turborepo 69 - 70 - # With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended) 71 - turbo dev 72 - 73 - # Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager 74 - npx turbo dev 75 - yarn exec turbo dev 76 - pnpm exec turbo dev 77 - ``` 78 - 79 - You can develop a specific package by using a [filter](https://turborepo.com/docs/crafting-your-repository/running-tasks#using-filters): 80 - 81 - ``` 82 - # With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended) 83 - turbo dev --filter=web 84 - 85 - # Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager 86 - npx turbo dev --filter=web 87 - yarn exec turbo dev --filter=web 88 - pnpm exec turbo dev --filter=web 89 - ``` 90 - 91 - ### Remote Caching 92 - 93 - > [!TIP] 94 - > Vercel Remote Cache is free for all plans. Get started today at [vercel.com](https://vercel.com/signup?/signup?utm_source=remote-cache-sdk&utm_campaign=free_remote_cache). 95 - 96 - Turborepo can use a technique known as [Remote Caching](https://turborepo.com/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines. 97 - 98 - By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup?utm_source=turborepo-examples), then enter the following commands: 99 - 100 - ``` 101 - cd my-turborepo 102 - 103 - # With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended) 104 - turbo login 105 - 106 - # Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager 107 - npx turbo login 108 - yarn exec turbo login 109 - pnpm exec turbo login 110 - ``` 111 - 112 - This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview). 113 - 114 - Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo: 115 - 116 - ``` 117 - # With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended) 118 - turbo link 119 - 120 - # Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager 121 - npx turbo link 122 - yarn exec turbo link 123 - pnpm exec turbo link 124 - ``` 125 - 126 - ## Useful Links 127 - 128 - Learn more about the power of Turborepo: 129 - 130 - - [Tasks](https://turborepo.com/docs/crafting-your-repository/running-tasks) 131 - - [Caching](https://turborepo.com/docs/crafting-your-repository/caching) 132 - - [Remote Caching](https://turborepo.com/docs/core-concepts/remote-caching) 133 - - [Filtering](https://turborepo.com/docs/crafting-your-repository/running-tasks#using-filters) 134 - - [Configuration Options](https://turborepo.com/docs/reference/configuration) 135 - - [CLI Usage](https://turborepo.com/docs/reference/command-line-reference) 98 + - [ ] Add Virtualizer
-2
apps/example/src/components/KitchenSink.tsx
··· 538 538 } 539 539 540 540 export function KitchenSink() { 541 - return <MenuExample />; 542 - 543 541 return ( 544 542 <Flex 545 543 direction="column"
+1 -1
apps/example/src/components/button/index.tsx
··· 6 6 } from "react-aria-components"; 7 7 import * as stylex from "@stylexjs/stylex"; 8 8 9 - import { useButtonStyles } from "./useButtonStyles"; 9 + import { useButtonStyles } from "../theme/useButtonStyles"; 10 10 import { Size, ButtonVariant } from "../types"; 11 11 12 12 interface ButtonProps extends Omit<AriaButtonProps, "className" | "style"> {
+10 -40
apps/example/src/components/context-menu/index.tsx
··· 26 26 import { SizeContext } from "../context"; 27 27 import { useMenuTriggerState } from "react-stately"; 28 28 import { AriaButtonProps, useMenuTrigger } from "react-aria"; 29 - import { radius } from "../theme/radius.stylex"; 30 - import { spacing } from "../theme/spacing.stylex"; 31 - 32 - const styles = stylex.create({ 33 - popover: { 34 - borderRadius: radius["md"], 35 - minWidth: spacing["40"], 36 - outline: "none", 37 - overflow: "auto", 38 - paddingBottom: spacing["1"], 39 - paddingTop: spacing["1"], 40 - }, 41 - menu: { 42 - outline: "none", 43 - }, 44 - }); 29 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 45 30 46 31 const ContextMenuTriggerProps = createContext< 47 32 AriaButtonProps<"button"> & { ref?: React.Ref<HTMLDivElement> } ··· 63 48 function ContextMenuRoot( 64 49 props: OverlayTriggerProps & { children: React.ReactNode } 65 50 ) { 51 + const scrollRef = useRef(null); 66 52 const state = useMenuTriggerState(props); 67 53 const ref = useRef<HTMLDivElement>(null); 68 - const [position, setPosition] = useState<Position>({ 69 - x: 0, 70 - y: 0, 71 - }); 54 + const [position, setPosition] = useState<Position>({ x: 0, y: 0 }); 72 55 const { menuTriggerProps, menuProps } = useMenuTrigger( 73 - { 74 - ...props, 75 - type: "menu", 76 - }, 56 + { ...props, type: "menu" }, 77 57 state, 78 58 ref 79 59 ); 80 - 81 - const scrollRef = useRef(null); 82 60 83 61 return ( 84 62 <Provider ··· 116 94 e.preventDefault(); 117 95 e.stopPropagation(); 118 96 overlayTriggerState?.open(); 119 - setPosition({ x: e.clientX, y: e.clientY }); 97 + setPosition({ x: e.pageX, y: e.pageY }); 120 98 }, 121 - [menuTriggerProps, overlayTriggerState, setPosition] 99 + [overlayTriggerState, setPosition] 122 100 ); 123 101 124 102 if (Children.count(props.children) !== 1) { ··· 139 117 )} 140 118 <div 141 119 ref={menuTriggerProps.ref} 142 - style={{ 143 - position: "absolute", 144 - top: position?.y, 145 - left: position?.x, 146 - }} 120 + style={{ position: "absolute", top: position?.y, left: position?.x }} 147 121 /> 148 122 </> 149 123 ); ··· 177 151 placement, 178 152 ...props 179 153 }: ContextMenuProps<T>) { 154 + const popoverStyles = usePopoverStyles(); 155 + 180 156 return ( 181 157 <SizeContext.Provider value={size}> 182 158 <ContextMenuRoot ··· 191 167 shouldFlip={shouldFlip} 192 168 shouldUpdatePosition={shouldUpdatePosition} 193 169 placement={placement} 194 - {...stylex.props( 195 - styles.popover, 196 - gray.bgSubtle, 197 - gray.text, 198 - gray.border 199 - )} 200 170 > 201 - <AriaMenu {...props} {...stylex.props(styles.menu)} /> 171 + <AriaMenu {...props} {...stylex.props(popoverStyles)} /> 202 172 </Popover> 203 173 </ContextMenuRoot> 204 174 </SizeContext.Provider>
+7 -22
apps/example/src/components/menu/index.tsx
··· 14 14 } from "react-aria-components"; 15 15 import * as stylex from "@stylexjs/stylex"; 16 16 import { spacing } from "../theme/spacing.stylex"; 17 - import { gray } from "../theme/semantic-color.stylex"; 18 17 import { radius } from "../theme/radius.stylex"; 19 18 import { Size } from "../types"; 20 19 import { ··· 28 27 import { useContext } from "react"; 29 28 import { Check, ChevronRight } from "lucide-react"; 30 29 import { plum, slate } from "../theme/colors.stylex"; 30 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 31 31 32 32 const styles = stylex.create({ 33 - popover: { 34 - borderRadius: radius["md"], 35 - minWidth: spacing["40"], 36 - outline: "none", 37 - overflow: "auto", 38 - paddingBottom: spacing["1"], 39 - paddingTop: spacing["1"], 40 - width: "var(--trigger-width)", 41 - }, 42 - menu: { 43 - outline: "none", 44 - }, 45 33 section: {}, 46 34 item: { 47 35 display: "flex", ··· 116 104 placement, 117 105 ...props 118 106 }: MenuProps<T>) { 107 + const popoverStyles = usePopoverStyles(); 108 + 119 109 return ( 120 110 <SizeContext.Provider value={size}> 121 111 <MenuTrigger ··· 130 120 shouldFlip={shouldFlip} 131 121 shouldUpdatePosition={shouldUpdatePosition} 132 122 placement={placement} 133 - {...stylex.props( 134 - styles.popover, 135 - gray.bgSubtle, 136 - gray.text, 137 - gray.border 138 - )} 139 123 > 140 - <AriaMenu {...props} {...stylex.props(styles.menu)} /> 124 + <AriaMenu {...props} {...stylex.props(popoverStyles)} /> 141 125 </Popover> 142 126 </MenuTrigger> 143 127 </SizeContext.Provider> ··· 169 153 placement, 170 154 ...props 171 155 }: SubMenuProps<T>) { 156 + const popoverStyles = usePopoverStyles(); 157 + 172 158 return ( 173 159 <SubmenuTrigger delay={delay}> 174 160 {trigger} ··· 179 165 placement={placement} 180 166 containerPadding={8} 181 167 offset={-8} 182 - {...stylex.props(styles.popover, gray.bgSubtle, gray.text, gray.border)} 183 168 > 184 - <AriaMenu {...props} /> 169 + <AriaMenu {...props} {...stylex.props(popoverStyles)} /> 185 170 </Popover> 186 171 </SubmenuTrigger> 187 172 );
+12 -7
apps/example/src/components/popover/index.tsx
··· 10 10 } from "react-aria-components"; 11 11 import * as stylex from "@stylexjs/stylex"; 12 12 13 - import { radius } from "../theme/radius.stylex"; 14 13 import { slate } from "../theme/colors.stylex"; 15 - import { gray } from "../theme/semantic-color.stylex"; 16 14 import { spacing } from "../theme/spacing.stylex"; 15 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 17 16 18 17 const styles = stylex.create({ 19 - popover: { 18 + wrapper: { 20 19 filter: `drop-shadow(-0.5px -0.5px 0 ${slate[7]}) drop-shadow(0.5px -0.5px 0 ${slate[7]}) drop-shadow(0.5px 0.5px 0 ${slate[7]}) drop-shadow(-0.5px 0.5px 0 ${slate[7]}) drop-shadow(0px 1px 3px rgb(0 0 0 / 0.1)) drop-shadow(0px -1px 3px rgb(0 0 0 / 0.1))`, 21 20 }, 22 21 content: { 23 - borderRadius: radius["md"], 24 - padding: spacing["2"], 22 + borderWidth: 0, 23 + boxShadow: "none", 24 + paddingBottom: spacing["2"], 25 + paddingLeft: spacing["2"], 26 + paddingRight: spacing["2"], 27 + paddingTop: spacing["2"], 25 28 position: "relative", 26 29 }, 27 30 caret: {}, ··· 53 56 onOpenChange, 54 57 ...popoverProps 55 58 }: TooltipProps) => { 59 + const popoverStyles = usePopoverStyles(); 60 + 56 61 return ( 57 62 <DialogTrigger 58 63 {...({ isOpen, onOpenChange, defaultOpen } as DialogTriggerProps)} ··· 60 65 {trigger} 61 66 62 67 <AriaPopover 63 - {...stylex.props(styles.popover)} 68 + {...stylex.props(styles.wrapper)} 64 69 {...popoverProps} 65 70 offset={8} 66 71 containerPadding={8} ··· 68 73 <OverlayArrow {...stylex.props(styles.caret)}> 69 74 <div {...stylex.props(styles.arrow)} /> 70 75 </OverlayArrow> 71 - <Dialog {...stylex.props(styles.content, gray.bgSubtle, gray.text)}> 76 + <Dialog {...stylex.props(popoverStyles, styles.content)}> 72 77 {children} 73 78 </Dialog> 74 79 </AriaPopover>
+31 -67
apps/example/src/components/select/index.tsx
··· 14 14 import { FieldError } from "react-aria-components"; 15 15 import { Description, Label } from "../label"; 16 16 import { ChevronDown } from "lucide-react"; 17 - import { spacing } from "../theme/spacing.stylex"; 18 - import { gray } from "../theme/semantic-color.stylex"; 19 - import { slate } from "../theme/colors.stylex"; 20 - import { radius } from "../theme/radius.stylex"; 21 - import { fontSize, lineHeight } from "../theme/typography.stylex"; 22 17 import { Size } from "../types"; 23 18 import { 24 19 ListBox, ··· 31 26 ListBoxSection, 32 27 } from "../listbox"; 33 28 import { SizeContext } from "../context"; 29 + import { useInputStyles } from "../theme/useInputStyles"; 30 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 34 31 35 32 const styles = stylex.create({ 36 - wrapper: { 37 - display: "flex", 38 - flexDirection: "column", 39 - gap: spacing["2"], 40 - }, 41 - trigger: { 42 - alignItems: "center", 43 - boxSizing: "border-box", 44 - display: "flex", 45 - gap: spacing["2"], 46 - justifyContent: "space-between", 47 - lineHeight: lineHeight["none"], 48 - 49 - borderColor: { 50 - default: slate[7], 51 - ":hover": slate[8], 52 - ":focus": slate[9], 53 - }, 54 - borderRadius: radius["md"], 55 - borderStyle: "solid", 56 - borderWidth: 1, 57 - }, 58 - sm: { 59 - fontSize: fontSize["xs"], 60 - height: spacing["6"], 61 - paddingLeft: { ":first-child": spacing["1"] }, 62 - paddingRight: spacing["1"], 63 - }, 64 - md: { 65 - fontSize: fontSize["sm"], 66 - height: spacing["8"], 67 - paddingLeft: { ":first-child": spacing["2"] }, 68 - paddingRight: spacing["2"], 69 - }, 70 - lg: { 71 - fontSize: fontSize["base"], 72 - height: spacing["10"], 73 - paddingLeft: spacing["3"], 74 - paddingRight: spacing["3"], 75 - }, 76 - popover: { 77 - borderRadius: radius["md"], 78 - minWidth: spacing["40"], 79 - overflow: "auto", 33 + matchWidth: { 80 34 width: "var(--trigger-width)", 81 35 }, 82 - value: { 83 - color: { 84 - ":is([data-placeholder])": slate[11], 85 - }, 86 - }, 87 36 }); 88 37 89 38 export interface SelectProps<T extends object, M extends "single" | "multiple"> ··· 102 51 items?: Iterable<T>; 103 52 children: React.ReactNode | ((item: T) => React.ReactNode); 104 53 size?: Size; 54 + placeholder?: string; 105 55 } 106 56 107 57 export function Select< ··· 119 69 shouldFlip, 120 70 shouldUpdatePosition, 121 71 placement, 72 + placeholder = "Select an option", 122 73 ...props 123 74 }: SelectProps<T, M>) { 75 + const inputStyles = useInputStyles({ size }); 76 + const popoverStyles = usePopoverStyles(); 77 + 124 78 return ( 125 79 <SizeContext.Provider value={size}> 126 - <AriaSelect {...props} {...stylex.props(styles.wrapper, style)}> 80 + <AriaSelect 81 + {...props} 82 + {...stylex.props(inputStyles.field, style)} 83 + placeholder={placeholder} 84 + > 127 85 {label && <Label size={size}>{label}</Label>} 128 - <Button 129 - {...stylex.props(styles.trigger, gray.bgUi, gray.text, styles[size])} 130 - > 131 - <SelectValue {...stylex.props(styles.value)} /> 132 - <ChevronDown size={16} aria-hidden="true" /> 86 + <Button {...stylex.props(inputStyles.wrapper)}> 87 + <SelectValue {...stylex.props(inputStyles.input)}> 88 + {({ selectedText, isPlaceholder, defaultChildren }) => { 89 + if (isPlaceholder) return placeholder; 90 + if (selectedText) return selectedText; 91 + 92 + return defaultChildren; 93 + }} 94 + </SelectValue> 95 + <div {...stylex.props(inputStyles.addon)}> 96 + <ChevronDown size={16} aria-hidden="true" /> 97 + </div> 133 98 </Button> 134 99 {description && <Description size={size}>{description}</Description>} 135 100 <FieldError>{errorMessage}</FieldError> ··· 139 104 shouldFlip={shouldFlip} 140 105 shouldUpdatePosition={shouldUpdatePosition} 141 106 placement={placement} 142 - {...stylex.props( 143 - styles.popover, 144 - gray.bgSubtle, 145 - gray.text, 146 - gray.border 147 - )} 148 107 > 149 - <ListBox items={items}>{children}</ListBox> 108 + <ListBox 109 + items={items} 110 + {...stylex.props(popoverStyles, styles.matchWidth)} 111 + > 112 + {children} 113 + </ListBox> 150 114 </Popover> 151 115 </AriaSelect> 152 116 </SizeContext.Provider>
+17 -105
apps/example/src/components/text-field/index.tsx
··· 11 11 TextField as AriaTextField, 12 12 } from "react-aria-components"; 13 13 import * as stylex from "@stylexjs/stylex"; 14 - import { gray } from "../theme/semantic-color.stylex"; 15 - import { spacing } from "../theme/spacing.stylex"; 16 14 import { Description, Label } from "../label"; 17 - import { radius } from "../theme/radius.stylex"; 18 - import { lineHeight, fontSize } from "../theme/typography.stylex"; 19 - import { slate } from "../theme/colors.stylex"; 20 15 import { useRef } from "react"; 21 16 import { useState } from "react"; 22 17 import { IconButton } from "../icon-button"; 23 18 import { Eye, EyeOff } from "lucide-react"; 24 19 import { use } from "react"; 25 20 import { Size } from "../types"; 26 - 27 - const styles = stylex.create({ 28 - wrapper: { 29 - display: "flex", 30 - flexDirection: "column", 31 - gap: spacing["2"], 32 - }, 33 - addon: { 34 - color: gray.textDim, 35 - flexShrink: 0, 36 - height: "100%", 37 - minWidth: spacing["8"], 38 - paddingLeft: { ":first-child": spacing["0.5"] }, 39 - paddingRight: { 40 - ":last-child": spacing["2"], 41 - ":last-child:has(svg)": spacing["0.5"], 42 - }, 43 - 44 - alignItems: "center", 45 - display: "flex", 46 - gap: spacing["0.5"], 47 - justifyContent: "center", 48 - 49 - // eslint-disable-next-line @stylexjs/no-legacy-contextual-styles, @stylexjs/valid-styles 50 - ":is(*) svg": { 51 - flexShrink: 0, 52 - height: spacing["4"], 53 - pointerEvents: "none", 54 - width: spacing["4"], 55 - }, 56 - }, 57 - inputWrapper: { 58 - borderRadius: radius["md"], 59 - boxSizing: "border-box", 60 - display: "flex", 61 - 62 - borderColor: { 63 - default: slate[7], 64 - ":hover": slate[8], 65 - ":focus": slate[9], 66 - }, 67 - borderStyle: "solid", 68 - borderWidth: 1, 69 - }, 70 - input: { 71 - backgroundColor: "transparent", 72 - borderWidth: 0, 73 - color: { 74 - "::placeholder": slate[11], 75 - }, 76 - flexGrow: 1, 77 - lineHeight: lineHeight["none"], 78 - outline: "none", 79 - }, 80 - sm: { 81 - height: spacing["6"], 82 - }, 83 - smInput: { 84 - fontSize: fontSize["xs"], 85 - paddingLeft: { ":first-child": spacing["1"] }, 86 - paddingRight: spacing["1"], 87 - }, 88 - md: { 89 - height: spacing["8"], 90 - }, 91 - mdInput: { 92 - fontSize: fontSize["sm"], 93 - paddingLeft: { ":first-child": spacing["2"] }, 94 - paddingRight: spacing["2"], 95 - }, 96 - lg: { 97 - height: spacing["10"], 98 - }, 99 - lgInput: { 100 - fontSize: fontSize["base"], 101 - paddingLeft: spacing["3"], 102 - paddingRight: spacing["3"], 103 - }, 104 - description: { 105 - color: gray.textDim, 106 - fontSize: fontSize["sm"], 107 - lineHeight: lineHeight["sm"], 108 - }, 109 - descriptionSm: { 110 - fontSize: fontSize["xs"], 111 - lineHeight: lineHeight["xs"], 112 - }, 113 - }); 21 + import { useInputStyles } from "../theme/useInputStyles"; 114 22 115 23 function PasswordToggle({ 116 24 type, 117 25 setType, 26 + style, 118 27 }: { 119 28 type: TextFieldProps["type"]; 120 29 setType: (type: TextFieldProps["type"]) => void; 30 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 121 31 }) { 122 32 const state = use(InputContext); 123 33 124 34 if (!state || !("value" in state) || !state.value) return null; 125 35 126 36 return ( 127 - <div {...stylex.props(styles.addon)}> 37 + <div {...stylex.props(style)}> 128 38 <IconButton 129 39 size="sm" 130 40 variant="tertiary" ··· 165 75 props.type || "text" 166 76 ); 167 77 const isPasswordInput = props.type === "password"; 78 + const inputStyles = useInputStyles({ size }); 168 79 169 80 return ( 170 81 <AriaTextField 171 82 {...props} 172 83 type={type} 173 - {...stylex.props(styles.wrapper, style)} 84 + {...stylex.props(inputStyles.field, style)} 174 85 > 175 86 <Label size={size}>{label}</Label> 176 87 <div 177 - {...stylex.props( 178 - styles.inputWrapper, 179 - gray.bgUi, 180 - gray.text, 181 - styles[size] 182 - )} 88 + {...stylex.props(inputStyles.wrapper)} 183 89 onClick={() => inputRef.current?.focus()} 184 90 > 185 - {prefix && <div {...stylex.props(styles.addon)}>{prefix}</div>} 91 + {prefix && <div {...stylex.props(inputStyles.addon)}>{prefix}</div>} 186 92 <Input 187 - {...stylex.props(styles.input, styles[`${size}Input`])} 93 + {...stylex.props(inputStyles.input)} 188 94 ref={inputRef} 189 95 placeholder={placeholder} 190 96 /> 191 - {suffix && <div {...stylex.props(styles.addon)}>{suffix}</div>} 192 - {isPasswordInput && <PasswordToggle type={type} setType={setType} />} 97 + {suffix && <div {...stylex.props(inputStyles.addon)}>{suffix}</div>} 98 + {isPasswordInput && ( 99 + <PasswordToggle 100 + type={type} 101 + setType={setType} 102 + style={inputStyles.addon} 103 + /> 104 + )} 193 105 </div> 194 106 {description && <Description size={size}>{description}</Description>} 195 107 <FieldError>{errorMessage}</FieldError>
+48 -48
apps/example/src/components/theme/colors.stylex.tsx
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 2 3 3 export const slateLight = stylex.defineVars({ 4 - 1: "#fcfcfd", 5 - 2: "#f9f9fb", 6 - 3: "#f0f0f3", 7 - 4: "#e8e8ec", 8 - 5: "#e0e1e6", 9 - 6: "#d9d9e0", 10 - 7: "#cdced6", 11 - 8: "#b9bbc6", 12 - 9: "#8b8d98", 13 - 10: "#80838d", 14 - 11: "#60646c", 15 - 12: "#1c2024", 4 + 1: stylex.types.color("#fcfcfd"), 5 + 2: stylex.types.color("#f9f9fb"), 6 + 3: stylex.types.color("#f0f0f3"), 7 + 4: stylex.types.color("#e8e8ec"), 8 + 5: stylex.types.color("#e0e1e6"), 9 + 6: stylex.types.color("#d9d9e0"), 10 + 7: stylex.types.color("#cdced6"), 11 + 8: stylex.types.color("#b9bbc6"), 12 + 9: stylex.types.color("#8b8d98"), 13 + 10: stylex.types.color("#80838d"), 14 + 11: stylex.types.color("#60646c"), 15 + 12: stylex.types.color("#1c2024"), 16 16 }); 17 17 18 18 export const slateLightP3 = stylex.defineVars({ 19 - 1: "color(display-p3 0.988 0.988 0.992)", 20 - 2: "color(display-p3 0.976 0.976 0.984)", 21 - 3: "color(display-p3 0.94 0.941 0.953)", 22 - 4: "color(display-p3 0.908 0.909 0.925)", 23 - 5: "color(display-p3 0.88 0.881 0.901)", 24 - 6: "color(display-p3 0.85 0.852 0.876)", 25 - 7: "color(display-p3 0.805 0.808 0.838)", 26 - 8: "color(display-p3 0.727 0.733 0.773)", 27 - 9: "color(display-p3 0.547 0.553 0.592)", 28 - 10: "color(display-p3 0.503 0.512 0.549)", 29 - 11: "color(display-p3 0.379 0.392 0.421)", 30 - 12: "color(display-p3 0.113 0.125 0.14)", 19 + 1: stylex.types.color("color(display-p3 0.988 0.988 0.992)"), 20 + 2: stylex.types.color("color(display-p3 0.976 0.976 0.984)"), 21 + 3: stylex.types.color("color(display-p3 0.94 0.941 0.953)"), 22 + 4: stylex.types.color("color(display-p3 0.908 0.909 0.925)"), 23 + 5: stylex.types.color("color(display-p3 0.88 0.881 0.901)"), 24 + 6: stylex.types.color("color(display-p3 0.85 0.852 0.876)"), 25 + 7: stylex.types.color("color(display-p3 0.805 0.808 0.838)"), 26 + 8: stylex.types.color("color(display-p3 0.727 0.733 0.773)"), 27 + 9: stylex.types.color("color(display-p3 0.547 0.553 0.592)"), 28 + 10: stylex.types.color("color(display-p3 0.503 0.512 0.549)"), 29 + 11: stylex.types.color("color(display-p3 0.379 0.392 0.421)"), 30 + 12: stylex.types.color("color(display-p3 0.113 0.125 0.14)"), 31 31 }); 32 32 33 33 export const slateDark = stylex.defineVars({ 34 - 1: "#111113", 35 - 2: "#18191b", 36 - 3: "#212225", 37 - 4: "#272a2d", 38 - 5: "#2e3135", 39 - 6: "#363a3f", 40 - 7: "#43484e", 41 - 8: "#5a6169", 42 - 9: "#696e77", 43 - 10: "#777b84", 44 - 11: "#b0b4ba", 45 - 12: "#edeef0", 34 + 1: stylex.types.color("#111113"), 35 + 2: stylex.types.color("#18191b"), 36 + 3: stylex.types.color("#212225"), 37 + 4: stylex.types.color("#272a2d"), 38 + 5: stylex.types.color("#2e3135"), 39 + 6: stylex.types.color("#363a3f"), 40 + 7: stylex.types.color("#43484e"), 41 + 8: stylex.types.color("#5a6169"), 42 + 9: stylex.types.color("#696e77"), 43 + 10: stylex.types.color("#777b84"), 44 + 11: stylex.types.color("#b0b4ba"), 45 + 12: stylex.types.color("#edeef0"), 46 46 }); 47 47 48 48 export const slateDarkP3 = stylex.defineVars({ 49 - 1: "color(display-p3 0.067 0.067 0.074)", 50 - 2: "color(display-p3 0.095 0.098 0.105)", 51 - 3: "color(display-p3 0.13 0.135 0.145)", 52 - 4: "color(display-p3 0.156 0.163 0.176)", 53 - 5: "color(display-p3 0.183 0.191 0.206)", 54 - 6: "color(display-p3 0.215 0.226 0.244)", 55 - 7: "color(display-p3 0.265 0.28 0.302)", 56 - 8: "color(display-p3 0.357 0.381 0.409)", 57 - 9: "color(display-p3 0.415 0.431 0.463)", 58 - 10: "color(display-p3 0.469 0.483 0.514)", 59 - 11: "color(display-p3 0.692 0.704 0.728)", 60 - 12: "color(display-p3 0.93 0.933 0.94)", 49 + 1: stylex.types.color("color(display-p3 0.067 0.067 0.074)"), 50 + 2: stylex.types.color("color(display-p3 0.095 0.098 0.105)"), 51 + 3: stylex.types.color("color(display-p3 0.13 0.135 0.145)"), 52 + 4: stylex.types.color("color(display-p3 0.156 0.163 0.176)"), 53 + 5: stylex.types.color("color(display-p3 0.183 0.191 0.206)"), 54 + 6: stylex.types.color("color(display-p3 0.215 0.226 0.244)"), 55 + 7: stylex.types.color("color(display-p3 0.265 0.28 0.302)"), 56 + 8: stylex.types.color("color(display-p3 0.357 0.381 0.409)"), 57 + 9: stylex.types.color("color(display-p3 0.415 0.431 0.463)"), 58 + 10: stylex.types.color("color(display-p3 0.469 0.483 0.514)"), 59 + 11: stylex.types.color("color(display-p3 0.692 0.704 0.728)"), 60 + 12: stylex.types.color("color(display-p3 0.93 0.933 0.94)"), 61 61 }); 62 62 63 63 export const slate = stylex.defineVars({
+176
apps/example/src/components/theme/useButtonStyles.ts
··· 1 + "use client"; 2 + 3 + import * as stylex from "@stylexjs/stylex"; 4 + 5 + import { spacing } from "./spacing.stylex"; 6 + import { radius } from "./radius.stylex"; 7 + import { gray, primary } from "./semantic-color.stylex"; 8 + import { 9 + fontFamily, 10 + fontSize, 11 + fontWeight, 12 + lineHeight, 13 + } from "./typography.stylex"; 14 + import { shadow } from "./shadow.stylex"; 15 + import { slate } from "./colors.stylex"; 16 + import { use } from "react"; 17 + import { Size, ButtonVariant } from "../types"; 18 + import { ButtonGroupContext } from "../button/context"; 19 + 20 + const styles = stylex.create({ 21 + shadow: { 22 + boxShadow: shadow["xs"], 23 + }, 24 + base: { 25 + alignItems: "center", 26 + borderRadius: radius["md"], 27 + borderStyle: "solid", 28 + borderWidth: 1, 29 + boxSizing: "border-box", 30 + display: "inline-flex", 31 + flexShrink: 0, 32 + fontFamily: fontFamily["sans"], 33 + fontWeight: fontWeight["medium"], 34 + gap: spacing["1"], 35 + justifyContent: "center", 36 + opacity: { 37 + ":disabled": 0.5, 38 + }, 39 + pointerEvents: { 40 + ":disabled": "none", 41 + }, 42 + transitionDuration: "100ms", 43 + transitionProperty: "all", 44 + transitionTimingFunction: "ease-in-out", 45 + whiteSpace: "nowrap", 46 + 47 + // eslint-disable-next-line @stylexjs/no-legacy-contextual-styles, @stylexjs/valid-styles 48 + ":is(*) svg": { 49 + flexShrink: 0, 50 + height: spacing["4"], 51 + pointerEvents: "none", 52 + width: spacing["4"], 53 + }, 54 + }, 55 + small: { 56 + fontSize: fontSize["xs"], 57 + height: spacing["7"], 58 + lineHeight: lineHeight["xs"], 59 + paddingLeft: { 60 + default: spacing["2"], 61 + }, 62 + paddingRight: spacing["2"], 63 + 64 + // eslint-disable-next-line @stylexjs/no-legacy-contextual-styles, @stylexjs/valid-styles 65 + ":is(*) svg": { 66 + flexShrink: 0, 67 + height: spacing["3.5"], 68 + pointerEvents: "none", 69 + width: spacing["3.5"], 70 + }, 71 + }, 72 + medium: { 73 + fontSize: fontSize["sm"], 74 + gap: spacing["1.5"], 75 + height: spacing["8"], 76 + lineHeight: lineHeight["xs"], 77 + paddingLeft: { 78 + default: spacing["3"], 79 + ":has(svg+*)": spacing["2.5"], 80 + }, 81 + paddingRight: spacing["3"], 82 + }, 83 + large: { 84 + gap: spacing["2"], 85 + height: spacing["10"], 86 + paddingLeft: { 87 + default: spacing["4"], 88 + ":has(svg+*)": spacing["3"], 89 + }, 90 + paddingRight: spacing["4"], 91 + }, 92 + outline: { 93 + borderWidth: 1, 94 + }, 95 + secondary: { 96 + borderColor: { 97 + default: slate[3], 98 + ":hover": slate[4], 99 + ":active": slate[5], 100 + }, 101 + }, 102 + tertiary: { 103 + borderColor: { 104 + default: "transparent", 105 + ":hover": slate[4], 106 + ":active": slate[5], 107 + }, 108 + }, 109 + 110 + groupHorizontal: { 111 + borderBottomLeftRadius: { ":not(:first-child)": 0 }, 112 + borderBottomRightRadius: { ":not(:last-child)": 0 }, 113 + borderLeftWidth: { ":not(:first-child)": 0 }, 114 + borderTopLeftRadius: { ":not(:first-child)": 0 }, 115 + borderTopRightRadius: { ":not(:last-child)": 0 }, 116 + }, 117 + secondaryGroupHorizontal: { 118 + borderRightColor: { ":not(:last-child)": slate[7] }, 119 + }, 120 + groupVertical: { 121 + borderBottomLeftRadius: { ":not(:last-child)": 0 }, 122 + borderBottomRightRadius: { ":not(:last-child)": 0 }, 123 + borderTopLeftRadius: { ":not(:first-child)": 0 }, 124 + borderTopRightRadius: { ":not(:first-child)": 0 }, 125 + borderTopWidth: { ":not(:first-child)": 0 }, 126 + }, 127 + secondaryGroupVertical: { 128 + borderBottomColor: { ":not(:last-child)": slate[7] }, 129 + }, 130 + }); 131 + 132 + export const useButtonStyles = ({ 133 + variant = "primary", 134 + size = "md", 135 + }: { 136 + variant?: ButtonVariant; 137 + size?: Size; 138 + }) => { 139 + const group = use(ButtonGroupContext); 140 + 141 + return [ 142 + styles.base, 143 + group === "horizontal" && styles.groupHorizontal, 144 + group === "vertical" && styles.groupVertical, 145 + variant === "primary" && [ 146 + primary.bgAction, 147 + primary.borderInteractive, 148 + primary.text, 149 + styles.shadow, 150 + ], 151 + variant === "secondary" && [ 152 + gray.bgUi, 153 + styles.secondary, 154 + gray.text, 155 + group === "horizontal" && styles.secondaryGroupHorizontal, 156 + group === "vertical" && styles.secondaryGroupVertical, 157 + ], 158 + variant === "tertiary" && [ 159 + gray.bgGhost, 160 + styles.tertiary, 161 + gray.text, 162 + group === "horizontal" && styles.secondaryGroupHorizontal, 163 + group === "vertical" && styles.secondaryGroupVertical, 164 + ], 165 + variant === "outline" && [ 166 + gray.borderInteractive, 167 + gray.bgGhost, 168 + gray.text, 169 + styles.outline, 170 + styles.shadow, 171 + ], 172 + size === "sm" && styles.small, 173 + size === "md" && styles.medium, 174 + size === "lg" && styles.large, 175 + ]; 176 + };
+100
apps/example/src/components/theme/useInputStyles.ts
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + import { gray } from "./semantic-color.stylex"; 3 + import { spacing } from "./spacing.stylex"; 4 + import { radius } from "./radius.stylex"; 5 + import { lineHeight, fontSize } from "./typography.stylex"; 6 + import { slate } from "./colors.stylex"; 7 + import { Size } from "../types"; 8 + 9 + const styles = stylex.create({ 10 + field: { 11 + display: "flex", 12 + flexDirection: "column", 13 + gap: spacing["2"], 14 + }, 15 + addon: { 16 + color: gray.textDim, 17 + flexShrink: 0, 18 + height: "100%", 19 + minWidth: spacing["8"], 20 + paddingLeft: { ":first-child": spacing["0.5"] }, 21 + paddingRight: { 22 + ":last-child": spacing["2"], 23 + ":last-child:has(svg)": spacing["0.5"], 24 + }, 25 + 26 + alignItems: "center", 27 + display: "flex", 28 + gap: spacing["0.5"], 29 + justifyContent: "center", 30 + 31 + // eslint-disable-next-line @stylexjs/no-legacy-contextual-styles, @stylexjs/valid-styles 32 + ":is(*) svg": { 33 + flexShrink: 0, 34 + height: spacing["4"], 35 + pointerEvents: "none", 36 + width: spacing["4"], 37 + }, 38 + }, 39 + inputWrapper: { 40 + borderRadius: radius["md"], 41 + boxSizing: "border-box", 42 + display: "flex", 43 + gap: spacing["2"], 44 + lineHeight: lineHeight["none"], 45 + padding: 0, 46 + 47 + borderColor: { 48 + default: slate[7], 49 + ":hover": slate[8], 50 + ":focus": slate[9], 51 + }, 52 + borderStyle: "solid", 53 + borderWidth: 1, 54 + }, 55 + input: { 56 + alignItems: "center", 57 + backgroundColor: "transparent", 58 + borderWidth: 0, 59 + color: { 60 + ":is(::placeholder,[data-placeholder])": slate[11], 61 + }, 62 + display: "flex", 63 + flexGrow: 1, 64 + lineHeight: lineHeight["none"], 65 + outline: "none", 66 + }, 67 + sm: { 68 + height: spacing["6"], 69 + }, 70 + smInput: { 71 + fontSize: fontSize["xs"], 72 + paddingLeft: { ":first-child": spacing["1"] }, 73 + paddingRight: spacing["1"], 74 + }, 75 + md: { 76 + height: spacing["8"], 77 + }, 78 + mdInput: { 79 + fontSize: fontSize["sm"], 80 + paddingLeft: { ":first-child": spacing["2"] }, 81 + paddingRight: spacing["2"], 82 + }, 83 + lg: { 84 + height: spacing["10"], 85 + }, 86 + lgInput: { 87 + fontSize: fontSize["base"], 88 + paddingLeft: spacing["3"], 89 + paddingRight: spacing["3"], 90 + }, 91 + }); 92 + 93 + export function useInputStyles({ size = "md" }: { size?: Size }) { 94 + return { 95 + field: [styles.field], 96 + wrapper: [styles.inputWrapper, gray.bgUi, gray.text, styles[size]], 97 + input: [styles.input, styles[`${size}Input`]], 98 + addon: [styles.addon], 99 + }; 100 + }
+23
apps/example/src/components/theme/usePopoverStyles.ts
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + import { radius } from "./radius.stylex"; 4 + import { spacing } from "./spacing.stylex"; 5 + import { gray } from "./semantic-color.stylex"; 6 + import { shadow } from "./shadow.stylex"; 7 + 8 + const styles = stylex.create({ 9 + popover: { 10 + borderRadius: radius["md"], 11 + boxShadow: shadow["md"], 12 + minWidth: spacing["40"], 13 + outline: "none", 14 + overflow: "auto", 15 + 16 + paddingBottom: spacing["1"], 17 + paddingTop: spacing["1"], 18 + }, 19 + }); 20 + 21 + export function usePopoverStyles() { 22 + return [styles.popover, gray.bgSubtle, gray.text, gray.border]; 23 + }
+1 -1
apps/example/src/components/toggle-button/index.tsx
··· 5 5 import { spacing } from "../theme/spacing.stylex"; 6 6 import { plum, slate } from "../theme/colors.stylex"; 7 7 import { Children } from "react"; 8 - import { useButtonStyles } from "../button/useButtonStyles"; 8 + import { useButtonStyles } from "../theme/useButtonStyles"; 9 9 import { ButtonVariant, Size } from "../types"; 10 10 11 11 const styles = stylex.create({
+1 -1
packages/hip-ui/src/components/button/button-config.ts
··· 11 11 "../theme/typography.stylex.tsx", 12 12 "../theme/breakpoints.stylex.tsx", 13 13 "../theme/shadow.stylex.tsx", 14 - "./useButtonStyles.ts", 14 + "../theme/useButtonStyles.ts", 15 15 "./context.ts", 16 16 "../types.ts", 17 17 ],
+1 -1
packages/hip-ui/src/components/button/index.tsx
··· 6 6 } from "react-aria-components"; 7 7 import * as stylex from "@stylexjs/stylex"; 8 8 9 - import { useButtonStyles } from "./useButtonStyles"; 9 + import { useButtonStyles } from "../theme/useButtonStyles"; 10 10 import { Size, ButtonVariant } from "../types"; 11 11 12 12 interface ButtonProps extends Omit<AriaButtonProps, "className" | "style"> {
+7 -7
packages/hip-ui/src/components/button/useButtonStyles.ts packages/hip-ui/src/components/theme/useButtonStyles.ts
··· 2 2 3 3 import * as stylex from "@stylexjs/stylex"; 4 4 5 - import { spacing } from "../theme/spacing.stylex"; 6 - import { radius } from "../theme/radius.stylex"; 7 - import { gray, primary } from "../theme/semantic-color.stylex"; 5 + import { spacing } from "./spacing.stylex"; 6 + import { radius } from "./radius.stylex"; 7 + import { gray, primary } from "./semantic-color.stylex"; 8 8 import { 9 9 fontFamily, 10 10 fontSize, 11 11 fontWeight, 12 12 lineHeight, 13 - } from "../theme/typography.stylex"; 14 - import { shadow } from "../theme/shadow.stylex"; 15 - import { slate } from "../theme/colors.stylex"; 13 + } from "./typography.stylex"; 14 + import { shadow } from "./shadow.stylex"; 15 + import { slate } from "./colors.stylex"; 16 16 import { use } from "react"; 17 17 import { Size, ButtonVariant } from "../types"; 18 - import { ButtonGroupContext } from "./context"; 18 + import { ButtonGroupContext } from "../button/context"; 19 19 20 20 const styles = stylex.create({ 21 21 shadow: {
+5 -25
packages/hip-ui/src/components/context-menu/index.tsx
··· 22 22 useState, 23 23 } from "react"; 24 24 import { Size } from "../types"; 25 - import { gray } from "../theme/semantic-color.stylex"; 26 25 import { SizeContext } from "../context"; 27 26 import { useMenuTriggerState } from "react-stately"; 28 27 import { AriaButtonProps, useMenuTrigger } from "react-aria"; 29 - import { radius } from "../theme/radius.stylex"; 30 - import { spacing } from "../theme/spacing.stylex"; 31 - 32 - const styles = stylex.create({ 33 - popover: { 34 - borderRadius: radius["md"], 35 - minWidth: spacing["40"], 36 - outline: "none", 37 - overflow: "auto", 38 - paddingBottom: spacing["1"], 39 - paddingTop: spacing["1"], 40 - }, 41 - menu: { 42 - outline: "none", 43 - }, 44 - }); 28 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 45 29 46 30 const ContextMenuTriggerProps = createContext< 47 31 AriaButtonProps<"button"> & { ref?: React.Ref<HTMLDivElement> } ··· 109 93 e.preventDefault(); 110 94 e.stopPropagation(); 111 95 overlayTriggerState?.open(); 112 - setPosition({ x: e.clientX, y: e.clientY }); 96 + setPosition({ x: e.pageX, y: e.pageY }); 113 97 }, 114 98 [overlayTriggerState, setPosition] 115 99 ); ··· 166 150 placement, 167 151 ...props 168 152 }: ContextMenuProps<T>) { 153 + const popoverStyles = usePopoverStyles(); 154 + 169 155 return ( 170 156 <SizeContext.Provider value={size}> 171 157 <ContextMenuRoot ··· 180 166 shouldFlip={shouldFlip} 181 167 shouldUpdatePosition={shouldUpdatePosition} 182 168 placement={placement} 183 - {...stylex.props( 184 - styles.popover, 185 - gray.bgSubtle, 186 - gray.text, 187 - gray.border 188 - )} 189 169 > 190 - <AriaMenu {...props} {...stylex.props(styles.menu)} /> 170 + <AriaMenu {...props} {...stylex.props(popoverStyles)} /> 191 171 </Popover> 192 172 </ContextMenuRoot> 193 173 </SizeContext.Provider>
+7 -22
packages/hip-ui/src/components/menu/index.tsx
··· 14 14 } from "react-aria-components"; 15 15 import * as stylex from "@stylexjs/stylex"; 16 16 import { spacing } from "../theme/spacing.stylex"; 17 - import { gray } from "../theme/semantic-color.stylex"; 18 17 import { radius } from "../theme/radius.stylex"; 19 18 import { Size } from "../types"; 20 19 import { ··· 28 27 import { useContext } from "react"; 29 28 import { Check, ChevronRight } from "lucide-react"; 30 29 import { plum, slate } from "../theme/colors.stylex"; 30 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 31 31 32 32 const styles = stylex.create({ 33 - popover: { 34 - borderRadius: radius["md"], 35 - minWidth: spacing["40"], 36 - outline: "none", 37 - overflow: "auto", 38 - paddingBottom: spacing["1"], 39 - paddingTop: spacing["1"], 40 - width: "var(--trigger-width)", 41 - }, 42 - menu: { 43 - outline: "none", 44 - }, 45 33 section: {}, 46 34 item: { 47 35 display: "flex", ··· 116 104 placement, 117 105 ...props 118 106 }: MenuProps<T>) { 107 + const popoverStyles = usePopoverStyles(); 108 + 119 109 return ( 120 110 <SizeContext.Provider value={size}> 121 111 <MenuTrigger ··· 130 120 shouldFlip={shouldFlip} 131 121 shouldUpdatePosition={shouldUpdatePosition} 132 122 placement={placement} 133 - {...stylex.props( 134 - styles.popover, 135 - gray.bgSubtle, 136 - gray.text, 137 - gray.border 138 - )} 139 123 > 140 - <AriaMenu {...props} {...stylex.props(styles.menu)} /> 124 + <AriaMenu {...props} {...stylex.props(popoverStyles)} /> 141 125 </Popover> 142 126 </MenuTrigger> 143 127 </SizeContext.Provider> ··· 169 153 placement, 170 154 ...props 171 155 }: SubMenuProps<T>) { 156 + const popoverStyles = usePopoverStyles(); 157 + 172 158 return ( 173 159 <SubmenuTrigger delay={delay}> 174 160 {trigger} ··· 179 165 placement={placement} 180 166 containerPadding={8} 181 167 offset={-8} 182 - {...stylex.props(styles.popover, gray.bgSubtle, gray.text, gray.border)} 183 168 > 184 - <AriaMenu {...props} /> 169 + <AriaMenu {...props} {...stylex.props(popoverStyles)} /> 185 170 </Popover> 186 171 </SubmenuTrigger> 187 172 );
+12 -7
packages/hip-ui/src/components/popover/index.tsx
··· 10 10 } from "react-aria-components"; 11 11 import * as stylex from "@stylexjs/stylex"; 12 12 13 - import { radius } from "../theme/radius.stylex"; 14 13 import { slate } from "../theme/colors.stylex"; 15 - import { gray } from "../theme/semantic-color.stylex"; 16 14 import { spacing } from "../theme/spacing.stylex"; 15 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 17 16 18 17 const styles = stylex.create({ 19 - popover: { 18 + wrapper: { 20 19 filter: `drop-shadow(-0.5px -0.5px 0 ${slate[7]}) drop-shadow(0.5px -0.5px 0 ${slate[7]}) drop-shadow(0.5px 0.5px 0 ${slate[7]}) drop-shadow(-0.5px 0.5px 0 ${slate[7]}) drop-shadow(0px 1px 3px rgb(0 0 0 / 0.1)) drop-shadow(0px -1px 3px rgb(0 0 0 / 0.1))`, 21 20 }, 22 21 content: { 23 - borderRadius: radius["md"], 24 - padding: spacing["2"], 22 + borderWidth: 0, 23 + boxShadow: "none", 24 + paddingBottom: spacing["2"], 25 + paddingLeft: spacing["2"], 26 + paddingRight: spacing["2"], 27 + paddingTop: spacing["2"], 25 28 position: "relative", 26 29 }, 27 30 caret: {}, ··· 53 56 onOpenChange, 54 57 ...popoverProps 55 58 }: TooltipProps) => { 59 + const popoverStyles = usePopoverStyles(); 60 + 56 61 return ( 57 62 <DialogTrigger 58 63 {...({ isOpen, onOpenChange, defaultOpen } as DialogTriggerProps)} ··· 60 65 {trigger} 61 66 62 67 <AriaPopover 63 - {...stylex.props(styles.popover)} 68 + {...stylex.props(styles.wrapper)} 64 69 {...popoverProps} 65 70 offset={8} 66 71 containerPadding={8} ··· 68 73 <OverlayArrow {...stylex.props(styles.caret)}> 69 74 <div {...stylex.props(styles.arrow)} /> 70 75 </OverlayArrow> 71 - <Dialog {...stylex.props(styles.content, gray.bgSubtle, gray.text)}> 76 + <Dialog {...stylex.props(popoverStyles, styles.content)}> 72 77 {children} 73 78 </Dialog> 74 79 </AriaPopover>
+31 -67
packages/hip-ui/src/components/select/index.tsx
··· 14 14 import { FieldError } from "react-aria-components"; 15 15 import { Description, Label } from "../label"; 16 16 import { ChevronDown } from "lucide-react"; 17 - import { spacing } from "../theme/spacing.stylex"; 18 - import { gray } from "../theme/semantic-color.stylex"; 19 - import { slate } from "../theme/colors.stylex"; 20 - import { radius } from "../theme/radius.stylex"; 21 - import { fontSize, lineHeight } from "../theme/typography.stylex"; 22 17 import { Size } from "../types"; 23 18 import { 24 19 ListBox, ··· 31 26 ListBoxSection, 32 27 } from "../listbox"; 33 28 import { SizeContext } from "../context"; 29 + import { useInputStyles } from "../theme/useInputStyles"; 30 + import { usePopoverStyles } from "../theme/usePopoverStyles"; 34 31 35 32 const styles = stylex.create({ 36 - wrapper: { 37 - display: "flex", 38 - flexDirection: "column", 39 - gap: spacing["2"], 40 - }, 41 - trigger: { 42 - alignItems: "center", 43 - boxSizing: "border-box", 44 - display: "flex", 45 - gap: spacing["2"], 46 - justifyContent: "space-between", 47 - lineHeight: lineHeight["none"], 48 - 49 - borderColor: { 50 - default: slate[7], 51 - ":hover": slate[8], 52 - ":focus": slate[9], 53 - }, 54 - borderRadius: radius["md"], 55 - borderStyle: "solid", 56 - borderWidth: 1, 57 - }, 58 - sm: { 59 - fontSize: fontSize["xs"], 60 - height: spacing["6"], 61 - paddingLeft: { ":first-child": spacing["1"] }, 62 - paddingRight: spacing["1"], 63 - }, 64 - md: { 65 - fontSize: fontSize["sm"], 66 - height: spacing["8"], 67 - paddingLeft: { ":first-child": spacing["2"] }, 68 - paddingRight: spacing["2"], 69 - }, 70 - lg: { 71 - fontSize: fontSize["base"], 72 - height: spacing["10"], 73 - paddingLeft: spacing["3"], 74 - paddingRight: spacing["3"], 75 - }, 76 - popover: { 77 - borderRadius: radius["md"], 78 - minWidth: spacing["40"], 79 - overflow: "auto", 33 + matchWidth: { 80 34 width: "var(--trigger-width)", 81 35 }, 82 - value: { 83 - color: { 84 - ":is([data-placeholder])": slate[11], 85 - }, 86 - }, 87 36 }); 88 37 89 38 export interface SelectProps<T extends object, M extends "single" | "multiple"> ··· 102 51 items?: Iterable<T>; 103 52 children: React.ReactNode | ((item: T) => React.ReactNode); 104 53 size?: Size; 54 + placeholder?: string; 105 55 } 106 56 107 57 export function Select< ··· 119 69 shouldFlip, 120 70 shouldUpdatePosition, 121 71 placement, 72 + placeholder = "Select an option", 122 73 ...props 123 74 }: SelectProps<T, M>) { 75 + const inputStyles = useInputStyles({ size }); 76 + const popoverStyles = usePopoverStyles(); 77 + 124 78 return ( 125 79 <SizeContext.Provider value={size}> 126 - <AriaSelect {...props} {...stylex.props(styles.wrapper, style)}> 80 + <AriaSelect 81 + {...props} 82 + {...stylex.props(inputStyles.field, style)} 83 + placeholder={placeholder} 84 + > 127 85 {label && <Label size={size}>{label}</Label>} 128 - <Button 129 - {...stylex.props(styles.trigger, gray.bgUi, gray.text, styles[size])} 130 - > 131 - <SelectValue {...stylex.props(styles.value)} /> 132 - <ChevronDown size={16} aria-hidden="true" /> 86 + <Button {...stylex.props(inputStyles.wrapper)}> 87 + <SelectValue {...stylex.props(inputStyles.input)}> 88 + {({ selectedText, isPlaceholder, defaultChildren }) => { 89 + if (isPlaceholder) return placeholder; 90 + if (selectedText) return selectedText; 91 + 92 + return defaultChildren; 93 + }} 94 + </SelectValue> 95 + <div {...stylex.props(inputStyles.addon)}> 96 + <ChevronDown size={16} aria-hidden="true" /> 97 + </div> 133 98 </Button> 134 99 {description && <Description size={size}>{description}</Description>} 135 100 <FieldError>{errorMessage}</FieldError> ··· 139 104 shouldFlip={shouldFlip} 140 105 shouldUpdatePosition={shouldUpdatePosition} 141 106 placement={placement} 142 - {...stylex.props( 143 - styles.popover, 144 - gray.bgSubtle, 145 - gray.text, 146 - gray.border 147 - )} 148 107 > 149 - <ListBox items={items}>{children}</ListBox> 108 + <ListBox 109 + items={items} 110 + {...stylex.props(popoverStyles, styles.matchWidth)} 111 + > 112 + {children} 113 + </ListBox> 150 114 </Popover> 151 115 </AriaSelect> 152 116 </SizeContext.Provider>
+11
packages/hip-ui/src/components/select/select-config.ts
··· 3 3 export const selectConfig: ComponentConfig = { 4 4 name: "select", 5 5 filepath: "./index.tsx", 6 + hipDependencies: [ 7 + "../theme/spacing.stylex.tsx", 8 + "../theme/colors.stylex.tsx", 9 + "../theme/radius.stylex.tsx", 10 + "../theme/semantic-color.stylex.tsx", 11 + "../theme/typography.stylex.tsx", 12 + "../theme/breakpoints.stylex.tsx", 13 + "../theme/shadow.stylex.tsx", 14 + "../theme/useInputStyles.ts", 15 + "../theme/usePopoverStyles.ts", 16 + ], 6 17 };
+17 -105
packages/hip-ui/src/components/text-field/index.tsx
··· 11 11 TextField as AriaTextField, 12 12 } from "react-aria-components"; 13 13 import * as stylex from "@stylexjs/stylex"; 14 - import { gray } from "../theme/semantic-color.stylex"; 15 - import { spacing } from "../theme/spacing.stylex"; 16 14 import { Description, Label } from "../label"; 17 - import { radius } from "../theme/radius.stylex"; 18 - import { lineHeight, fontSize } from "../theme/typography.stylex"; 19 - import { slate } from "../theme/colors.stylex"; 20 15 import { useRef } from "react"; 21 16 import { useState } from "react"; 22 17 import { IconButton } from "../icon-button"; 23 18 import { Eye, EyeOff } from "lucide-react"; 24 19 import { use } from "react"; 25 20 import { Size } from "../types"; 26 - 27 - const styles = stylex.create({ 28 - wrapper: { 29 - display: "flex", 30 - flexDirection: "column", 31 - gap: spacing["2"], 32 - }, 33 - addon: { 34 - color: gray.textDim, 35 - flexShrink: 0, 36 - height: "100%", 37 - minWidth: spacing["8"], 38 - paddingLeft: { ":first-child": spacing["0.5"] }, 39 - paddingRight: { 40 - ":last-child": spacing["2"], 41 - ":last-child:has(svg)": spacing["0.5"], 42 - }, 43 - 44 - alignItems: "center", 45 - display: "flex", 46 - gap: spacing["0.5"], 47 - justifyContent: "center", 48 - 49 - // eslint-disable-next-line @stylexjs/no-legacy-contextual-styles, @stylexjs/valid-styles 50 - ":is(*) svg": { 51 - flexShrink: 0, 52 - height: spacing["4"], 53 - pointerEvents: "none", 54 - width: spacing["4"], 55 - }, 56 - }, 57 - inputWrapper: { 58 - borderRadius: radius["md"], 59 - boxSizing: "border-box", 60 - display: "flex", 61 - 62 - borderColor: { 63 - default: slate[7], 64 - ":hover": slate[8], 65 - ":focus": slate[9], 66 - }, 67 - borderStyle: "solid", 68 - borderWidth: 1, 69 - }, 70 - input: { 71 - backgroundColor: "transparent", 72 - borderWidth: 0, 73 - color: { 74 - "::placeholder": slate[11], 75 - }, 76 - flexGrow: 1, 77 - lineHeight: lineHeight["none"], 78 - outline: "none", 79 - }, 80 - sm: { 81 - height: spacing["6"], 82 - }, 83 - smInput: { 84 - fontSize: fontSize["xs"], 85 - paddingLeft: { ":first-child": spacing["1"] }, 86 - paddingRight: spacing["1"], 87 - }, 88 - md: { 89 - height: spacing["8"], 90 - }, 91 - mdInput: { 92 - fontSize: fontSize["sm"], 93 - paddingLeft: { ":first-child": spacing["2"] }, 94 - paddingRight: spacing["2"], 95 - }, 96 - lg: { 97 - height: spacing["10"], 98 - }, 99 - lgInput: { 100 - fontSize: fontSize["base"], 101 - paddingLeft: spacing["3"], 102 - paddingRight: spacing["3"], 103 - }, 104 - description: { 105 - color: gray.textDim, 106 - fontSize: fontSize["sm"], 107 - lineHeight: lineHeight["sm"], 108 - }, 109 - descriptionSm: { 110 - fontSize: fontSize["xs"], 111 - lineHeight: lineHeight["xs"], 112 - }, 113 - }); 21 + import { useInputStyles } from "../theme/useInputStyles"; 114 22 115 23 function PasswordToggle({ 116 24 type, 117 25 setType, 26 + style, 118 27 }: { 119 28 type: TextFieldProps["type"]; 120 29 setType: (type: TextFieldProps["type"]) => void; 30 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 121 31 }) { 122 32 const state = use(InputContext); 123 33 124 34 if (!state || !("value" in state) || !state.value) return null; 125 35 126 36 return ( 127 - <div {...stylex.props(styles.addon)}> 37 + <div {...stylex.props(style)}> 128 38 <IconButton 129 39 size="sm" 130 40 variant="tertiary" ··· 165 75 props.type || "text" 166 76 ); 167 77 const isPasswordInput = props.type === "password"; 78 + const inputStyles = useInputStyles({ size }); 168 79 169 80 return ( 170 81 <AriaTextField 171 82 {...props} 172 83 type={type} 173 - {...stylex.props(styles.wrapper, style)} 84 + {...stylex.props(inputStyles.field, style)} 174 85 > 175 86 <Label size={size}>{label}</Label> 176 87 <div 177 - {...stylex.props( 178 - styles.inputWrapper, 179 - gray.bgUi, 180 - gray.text, 181 - styles[size] 182 - )} 88 + {...stylex.props(inputStyles.wrapper)} 183 89 onClick={() => inputRef.current?.focus()} 184 90 > 185 - {prefix && <div {...stylex.props(styles.addon)}>{prefix}</div>} 91 + {prefix && <div {...stylex.props(inputStyles.addon)}>{prefix}</div>} 186 92 <Input 187 - {...stylex.props(styles.input, styles[`${size}Input`])} 93 + {...stylex.props(inputStyles.input)} 188 94 ref={inputRef} 189 95 placeholder={placeholder} 190 96 /> 191 - {suffix && <div {...stylex.props(styles.addon)}>{suffix}</div>} 192 - {isPasswordInput && <PasswordToggle type={type} setType={setType} />} 97 + {suffix && <div {...stylex.props(inputStyles.addon)}>{suffix}</div>} 98 + {isPasswordInput && ( 99 + <PasswordToggle 100 + type={type} 101 + setType={setType} 102 + style={inputStyles.addon} 103 + /> 104 + )} 193 105 </div> 194 106 {description && <Description size={size}>{description}</Description>} 195 107 <FieldError>{errorMessage}</FieldError>
+1
packages/hip-ui/src/components/text-field/text-field-config.ts
··· 11 11 "../theme/typography.stylex.tsx", 12 12 "../theme/breakpoints.stylex.tsx", 13 13 "../theme/shadow.stylex.tsx", 14 + "../theme/useInputStyles.ts", 14 15 ], 15 16 dependencies: { 16 17 "lucide-react": "^0.545.0",
+48 -48
packages/hip-ui/src/components/theme/colors.stylex.tsx
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 2 3 3 export const slateLight = stylex.defineVars({ 4 - 1: "#fcfcfd", 5 - 2: "#f9f9fb", 6 - 3: "#f0f0f3", 7 - 4: "#e8e8ec", 8 - 5: "#e0e1e6", 9 - 6: "#d9d9e0", 10 - 7: "#cdced6", 11 - 8: "#b9bbc6", 12 - 9: "#8b8d98", 13 - 10: "#80838d", 14 - 11: "#60646c", 15 - 12: "#1c2024", 4 + 1: stylex.types.color("#fcfcfd"), 5 + 2: stylex.types.color("#f9f9fb"), 6 + 3: stylex.types.color("#f0f0f3"), 7 + 4: stylex.types.color("#e8e8ec"), 8 + 5: stylex.types.color("#e0e1e6"), 9 + 6: stylex.types.color("#d9d9e0"), 10 + 7: stylex.types.color("#cdced6"), 11 + 8: stylex.types.color("#b9bbc6"), 12 + 9: stylex.types.color("#8b8d98"), 13 + 10: stylex.types.color("#80838d"), 14 + 11: stylex.types.color("#60646c"), 15 + 12: stylex.types.color("#1c2024"), 16 16 }); 17 17 18 18 export const slateLightP3 = stylex.defineVars({ 19 - 1: "color(display-p3 0.988 0.988 0.992)", 20 - 2: "color(display-p3 0.976 0.976 0.984)", 21 - 3: "color(display-p3 0.94 0.941 0.953)", 22 - 4: "color(display-p3 0.908 0.909 0.925)", 23 - 5: "color(display-p3 0.88 0.881 0.901)", 24 - 6: "color(display-p3 0.85 0.852 0.876)", 25 - 7: "color(display-p3 0.805 0.808 0.838)", 26 - 8: "color(display-p3 0.727 0.733 0.773)", 27 - 9: "color(display-p3 0.547 0.553 0.592)", 28 - 10: "color(display-p3 0.503 0.512 0.549)", 29 - 11: "color(display-p3 0.379 0.392 0.421)", 30 - 12: "color(display-p3 0.113 0.125 0.14)", 19 + 1: stylex.types.color("color(display-p3 0.988 0.988 0.992)"), 20 + 2: stylex.types.color("color(display-p3 0.976 0.976 0.984)"), 21 + 3: stylex.types.color("color(display-p3 0.94 0.941 0.953)"), 22 + 4: stylex.types.color("color(display-p3 0.908 0.909 0.925)"), 23 + 5: stylex.types.color("color(display-p3 0.88 0.881 0.901)"), 24 + 6: stylex.types.color("color(display-p3 0.85 0.852 0.876)"), 25 + 7: stylex.types.color("color(display-p3 0.805 0.808 0.838)"), 26 + 8: stylex.types.color("color(display-p3 0.727 0.733 0.773)"), 27 + 9: stylex.types.color("color(display-p3 0.547 0.553 0.592)"), 28 + 10: stylex.types.color("color(display-p3 0.503 0.512 0.549)"), 29 + 11: stylex.types.color("color(display-p3 0.379 0.392 0.421)"), 30 + 12: stylex.types.color("color(display-p3 0.113 0.125 0.14)"), 31 31 }); 32 32 33 33 export const slateDark = stylex.defineVars({ 34 - 1: "#111113", 35 - 2: "#18191b", 36 - 3: "#212225", 37 - 4: "#272a2d", 38 - 5: "#2e3135", 39 - 6: "#363a3f", 40 - 7: "#43484e", 41 - 8: "#5a6169", 42 - 9: "#696e77", 43 - 10: "#777b84", 44 - 11: "#b0b4ba", 45 - 12: "#edeef0", 34 + 1: stylex.types.color("#111113"), 35 + 2: stylex.types.color("#18191b"), 36 + 3: stylex.types.color("#212225"), 37 + 4: stylex.types.color("#272a2d"), 38 + 5: stylex.types.color("#2e3135"), 39 + 6: stylex.types.color("#363a3f"), 40 + 7: stylex.types.color("#43484e"), 41 + 8: stylex.types.color("#5a6169"), 42 + 9: stylex.types.color("#696e77"), 43 + 10: stylex.types.color("#777b84"), 44 + 11: stylex.types.color("#b0b4ba"), 45 + 12: stylex.types.color("#edeef0"), 46 46 }); 47 47 48 48 export const slateDarkP3 = stylex.defineVars({ 49 - 1: "color(display-p3 0.067 0.067 0.074)", 50 - 2: "color(display-p3 0.095 0.098 0.105)", 51 - 3: "color(display-p3 0.13 0.135 0.145)", 52 - 4: "color(display-p3 0.156 0.163 0.176)", 53 - 5: "color(display-p3 0.183 0.191 0.206)", 54 - 6: "color(display-p3 0.215 0.226 0.244)", 55 - 7: "color(display-p3 0.265 0.28 0.302)", 56 - 8: "color(display-p3 0.357 0.381 0.409)", 57 - 9: "color(display-p3 0.415 0.431 0.463)", 58 - 10: "color(display-p3 0.469 0.483 0.514)", 59 - 11: "color(display-p3 0.692 0.704 0.728)", 60 - 12: "color(display-p3 0.93 0.933 0.94)", 49 + 1: stylex.types.color("color(display-p3 0.067 0.067 0.074)"), 50 + 2: stylex.types.color("color(display-p3 0.095 0.098 0.105)"), 51 + 3: stylex.types.color("color(display-p3 0.13 0.135 0.145)"), 52 + 4: stylex.types.color("color(display-p3 0.156 0.163 0.176)"), 53 + 5: stylex.types.color("color(display-p3 0.183 0.191 0.206)"), 54 + 6: stylex.types.color("color(display-p3 0.215 0.226 0.244)"), 55 + 7: stylex.types.color("color(display-p3 0.265 0.28 0.302)"), 56 + 8: stylex.types.color("color(display-p3 0.357 0.381 0.409)"), 57 + 9: stylex.types.color("color(display-p3 0.415 0.431 0.463)"), 58 + 10: stylex.types.color("color(display-p3 0.469 0.483 0.514)"), 59 + 11: stylex.types.color("color(display-p3 0.692 0.704 0.728)"), 60 + 12: stylex.types.color("color(display-p3 0.93 0.933 0.94)"), 61 61 }); 62 62 63 63 export const slate = stylex.defineVars({
+100
packages/hip-ui/src/components/theme/useInputStyles.ts
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + import { gray } from "./semantic-color.stylex"; 3 + import { spacing } from "./spacing.stylex"; 4 + import { radius } from "./radius.stylex"; 5 + import { lineHeight, fontSize } from "./typography.stylex"; 6 + import { slate } from "./colors.stylex"; 7 + import { Size } from "../types"; 8 + 9 + const styles = stylex.create({ 10 + field: { 11 + display: "flex", 12 + flexDirection: "column", 13 + gap: spacing["2"], 14 + }, 15 + addon: { 16 + color: gray.textDim, 17 + flexShrink: 0, 18 + height: "100%", 19 + minWidth: spacing["8"], 20 + paddingLeft: { ":first-child": spacing["0.5"] }, 21 + paddingRight: { 22 + ":last-child": spacing["2"], 23 + ":last-child:has(svg)": spacing["0.5"], 24 + }, 25 + 26 + alignItems: "center", 27 + display: "flex", 28 + gap: spacing["0.5"], 29 + justifyContent: "center", 30 + 31 + // eslint-disable-next-line @stylexjs/no-legacy-contextual-styles, @stylexjs/valid-styles 32 + ":is(*) svg": { 33 + flexShrink: 0, 34 + height: spacing["4"], 35 + pointerEvents: "none", 36 + width: spacing["4"], 37 + }, 38 + }, 39 + inputWrapper: { 40 + borderRadius: radius["md"], 41 + boxSizing: "border-box", 42 + display: "flex", 43 + gap: spacing["2"], 44 + lineHeight: lineHeight["none"], 45 + padding: 0, 46 + 47 + borderColor: { 48 + default: slate[7], 49 + ":hover": slate[8], 50 + ":focus": slate[9], 51 + }, 52 + borderStyle: "solid", 53 + borderWidth: 1, 54 + }, 55 + input: { 56 + alignItems: "center", 57 + backgroundColor: "transparent", 58 + borderWidth: 0, 59 + color: { 60 + ":is(::placeholder,[data-placeholder])": slate[11], 61 + }, 62 + display: "flex", 63 + flexGrow: 1, 64 + lineHeight: lineHeight["none"], 65 + outline: "none", 66 + }, 67 + sm: { 68 + height: spacing["6"], 69 + }, 70 + smInput: { 71 + fontSize: fontSize["xs"], 72 + paddingLeft: { ":first-child": spacing["1"] }, 73 + paddingRight: spacing["1"], 74 + }, 75 + md: { 76 + height: spacing["8"], 77 + }, 78 + mdInput: { 79 + fontSize: fontSize["sm"], 80 + paddingLeft: { ":first-child": spacing["2"] }, 81 + paddingRight: spacing["2"], 82 + }, 83 + lg: { 84 + height: spacing["10"], 85 + }, 86 + lgInput: { 87 + fontSize: fontSize["base"], 88 + paddingLeft: spacing["3"], 89 + paddingRight: spacing["3"], 90 + }, 91 + }); 92 + 93 + export function useInputStyles({ size = "md" }: { size?: Size }) { 94 + return { 95 + field: [styles.field], 96 + wrapper: [styles.inputWrapper, gray.bgUi, gray.text, styles[size]], 97 + input: [styles.input, styles[`${size}Input`]], 98 + addon: [styles.addon], 99 + }; 100 + }
+23
packages/hip-ui/src/components/theme/usePopoverStyles.ts
··· 1 + import * as stylex from "@stylexjs/stylex"; 2 + 3 + import { radius } from "./radius.stylex"; 4 + import { spacing } from "./spacing.stylex"; 5 + import { gray } from "./semantic-color.stylex"; 6 + import { shadow } from "./shadow.stylex"; 7 + 8 + const styles = stylex.create({ 9 + popover: { 10 + borderRadius: radius["md"], 11 + boxShadow: shadow["md"], 12 + minWidth: spacing["40"], 13 + outline: "none", 14 + overflow: "auto", 15 + 16 + paddingBottom: spacing["1"], 17 + paddingTop: spacing["1"], 18 + }, 19 + }); 20 + 21 + export function usePopoverStyles() { 22 + return [styles.popover, gray.bgSubtle, gray.text, gray.border]; 23 + }
+131
packages/hip-ui/src/components/toggle-button copy/index.tsx
··· 1 + import { ToggleButtonProps as AriaToggleButtonProps } from "react-aria-components"; 2 + import { ToggleButton as AriaToggleButton } from "react-aria-components"; 3 + import * as stylex from "@stylexjs/stylex"; 4 + 5 + import { spacing } from "../theme/spacing.stylex"; 6 + import { plum, slate } from "../theme/colors.stylex"; 7 + import { Children } from "react"; 8 + import { useButtonStyles } from "../theme/useButtonStyles"; 9 + 10 + const styles = stylex.create({ 11 + primarySelected: { 12 + backgroundColor: { 13 + default: plum[9], 14 + ":hover": plum[10], 15 + ":active": plum[11], 16 + }, 17 + color: "light-dark(white, black)", 18 + }, 19 + secondarySelected: { 20 + backgroundColor: { 21 + default: slate[6], 22 + ":hover": slate[7], 23 + ":active": slate[8], 24 + }, 25 + borderColor: { 26 + default: slate[6], 27 + ":hover": slate[7], 28 + ":active": slate[8], 29 + }, 30 + }, 31 + tertiarySelected: { 32 + backgroundColor: { 33 + default: slate[6], 34 + ":hover": slate[7], 35 + ":active": slate[8], 36 + }, 37 + borderColor: { 38 + default: slate[6], 39 + ":hover": slate[7], 40 + ":active": slate[8], 41 + }, 42 + }, 43 + outlineSelected: { 44 + backgroundColor: { 45 + default: slate[6], 46 + ":hover": slate[7], 47 + ":active": slate[8], 48 + }, 49 + borderColor: { 50 + default: slate[6], 51 + ":hover": slate[7], 52 + ":active": slate[8], 53 + }, 54 + }, 55 + sm: { 56 + paddingLeft: { 57 + ":has(> * + *, > *:not(svg):only-child)": spacing["2"], 58 + }, 59 + paddingRight: { 60 + ":has(> * + *, > *:not(svg):only-child)": spacing["2"], 61 + }, 62 + width: { 63 + ":has(svg:only-child)": spacing["7"], 64 + }, 65 + }, 66 + md: { 67 + paddingLeft: { 68 + ":has(> * + *, > *:not(svg):only-child)": spacing["3"], 69 + }, 70 + paddingRight: { 71 + ":has(> * + *, > *:not(svg):only-child)": spacing["3"], 72 + }, 73 + width: { 74 + ":has(svg:only-child)": spacing["8"], 75 + }, 76 + }, 77 + lg: { 78 + paddingLeft: { 79 + ":has(> * + *, > *:not(svg):only-child)": spacing["4"], 80 + }, 81 + paddingRight: { 82 + ":has(> * + *, > *:not(svg):only-child)": spacing["4"], 83 + }, 84 + width: { 85 + ":has(svg:only-child)": spacing["10"], 86 + }, 87 + }, 88 + }); 89 + 90 + export interface ToggleButtonProps 91 + extends Omit<AriaToggleButtonProps, "style" | "className" | "children"> { 92 + style?: stylex.StyleXStyles | stylex.StyleXStyles[]; 93 + variant?: "primary" | "secondary" | "tertiary" | "outline"; 94 + size?: "sm" | "md" | "lg"; 95 + children?: React.ReactNode; 96 + } 97 + 98 + export function ToggleButton({ 99 + style, 100 + variant = "primary", 101 + size = "md", 102 + children, 103 + ...props 104 + }: ToggleButtonProps) { 105 + const buttonStyles = useButtonStyles({ variant, size }); 106 + const toggleButtonStyles = (isSelected?: boolean) => 107 + stylex.props( 108 + buttonStyles, 109 + styles[size], 110 + isSelected ? styles[`${variant}Selected`] : undefined, 111 + style 112 + ); 113 + 114 + return ( 115 + <AriaToggleButton 116 + {...props} 117 + {...toggleButtonStyles()} 118 + className={({ isSelected }) => 119 + toggleButtonStyles(isSelected).className || "" 120 + } 121 + > 122 + {Children.map(children, (child, index) => 123 + typeof child === "string" ? ( 124 + <span key={`${child}-${index}`}>{child}</span> 125 + ) : ( 126 + child 127 + ) 128 + )} 129 + </AriaToggleButton> 130 + ); 131 + }
+1 -1
packages/hip-ui/src/components/toggle-button/index.tsx
··· 5 5 import { spacing } from "../theme/spacing.stylex"; 6 6 import { plum, slate } from "../theme/colors.stylex"; 7 7 import { Children } from "react"; 8 - import { useButtonStyles } from "../button/useButtonStyles"; 8 + import { useButtonStyles } from "../theme/useButtonStyles"; 9 9 import { ButtonVariant, Size } from "../types"; 10 10 11 11 const styles = stylex.create({