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.

tweaks

+908 -220
+1
apps/docs/src/components/card/index.tsx
··· 100 100 margin: 0, 101 101 fontSize: fontSize["sm"], 102 102 fontWeight: fontWeight["normal"], 103 + lineHeight: lineHeight["sm"], 103 104 }, 104 105 cardBody: { 105 106 gap: "calc(var(--card-gap) * 0.5)",
-2
apps/docs/src/components/haptics/index.tsx
··· 1 - /* eslint-disable react/only-export-components -- Barrel file for haptics utility */ 2 1 export { 3 2 setHapticsEnabled, 4 3 isHapticsEnabled, ··· 6 5 } from "./haptics"; 7 6 export { HapticsContext, HapticsProvider } from "./context"; 8 7 export { useHaptics } from "./useHaptics"; 9 - /* eslint-enable react/only-export-components */
+14 -2
apps/docs/src/components/select/index.tsx
··· 21 21 import type { 22 22 InputValidationState, 23 23 InputVariant, 24 + LabelVariant, 24 25 Size, 25 26 StyleXComponentProps, 26 27 } from "../theme/types"; ··· 65 66 shouldUpdatePosition?: boolean; 66 67 placement?: PopoverProps["placement"]; 67 68 isVirtualized?: boolean; 69 + labelVariant?: "vertical" | "horizontal"; 68 70 } 69 71 70 72 function SelectContent<T extends object>({ ··· 86 88 shouldFlip, 87 89 shouldUpdatePosition, 88 90 placement, 91 + labelVariant, 89 92 }: SelectContentProps<T>) { 90 93 const inputStyles = useInputStyles({ 91 94 size, 92 95 variant, 96 + labelVariant, 93 97 validationState: isInvalid ? "invalid" : validationState, 94 98 }); 95 99 const popoverStyles = usePopoverStyles(); ··· 122 126 123 127 return ( 124 128 <> 125 - <Label>{label}</Label> 129 + <Label style={inputStyles.label}>{label}</Label> 126 130 <Button {...stylex.props(inputStyles.wrapper)}> 127 131 {prefix != null && ( 128 132 <div {...stylex.props(inputStyles.addon)}>{prefix}</div> ··· 178 182 | "placement" 179 183 > { 180 184 label?: string; 185 + labelVariant?: LabelVariant; 181 186 description?: string; 182 187 errorMessage?: string | ((validation: ValidationResult) => string); 183 188 items?: Iterable<T>; ··· 204 209 style, 205 210 size: sizeProp, 206 211 variant, 212 + labelVariant, 207 213 validationState, 208 214 shouldCloseOnInteractOutside, 209 215 shouldFlip, ··· 217 223 ...props 218 224 }: SelectProps<T, M>) { 219 225 const size = sizeProp || use(SizeContext); 220 - const inputStyles = useInputStyles({ size, variant, validationState }); 226 + const inputStyles = useInputStyles({ 227 + size, 228 + variant, 229 + labelVariant, 230 + validationState, 231 + }); 221 232 222 233 return ( 223 234 <SizeContext value={size}> ··· 246 257 shouldFlip={shouldFlip} 247 258 shouldUpdatePosition={shouldUpdatePosition} 248 259 placement={placement} 260 + labelVariant={labelVariant} 249 261 > 250 262 {children} 251 263 </SelectContent>
+20 -3
apps/docs/src/components/switch/index.tsx
··· 15 15 import { typeramp } from "../theme/typography.stylex"; 16 16 17 17 const styles = stylex.create({ 18 + labelLeft: { 19 + flexGrow: 1, 20 + minWidth: 0, 21 + }, 18 22 wrapper: { 19 23 gap: spacing["3"], 20 24 alignItems: "center", ··· 66 70 67 71 interface SwitchBaseProps extends StyleXComponentProps< 68 72 Omit<AriaSwitchProps, "children"> 69 - > {} 73 + > { 74 + labelVariant?: "left" | "right"; 75 + } 70 76 71 77 interface SwitchWithChildrenProps extends SwitchBaseProps { 72 78 children: React.ReactNode; ··· 87 93 | SwitchWithAriaLabelProps 88 94 | SwitchWithAriaLabelledbyProps; 89 95 90 - export function Switch({ children, style, onChange, ...props }: SwitchProps) { 96 + export function Switch({ 97 + children, 98 + style, 99 + onChange, 100 + labelVariant = "right", 101 + ...props 102 + }: SwitchProps) { 91 103 const { trigger } = useHaptics(); 92 104 93 105 const handleChange = (isSelected: boolean) => { ··· 101 113 onChange={handleChange} 102 114 {...stylex.props(styles.wrapper, style)} 103 115 > 116 + {children != null && labelVariant === "left" && ( 117 + <div {...stylex.props(typeramp.label, styles.labelLeft)}> 118 + {children} 119 + </div> 120 + )} 104 121 <div {...stylex.props(styles.indicator)}> 105 122 <div {...stylex.props(styles.thumb)} /> 106 123 </div> 107 - {children != null && ( 124 + {children != null && labelVariant === "right" && ( 108 125 <div {...stylex.props(typeramp.label)}>{children}</div> 109 126 )} 110 127 </AriaSwitch>
-1
apps/docs/src/components/table/index.tsx
··· 62 62 backgroundColor: uiColor.component1, 63 63 display: "flex", 64 64 justifyContent: "space-between", 65 - height: spacing["10"], 66 65 paddingLeft: { 67 66 default: spacing["2"], 68 67 ":is(:first-child > *)": spacing["2"],
+1
apps/docs/src/components/tabs/index.tsx
··· 39 39 }, 40 40 tabList: { 41 41 gap: spacing["1"], 42 + overflow: "auto", 42 43 alignItems: { 43 44 ":is([data-orientation=horizontal])": "flex-start", 44 45 ":is([data-orientation=vertical])": "stretch",
+35 -5
apps/docs/src/components/text-field/index.tsx
··· 16 16 import type { 17 17 InputValidationState, 18 18 InputVariant, 19 + LabelVariant, 19 20 Size, 20 21 StyleXComponentProps, 21 22 } from "../theme/types"; 22 23 23 24 import { SizeContext } from "../context"; 25 + import { Flex } from "../flex"; 24 26 import { IconButton } from "../icon-button"; 25 27 import { Description, FieldErrorMessage, Label } from "../label"; 26 28 import { SuffixIcon } from "../suffix-icon"; ··· 57 59 58 60 interface TextFieldContentProps { 59 61 label?: React.ReactNode; 62 + labelVariant?: LabelVariant; 60 63 description?: string; 61 64 errorMessage?: string | ((validation: ValidationResult) => string); 62 65 size: Size; ··· 72 75 73 76 function TextFieldContent({ 74 77 label, 78 + labelVariant, 75 79 description, 76 80 errorMessage, 77 81 size, ··· 89 93 const inputStyles = useInputStyles({ 90 94 size, 91 95 variant, 96 + labelVariant, 92 97 validationState: isInvalid ? "invalid" : validationState, 93 98 }); 94 99 95 - return ( 100 + const content = ( 96 101 <> 97 - <Label>{label}</Label> 98 102 {/* 99 103 This onClick is specifically for mouse users not clicking directly on the input. 100 104 A keyboard user would not encounter the same issue. ··· 126 130 validationState={validationState} 127 131 /> 128 132 </div> 129 - <Description>{description}</Description> 130 - {errorMessage && <FieldErrorMessage>{errorMessage}</FieldErrorMessage>} 133 + <Description style={inputStyles.description}>{description}</Description> 134 + {errorMessage && ( 135 + <FieldErrorMessage style={inputStyles.errorMessage}> 136 + {errorMessage} 137 + </FieldErrorMessage> 138 + )} 139 + </> 140 + ); 141 + 142 + return ( 143 + <> 144 + <Label style={inputStyles.label}>{label}</Label> 145 + 146 + {labelVariant === "horizontal" ? ( 147 + <Flex direction="column" gap="2"> 148 + {content} 149 + </Flex> 150 + ) : ( 151 + content 152 + )} 131 153 </> 132 154 ); 133 155 } ··· 137 159 StyleXComponentProps<Omit<AriaTextFieldProps, "isInvalid">>, 138 160 Pick<InputProps, "placeholder"> { 139 161 label?: React.ReactNode; 162 + labelVariant?: LabelVariant; 140 163 description?: string; 141 164 errorMessage?: string | ((validation: ValidationResult) => string); 142 165 size?: Size; ··· 157 180 prefix, 158 181 suffix, 159 182 placeholder, 183 + labelVariant, 160 184 ...props 161 185 }: TextFieldProps) { 162 186 const size = sizeProp || use(SizeContext); 163 187 const [type, setType] = useState<TextFieldProps["type"]>( 164 188 props.type || "text", 165 189 ); 166 - const inputStyles = useInputStyles({ size, variant, validationState }); 190 + const inputStyles = useInputStyles({ 191 + size, 192 + variant, 193 + labelVariant, 194 + validationState, 195 + }); 167 196 168 197 return ( 169 198 <SizeContext value={size}> ··· 176 205 {({ isInvalid }) => ( 177 206 <TextFieldContent 178 207 label={label} 208 + labelVariant={labelVariant} 179 209 description={description} 180 210 errorMessage={errorMessage} 181 211 size={size}
+1
apps/docs/src/components/theme/types.ts
··· 11 11 | "outline" 12 12 | "critical" 13 13 | "critical-outline"; 14 + export type LabelVariant = "vertical" | "horizontal"; 14 15 export type InputVariant = "primary" | "secondary" | "tertiary"; 15 16 export type InputValidationState = "valid" | "invalid" | "warning"; 16 17 export type ButtonGroupVariant = "grouped" | "separate";
+71 -22
apps/docs/src/components/theme/useInputStyles.ts
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 2 import { use } from "react"; 3 3 4 - import type { InputValidationState, InputVariant, Size } from "../theme/types"; 4 + import type { 5 + InputValidationState, 6 + InputVariant, 7 + LabelVariant, 8 + Size, 9 + } from "../theme/types"; 5 10 6 11 import { SizeContext } from "../context"; 7 12 import { animationDuration } from "./animations.stylex"; ··· 15 20 import { radius } from "./radius.stylex"; 16 21 import { ui } from "./semantic-color.stylex"; 17 22 import { spacing } from "./spacing.stylex"; 18 - import { fontSize, lineHeight } from "./typography.stylex"; 23 + import { fontSize, fontWeight, lineHeight } from "./typography.stylex"; 19 24 20 25 const styles = stylex.create({ 21 26 field: { ··· 122 127 borderWidth: 1, 123 128 backgroundColor: { 124 129 default: uiColor.bg, 125 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 130 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 126 131 uiColor.component1, 127 132 ":is([data-pressed=true]):not(:disabled)": uiColor.component2, 128 133 ":disabled": "transparent", ··· 142 147 }, 143 148 backgroundColor: { 144 149 default: criticalColor.bgSubtle, 145 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 150 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 146 151 criticalColor.component2, 147 152 ":disabled": "transparent", 148 153 }, ··· 157 162 }, 158 163 backgroundColor: { 159 164 default: warningColor.bgSubtle, 160 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 165 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 161 166 warningColor.component2, 162 167 ":disabled": "transparent", 163 168 }, ··· 172 177 }, 173 178 backgroundColor: { 174 179 default: successColor.bgSubtle, 175 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 180 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 176 181 successColor.component2, 177 182 ":disabled": "transparent", 178 183 }, ··· 190 195 borderWidth: 1, 191 196 backgroundColor: { 192 197 default: uiColor.component1, 193 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 198 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 194 199 uiColor.component2, 195 200 ":is([data-pressed=true]):not(:disabled)": uiColor.component3, 196 201 ":disabled": uiColor.component1, ··· 202 207 secondaryInvalid: { 203 208 borderColor: { 204 209 default: criticalColor.component1, 205 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 210 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 206 211 criticalColor.component2, 207 212 }, 208 213 backgroundColor: { 209 214 default: criticalColor.component1, 210 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 215 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 211 216 criticalColor.component2, 212 217 }, 213 218 }, 214 219 secondaryWarning: { 215 220 borderColor: { 216 221 default: warningColor.component1, 217 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 222 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 218 223 warningColor.component2, 219 224 }, 220 225 backgroundColor: { 221 226 default: warningColor.component1, 222 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 227 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 223 228 warningColor.component2, 224 229 }, 225 230 color: warningColor.text2, ··· 227 232 secondaryValid: { 228 233 borderColor: { 229 234 default: successColor.component1, 230 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 235 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 231 236 successColor.component2, 232 237 }, 233 238 backgroundColor: { 234 239 default: successColor.component1, 235 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 240 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 236 241 successColor.component2, 237 242 }, 238 243 color: successColor.text2, ··· 240 245 tertiary: { 241 246 borderColor: { 242 247 default: "transparent", 243 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 248 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 244 249 uiColor.component2, 245 250 ":is([data-pressed=true]):not(:disabled)": uiColor.component3, 246 251 ":disabled": "transparent", ··· 249 254 borderWidth: 1, 250 255 backgroundColor: { 251 256 default: "transparent", 252 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 257 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 253 258 uiColor.component2, 254 259 ":is([data-pressed=true]):not(:disabled)": uiColor.component3, 255 260 ":disabled": "transparent", ··· 261 266 tertiaryInvalid: { 262 267 borderColor: { 263 268 default: "transparent", 264 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 269 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 265 270 criticalColor.component1, 266 271 ":is([data-pressed=true]):not(:disabled)": criticalColor.component2, 267 272 ":disabled": "transparent", 268 273 }, 269 274 backgroundColor: { 270 275 default: "transparent", 271 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 276 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 272 277 criticalColor.component1, 273 278 ":is([data-pressed=true]):not(:disabled)": criticalColor.component2, 274 279 ":disabled": "transparent", ··· 278 283 tertiaryWarning: { 279 284 borderColor: { 280 285 default: "transparent", 281 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 286 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 282 287 warningColor.component1, 283 288 ":is([data-pressed=true]):not(:disabled)": warningColor.component2, 284 289 ":disabled": "transparent", 285 290 }, 286 291 backgroundColor: { 287 292 default: "transparent", 288 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 293 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 289 294 warningColor.component1, 290 295 ":is([data-pressed=true]):not(:disabled)": warningColor.component2, 291 296 ":disabled": "transparent", ··· 295 300 tertiaryValid: { 296 301 borderColor: { 297 302 default: "transparent", 298 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 303 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 299 304 successColor.component1, 300 305 ":is([data-pressed=true]):not(:disabled)": successColor.component2, 301 306 ":disabled": "transparent", 302 307 }, 303 308 backgroundColor: { 304 309 default: "transparent", 305 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 310 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 306 311 successColor.component1, 307 312 ":is([data-pressed=true]):not(:disabled)": successColor.component2, 308 313 ":disabled": "transparent", ··· 340 345 wrapperSizeLg: { 341 346 height: spacing["10"], 342 347 }, 348 + horizontalLabel: { 349 + gap: spacing["4"], 350 + alignItems: "flex-start", 351 + flexDirection: "row", 352 + }, 353 + horizontalLabelText: { 354 + flexGrow: 1, 355 + minWidth: 0, 356 + }, 357 + horizontalLabelTextSm: { 358 + lineHeight: spacing["6"], 359 + }, 360 + horizontalLabelTextMd: { 361 + lineHeight: spacing["8"], 362 + }, 363 + horizontalLabelTextLg: { 364 + fontSize: fontSize["base"], 365 + fontWeight: fontWeight["medium"], 366 + lineHeight: spacing["10"], 367 + }, 368 + label: { 369 + paddingLeft: spacing["1"], 370 + paddingRight: spacing["1"], 371 + }, 372 + additionalText: { 373 + paddingLeft: spacing["2"], 374 + paddingRight: spacing["2"], 375 + }, 343 376 }); 344 377 345 378 export function useInputStyles({ 346 379 size: sizeProp, 347 380 variant = "primary", 381 + labelVariant = "vertical", 348 382 validationState, 349 383 }: { 350 384 size: Size | undefined; 351 385 variant: InputVariant | undefined; 386 + labelVariant: LabelVariant | undefined; 352 387 validationState: InputValidationState | undefined; 353 388 }) { 354 389 const size = sizeProp || use(SizeContext); 355 390 356 391 return { 357 - field: [styles.field], 392 + field: [ 393 + styles.field, 394 + labelVariant === "horizontal" && styles.horizontalLabel, 395 + ], 358 396 wrapper: [ 359 397 styles.inputWrapper, 360 398 ui.text, ··· 380 418 size === "md" && styles.wrapperSizeMd, 381 419 size === "lg" && styles.wrapperSizeLg, 382 420 ], 421 + label: [ 422 + styles.label, 423 + labelVariant === "horizontal" && [ 424 + styles.horizontalLabelText, 425 + size === "sm" && styles.horizontalLabelTextSm, 426 + size === "md" && styles.horizontalLabelTextMd, 427 + size === "lg" && styles.horizontalLabelTextLg, 428 + ], 429 + ], 430 + description: [styles.additionalText], 431 + errorMessage: [styles.additionalText], 383 432 input: [ 384 433 styles.input, 385 434 size === "sm" && styles.inputSizeSm,
+15 -13
apps/docs/src/components/toast/Toast.tsx
··· 31 31 import { lineHeight, typeramp } from "../theme/typography.stylex"; 32 32 import { usePopoverStyles } from "../theme/usePopoverStyles"; 33 33 import { toasts } from "./queue"; 34 + import { Flex } from "../flex"; 34 35 35 36 const styles = stylex.create({ 36 37 region: { ··· 154 155 {toast.content.description} 155 156 </Text> 156 157 </ToastContent> 157 - {toast.content.action ? ( 158 - <Button 159 - size="sm" 160 - variant={toast.content.action.variant} 161 - onPress={() => { 162 - toast.content.action?.onPress(); 163 - toasts.close(toast.key); 164 - }} 165 - > 166 - {toast.content.action.label} 167 - </Button> 168 - ) : ( 158 + <Flex direction="row" gap="1"> 159 + {toast.content.action && ( 160 + <Button 161 + size="sm" 162 + variant={toast.content.action.variant} 163 + onPress={() => { 164 + toast.content.action?.onPress(); 165 + toasts.close(toast.key); 166 + }} 167 + > 168 + {toast.content.action.label} 169 + </Button> 170 + )} 169 171 <IconButton 170 172 aria-label="Close" 171 173 size="sm" ··· 174 176 > 175 177 <X /> 176 178 </IconButton> 177 - )} 179 + </Flex> 178 180 </Toast> 179 181 ); 180 182 }
-3
apps/docs/src/components/toast/index.tsx
··· 1 - /* eslint-disable react/only-export-components -- Barrel re-exports ToastRegion and toasts */ 2 1 export { ToastRegion, type ToastRegionProps } from "./Toast"; 3 - export { toasts } from "./queue"; 4 - /* eslint-enable react/only-export-components */
+7
apps/docs/src/docs/components/color/color-field.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/color-field/basic"; 9 + import { LabelVariant } from "../../../examples/color-field/label-variant"; 9 10 import { Validation } from "../../../examples/color-field/validation"; 10 11 import { ValidationWarning } from "../../../examples/color-field/validation-warning"; 11 12 import { ValidationSuccess } from "../../../examples/color-field/validation-success"; ··· 27 28 <PropDocs components={["ColorField"]} /> 28 29 29 30 ## Features 31 + 32 + ### Label Variant 33 + 34 + The color field supports two different label variants: vertical and horizontal. 35 + 36 + <Example src={LabelVariant} /> 30 37 31 38 ### Validation 32 39
+7
apps/docs/src/docs/components/date-and-time/date-field.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/date-field/basic"; 9 + import { LabelVariant } from "../../../examples/date-field/label-variant"; 9 10 import { Validation } from "../../../examples/date-field/validation"; 10 11 import { ValidationWarning } from "../../../examples/date-field/validation-warning"; 11 12 import { ValidationSuccess } from "../../../examples/date-field/validation-success"; ··· 27 28 <PropDocs components={["DateField"]} /> 28 29 29 30 ## Features 31 + 32 + ### Label Variant 33 + 34 + The date field supports two different label variants: vertical and horizontal. 35 + 36 + <Example src={LabelVariant} /> 30 37 31 38 ### Validation 32 39
+7
apps/docs/src/docs/components/date-and-time/date-picker.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/date-picker/basic"; 9 + import { LabelVariant } from "../../../examples/date-picker/label-variant"; 9 10 import { Validation } from "../../../examples/date-picker/validation"; 10 11 import { ValidationWarning } from "../../../examples/date-picker/validation-warning"; 11 12 import { ValidationSuccess } from "../../../examples/date-picker/validation-success"; ··· 27 28 <PropDocs components={["DatePicker"]} /> 28 29 29 30 ## Features 31 + 32 + ### Label Variant 33 + 34 + The date picker supports two different label variants: vertical and horizontal. 35 + 36 + <Example src={LabelVariant} /> 30 37 31 38 ### Validation 32 39
+7
apps/docs/src/docs/components/date-and-time/date-range-picker.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/date-range-picker/basic"; 9 + import { LabelVariant } from "../../../examples/date-range-picker/label-variant"; 9 10 import { Validation } from "../../../examples/date-range-picker/validation"; 10 11 import { ValidationWarning } from "../../../examples/date-range-picker/validation-warning"; 11 12 import { ValidationSuccess } from "../../../examples/date-range-picker/validation-success"; ··· 27 28 <PropDocs components={["DateRangePicker"]} /> 28 29 29 30 ## Features 31 + 32 + ### Label Variant 33 + 34 + The date range picker supports two different label variants: vertical and horizontal. 35 + 36 + <Example src={LabelVariant} /> 30 37 31 38 ### Validation 32 39
+7
apps/docs/src/docs/components/date-and-time/time-field.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/time-field/basic"; 9 + import { LabelVariant } from "../../../examples/time-field/label-variant"; 9 10 import { Sizes } from "../../../examples/time-field/sizes"; 10 11 import { Variants } from "../../../examples/time-field/variants"; 11 12 import { Description } from "../../../examples/time-field/description"; ··· 25 26 ``` 26 27 27 28 ## Features 29 + 30 + ### Label Variant 31 + 32 + The time field supports two different label variants: vertical and horizontal. 33 + 34 + <Example src={LabelVariant} /> 28 35 29 36 ### Prefix and Suffix 30 37
+7
apps/docs/src/docs/components/form/combobox.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/combobox/basic"; 9 + import { LabelVariant } from "../../../examples/combobox/label-variant"; 9 10 import { Validation } from "../../../examples/combobox/validation"; 10 11 import { ValidationWarning } from "../../../examples/combobox/validation-warning"; 11 12 import { ValidationSuccess } from "../../../examples/combobox/validation-success"; ··· 36 37 /> 37 38 38 39 ## Features 40 + 41 + ### Label Variant 42 + 43 + The combo box supports two different label variants: vertical and horizontal. 44 + 45 + <Example src={LabelVariant} /> 39 46 40 47 ### Validation 41 48
+7
apps/docs/src/docs/components/form/number-field.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/number-field/basic"; 9 + import { LabelVariant } from "../../../examples/number-field/label-variant"; 9 10 import { Validation } from "../../../examples/number-field/validation"; 10 11 import { ValidationWarning } from "../../../examples/number-field/validation-warning"; 11 12 import { ValidationSuccess } from "../../../examples/number-field/validation-success"; ··· 27 28 <PropDocs components={["NumberField"]} /> 28 29 29 30 ## Features 31 + 32 + ### Label Variant 33 + 34 + The number field supports two different label variants: vertical and horizontal. 35 + 36 + <Example src={LabelVariant} /> 30 37 31 38 ### Validation 32 39
+7
apps/docs/src/docs/components/form/search-field.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/search-field/basic"; 9 + import { LabelVariant } from "../../../examples/search-field/label-variant"; 9 10 import { Validation } from "../../../examples/search-field/validation"; 10 11 import { ValidationWarning } from "../../../examples/search-field/validation-warning"; 11 12 import { ValidationSuccess } from "../../../examples/search-field/validation-success"; ··· 27 28 <PropDocs components={["SearchField"]} /> 28 29 29 30 ## Features 31 + 32 + ### Label Variant 33 + 34 + The search field supports two different label variants: vertical and horizontal. 35 + 36 + <Example src={LabelVariant} /> 30 37 31 38 ### Validation 32 39
+7
apps/docs/src/docs/components/form/select.mdx
··· 6 6 import { PropDocs } from "../../../lib/PropDocs"; 7 7 import { Example } from "../../../lib/Example"; 8 8 import { Basic } from "../../../examples/select/basic"; 9 + import { LabelVariant } from "../../../examples/select/label-variant"; 9 10 import { SelectWithDescription } from "../../../examples/select/with-description"; 10 11 import { SelectSizes } from "../../../examples/select/sizes"; 11 12 import { Validation } from "../../../examples/select/validation"; ··· 38 39 /> 39 40 40 41 ## Features 42 + 43 + ### Label Variant 44 + 45 + The select supports two different label variants: vertical and horizontal. 46 + 47 + <Example src={LabelVariant} /> 41 48 42 49 ### With Description 43 50
+7
apps/docs/src/docs/components/form/text-field.mdx
··· 8 8 import { Basic } from "../../../examples/text-field/basic"; 9 9 import { TextFieldVariants } from "../../../examples/text-field/variants"; 10 10 import { TextFieldSizes } from "../../../examples/text-field/sizes"; 11 + import { LabelVariant } from "../../../examples/text-field/label-variant"; 11 12 import { PasswordField } from "../../../examples/text-field/password"; 12 13 import { PrefixAndSuffix } from "../../../examples/text-field/prefix-and-suffix"; 13 14 import { Validation } from "../../../examples/text-field/validation"; ··· 31 32 <PropDocs components={["TextField"]} /> 32 33 33 34 ## Features 35 + 36 + ### Label Variant 37 + 38 + The text field supports two different label variants: vertical and horizontal. 39 + 40 + <Example src={LabelVariant} /> 34 41 35 42 ### Prefix and Suffix 36 43
+15
apps/docs/src/examples/color-field/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { ColorField } from "@/components/color-field"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <ColorField 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + placeholder="#000000" 11 + description="This is a description" 12 + /> 13 + </Flex> 14 + ); 15 + }
+28
apps/docs/src/examples/combobox/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { ComboBox, ComboBoxItem } from "@/components/combobox"; 3 + 4 + const options = [ 5 + { id: "option1", name: "Option 1" }, 6 + { id: "option2", name: "Option 2" }, 7 + { id: "option3", name: "Option 3" }, 8 + ]; 9 + 10 + export function LabelVariant() { 11 + return ( 12 + <Flex direction="column" gap="4"> 13 + <ComboBox 14 + label="Horizontal label" 15 + labelVariant="horizontal" 16 + placeholder="Type to search..." 17 + items={options} 18 + description="This is a description" 19 + > 20 + {(item) => ( 21 + <ComboBoxItem key={item.id} id={item.id}> 22 + {item.name} 23 + </ComboBoxItem> 24 + )} 25 + </ComboBox> 26 + </Flex> 27 + ); 28 + }
+15
apps/docs/src/examples/date-field/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { DateField } from "@/components/date-field"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <DateField 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + placeholder="Select a date" 11 + description="This is a description" 12 + /> 13 + </Flex> 14 + ); 15 + }
+14
apps/docs/src/examples/date-picker/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { DatePicker } from "@/components/date-picker"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <DatePicker 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + description="This is a description" 11 + /> 12 + </Flex> 13 + ); 14 + }
+14
apps/docs/src/examples/date-range-picker/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { DateRangePicker } from "@/components/date-range-picker"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <DateRangePicker 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + description="This is a description" 11 + /> 12 + </Flex> 13 + ); 14 + }
+15
apps/docs/src/examples/number-field/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { NumberField } from "@/components/number-field"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <NumberField 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + placeholder="Label appears beside the field" 11 + description="This is a description" 12 + /> 13 + </Flex> 14 + ); 15 + }
+15
apps/docs/src/examples/search-field/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { SearchField } from "@/components/search-field"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <SearchField 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + placeholder="Search for something..." 11 + description="This is a description" 12 + /> 13 + </Flex> 14 + ); 15 + }
+24
apps/docs/src/examples/select/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { Select, SelectItem } from "@/components/select"; 3 + 4 + const options = [ 5 + { id: "option1", name: "Option 1" }, 6 + { id: "option2", name: "Option 2" }, 7 + { id: "option3", name: "Option 3" }, 8 + ]; 9 + 10 + export function LabelVariant() { 11 + return ( 12 + <Flex direction="column" gap="4"> 13 + <Select 14 + label="Horizontal label" 15 + labelVariant="horizontal" 16 + placeholder="Select an option" 17 + items={options} 18 + description="This is a description" 19 + > 20 + {(item) => <SelectItem id={item.id}>{item.name}</SelectItem>} 21 + </Select> 22 + </Flex> 23 + ); 24 + }
+15
apps/docs/src/examples/text-field/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { TextField } from "@/components/text-field"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <TextField 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + placeholder="Label appears beside the field" 11 + description="This is a description" 12 + /> 13 + </Flex> 14 + ); 15 + }
+14
apps/docs/src/examples/time-field/label-variant.tsx
··· 1 + import { Flex } from "@/components/flex"; 2 + import { TimeField } from "@/components/time-field"; 3 + 4 + export function LabelVariant() { 5 + return ( 6 + <Flex direction="column" gap="4"> 7 + <TimeField 8 + label="Horizontal label" 9 + labelVariant="horizontal" 10 + description="This is a description" 11 + /> 12 + </Flex> 13 + ); 14 + }
+1
packages/hip-ui/src/components/card/index.tsx
··· 100 100 margin: 0, 101 101 fontSize: fontSize["sm"], 102 102 fontWeight: fontWeight["normal"], 103 + lineHeight: lineHeight["sm"], 103 104 }, 104 105 cardBody: { 105 106 gap: "calc(var(--card-gap) * 0.5)",
+32 -5
packages/hip-ui/src/components/color-field/index.tsx
··· 11 11 import type { 12 12 InputValidationState, 13 13 InputVariant, 14 + LabelVariant, 14 15 Size, 15 16 StyleXComponentProps, 16 17 } from "../theme/types"; 17 18 18 19 import { SizeContext } from "../context"; 20 + import { Flex } from "../flex"; 19 21 import { Description, FieldErrorMessage, Label } from "../label"; 20 22 import { SuffixIcon } from "../suffix-icon"; 21 23 import { useInputStyles } from "../theme/useInputStyles"; 22 24 23 25 interface ColorFieldContentProps { 24 26 label?: React.ReactNode; 27 + labelVariant?: LabelVariant; 25 28 description?: string; 26 29 errorMessage?: string | ((validation: ValidationResult) => string); 27 30 size: Size; ··· 35 38 36 39 function ColorFieldContent({ 37 40 label, 41 + labelVariant, 38 42 description, 39 43 errorMessage, 40 44 size, ··· 49 53 const inputStyles = useInputStyles({ 50 54 size, 51 55 variant, 56 + labelVariant, 52 57 validationState: isInvalid ? "invalid" : validationState, 53 58 }); 54 59 55 - return ( 60 + const content = ( 56 61 <> 57 - <Label>{label}</Label> 58 62 {/* 59 63 This onClick is specifically for mouse users not clicking directly on the input. 60 64 A keyboard user would not encounter the same issue. ··· 79 83 validationState={validationState} 80 84 /> 81 85 </div> 82 - <Description>{description}</Description> 83 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 86 + <Description style={inputStyles.description}>{description}</Description> 87 + <FieldErrorMessage style={inputStyles.errorMessage}> 88 + {errorMessage} 89 + </FieldErrorMessage> 90 + </> 91 + ); 92 + 93 + return ( 94 + <> 95 + <Label style={inputStyles.label}>{label}</Label> 96 + {labelVariant === "horizontal" ? ( 97 + <Flex direction="column" gap="2"> 98 + {content} 99 + </Flex> 100 + ) : ( 101 + content 102 + )} 84 103 </> 85 104 ); 86 105 } ··· 94 113 errorMessage?: string | ((validation: ValidationResult) => string); 95 114 size?: Size; 96 115 variant?: InputVariant; 116 + labelVariant?: LabelVariant; 97 117 validationState?: InputValidationState; 98 118 prefix?: React.ReactNode; 99 119 suffix?: React.ReactNode; ··· 106 126 style, 107 127 size: sizeProp, 108 128 variant, 129 + labelVariant, 109 130 validationState, 110 131 prefix, 111 132 suffix, ··· 113 134 ...props 114 135 }: ColorFieldProps) { 115 136 const size = sizeProp || use(SizeContext); 116 - const inputStyles = useInputStyles({ size, variant, validationState }); 137 + const inputStyles = useInputStyles({ 138 + size, 139 + variant, 140 + labelVariant, 141 + validationState, 142 + }); 117 143 118 144 return ( 119 145 <SizeContext value={size}> ··· 125 151 {({ isInvalid }) => ( 126 152 <ColorFieldContent 127 153 label={label} 154 + labelVariant={labelVariant} 128 155 description={description} 129 156 errorMessage={errorMessage} 130 157 size={size}
+36 -5
packages/hip-ui/src/components/combobox/index.tsx
··· 20 20 import type { 21 21 InputValidationState, 22 22 InputVariant, 23 + LabelVariant, 23 24 Size, 24 25 StyleXComponentProps, 25 26 } from "../theme/types"; 26 27 27 28 import { SizeContext } from "../context"; 29 + import { Flex } from "../flex"; 28 30 import { Description, FieldErrorMessage, Label } from "../label"; 29 31 import { ListBox } from "../listbox"; 30 32 import { SuffixIcon } from "../suffix-icon"; ··· 55 57 56 58 interface ComboBoxContentProps<T extends object> { 57 59 label?: string; 60 + labelVariant?: LabelVariant; 58 61 description?: string; 59 62 errorMessage?: string | ((validation: ValidationResult) => string); 60 63 size: Size; ··· 76 79 77 80 function ComboBoxContent<T extends object>({ 78 81 label, 82 + labelVariant, 79 83 description, 80 84 errorMessage, 81 85 size, ··· 97 101 const inputStyles = useInputStyles({ 98 102 size, 99 103 variant, 104 + labelVariant, 100 105 validationState: _isInvalid ? "invalid" : validationState, 101 106 }); 102 107 const popoverStyles = usePopoverStyles(); ··· 118 123 ); 119 124 } 120 125 121 - return ( 126 + const content = ( 122 127 <> 123 - <Label>{label}</Label> 124 128 <Button {...stylex.props(inputStyles.wrapper)}> 125 129 {prefix != null && ( 126 130 <div {...stylex.props(inputStyles.addon)}>{prefix}</div> ··· 149 153 validationState={validationState} 150 154 /> 151 155 </Button> 152 - {description && <Description>{description}</Description>} 153 - {errorMessage && <FieldErrorMessage>{errorMessage}</FieldErrorMessage>} 156 + {description && ( 157 + <Description style={inputStyles.description}>{description}</Description> 158 + )} 159 + {errorMessage && ( 160 + <FieldErrorMessage style={inputStyles.errorMessage}> 161 + {errorMessage} 162 + </FieldErrorMessage> 163 + )} 164 + </> 165 + ); 166 + 167 + return ( 168 + <> 169 + <Label style={inputStyles.label}>{label}</Label> 170 + {labelVariant === "horizontal" ? ( 171 + <Flex direction="column" gap="2"> 172 + {content} 173 + </Flex> 174 + ) : ( 175 + content 176 + )} 154 177 <Popover 155 178 containerPadding={8} 156 179 shouldCloseOnInteractOutside={shouldCloseOnInteractOutside} ··· 187 210 children: React.ReactNode | ((item: T) => React.ReactNode); 188 211 size?: Size; 189 212 variant?: InputVariant; 213 + labelVariant?: LabelVariant; 190 214 validationState?: InputValidationState; 191 215 placeholder?: string; 192 216 prefix?: React.ReactNode; ··· 203 227 style, 204 228 size: sizeProp, 205 229 variant, 230 + labelVariant, 206 231 validationState, 207 232 shouldCloseOnInteractOutside, 208 233 shouldFlip, ··· 216 241 ...props 217 242 }: ComboBoxProps<T>) { 218 243 const size = sizeProp || use(SizeContext); 219 - const inputStyles = useInputStyles({ size, variant, validationState }); 244 + const inputStyles = useInputStyles({ 245 + size, 246 + variant, 247 + labelVariant, 248 + validationState, 249 + }); 220 250 221 251 return ( 222 252 <SizeContext value={size}> ··· 228 258 {({ isInvalid }) => ( 229 259 <ComboBoxContent 230 260 label={label} 261 + labelVariant={labelVariant} 231 262 description={description} 232 263 errorMessage={errorMessage} 233 264 size={size}
+32 -5
packages/hip-ui/src/components/date-field/index.tsx
··· 15 15 import type { 16 16 InputValidationState, 17 17 InputVariant, 18 + LabelVariant, 18 19 Size, 19 20 StyleXComponentProps, 20 21 } from "../theme/types"; 21 22 22 23 import { SizeContext } from "../context"; 24 + import { Flex } from "../flex"; 23 25 import { Description, FieldErrorMessage, Label } from "../label"; 24 26 import { SuffixIcon } from "../suffix-icon"; 25 27 import { useInputStyles } from "../theme/useInputStyles"; 26 28 27 29 interface DateFieldContentProps { 28 30 label?: React.ReactNode; 31 + labelVariant?: LabelVariant; 29 32 description?: string; 30 33 errorMessage?: string | ((validation: ValidationResult) => string); 31 34 size: Size; ··· 38 41 39 42 function DateFieldContent({ 40 43 label, 44 + labelVariant, 41 45 description, 42 46 errorMessage, 43 47 size, ··· 51 55 const inputStyles = useInputStyles({ 52 56 size, 53 57 variant, 58 + labelVariant, 54 59 validationState: isInvalid ? "invalid" : validationState, 55 60 }); 56 61 57 - return ( 62 + const content = ( 58 63 <> 59 - <Label>{label}</Label> 60 64 {/* 61 65 This onClick is specifically for mouse users not clicking directly on the input. 62 66 A keyboard user would not encounter the same issue. ··· 79 83 validationState={validationState} 80 84 /> 81 85 </div> 82 - <Description>{description}</Description> 83 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 86 + <Description style={inputStyles.description}>{description}</Description> 87 + <FieldErrorMessage style={inputStyles.errorMessage}> 88 + {errorMessage} 89 + </FieldErrorMessage> 90 + </> 91 + ); 92 + 93 + return ( 94 + <> 95 + <Label style={inputStyles.label}>{label}</Label> 96 + {labelVariant === "horizontal" ? ( 97 + <Flex direction="column" gap="2"> 98 + {content} 99 + </Flex> 100 + ) : ( 101 + content 102 + )} 84 103 </> 85 104 ); 86 105 } ··· 93 112 errorMessage?: string | ((validation: ValidationResult) => string); 94 113 size?: Size; 95 114 variant?: InputVariant; 115 + labelVariant?: LabelVariant; 96 116 validationState?: InputValidationState; 97 117 prefix?: React.ReactNode; 98 118 suffix?: React.ReactNode; ··· 105 125 style, 106 126 size: sizeProp, 107 127 variant, 128 + labelVariant, 108 129 validationState, 109 130 prefix, 110 131 suffix, 111 132 ...props 112 133 }: DateFieldProps<T>) { 113 134 const size = sizeProp || use(SizeContext); 114 - const inputStyles = useInputStyles({ size, variant, validationState }); 135 + const inputStyles = useInputStyles({ 136 + size, 137 + variant, 138 + labelVariant, 139 + validationState, 140 + }); 115 141 116 142 return ( 117 143 <SizeContext value={size}> ··· 123 149 {({ isInvalid }) => ( 124 150 <DateFieldContent 125 151 label={label} 152 + labelVariant={labelVariant} 126 153 description={description} 127 154 errorMessage={errorMessage} 128 155 size={size}
+38 -6
packages/hip-ui/src/components/date-picker/index.tsx
··· 18 18 import type { 19 19 InputValidationState, 20 20 InputVariant, 21 + LabelVariant, 21 22 Size, 22 23 StyleXComponentProps, 23 24 } from "../theme/types"; ··· 25 26 import { Calendar } from "../calendar"; 26 27 import { SizeContext } from "../context"; 27 28 import { DateField } from "../date-field"; 29 + import { Flex } from "../flex"; 28 30 import { IconButton } from "../icon-button"; 29 31 import { Description, FieldErrorMessage, Label } from "../label"; 30 32 import { spacing } from "../theme/spacing.stylex"; ··· 40 42 errorMessage?: string | ((validation: ValidationResult) => string); 41 43 size?: Size; 42 44 variant?: InputVariant; 45 + labelVariant?: LabelVariant; 43 46 validationState?: InputValidationState; 44 47 } 45 48 ··· 51 54 52 55 interface DatePickerContentProps<T extends DateValue> { 53 56 label?: React.ReactNode; 57 + labelVariant?: LabelVariant; 54 58 description?: string; 55 59 errorMessage?: string | ((validation: ValidationResult) => string); 56 60 size: Size; ··· 63 67 64 68 function DatePickerContent<T extends DateValue>({ 65 69 label, 70 + labelVariant, 66 71 description, 67 72 errorMessage, 68 - size: _size, 73 + size, 69 74 variant, 70 75 validationState, 71 76 isInvalid: _isInvalid, 72 77 weekdayStyle, 73 78 visibleDuration, 74 79 }: DatePickerContentProps<T>) { 80 + const inputStyles = useInputStyles({ 81 + size, 82 + variant, 83 + labelVariant, 84 + validationState, 85 + }); 75 86 const popoverStyles = usePopoverStyles(); 76 87 77 - return ( 88 + const content = ( 78 89 <> 79 - <Label>{label}</Label> 80 90 <Group> 81 91 <DateField 82 92 variant={variant} ··· 92 102 } 93 103 /> 94 104 </Group> 95 - <Description>{description}</Description> 96 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 105 + <Description style={inputStyles.description}>{description}</Description> 106 + <FieldErrorMessage style={inputStyles.errorMessage}> 107 + {errorMessage} 108 + </FieldErrorMessage> 109 + </> 110 + ); 111 + 112 + return ( 113 + <> 114 + <Label style={inputStyles.label}>{label}</Label> 115 + {labelVariant === "horizontal" ? ( 116 + <Flex direction="column" gap="2"> 117 + {content} 118 + </Flex> 119 + ) : ( 120 + content 121 + )} 97 122 <AriaPopover 98 123 {...stylex.props(popoverStyles.wrapper, popoverStyles.animation)} 99 124 > ··· 117 142 weekdayStyle, 118 143 visibleDuration, 119 144 variant, 145 + labelVariant, 120 146 validationState, 121 147 ...props 122 148 }: DatePickerProps<T>) { 123 149 const size = sizeProp || use(SizeContext); 124 - const inputStyles = useInputStyles({ size, variant, validationState }); 150 + const inputStyles = useInputStyles({ 151 + size, 152 + variant, 153 + labelVariant, 154 + validationState, 155 + }); 125 156 126 157 return ( 127 158 <SizeContext value={size}> ··· 133 164 {({ isInvalid }) => ( 134 165 <DatePickerContent 135 166 label={label} 167 + labelVariant={labelVariant} 136 168 description={description} 137 169 errorMessage={errorMessage} 138 170 size={size}
+32 -5
packages/hip-ui/src/components/date-range-picker/index.tsx
··· 20 20 import type { 21 21 InputValidationState, 22 22 InputVariant, 23 + LabelVariant, 23 24 Size, 24 25 StyleXComponentProps, 25 26 } from "../theme/types"; 26 27 27 28 import { SizeContext } from "../context"; 29 + import { Flex } from "../flex"; 28 30 import { IconButton } from "../icon-button"; 29 31 import { Description, FieldErrorMessage, Label } from "../label"; 30 32 import { RangeCalendar } from "../range-calendar"; ··· 44 46 errorMessage?: string | ((validation: ValidationResult) => string); 45 47 size?: Size; 46 48 variant?: InputVariant; 49 + labelVariant?: LabelVariant; 47 50 validationState?: InputValidationState; 48 51 } 49 52 ··· 81 84 82 85 interface DateRangePickerContentProps<T extends DateValue> { 83 86 label?: React.ReactNode; 87 + labelVariant?: LabelVariant; 84 88 description?: string; 85 89 errorMessage?: string | ((validation: ValidationResult) => string); 86 90 size: Size; ··· 93 97 94 98 function DateRangePickerContent<T extends DateValue>({ 95 99 label, 100 + labelVariant, 96 101 description, 97 102 errorMessage, 98 103 size, ··· 105 110 const inputStyles = useInputStyles({ 106 111 size, 107 112 variant, 113 + labelVariant, 108 114 validationState: isInvalid ? "invalid" : validationState, 109 115 }); 110 116 const popoverStyles = usePopoverStyles(); 111 117 112 - return ( 118 + const content = ( 113 119 <> 114 - <Label>{label}</Label> 115 120 <Group 116 121 data-size={size} 117 122 {...stylex.props(inputStyles.wrapper, styles.group)} ··· 147 152 validationState={validationState} 148 153 /> 149 154 </Group> 150 - <Description>{description}</Description> 151 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 155 + <Description style={inputStyles.description}>{description}</Description> 156 + <FieldErrorMessage style={inputStyles.errorMessage}> 157 + {errorMessage} 158 + </FieldErrorMessage> 159 + </> 160 + ); 161 + 162 + return ( 163 + <> 164 + <Label style={inputStyles.label}>{label}</Label> 165 + {labelVariant === "horizontal" ? ( 166 + <Flex direction="column" gap="2"> 167 + {content} 168 + </Flex> 169 + ) : ( 170 + content 171 + )} 152 172 <AriaPopover 153 173 {...stylex.props(popoverStyles.wrapper, popoverStyles.animation)} 154 174 > ··· 172 192 weekdayStyle, 173 193 visibleDuration, 174 194 variant, 195 + labelVariant, 175 196 validationState, 176 197 ...props 177 198 }: DateRangePickerProps<T>) { 178 199 const size = sizeProp || use(SizeContext); 179 - const inputStyles = useInputStyles({ size, variant, validationState }); 200 + const inputStyles = useInputStyles({ 201 + size, 202 + variant, 203 + labelVariant, 204 + validationState, 205 + }); 180 206 181 207 return ( 182 208 <SizeContext value={size}> ··· 188 214 {({ isInvalid }) => ( 189 215 <DateRangePickerContent 190 216 label={label} 217 + labelVariant={labelVariant} 191 218 description={description} 192 219 errorMessage={errorMessage} 193 220 size={size}
+32 -5
packages/hip-ui/src/components/number-field/index.tsx
··· 20 20 import type { 21 21 InputValidationState, 22 22 InputVariant, 23 + LabelVariant, 23 24 Size, 24 25 StyleXComponentProps, 25 26 } from "../theme/types"; 26 27 27 28 import { SizeContext } from "../context"; 29 + import { Flex } from "../flex"; 28 30 import { Description, FieldErrorMessage, Label } from "../label"; 29 31 import { SuffixIcon } from "../suffix-icon"; 30 32 import { uiColor } from "../theme/color.stylex"; ··· 132 134 133 135 interface NumberFieldContentProps { 134 136 label?: React.ReactNode; 137 + labelVariant?: LabelVariant; 135 138 description?: string; 136 139 errorMessage?: string | ((validation: ValidationResult) => string); 137 140 size: Size; ··· 146 149 147 150 function NumberFieldContent({ 148 151 label, 152 + labelVariant, 149 153 description, 150 154 errorMessage, 151 155 size, ··· 161 165 const inputStyles = useInputStyles({ 162 166 size, 163 167 variant, 168 + labelVariant, 164 169 validationState: isInvalid ? "invalid" : validationState, 165 170 }); 166 171 167 - return ( 172 + const content = ( 168 173 <> 169 - <Label>{label}</Label> 170 174 {/* 171 175 This onClick is specifically for mouse users not clicking directly on the input. 172 176 A keyboard user would not encounter the same issue. ··· 220 224 </Button> 221 225 )} 222 226 </NumberInputWrapper> 223 - <Description>{description}</Description> 224 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 227 + <Description style={inputStyles.description}>{description}</Description> 228 + <FieldErrorMessage style={inputStyles.errorMessage}> 229 + {errorMessage} 230 + </FieldErrorMessage> 231 + </> 232 + ); 233 + 234 + return ( 235 + <> 236 + <Label style={inputStyles.label}>{label}</Label> 237 + {labelVariant === "horizontal" ? ( 238 + <Flex direction="column" gap="2"> 239 + {content} 240 + </Flex> 241 + ) : ( 242 + content 243 + )} 225 244 </> 226 245 ); 227 246 } ··· 235 254 errorMessage?: string | ((validation: ValidationResult) => string); 236 255 size?: Size; 237 256 variant?: InputVariant; 257 + labelVariant?: LabelVariant; 238 258 validationState?: InputValidationState; 239 259 prefix?: React.ReactNode; 240 260 suffix?: React.ReactNode; ··· 248 268 style, 249 269 size: sizeProp, 250 270 variant, 271 + labelVariant, 251 272 validationState, 252 273 prefix, 253 274 suffix, ··· 256 277 ...props 257 278 }: NumberFieldProps) { 258 279 const size = sizeProp || use(SizeContext); 259 - const inputStyles = useInputStyles({ size, variant, validationState }); 280 + const inputStyles = useInputStyles({ 281 + size, 282 + variant, 283 + labelVariant, 284 + validationState, 285 + }); 260 286 261 287 return ( 262 288 <SizeContext value={size}> ··· 268 294 {({ isInvalid }) => ( 269 295 <NumberFieldContent 270 296 label={label} 297 + labelVariant={labelVariant} 271 298 description={description} 272 299 errorMessage={errorMessage} 273 300 size={size}
+32 -5
packages/hip-ui/src/components/search-field/index.tsx
··· 12 12 import type { 13 13 InputValidationState, 14 14 InputVariant, 15 + LabelVariant, 15 16 Size, 16 17 StyleXComponentProps, 17 18 } from "../theme/types"; 18 19 19 20 import { SizeContext } from "../context"; 21 + import { Flex } from "../flex"; 20 22 import { IconButton } from "../icon-button"; 21 23 import { Description, FieldErrorMessage, Label } from "../label"; 22 24 import { SuffixIcon } from "../suffix-icon"; ··· 40 42 41 43 interface SearchFieldContentProps { 42 44 label?: React.ReactNode; 45 + labelVariant?: LabelVariant; 43 46 description?: string; 44 47 errorMessage?: string | ((validation: ValidationResult) => string); 45 48 size: Size; ··· 54 57 55 58 function SearchFieldContent({ 56 59 label, 60 + labelVariant, 57 61 description, 58 62 errorMessage, 59 63 size, ··· 69 73 const inputStyles = useInputStyles({ 70 74 size, 71 75 variant, 76 + labelVariant, 72 77 validationState: isInvalid ? "invalid" : validationState, 73 78 }); 74 79 75 - return ( 80 + const content = ( 76 81 <> 77 - <Label>{label}</Label> 78 82 {/* 79 83 This onClick is specifically for mouse users not clicking directly on the input. 80 84 A keyboard user would not encounter the same issue. ··· 109 113 </div> 110 114 )} 111 115 </div> 112 - <Description>{description}</Description> 113 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 116 + <Description style={inputStyles.description}>{description}</Description> 117 + <FieldErrorMessage style={inputStyles.errorMessage}> 118 + {errorMessage} 119 + </FieldErrorMessage> 120 + </> 121 + ); 122 + 123 + return ( 124 + <> 125 + <Label style={inputStyles.label}>{label}</Label> 126 + {labelVariant === "horizontal" ? ( 127 + <Flex direction="column" gap="2"> 128 + {content} 129 + </Flex> 130 + ) : ( 131 + content 132 + )} 114 133 </> 115 134 ); 116 135 } ··· 124 143 errorMessage?: string | ((validation: ValidationResult) => string); 125 144 size?: Size; 126 145 variant?: InputVariant; 146 + labelVariant?: LabelVariant; 127 147 validationState?: InputValidationState; 128 148 prefix?: React.ReactNode; 129 149 suffix?: React.ReactNode; ··· 138 158 style, 139 159 size: sizeProp, 140 160 variant, 161 + labelVariant, 141 162 validationState, 142 163 prefix = defaultPrefix, 143 164 suffix, ··· 145 166 ...props 146 167 }: SearchFieldProps) { 147 168 const size = sizeProp || use(SizeContext); 148 - const inputStyles = useInputStyles({ size, variant, validationState }); 169 + const inputStyles = useInputStyles({ 170 + size, 171 + variant, 172 + labelVariant, 173 + validationState, 174 + }); 149 175 150 176 return ( 151 177 <SizeContext value={size}> ··· 157 183 {({ isInvalid, isEmpty }) => ( 158 184 <SearchFieldContent 159 185 label={label} 186 + labelVariant={labelVariant} 160 187 description={description} 161 188 errorMessage={errorMessage} 162 189 size={size}
+18 -4
packages/hip-ui/src/components/select/index.tsx
··· 21 21 import type { 22 22 InputValidationState, 23 23 InputVariant, 24 + LabelVariant, 24 25 Size, 25 26 StyleXComponentProps, 26 27 } from "../theme/types"; ··· 65 66 shouldUpdatePosition?: boolean; 66 67 placement?: PopoverProps["placement"]; 67 68 isVirtualized?: boolean; 69 + labelVariant?: "vertical" | "horizontal"; 68 70 } 69 71 70 72 function SelectContent<T extends object>({ ··· 86 88 shouldFlip, 87 89 shouldUpdatePosition, 88 90 placement, 91 + labelVariant, 89 92 }: SelectContentProps<T>) { 90 93 const inputStyles = useInputStyles({ 91 94 size, 92 95 variant, 96 + labelVariant, 93 97 validationState: isInvalid ? "invalid" : validationState, 94 98 }); 95 99 const popoverStyles = usePopoverStyles(); ··· 122 126 123 127 return ( 124 128 <> 125 - <Label>{label}</Label> 129 + <Label style={inputStyles.label}>{label}</Label> 126 130 <Button {...stylex.props(inputStyles.wrapper)}> 127 131 {prefix != null && ( 128 132 <div {...stylex.props(inputStyles.addon)}>{prefix}</div> ··· 147 151 validationState={validationState} 148 152 /> 149 153 </Button> 150 - <Description>{description}</Description> 151 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 154 + <Description style={inputStyles.description}>{description}</Description> 155 + <FieldErrorMessage style={inputStyles.errorMessage}> 156 + {errorMessage} 157 + </FieldErrorMessage> 152 158 <Popover 153 159 containerPadding={8} 154 160 shouldCloseOnInteractOutside={shouldCloseOnInteractOutside} ··· 178 184 | "placement" 179 185 > { 180 186 label?: string; 187 + labelVariant?: LabelVariant; 181 188 description?: string; 182 189 errorMessage?: string | ((validation: ValidationResult) => string); 183 190 items?: Iterable<T>; ··· 204 211 style, 205 212 size: sizeProp, 206 213 variant, 214 + labelVariant, 207 215 validationState, 208 216 shouldCloseOnInteractOutside, 209 217 shouldFlip, ··· 217 225 ...props 218 226 }: SelectProps<T, M>) { 219 227 const size = sizeProp || use(SizeContext); 220 - const inputStyles = useInputStyles({ size, variant, validationState }); 228 + const inputStyles = useInputStyles({ 229 + size, 230 + variant, 231 + labelVariant, 232 + validationState, 233 + }); 221 234 222 235 return ( 223 236 <SizeContext value={size}> ··· 246 259 shouldFlip={shouldFlip} 247 260 shouldUpdatePosition={shouldUpdatePosition} 248 261 placement={placement} 262 + labelVariant={labelVariant} 249 263 > 250 264 {children} 251 265 </SelectContent>
+20 -3
packages/hip-ui/src/components/switch/index.tsx
··· 15 15 import { typeramp } from "../theme/typography.stylex"; 16 16 17 17 const styles = stylex.create({ 18 + labelLeft: { 19 + flexGrow: 1, 20 + minWidth: 0, 21 + }, 18 22 wrapper: { 19 23 gap: spacing["3"], 20 24 alignItems: "center", ··· 66 70 67 71 interface SwitchBaseProps extends StyleXComponentProps< 68 72 Omit<AriaSwitchProps, "children"> 69 - > {} 73 + > { 74 + labelVariant?: "left" | "right"; 75 + } 70 76 71 77 interface SwitchWithChildrenProps extends SwitchBaseProps { 72 78 children: React.ReactNode; ··· 87 93 | SwitchWithAriaLabelProps 88 94 | SwitchWithAriaLabelledbyProps; 89 95 90 - export function Switch({ children, style, onChange, ...props }: SwitchProps) { 96 + export function Switch({ 97 + children, 98 + style, 99 + onChange, 100 + labelVariant = "right", 101 + ...props 102 + }: SwitchProps) { 91 103 const { trigger } = useHaptics(); 92 104 93 105 const handleChange = (isSelected: boolean) => { ··· 101 113 onChange={handleChange} 102 114 {...stylex.props(styles.wrapper, style)} 103 115 > 116 + {children != null && labelVariant === "left" && ( 117 + <div {...stylex.props(typeramp.label, styles.labelLeft)}> 118 + {children} 119 + </div> 120 + )} 104 121 <div {...stylex.props(styles.indicator)}> 105 122 <div {...stylex.props(styles.thumb)} /> 106 123 </div> 107 - {children != null && ( 124 + {children != null && labelVariant === "right" && ( 108 125 <div {...stylex.props(typeramp.label)}>{children}</div> 109 126 )} 110 127 </AriaSwitch>
-1
packages/hip-ui/src/components/table/index.tsx
··· 62 62 backgroundColor: uiColor.component1, 63 63 display: "flex", 64 64 justifyContent: "space-between", 65 - height: spacing["10"], 66 65 paddingLeft: { 67 66 default: spacing["2"], 68 67 ":is(:first-child > *)": spacing["2"],
+1
packages/hip-ui/src/components/tabs/index.tsx
··· 39 39 }, 40 40 tabList: { 41 41 gap: spacing["1"], 42 + overflow: "auto", 42 43 alignItems: { 43 44 ":is([data-orientation=horizontal])": "flex-start", 44 45 ":is([data-orientation=vertical])": "stretch",
+35 -5
packages/hip-ui/src/components/text-field/index.tsx
··· 16 16 import type { 17 17 InputValidationState, 18 18 InputVariant, 19 + LabelVariant, 19 20 Size, 20 21 StyleXComponentProps, 21 22 } from "../theme/types"; 22 23 23 24 import { SizeContext } from "../context"; 25 + import { Flex } from "../flex"; 24 26 import { IconButton } from "../icon-button"; 25 27 import { Description, FieldErrorMessage, Label } from "../label"; 26 28 import { SuffixIcon } from "../suffix-icon"; ··· 57 59 58 60 interface TextFieldContentProps { 59 61 label?: React.ReactNode; 62 + labelVariant?: LabelVariant; 60 63 description?: string; 61 64 errorMessage?: string | ((validation: ValidationResult) => string); 62 65 size: Size; ··· 72 75 73 76 function TextFieldContent({ 74 77 label, 78 + labelVariant, 75 79 description, 76 80 errorMessage, 77 81 size, ··· 89 93 const inputStyles = useInputStyles({ 90 94 size, 91 95 variant, 96 + labelVariant, 92 97 validationState: isInvalid ? "invalid" : validationState, 93 98 }); 94 99 95 - return ( 100 + const content = ( 96 101 <> 97 - <Label>{label}</Label> 98 102 {/* 99 103 This onClick is specifically for mouse users not clicking directly on the input. 100 104 A keyboard user would not encounter the same issue. ··· 126 130 validationState={validationState} 127 131 /> 128 132 </div> 129 - <Description>{description}</Description> 130 - {errorMessage && <FieldErrorMessage>{errorMessage}</FieldErrorMessage>} 133 + <Description style={inputStyles.description}>{description}</Description> 134 + {errorMessage && ( 135 + <FieldErrorMessage style={inputStyles.errorMessage}> 136 + {errorMessage} 137 + </FieldErrorMessage> 138 + )} 139 + </> 140 + ); 141 + 142 + return ( 143 + <> 144 + <Label style={inputStyles.label}>{label}</Label> 145 + 146 + {labelVariant === "horizontal" ? ( 147 + <Flex direction="column" gap="2"> 148 + {content} 149 + </Flex> 150 + ) : ( 151 + content 152 + )} 131 153 </> 132 154 ); 133 155 } ··· 137 159 StyleXComponentProps<Omit<AriaTextFieldProps, "isInvalid">>, 138 160 Pick<InputProps, "placeholder"> { 139 161 label?: React.ReactNode; 162 + labelVariant?: LabelVariant; 140 163 description?: string; 141 164 errorMessage?: string | ((validation: ValidationResult) => string); 142 165 size?: Size; ··· 157 180 prefix, 158 181 suffix, 159 182 placeholder, 183 + labelVariant, 160 184 ...props 161 185 }: TextFieldProps) { 162 186 const size = sizeProp || use(SizeContext); 163 187 const [type, setType] = useState<TextFieldProps["type"]>( 164 188 props.type || "text", 165 189 ); 166 - const inputStyles = useInputStyles({ size, variant, validationState }); 190 + const inputStyles = useInputStyles({ 191 + size, 192 + variant, 193 + labelVariant, 194 + validationState, 195 + }); 167 196 168 197 return ( 169 198 <SizeContext value={size}> ··· 176 205 {({ isInvalid }) => ( 177 206 <TextFieldContent 178 207 label={label} 208 + labelVariant={labelVariant} 179 209 description={description} 180 210 errorMessage={errorMessage} 181 211 size={size}
+1
packages/hip-ui/src/components/theme/types.ts
··· 11 11 | "outline" 12 12 | "critical" 13 13 | "critical-outline"; 14 + export type LabelVariant = "vertical" | "horizontal"; 14 15 export type InputVariant = "primary" | "secondary" | "tertiary"; 15 16 export type InputValidationState = "valid" | "invalid" | "warning"; 16 17 export type ButtonGroupVariant = "grouped" | "separate";
+73 -22
packages/hip-ui/src/components/theme/useInputStyles.ts
··· 1 1 import * as stylex from "@stylexjs/stylex"; 2 2 import { use } from "react"; 3 3 4 - import type { InputValidationState, InputVariant, Size } from "../theme/types"; 4 + import type { 5 + InputValidationState, 6 + InputVariant, 7 + LabelVariant, 8 + Size, 9 + } from "../theme/types"; 5 10 6 11 import { SizeContext } from "../context"; 7 12 import { animationDuration } from "./animations.stylex"; ··· 15 20 import { radius } from "./radius.stylex"; 16 21 import { ui } from "./semantic-color.stylex"; 17 22 import { spacing } from "./spacing.stylex"; 18 - import { fontSize, lineHeight } from "./typography.stylex"; 23 + import { fontSize, fontWeight, lineHeight } from "./typography.stylex"; 19 24 20 25 const styles = stylex.create({ 21 26 field: { ··· 122 127 borderWidth: 1, 123 128 backgroundColor: { 124 129 default: uiColor.bg, 125 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 130 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 126 131 uiColor.component1, 127 132 ":is([data-pressed=true]):not(:disabled)": uiColor.component2, 128 133 ":disabled": "transparent", ··· 142 147 }, 143 148 backgroundColor: { 144 149 default: criticalColor.bgSubtle, 145 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 150 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 146 151 criticalColor.component2, 147 152 ":disabled": "transparent", 148 153 }, ··· 157 162 }, 158 163 backgroundColor: { 159 164 default: warningColor.bgSubtle, 160 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 165 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 161 166 warningColor.component2, 162 167 ":disabled": "transparent", 163 168 }, ··· 172 177 }, 173 178 backgroundColor: { 174 179 default: successColor.bgSubtle, 175 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 180 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 176 181 successColor.component2, 177 182 ":disabled": "transparent", 178 183 }, ··· 190 195 borderWidth: 1, 191 196 backgroundColor: { 192 197 default: uiColor.component1, 193 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 198 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 194 199 uiColor.component2, 195 200 ":is([data-pressed=true]):not(:disabled)": uiColor.component3, 196 201 ":disabled": uiColor.component1, ··· 202 207 secondaryInvalid: { 203 208 borderColor: { 204 209 default: criticalColor.component1, 205 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 210 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 206 211 criticalColor.component2, 207 212 }, 208 213 backgroundColor: { 209 214 default: criticalColor.component1, 210 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 215 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 211 216 criticalColor.component2, 212 217 }, 213 218 }, 214 219 secondaryWarning: { 215 220 borderColor: { 216 221 default: warningColor.component1, 217 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 222 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 218 223 warningColor.component2, 219 224 }, 220 225 backgroundColor: { 221 226 default: warningColor.component1, 222 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 227 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 223 228 warningColor.component2, 224 229 }, 225 230 color: warningColor.text2, ··· 227 232 secondaryValid: { 228 233 borderColor: { 229 234 default: successColor.component1, 230 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 235 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 231 236 successColor.component2, 232 237 }, 233 238 backgroundColor: { 234 239 default: successColor.component1, 235 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 240 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 236 241 successColor.component2, 237 242 }, 238 243 color: successColor.text2, ··· 240 245 tertiary: { 241 246 borderColor: { 242 247 default: "transparent", 243 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 248 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 244 249 uiColor.component2, 245 250 ":is([data-pressed=true]):not(:disabled)": uiColor.component3, 246 251 ":disabled": "transparent", ··· 249 254 borderWidth: 1, 250 255 backgroundColor: { 251 256 default: "transparent", 252 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 257 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 253 258 uiColor.component2, 254 259 ":is([data-pressed=true]):not(:disabled)": uiColor.component3, 255 260 ":disabled": "transparent", ··· 261 266 tertiaryInvalid: { 262 267 borderColor: { 263 268 default: "transparent", 264 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 269 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 265 270 criticalColor.component1, 266 271 ":is([data-pressed=true]):not(:disabled)": criticalColor.component2, 267 272 ":disabled": "transparent", 268 273 }, 269 274 backgroundColor: { 270 275 default: "transparent", 271 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 276 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 272 277 criticalColor.component1, 273 278 ":is([data-pressed=true]):not(:disabled)": criticalColor.component2, 274 279 ":disabled": "transparent", ··· 278 283 tertiaryWarning: { 279 284 borderColor: { 280 285 default: "transparent", 281 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 286 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 282 287 warningColor.component1, 283 288 ":is([data-pressed=true]):not(:disabled)": warningColor.component2, 284 289 ":disabled": "transparent", 285 290 }, 286 291 backgroundColor: { 287 292 default: "transparent", 288 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 293 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 289 294 warningColor.component1, 290 295 ":is([data-pressed=true]):not(:disabled)": warningColor.component2, 291 296 ":disabled": "transparent", ··· 295 300 tertiaryValid: { 296 301 borderColor: { 297 302 default: "transparent", 298 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 303 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 299 304 successColor.component1, 300 305 ":is([data-pressed=true]):not(:disabled)": successColor.component2, 301 306 ":disabled": "transparent", 302 307 }, 303 308 backgroundColor: { 304 309 default: "transparent", 305 - ":is([data-hovered]):not(:has(* [data-hovered])):not(:disabled)": 310 + ":is([data-hovered]:not(:has(* [data-hovered])),:has(input[data-hovered])):not(:disabled)": 306 311 successColor.component1, 307 312 ":is([data-pressed=true]):not(:disabled)": successColor.component2, 308 313 ":disabled": "transparent", ··· 340 345 wrapperSizeLg: { 341 346 height: spacing["10"], 342 347 }, 348 + horizontalLabel: { 349 + gap: spacing["4"], 350 + alignItems: "flex-start", 351 + flexDirection: "row", 352 + }, 353 + horizontalLabelText: { 354 + flexGrow: 1, 355 + minWidth: 0, 356 + paddingLeft: 0, 357 + paddingRight: 0, 358 + }, 359 + horizontalLabelTextSm: { 360 + lineHeight: spacing["6"], 361 + }, 362 + horizontalLabelTextMd: { 363 + lineHeight: spacing["8"], 364 + }, 365 + horizontalLabelTextLg: { 366 + fontSize: fontSize["base"], 367 + fontWeight: fontWeight["medium"], 368 + lineHeight: spacing["10"], 369 + }, 370 + label: { 371 + paddingLeft: spacing["1"], 372 + paddingRight: spacing["1"], 373 + }, 374 + additionalText: { 375 + paddingLeft: spacing["2"], 376 + paddingRight: spacing["2"], 377 + }, 343 378 }); 344 379 345 380 export function useInputStyles({ 346 381 size: sizeProp, 347 382 variant = "primary", 383 + labelVariant = "vertical", 348 384 validationState, 349 385 }: { 350 386 size: Size | undefined; 351 387 variant: InputVariant | undefined; 388 + labelVariant: LabelVariant | undefined; 352 389 validationState: InputValidationState | undefined; 353 390 }) { 354 391 const size = sizeProp || use(SizeContext); 355 392 356 393 return { 357 - field: [styles.field], 394 + field: [ 395 + styles.field, 396 + labelVariant === "horizontal" && styles.horizontalLabel, 397 + ], 358 398 wrapper: [ 359 399 styles.inputWrapper, 360 400 ui.text, ··· 380 420 size === "md" && styles.wrapperSizeMd, 381 421 size === "lg" && styles.wrapperSizeLg, 382 422 ], 423 + label: [ 424 + styles.label, 425 + labelVariant === "horizontal" && [ 426 + styles.horizontalLabelText, 427 + size === "sm" && styles.horizontalLabelTextSm, 428 + size === "md" && styles.horizontalLabelTextMd, 429 + size === "lg" && styles.horizontalLabelTextLg, 430 + ], 431 + ], 432 + description: [styles.additionalText], 433 + errorMessage: [styles.additionalText], 383 434 input: [ 384 435 styles.input, 385 436 size === "sm" && styles.inputSizeSm,
+32 -5
packages/hip-ui/src/components/time-field/index.tsx
··· 15 15 import type { 16 16 InputValidationState, 17 17 InputVariant, 18 + LabelVariant, 18 19 Size, 19 20 StyleXComponentProps, 20 21 } from "../theme/types"; 21 22 22 23 import { SizeContext } from "../context"; 24 + import { Flex } from "../flex"; 23 25 import { Description, FieldErrorMessage, Label } from "../label"; 24 26 import { SuffixIcon } from "../suffix-icon"; 25 27 import { useInputStyles } from "../theme/useInputStyles"; 26 28 27 29 interface TimeFieldContentProps { 28 30 label?: React.ReactNode; 31 + labelVariant?: LabelVariant; 29 32 description?: string; 30 33 errorMessage?: string | ((validation: ValidationResult) => string); 31 34 size: Size; ··· 38 41 39 42 function TimeFieldContent({ 40 43 label, 44 + labelVariant, 41 45 description, 42 46 errorMessage, 43 47 size, ··· 51 55 const inputStyles = useInputStyles({ 52 56 size, 53 57 variant, 58 + labelVariant, 54 59 validationState: isInvalid ? "invalid" : validationState, 55 60 }); 56 61 57 - return ( 62 + const content = ( 58 63 <> 59 - <Label>{label}</Label> 60 64 {/* 61 65 This onClick is specifically for mouse users not clicking directly on the input. 62 66 A keyboard user would not encounter the same issue. ··· 79 83 validationState={validationState} 80 84 /> 81 85 </div> 82 - <Description>{description}</Description> 83 - <FieldErrorMessage>{errorMessage}</FieldErrorMessage> 86 + <Description style={inputStyles.description}>{description}</Description> 87 + <FieldErrorMessage style={inputStyles.errorMessage}> 88 + {errorMessage} 89 + </FieldErrorMessage> 90 + </> 91 + ); 92 + 93 + return ( 94 + <> 95 + <Label style={inputStyles.label}>{label}</Label> 96 + {labelVariant === "horizontal" ? ( 97 + <Flex direction="column" gap="2"> 98 + {content} 99 + </Flex> 100 + ) : ( 101 + content 102 + )} 84 103 </> 85 104 ); 86 105 } ··· 93 112 errorMessage?: string | ((validation: ValidationResult) => string); 94 113 size?: Size; 95 114 variant?: InputVariant; 115 + labelVariant?: LabelVariant; 96 116 validationState?: InputValidationState; 97 117 prefix?: React.ReactNode; 98 118 suffix?: React.ReactNode; ··· 105 125 style, 106 126 size: sizeProp, 107 127 variant, 128 + labelVariant, 108 129 validationState, 109 130 prefix, 110 131 suffix, 111 132 ...props 112 133 }: TimeFieldProps<T>) { 113 134 const size = sizeProp || use(SizeContext); 114 - const inputStyles = useInputStyles({ size, variant, validationState }); 135 + const inputStyles = useInputStyles({ 136 + size, 137 + variant, 138 + labelVariant, 139 + validationState, 140 + }); 115 141 116 142 return ( 117 143 <SizeContext value={size}> ··· 123 149 {({ isInvalid }) => ( 124 150 <TimeFieldContent 125 151 label={label} 152 + labelVariant={labelVariant} 126 153 description={description} 127 154 errorMessage={errorMessage} 128 155 size={size}
+15 -13
packages/hip-ui/src/components/toast/Toast.tsx
··· 31 31 import { lineHeight, typeramp } from "../theme/typography.stylex"; 32 32 import { usePopoverStyles } from "../theme/usePopoverStyles"; 33 33 import { toasts } from "./queue"; 34 + import { Flex } from "../flex"; 34 35 35 36 const styles = stylex.create({ 36 37 region: { ··· 154 155 {toast.content.description} 155 156 </Text> 156 157 </ToastContent> 157 - {toast.content.action ? ( 158 - <Button 159 - size="sm" 160 - variant={toast.content.action.variant} 161 - onPress={() => { 162 - toast.content.action?.onPress(); 163 - toasts.close(toast.key); 164 - }} 165 - > 166 - {toast.content.action.label} 167 - </Button> 168 - ) : ( 158 + <Flex direction="row" gap="1"> 159 + {toast.content.action && ( 160 + <Button 161 + size="sm" 162 + variant={toast.content.action.variant} 163 + onPress={() => { 164 + toast.content.action?.onPress(); 165 + toasts.close(toast.key); 166 + }} 167 + > 168 + {toast.content.action.label} 169 + </Button> 170 + )} 169 171 <IconButton 170 172 aria-label="Close" 171 173 size="sm" ··· 174 176 > 175 177 <X /> 176 178 </IconButton> 177 - )} 179 + </Flex> 178 180 </Toast> 179 181 ); 180 182 }
+81 -80
pnpm-lock.yaml
··· 94 94 version: 61.0.2(eslint@9.38.0(jiti@2.6.1)) 95 95 oxfmt: 96 96 specifier: latest 97 - version: 0.36.0 97 + version: 0.40.0 98 98 oxlint: 99 99 specifier: ^1.48.0 100 100 version: 1.50.0 ··· 1231 1231 react: ^19.1.0 1232 1232 react-dom: ^19.1.0 1233 1233 1234 - '@oxfmt/binding-android-arm-eabi@0.36.0': 1235 - resolution: {integrity: sha512-Z4yVHJWx/swHHjtr0dXrBZb6LxS+qNz1qdza222mWwPTUK4L790+5i3LTgjx3KYGBzcYpjaiZBw4vOx94dH7MQ==} 1234 + '@oxfmt/binding-android-arm-eabi@0.40.0': 1235 + resolution: {integrity: sha512-S6zd5r1w/HmqR8t0CTnGjFTBLDq2QKORPwriCHxo4xFNuhmOTABGjPaNvCJJVnrKBLsohOeiDX3YqQfJPF+FXw==} 1236 1236 engines: {node: ^20.19.0 || >=22.12.0} 1237 1237 cpu: [arm] 1238 1238 os: [android] 1239 1239 1240 - '@oxfmt/binding-android-arm64@0.36.0': 1241 - resolution: {integrity: sha512-3ElCJRFNPQl7jexf2CAa9XmAm8eC5JPrIDSjc9jSchkVSFTEqyL0NtZinBB2h1a4i4JgP1oGl/5G5n8YR4FN8Q==} 1240 + '@oxfmt/binding-android-arm64@0.40.0': 1241 + resolution: {integrity: sha512-/mbS9UUP/5Vbl2D6osIdcYiP0oie63LKMoTyGj5hyMCK/SFkl3EhtyRAfdjPvuvHC0SXdW6ePaTKkBSq1SNcIw==} 1242 1242 engines: {node: ^20.19.0 || >=22.12.0} 1243 1243 cpu: [arm64] 1244 1244 os: [android] 1245 1245 1246 - '@oxfmt/binding-darwin-arm64@0.36.0': 1247 - resolution: {integrity: sha512-nak4znWCqIExKhYSY/mz/lWsqWIpdsS7o0+SRzXR1Q0m7GrMcG1UrF1pS7TLGZhhkf7nTfEF7q6oZzJiodRDuw==} 1246 + '@oxfmt/binding-darwin-arm64@0.40.0': 1247 + resolution: {integrity: sha512-wRt8fRdfLiEhnRMBonlIbKrJWixoEmn6KCjKE9PElnrSDSXETGZfPb8ee+nQNTobXkCVvVLytp2o0obAsxl78Q==} 1248 1248 engines: {node: ^20.19.0 || >=22.12.0} 1249 1249 cpu: [arm64] 1250 1250 os: [darwin] 1251 1251 1252 - '@oxfmt/binding-darwin-x64@0.36.0': 1253 - resolution: {integrity: sha512-V4GP96thDnpKx6ADnMDnhIXNdtV+Ql9D4HUU+a37VTeVbs5qQSF/s6hhUP1b3xUqU7iRcwh72jUU2Y12rtGHAw==} 1252 + '@oxfmt/binding-darwin-x64@0.40.0': 1253 + resolution: {integrity: sha512-fzowhqbOE/NRy+AE5ob0+Y4X243WbWzDb00W+pKwD7d9tOqsAFbtWUwIyqqCoCLxj791m2xXIEeLH/3uz7zCCg==} 1254 1254 engines: {node: ^20.19.0 || >=22.12.0} 1255 1255 cpu: [x64] 1256 1256 os: [darwin] 1257 1257 1258 - '@oxfmt/binding-freebsd-x64@0.36.0': 1259 - resolution: {integrity: sha512-/xapWCADfI5wrhxpEUjhI9fnw7MV5BUZizVa8e24n3VSK6A3Y1TB/ClOP1tfxNspykFKXp4NBWl6NtDJP3osqQ==} 1258 + '@oxfmt/binding-freebsd-x64@0.40.0': 1259 + resolution: {integrity: sha512-agZ9ITaqdBjcerRRFEHB8s0OyVcQW8F9ZxsszjxzeSthQ4fcN2MuOtQFWec1ed8/lDa50jSLHVE2/xPmTgtCfQ==} 1260 1260 engines: {node: ^20.19.0 || >=22.12.0} 1261 1261 cpu: [x64] 1262 1262 os: [freebsd] 1263 1263 1264 - '@oxfmt/binding-linux-arm-gnueabihf@0.36.0': 1265 - resolution: {integrity: sha512-1lOmv61XMFIH5uNm27620kRRzWt/RK6tdn250BRDoG9W7OXGOQ5UyI1HVT+SFkoOoKztBiinWgi68+NA1MjBVQ==} 1264 + '@oxfmt/binding-linux-arm-gnueabihf@0.40.0': 1265 + resolution: {integrity: sha512-ZM2oQ47p28TP1DVIp7HL1QoMUgqlBFHey0ksHct7tMXoU5BqjNvPWw7888azzMt25lnyPODVuye1wvNbvVUFOA==} 1266 1266 engines: {node: ^20.19.0 || >=22.12.0} 1267 1267 cpu: [arm] 1268 1268 os: [linux] 1269 1269 1270 - '@oxfmt/binding-linux-arm-musleabihf@0.36.0': 1271 - resolution: {integrity: sha512-vMH23AskdR1ujUS9sPck2Df9rBVoZUnCVY86jisILzIQ/QQ/yKUTi7tgnIvydPx7TyB/48wsQ5QMr5Knq5p/aw==} 1270 + '@oxfmt/binding-linux-arm-musleabihf@0.40.0': 1271 + resolution: {integrity: sha512-RBFPAxRAIsMisKM47Oe6Lwdv6agZYLz02CUhVCD1sOv5ajAcRMrnwCFBPWwGXpazToW2mjnZxFos8TuFjTU15A==} 1272 1272 engines: {node: ^20.19.0 || >=22.12.0} 1273 1273 cpu: [arm] 1274 1274 os: [linux] 1275 1275 1276 - '@oxfmt/binding-linux-arm64-gnu@0.36.0': 1277 - resolution: {integrity: sha512-Hy1V+zOBHpBiENRx77qrUTt5aPDHeCASRc8K5KwwAHkX2AKP0nV89eL17hsZrE9GmnXFjsNmd80lyf7aRTXsbw==} 1276 + '@oxfmt/binding-linux-arm64-gnu@0.40.0': 1277 + resolution: {integrity: sha512-Nb2XbQ+wV3W2jSIihXdPj7k83eOxeSgYP3N/SRXvQ6ZYPIk6Q86qEh5Gl/7OitX3bQoQrESqm1yMLvZV8/J7dA==} 1278 1278 engines: {node: ^20.19.0 || >=22.12.0} 1279 1279 cpu: [arm64] 1280 1280 os: [linux] 1281 1281 1282 - '@oxfmt/binding-linux-arm64-musl@0.36.0': 1283 - resolution: {integrity: sha512-SPGLJkOIHSIC6ABUQ5V8NqJpvYhMJueJv26NYqfCnwi/Mn6A61amkpJJ9Suy0Nmvs+OWESJpcebrBUbXPGZyQQ==} 1282 + '@oxfmt/binding-linux-arm64-musl@0.40.0': 1283 + resolution: {integrity: sha512-tGmWhLD/0YMotCdfezlT6tC/MJG/wKpo4vnQ3Cq+4eBk/BwNv7EmkD0VkD5F/dYkT3b8FNU01X2e8vvJuWoM1w==} 1284 1284 engines: {node: ^20.19.0 || >=22.12.0} 1285 1285 cpu: [arm64] 1286 1286 os: [linux] 1287 1287 1288 - '@oxfmt/binding-linux-ppc64-gnu@0.36.0': 1289 - resolution: {integrity: sha512-3EuoyB8x9x8ysYJjbEO/M9fkSk72zQKnXCvpZMDHXlnY36/1qMp55Nm0PrCwjGO/1pen5hdOVkz9WmP3nAp2IQ==} 1288 + '@oxfmt/binding-linux-ppc64-gnu@0.40.0': 1289 + resolution: {integrity: sha512-rVbFyM3e7YhkVnp0IVYjaSHfrBWcTRWb60LEcdNAJcE2mbhTpbqKufx0FrhWfoxOrW/+7UJonAOShoFFLigDqQ==} 1290 1290 engines: {node: ^20.19.0 || >=22.12.0} 1291 1291 cpu: [ppc64] 1292 1292 os: [linux] 1293 1293 1294 - '@oxfmt/binding-linux-riscv64-gnu@0.36.0': 1295 - resolution: {integrity: sha512-MpY3itLwpGh8dnywtrZtaZ604T1m715SydCKy0+qTxetv+IHzuA+aO/AGzrlzUNYZZmtWtmDBrChZGibvZxbRQ==} 1294 + '@oxfmt/binding-linux-riscv64-gnu@0.40.0': 1295 + resolution: {integrity: sha512-3ZqBw14JtWeEoLiioJcXSJz8RQyPE+3jLARnYM1HdPzZG4vk+Ua8CUupt2+d+vSAvMyaQBTN2dZK+kbBS/j5mA==} 1296 1296 engines: {node: ^20.19.0 || >=22.12.0} 1297 1297 cpu: [riscv64] 1298 1298 os: [linux] 1299 1299 1300 - '@oxfmt/binding-linux-riscv64-musl@0.36.0': 1301 - resolution: {integrity: sha512-mmDhe4Vtx+XwQPRPn/V25+APnkApYgZ23q+6GVsNYY98pf3aU0aI3Me96pbRs/AfJ1jIiGC+/6q71FEu8dHcHw==} 1300 + '@oxfmt/binding-linux-riscv64-musl@0.40.0': 1301 + resolution: {integrity: sha512-JJ4PPSdcbGBjPvb+O7xYm2FmAsKCyuEMYhqatBAHMp/6TA6rVlf9Z/sYPa4/3Bommb+8nndm15SPFRHEPU5qFA==} 1302 1302 engines: {node: ^20.19.0 || >=22.12.0} 1303 1303 cpu: [riscv64] 1304 1304 os: [linux] 1305 1305 1306 - '@oxfmt/binding-linux-s390x-gnu@0.36.0': 1307 - resolution: {integrity: sha512-AYXhU+DmNWLSnvVwkHM92fuYhogtVHab7UQrPNaDf1sxadugg9gWVmcgJDlIwxJdpk5CVW/TFvwUKwI432zhhA==} 1306 + '@oxfmt/binding-linux-s390x-gnu@0.40.0': 1307 + resolution: {integrity: sha512-Kp0zNJoX9Ik77wUya2tpBY3W9f40VUoMQLWVaob5SgCrblH/t2xr/9B2bWHfs0WCefuGmqXcB+t0Lq77sbBmZw==} 1308 1308 engines: {node: ^20.19.0 || >=22.12.0} 1309 1309 cpu: [s390x] 1310 1310 os: [linux] 1311 1311 1312 - '@oxfmt/binding-linux-x64-gnu@0.36.0': 1313 - resolution: {integrity: sha512-H16QhhQ3usoakMleiAAQ2mg0NsBDAdyE9agUgfC8IHHh3jZEbr0rIKwjEqwbOHK5M0EmfhJmr+aGO/MgZPsneA==} 1312 + '@oxfmt/binding-linux-x64-gnu@0.40.0': 1313 + resolution: {integrity: sha512-7YTCNzleWTaQTqNGUNQ66qVjpoV6DjbCOea+RnpMBly2bpzrI/uu7Rr+2zcgRfNxyjXaFTVQKaRKjqVdeUfeVA==} 1314 1314 engines: {node: ^20.19.0 || >=22.12.0} 1315 1315 cpu: [x64] 1316 1316 os: [linux] 1317 1317 1318 - '@oxfmt/binding-linux-x64-musl@0.36.0': 1319 - resolution: {integrity: sha512-EFFGkixA39BcmHiCe2ECdrq02D6FCve5ka6ObbvrheXl4V+R0U/E+/uLyVx1X65LW8TA8QQHdnbdDallRekohw==} 1318 + '@oxfmt/binding-linux-x64-musl@0.40.0': 1319 + resolution: {integrity: sha512-hWnSzJ0oegeOwfOEeejYXfBqmnRGHusgtHfCPzmvJvHTwy1s3Neo59UKc1CmpE3zxvrCzJoVHos0rr97GHMNPw==} 1320 1320 engines: {node: ^20.19.0 || >=22.12.0} 1321 1321 cpu: [x64] 1322 1322 os: [linux] 1323 1323 1324 - '@oxfmt/binding-openharmony-arm64@0.36.0': 1325 - resolution: {integrity: sha512-zr/t369wZWFOj1qf06Z5gGNjFymfUNDrxKMmr7FKiDRVI1sNsdKRCuRL4XVjtcptKQ+ao3FfxLN1vrynivmCYg==} 1324 + '@oxfmt/binding-openharmony-arm64@0.40.0': 1325 + resolution: {integrity: sha512-28sJC1lR4qtBJGzSRRbPnSW3GxU2+4YyQFE6rCmsUYqZ5XYH8jg0/w+CvEzQ8TuAQz5zLkcA25nFQGwoU0PT3Q==} 1326 1326 engines: {node: ^20.19.0 || >=22.12.0} 1327 1327 cpu: [arm64] 1328 1328 os: [openharmony] 1329 1329 1330 - '@oxfmt/binding-win32-arm64-msvc@0.36.0': 1331 - resolution: {integrity: sha512-FxO7UksTv8h4olzACgrqAXNF6BP329+H322323iDrMB5V/+a1kcAw07fsOsUmqNrb9iJBsCQgH/zqcqp5903ag==} 1330 + '@oxfmt/binding-win32-arm64-msvc@0.40.0': 1331 + resolution: {integrity: sha512-cDkRnyT0dqwF5oIX1Cv59HKCeZQFbWWdUpXa3uvnHFT2iwYSSZspkhgjXjU6iDp5pFPaAEAe9FIbMoTgkTmKPg==} 1332 1332 engines: {node: ^20.19.0 || >=22.12.0} 1333 1333 cpu: [arm64] 1334 1334 os: [win32] 1335 1335 1336 - '@oxfmt/binding-win32-ia32-msvc@0.36.0': 1337 - resolution: {integrity: sha512-OjoMQ89H01M0oLMfr/CPNH1zi48ZIwxAKObUl57oh7ssUBNDp/2Vjf7E1TQ8M4oj4VFQ/byxl2SmcPNaI2YNDg==} 1336 + '@oxfmt/binding-win32-ia32-msvc@0.40.0': 1337 + resolution: {integrity: sha512-7rPemBJjqm5Gkv6ZRCPvK8lE6AqQ/2z31DRdWazyx2ZvaSgL7QGofHXHNouRpPvNsT9yxRNQJgigsWkc+0qg4w==} 1338 1338 engines: {node: ^20.19.0 || >=22.12.0} 1339 1339 cpu: [ia32] 1340 1340 os: [win32] 1341 1341 1342 - '@oxfmt/binding-win32-x64-msvc@0.36.0': 1343 - resolution: {integrity: sha512-MoyeQ9S36ZTz/4bDhOKJgOBIDROd4dQ5AkT9iezhEaUBxAPdNX9Oq0jD8OSnCj3G4wam/XNxVWKMA52kmzmPtQ==} 1342 + '@oxfmt/binding-win32-x64-msvc@0.40.0': 1343 + resolution: {integrity: sha512-/Zmj0yTYSvmha6TG1QnoLqVT7ZMRDqXvFXXBQpIjteEwx9qvUYMBH2xbiOFhDeMUJkGwC3D6fdKsFtaqUvkwNA==} 1344 1344 engines: {node: ^20.19.0 || >=22.12.0} 1345 1345 cpu: [x64] 1346 1346 os: [win32] ··· 6578 6578 resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} 6579 6579 engines: {node: '>= 0.4'} 6580 6580 6581 - oxfmt@0.36.0: 6582 - resolution: {integrity: sha512-/ejJ+KoSW6J9bcNT9a9UtJSJNWhJ3yOLSBLbkoFHJs/8CZjmaZVZAJe4YgO1KMJlKpNQasrn/G9JQUEZI3p0EQ==} 6581 + oxfmt@0.40.0: 6582 + resolution: {integrity: sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ==} 6583 6583 engines: {node: ^20.19.0 || >=22.12.0} 6584 6584 hasBin: true 6585 6585 ··· 7459 7459 tar@7.5.1: 7460 7460 resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} 7461 7461 engines: {node: '>=18'} 7462 + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me 7462 7463 7463 7464 terser-webpack-plugin@5.3.14: 7464 7465 resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} ··· 9080 9081 react: 19.2.0 9081 9082 react-dom: 19.2.0(react@19.2.0) 9082 9083 9083 - '@oxfmt/binding-android-arm-eabi@0.36.0': 9084 + '@oxfmt/binding-android-arm-eabi@0.40.0': 9084 9085 optional: true 9085 9086 9086 - '@oxfmt/binding-android-arm64@0.36.0': 9087 + '@oxfmt/binding-android-arm64@0.40.0': 9087 9088 optional: true 9088 9089 9089 - '@oxfmt/binding-darwin-arm64@0.36.0': 9090 + '@oxfmt/binding-darwin-arm64@0.40.0': 9090 9091 optional: true 9091 9092 9092 - '@oxfmt/binding-darwin-x64@0.36.0': 9093 + '@oxfmt/binding-darwin-x64@0.40.0': 9093 9094 optional: true 9094 9095 9095 - '@oxfmt/binding-freebsd-x64@0.36.0': 9096 + '@oxfmt/binding-freebsd-x64@0.40.0': 9096 9097 optional: true 9097 9098 9098 - '@oxfmt/binding-linux-arm-gnueabihf@0.36.0': 9099 + '@oxfmt/binding-linux-arm-gnueabihf@0.40.0': 9099 9100 optional: true 9100 9101 9101 - '@oxfmt/binding-linux-arm-musleabihf@0.36.0': 9102 + '@oxfmt/binding-linux-arm-musleabihf@0.40.0': 9102 9103 optional: true 9103 9104 9104 - '@oxfmt/binding-linux-arm64-gnu@0.36.0': 9105 + '@oxfmt/binding-linux-arm64-gnu@0.40.0': 9105 9106 optional: true 9106 9107 9107 - '@oxfmt/binding-linux-arm64-musl@0.36.0': 9108 + '@oxfmt/binding-linux-arm64-musl@0.40.0': 9108 9109 optional: true 9109 9110 9110 - '@oxfmt/binding-linux-ppc64-gnu@0.36.0': 9111 + '@oxfmt/binding-linux-ppc64-gnu@0.40.0': 9111 9112 optional: true 9112 9113 9113 - '@oxfmt/binding-linux-riscv64-gnu@0.36.0': 9114 + '@oxfmt/binding-linux-riscv64-gnu@0.40.0': 9114 9115 optional: true 9115 9116 9116 - '@oxfmt/binding-linux-riscv64-musl@0.36.0': 9117 + '@oxfmt/binding-linux-riscv64-musl@0.40.0': 9117 9118 optional: true 9118 9119 9119 - '@oxfmt/binding-linux-s390x-gnu@0.36.0': 9120 + '@oxfmt/binding-linux-s390x-gnu@0.40.0': 9120 9121 optional: true 9121 9122 9122 - '@oxfmt/binding-linux-x64-gnu@0.36.0': 9123 + '@oxfmt/binding-linux-x64-gnu@0.40.0': 9123 9124 optional: true 9124 9125 9125 - '@oxfmt/binding-linux-x64-musl@0.36.0': 9126 + '@oxfmt/binding-linux-x64-musl@0.40.0': 9126 9127 optional: true 9127 9128 9128 - '@oxfmt/binding-openharmony-arm64@0.36.0': 9129 + '@oxfmt/binding-openharmony-arm64@0.40.0': 9129 9130 optional: true 9130 9131 9131 - '@oxfmt/binding-win32-arm64-msvc@0.36.0': 9132 + '@oxfmt/binding-win32-arm64-msvc@0.40.0': 9132 9133 optional: true 9133 9134 9134 - '@oxfmt/binding-win32-ia32-msvc@0.36.0': 9135 + '@oxfmt/binding-win32-ia32-msvc@0.40.0': 9135 9136 optional: true 9136 9137 9137 - '@oxfmt/binding-win32-x64-msvc@0.36.0': 9138 + '@oxfmt/binding-win32-x64-msvc@0.40.0': 9138 9139 optional: true 9139 9140 9140 9141 '@oxlint/binding-android-arm-eabi@1.50.0': ··· 15705 15706 object-keys: 1.1.1 15706 15707 safe-push-apply: 1.0.0 15707 15708 15708 - oxfmt@0.36.0: 15709 + oxfmt@0.40.0: 15709 15710 dependencies: 15710 15711 tinypool: 2.1.0 15711 15712 optionalDependencies: 15712 - '@oxfmt/binding-android-arm-eabi': 0.36.0 15713 - '@oxfmt/binding-android-arm64': 0.36.0 15714 - '@oxfmt/binding-darwin-arm64': 0.36.0 15715 - '@oxfmt/binding-darwin-x64': 0.36.0 15716 - '@oxfmt/binding-freebsd-x64': 0.36.0 15717 - '@oxfmt/binding-linux-arm-gnueabihf': 0.36.0 15718 - '@oxfmt/binding-linux-arm-musleabihf': 0.36.0 15719 - '@oxfmt/binding-linux-arm64-gnu': 0.36.0 15720 - '@oxfmt/binding-linux-arm64-musl': 0.36.0 15721 - '@oxfmt/binding-linux-ppc64-gnu': 0.36.0 15722 - '@oxfmt/binding-linux-riscv64-gnu': 0.36.0 15723 - '@oxfmt/binding-linux-riscv64-musl': 0.36.0 15724 - '@oxfmt/binding-linux-s390x-gnu': 0.36.0 15725 - '@oxfmt/binding-linux-x64-gnu': 0.36.0 15726 - '@oxfmt/binding-linux-x64-musl': 0.36.0 15727 - '@oxfmt/binding-openharmony-arm64': 0.36.0 15728 - '@oxfmt/binding-win32-arm64-msvc': 0.36.0 15729 - '@oxfmt/binding-win32-ia32-msvc': 0.36.0 15730 - '@oxfmt/binding-win32-x64-msvc': 0.36.0 15713 + '@oxfmt/binding-android-arm-eabi': 0.40.0 15714 + '@oxfmt/binding-android-arm64': 0.40.0 15715 + '@oxfmt/binding-darwin-arm64': 0.40.0 15716 + '@oxfmt/binding-darwin-x64': 0.40.0 15717 + '@oxfmt/binding-freebsd-x64': 0.40.0 15718 + '@oxfmt/binding-linux-arm-gnueabihf': 0.40.0 15719 + '@oxfmt/binding-linux-arm-musleabihf': 0.40.0 15720 + '@oxfmt/binding-linux-arm64-gnu': 0.40.0 15721 + '@oxfmt/binding-linux-arm64-musl': 0.40.0 15722 + '@oxfmt/binding-linux-ppc64-gnu': 0.40.0 15723 + '@oxfmt/binding-linux-riscv64-gnu': 0.40.0 15724 + '@oxfmt/binding-linux-riscv64-musl': 0.40.0 15725 + '@oxfmt/binding-linux-s390x-gnu': 0.40.0 15726 + '@oxfmt/binding-linux-x64-gnu': 0.40.0 15727 + '@oxfmt/binding-linux-x64-musl': 0.40.0 15728 + '@oxfmt/binding-openharmony-arm64': 0.40.0 15729 + '@oxfmt/binding-win32-arm64-msvc': 0.40.0 15730 + '@oxfmt/binding-win32-ia32-msvc': 0.40.0 15731 + '@oxfmt/binding-win32-x64-msvc': 0.40.0 15731 15732 15732 15733 oxlint@1.50.0: 15733 15734 optionalDependencies: