@spear-ai/spectral 1.20.1 → 1.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/Accordion.js +0 -4
  2. package/dist/Accordion.js.map +1 -1
  3. package/dist/Alert/AlertBase.d.ts +0 -1
  4. package/dist/Alert/AlertBase.d.ts.map +1 -1
  5. package/dist/Alert/AlertBase.js +14 -17
  6. package/dist/Alert/AlertBase.js.map +1 -1
  7. package/dist/Alert.js +16 -4
  8. package/dist/Alert.js.map +1 -1
  9. package/dist/AlertDialog.js +3 -3
  10. package/dist/AlertDialog.js.map +1 -1
  11. package/dist/Avatar.js +1 -9
  12. package/dist/Avatar.js.map +1 -1
  13. package/dist/Badge.js +0 -1
  14. package/dist/Badge.js.map +1 -1
  15. package/dist/Button.js +0 -3
  16. package/dist/Button.js.map +1 -1
  17. package/dist/ButtonGroup.js +0 -4
  18. package/dist/ButtonGroup.js.map +1 -1
  19. package/dist/ButtonIcon.js +0 -1
  20. package/dist/ButtonIcon.js.map +1 -1
  21. package/dist/ButtonIconSlideout.js +0 -3
  22. package/dist/ButtonIconSlideout.js.map +1 -1
  23. package/dist/Checkbox.d.ts.map +1 -1
  24. package/dist/Checkbox.js +5 -8
  25. package/dist/Checkbox.js.map +1 -1
  26. package/dist/Combobox.d.ts +1 -0
  27. package/dist/Combobox.d.ts.map +1 -1
  28. package/dist/Combobox.js +0 -4
  29. package/dist/Combobox.js.map +1 -1
  30. package/dist/ControlGroup/ControlGroupSelect.js +0 -5
  31. package/dist/ControlGroup/ControlGroupSelect.js.map +1 -1
  32. package/dist/DataCard/Card.js +0 -6
  33. package/dist/DataCard/Card.js.map +1 -1
  34. package/dist/DataCard.js +1 -7
  35. package/dist/DataCard.js.map +1 -1
  36. package/dist/DateTimePicker/Calendar.js +0 -1
  37. package/dist/DateTimePicker/Calendar.js.map +1 -1
  38. package/dist/DateTimePicker/DateTimeInput.js +0 -1
  39. package/dist/DateTimePicker/DateTimeInput.js.map +1 -1
  40. package/dist/DateTimePicker/TimePeriodSelect.js +0 -4
  41. package/dist/DateTimePicker/TimePeriodSelect.js.map +1 -1
  42. package/dist/DateTimePicker/TimePicker.js +0 -3
  43. package/dist/DateTimePicker/TimePicker.js.map +1 -1
  44. package/dist/DateTimePicker.js +0 -4
  45. package/dist/DateTimePicker.js.map +1 -1
  46. package/dist/Dialog.js +0 -16
  47. package/dist/Dialog.js.map +1 -1
  48. package/dist/DirectionalColorWheel/DirectionalColorWheelDisclosure.js +0 -2
  49. package/dist/DirectionalColorWheel/DirectionalColorWheelDisclosure.js.map +1 -1
  50. package/dist/DirectionalColorWheel/DirectionalColorWheelGlyph.js +0 -1
  51. package/dist/DirectionalColorWheel/DirectionalColorWheelGlyph.js.map +1 -1
  52. package/dist/DirectionalColorWheel.js +9 -21
  53. package/dist/DirectionalColorWheel.js.map +1 -1
  54. package/dist/Drawer.js +6 -29
  55. package/dist/Drawer.js.map +1 -1
  56. package/dist/DropdownMenu.js +1 -9
  57. package/dist/DropdownMenu.js.map +1 -1
  58. package/dist/FormFieldMessage.js +0 -1
  59. package/dist/FormFieldMessage.js.map +1 -1
  60. package/dist/HoverCard.js +0 -3
  61. package/dist/HoverCard.js.map +1 -1
  62. package/dist/Input.js +0 -10
  63. package/dist/Input.js.map +1 -1
  64. package/dist/InputOTP.js +0 -4
  65. package/dist/InputOTP.js.map +1 -1
  66. package/dist/InputSearch.js +3 -15
  67. package/dist/InputSearch.js.map +1 -1
  68. package/dist/Kbd.js +0 -2
  69. package/dist/Kbd.js.map +1 -1
  70. package/dist/Meter.d.ts +23 -0
  71. package/dist/Meter.d.ts.map +1 -0
  72. package/dist/Meter.js +45 -0
  73. package/dist/Meter.js.map +1 -0
  74. package/dist/MultiSelect/MultiSelectBase.js +1 -16
  75. package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
  76. package/dist/Popover.js +0 -3
  77. package/dist/Popover.js.map +1 -1
  78. package/dist/RadialMenu.js +1 -7
  79. package/dist/RadialMenu.js.map +1 -1
  80. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
  81. package/dist/RadioButtonGroup/RadioButtonGroupBase.js +1 -4
  82. package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
  83. package/dist/RadioButtonGroup.js +1 -1
  84. package/dist/RadioButtonGroup.js.map +1 -1
  85. package/dist/RadioGroup.js +0 -6
  86. package/dist/RadioGroup.js.map +1 -1
  87. package/dist/Select.js +11 -40
  88. package/dist/Select.js.map +1 -1
  89. package/dist/Slider.js +2 -11
  90. package/dist/Slider.js.map +1 -1
  91. package/dist/Switch.js +0 -6
  92. package/dist/Switch.js.map +1 -1
  93. package/dist/Tabs/TabsBase.js +0 -5
  94. package/dist/Tabs/TabsBase.js.map +1 -1
  95. package/dist/Textarea.js +0 -4
  96. package/dist/Textarea.js.map +1 -1
  97. package/dist/Toast.js +1 -3
  98. package/dist/Toast.js.map +1 -1
  99. package/dist/Toggle.js +0 -1
  100. package/dist/Toggle.js.map +1 -1
  101. package/dist/ToggleGroup/ToggleGroupItem.js +0 -1
  102. package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
  103. package/dist/ToggleGroup.js +0 -1
  104. package/dist/ToggleGroup.js.map +1 -1
  105. package/dist/Tooltip.d.ts.map +1 -1
  106. package/dist/Tooltip.js +4 -5
  107. package/dist/Tooltip.js.map +1 -1
  108. package/dist/Tray.js +1 -9
  109. package/dist/Tray.js.map +1 -1
  110. package/dist/index.d.ts +2 -1
  111. package/dist/index.js +2 -1
  112. package/dist/styles/horizon/base.css +31 -16
  113. package/dist/styles/horizon/colors.css +37 -21
  114. package/dist/styles/horizon/theme.css +15 -7
  115. package/dist/styles/horizon/utilities.css +19 -45
  116. package/dist/styles/spectral.css +1 -1
  117. package/package.json +4 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonIcon.js","names":[],"sources":["../src/components/ButtonIcon/ButtonIcon.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { cloneElement, isValidElement, type ButtonHTMLAttributes, type MouseEvent, type ReactElement, type Ref, type SVGProps } from 'react'\n\ntype IconOrSVG = ReactElement | (() => ReactElement)\n\nexport interface ButtonIconProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> {\n className?: string\n icon: IconOrSVG\n isLoading?: boolean\n label: string\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n shape?: 'circle' | 'square'\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst buttonStyles = `bg-level-one hover:bg-level-three text-text-primary hover:text-text-secondary inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-[background-color,color,transform]\n active:scale-[0.97] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-level-three cursor-pointer [&_svg]:pointer-events-none [&_svg]:shrink-0 disabled:opacity-50\n disabled:pointer-events-none disabled:text-text-secondary disabled:hover:bg-level-one`\n\nconst sizeConfig = {\n sm: { button: 'size-8 min-size-8', icon: 16 },\n md: { button: 'size-10 min-size-10', icon: 24 },\n lg: { button: 'size-12 min-size-12', icon: 32 },\n} as const\n\nexport const ButtonIcon = ({\n className,\n disabled,\n icon,\n isLoading = false,\n label,\n onClick,\n ref,\n shape = 'square',\n size = 'md',\n ...props\n}: ButtonIconProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => onClick?.(event)\n\n const effectiveLabel = isLoading ? `${label} - Loading` : label\n\n const renderIcon = (): ReactElement => {\n if (isLoading) {\n return <LoaderIcon size={sizeConfig[size as keyof typeof sizeConfig].icon} aria-hidden='true' />\n }\n\n const iconElement = typeof icon === 'function' ? icon() : icon\n\n if (isValidElement(iconElement)) {\n const currentSize = sizeConfig[size as keyof typeof sizeConfig].icon\n\n if (iconElement.type === 'svg') {\n return cloneElement(iconElement as ReactElement<SVGProps<SVGSVGElement>>, {\n className: cn('shrink-0', (iconElement.props as { className?: string }).className),\n height: currentSize,\n width: currentSize,\n 'aria-hidden': 'true',\n })\n }\n\n // For icon components, pass size prop if the element accepts it\n const baseIconProps = {\n 'aria-hidden': 'true',\n className: cn('shrink-0', (iconElement.props as { className?: string }).className),\n }\n\n // Check if this is an icon component that accepts size prop\n // All our icon components accept refs and have displayName containing 'Icon'\n const componentType = iconElement.type as { displayName?: string }\n const isIconComponent = componentType.displayName?.endsWith('Icon') ?? false\n\n if (isIconComponent) {\n const iconPropsWithSize = {\n ...baseIconProps,\n size: currentSize,\n }\n return cloneElement(iconElement, iconPropsWithSize)\n }\n\n return cloneElement(iconElement, baseIconProps)\n }\n\n return iconElement\n }\n\n return (\n <button\n aria-label={effectiveLabel}\n className={cn(buttonStyles, shape === 'circle' ? 'rounded-full' : 'rounded-lg', sizeConfig[size as keyof typeof sizeConfig].button, isLoading && 'cursor-wait', disabled && 'cursor-not-allowed opacity-50', className)}\n data-testid='spectral-button-icon'\n disabled={disabled ?? isLoading}\n onClick={handleClick}\n ref={ref}\n type='button'\n {...props}\n >\n {renderIcon()}\n </button>\n )\n}\nButtonIcon.displayName = 'ButtonIcon'\n"],"mappings":";;;;;;;AAgBA,MAAM,eAAe;;;AAIrB,MAAM,aAAa;CACjB,IAAI;EAAE,QAAQ;EAAqB,MAAM;EAAI;CAC7C,IAAI;EAAE,QAAQ;EAAuB,MAAM;EAAI;CAC/C,IAAI;EAAE,QAAQ;EAAuB,MAAM;EAAI;CAChD;AAED,MAAa,cAAc,EACzB,WACA,UACA,MACA,YAAY,OACZ,OACA,SACA,KACA,QAAQ,UACR,OAAO,MACP,GAAG,YAGC;CACJ,MAAM,eAAe,UAAyC,UAAU,MAAM;CAE9E,MAAM,iBAAiB,YAAY,GAAG,MAAM,cAAc;CAE1D,MAAM,mBAAiC;AACrC,MAAI,UACF,QAAO,oBAAC,YAAD;GAAY,MAAM,WAAW,MAAiC;GAAM,eAAY;GAAS;EAGlG,MAAM,cAAc,OAAO,SAAS,aAAa,MAAM,GAAG;AAE1D,MAAI,eAAe,YAAY,EAAE;GAC/B,MAAM,cAAc,WAAW,MAAiC;AAEhE,OAAI,YAAY,SAAS,MACvB,QAAO,aAAa,aAAsD;IACxE,WAAW,GAAG,YAAa,YAAY,MAAiC,UAAU;IAClF,QAAQ;IACR,OAAO;IACP,eAAe;IAChB,CAAC;GAIJ,MAAM,gBAAgB;IACpB,eAAe;IACf,WAAW,GAAG,YAAa,YAAY,MAAiC,UAAU;IACnF;AAOD,OAHsB,YAAY,KACI,aAAa,SAAS,OAAO,IAAI,MAOrE,QAAO,aAAa,aAAa;IAH/B,GAAG;IACH,MAAM;IAE0C,CAAC;AAGrD,UAAO,aAAa,aAAa,cAAc;;AAGjD,SAAO;;AAGT,QACE,oBAAC,UAAD;EACE,cAAY;EACZ,WAAW,GAAG,cAAc,UAAU,WAAW,iBAAiB,cAAc,WAAW,MAAiC,QAAQ,aAAa,eAAe,YAAY,iCAAiC,UAAU;EACvN,eAAY;EACZ,UAAU,YAAY;EACtB,SAAS;EACJ;EACL,MAAK;EACL,GAAI;YAEH,YAAY;EACN;;AAGb,WAAW,cAAc"}
1
+ {"version":3,"file":"ButtonIcon.js","names":[],"sources":["../src/components/ButtonIcon/ButtonIcon.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { cloneElement, isValidElement, type ButtonHTMLAttributes, type MouseEvent, type ReactElement, type Ref, type SVGProps } from 'react'\n\ntype IconOrSVG = ReactElement | (() => ReactElement)\n\nexport interface ButtonIconProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> {\n className?: string\n icon: IconOrSVG\n isLoading?: boolean\n label: string\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n shape?: 'circle' | 'square'\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst buttonStyles = `bg-level-one hover:bg-level-three text-text-primary hover:text-text-secondary inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-[background-color,color,transform]\n active:scale-[0.97] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-level-three cursor-pointer [&_svg]:pointer-events-none [&_svg]:shrink-0 disabled:opacity-50\n disabled:pointer-events-none disabled:text-text-secondary disabled:hover:bg-level-one`\n\nconst sizeConfig = {\n sm: { button: 'size-8 min-size-8', icon: 16 },\n md: { button: 'size-10 min-size-10', icon: 24 },\n lg: { button: 'size-12 min-size-12', icon: 32 },\n} as const\n\nexport const ButtonIcon = ({\n className,\n disabled,\n icon,\n isLoading = false,\n label,\n onClick,\n ref,\n shape = 'square',\n size = 'md',\n ...props\n}: ButtonIconProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => onClick?.(event)\n\n const effectiveLabel = isLoading ? `${label} - Loading` : label\n\n const renderIcon = (): ReactElement => {\n if (isLoading) {\n return <LoaderIcon size={sizeConfig[size as keyof typeof sizeConfig].icon} aria-hidden='true' />\n }\n\n const iconElement = typeof icon === 'function' ? icon() : icon\n\n if (isValidElement(iconElement)) {\n const currentSize = sizeConfig[size as keyof typeof sizeConfig].icon\n\n if (iconElement.type === 'svg') {\n return cloneElement(iconElement as ReactElement<SVGProps<SVGSVGElement>>, {\n className: cn('shrink-0', (iconElement.props as { className?: string }).className),\n height: currentSize,\n width: currentSize,\n 'aria-hidden': 'true',\n })\n }\n\n // For icon components, pass size prop if the element accepts it\n const baseIconProps = {\n 'aria-hidden': 'true',\n className: cn('shrink-0', (iconElement.props as { className?: string }).className),\n }\n\n // Check if this is an icon component that accepts size prop\n // All our icon components accept refs and have displayName containing 'Icon'\n const componentType = iconElement.type as { displayName?: string }\n const isIconComponent = componentType.displayName?.endsWith('Icon') ?? false\n\n if (isIconComponent) {\n const iconPropsWithSize = {\n ...baseIconProps,\n size: currentSize,\n }\n return cloneElement(iconElement, iconPropsWithSize)\n }\n\n return cloneElement(iconElement, baseIconProps)\n }\n\n return iconElement\n }\n\n return (\n <button\n aria-label={effectiveLabel}\n className={cn(buttonStyles, shape === 'circle' ? 'rounded-full' : 'rounded-lg', sizeConfig[size as keyof typeof sizeConfig].button, isLoading && 'cursor-wait', disabled && 'cursor-not-allowed opacity-50', className)}\n data-testid='spectral-button-icon'\n disabled={disabled ?? isLoading}\n onClick={handleClick}\n ref={ref}\n type='button'\n {...props}\n >\n {renderIcon()}\n </button>\n )\n}\nButtonIcon.displayName = 'ButtonIcon'\n"],"mappings":";;;;;;;AAgBA,MAAM,eAAe;;;AAIrB,MAAM,aAAa;CACjB,IAAI;EAAE,QAAQ;EAAqB,MAAM;EAAI;CAC7C,IAAI;EAAE,QAAQ;EAAuB,MAAM;EAAI;CAC/C,IAAI;EAAE,QAAQ;EAAuB,MAAM;EAAI;CAChD;AAED,MAAa,cAAc,EACzB,WACA,UACA,MACA,YAAY,OACZ,OACA,SACA,KACA,QAAQ,UACR,OAAO,MACP,GAAG,YAGC;CACJ,MAAM,eAAe,UAAyC,UAAU,MAAK;CAE7E,MAAM,iBAAiB,YAAY,GAAG,MAAM,cAAc;CAE1D,MAAM,mBAAiC;AACrC,MAAI,UACF,QAAO,oBAAC,YAAD;GAAY,MAAM,WAAW,MAAiC;GAAM,eAAY;GAAQ;EAGjG,MAAM,cAAc,OAAO,SAAS,aAAa,MAAM,GAAG;AAE1D,MAAI,eAAe,YAAY,EAAE;GAC/B,MAAM,cAAc,WAAW,MAAiC;AAEhE,OAAI,YAAY,SAAS,MACvB,QAAO,aAAa,aAAsD;IACxE,WAAW,GAAG,YAAa,YAAY,MAAiC,UAAU;IAClF,QAAQ;IACR,OAAO;IACP,eAAe;IAChB,CAAA;GAIH,MAAM,gBAAgB;IACpB,eAAe;IACf,WAAW,GAAG,YAAa,YAAY,MAAiC,UAAU;IACpF;AAOA,OAHsB,YAAY,KACI,aAAa,SAAS,OAAO,IAAI,MAOrE,QAAO,aAAa,aAAa;IAH/B,GAAG;IACH,MAAM;IAE0C,CAAA;AAGpD,UAAO,aAAa,aAAa,cAAa;;AAGhD,SAAO;;AAGT,QACE,oBAAC,UAAD;EACE,cAAY;EACZ,WAAW,GAAG,cAAc,UAAU,WAAW,iBAAiB,cAAc,WAAW,MAAiC,QAAQ,aAAa,eAAe,YAAY,iCAAiC,UAAU;EAEvN,UAAU,YAAY;EACtB,SAAS;EACJ;EACL,MAAK;EACL,GAAI;YAEH,YAAY;EACP;;AAGZ,WAAW,cAAc"}
@@ -63,13 +63,11 @@ const ButtonIconSlideout = ({ buttonClassName, className, closeLabel = "Close pa
63
63
  const inlineContentMargin = shape === "circle" ? inlineCircleMarginBySize[size] : "-ml-3";
64
64
  return /* @__PURE__ */ jsxs("div", {
65
65
  className: cn("relative isolate items-center", isInlineLayout ? cn("inline-grid transition-[grid-template-columns] duration-200 ease-in motion-reduce:transition-none", isOpen ? "grid-cols-[auto_1fr]" : "grid-cols-[auto_0fr]") : "inline-flex w-fit", className),
66
- "data-testid": dataTestId,
67
66
  children: [/* @__PURE__ */ jsx(ButtonIcon, {
68
67
  ...buttonProps,
69
68
  "aria-controls": contentId,
70
69
  "aria-expanded": isOpen,
71
70
  className: cn("relative z-10", isOpen && "bg-level-three shadow-[4px_0_10px_rgb(0_0_0_/_0.18)] hover:bg-level-three", buttonClassName),
72
- "data-testid": `${dataTestId}-button`,
73
71
  icon: () => /* @__PURE__ */ jsxs("span", {
74
72
  className: cn("relative inline-flex items-center justify-center", iconContainerSizeByButtonSize[size]),
75
73
  children: [/* @__PURE__ */ jsx("span", {
@@ -99,7 +97,6 @@ const ButtonIconSlideout = ({ buttonClassName, className, closeLabel = "Close pa
99
97
  }), /* @__PURE__ */ jsx("div", {
100
98
  "aria-hidden": !isOpen,
101
99
  className: cn("rounded-r-xl pr-3 font-medium pointer-events-none bg-level-three text-text-primary", contentHeightBySize[size], "flex items-center overflow-hidden transition-[transform,opacity,clip-path] duration-200 ease-in motion-reduce:transition-none", isOpen ? "translate-x-0 opacity-100 [clip-path:inset(0_0_0_0)]" : "-translate-x-2 opacity-0 [clip-path:inset(0_100%_0_0)]", isInlineLayout ? cn("min-w-0 max-w-44 relative z-0", inlineContentMargin, contentLeftPadding) : cn("inset-y-0 max-w-44 absolute z-0 w-max", overlayContentLeftPosition, contentLeftPadding)),
102
- "data-testid": `${dataTestId}-content`,
103
100
  id: contentId,
104
101
  children: /* @__PURE__ */ jsx("span", {
105
102
  className: cn("leading-5 block max-w-full truncate", fontSizeByButtonSize[size], contentClassName),
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonIconSlideout.js","names":[],"sources":["../src/components/ButtonIconSlideout/ButtonIconSlideout.tsx"],"sourcesContent":["import { ButtonIcon, type ButtonIconProps } from '@components/ButtonIcon/ButtonIcon'\nimport { CloseIcon, LabelIcon } from '@components/Icons'\nimport { type IconProps } from '@components/Icons/iconTypes'\nimport { useControllableState } from '@hooks/useControllableState'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentType, type MouseEvent, useId } from 'react'\n\ntype SlideoutSize = NonNullable<ButtonIconProps['size']>\ntype SlideoutIcons = [openIcon: ComponentType<IconProps>, closeIcon: ComponentType<IconProps>]\ntype SlideoutLayout = 'overlay' | 'inline'\n\nconst contentHeightBySize: Record<SlideoutSize, string> = {\n sm: 'h-8',\n md: 'h-10',\n lg: 'h-12',\n}\n\nconst iconContainerSizeByButtonSize: Record<SlideoutSize, string> = {\n sm: 'size-4',\n md: 'size-6',\n lg: 'size-8',\n}\n\nconst iconPixelsByButtonSize: Record<SlideoutSize, number> = {\n sm: 16,\n md: 24,\n lg: 32,\n}\n\nconst fontSizeByButtonSize: Record<SlideoutSize, string> = {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n}\n\nconst inlineCircleMarginBySize: Record<SlideoutSize, string> = {\n sm: '-ml-4',\n md: '-ml-5',\n lg: '-ml-6',\n}\n\nexport interface ButtonIconSlideoutProps extends Omit<ButtonIconProps, 'className' | 'content' | 'icon' | 'label' | 'onClick'> {\n buttonClassName?: string\n className?: string\n closeLabel?: string\n content: number | string\n contentClassName?: string\n dataTestId?: string\n defaultOpen?: boolean\n icons?: SlideoutIcons\n label: string\n /**\n * Controls how the slideout panel relates to surrounding layout flow:\n *\n * - `'overlay'` (default): the panel is absolutely positioned and slides over its\n * neighbors. Use when the trigger sits in free space (toolbars, floating actions).\n * - `'inline'`: the panel participates in flex/grid flow and pushes its neighbors as\n * it opens. Use when the trigger sits inside a row alongside other content (such\n * as a header where a title should slide aside).\n */\n layout?: SlideoutLayout\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n onClose?: (event: MouseEvent<HTMLButtonElement>) => void\n onOpen?: (event: MouseEvent<HTMLButtonElement>) => void\n onOpenChange?: (isOpen: boolean) => void\n open?: boolean\n}\n\nexport const ButtonIconSlideout = ({\n buttonClassName,\n className,\n closeLabel = 'Close panel',\n content,\n contentClassName,\n dataTestId = 'spectral-button-icon-slideout',\n defaultOpen = false,\n icons = [LabelIcon, CloseIcon],\n label,\n layout = 'overlay',\n shape = 'square',\n size = 'md',\n onClick,\n onClose,\n onOpen,\n onOpenChange,\n open,\n ...buttonProps\n}: ButtonIconSlideoutProps) => {\n const [isOpen, setIsOpen] = useControllableState<boolean>({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n })\n const contentId = useId()\n\n const handleToggle = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event)\n\n if (event.defaultPrevented) return\n\n if (isOpen) {\n onClose?.(event)\n } else {\n onOpen?.(event)\n }\n\n setIsOpen((previous) => !previous)\n }\n\n const [OpenIcon, CloseIconComponent] = icons\n const iconSize = iconPixelsByButtonSize[size]\n const isInlineLayout = layout === 'inline'\n const overlayContentLeftPosition =\n shape === 'circle'\n ? {\n sm: 'left-[calc(100%-1rem)]',\n md: 'left-[calc(100%-1.25rem)]',\n lg: 'left-[calc(100%-1.5rem)]',\n }[size]\n : 'left-[calc(100%-0.75rem)]'\n const contentLeftPadding =\n shape === 'circle'\n ? {\n sm: 'pl-5',\n md: 'pl-6',\n lg: 'pl-7',\n }[size]\n : 'pl-4'\n const inlineContentMargin = shape === 'circle' ? inlineCircleMarginBySize[size] : '-ml-3'\n\n return (\n <div\n // This is an approved exception to the layout-property animation rule in order to maintain lockstep sibling reflow animation.\n className={cn('relative isolate items-center', isInlineLayout ? cn('inline-grid transition-[grid-template-columns] duration-200 ease-in motion-reduce:transition-none', isOpen ? 'grid-cols-[auto_1fr]' : 'grid-cols-[auto_0fr]') : 'inline-flex w-fit', className)}\n data-testid={dataTestId}\n >\n <ButtonIcon\n {...buttonProps}\n aria-controls={contentId}\n aria-expanded={isOpen}\n className={cn('relative z-10', isOpen && 'bg-level-three shadow-[4px_0_10px_rgb(0_0_0_/_0.18)] hover:bg-level-three', buttonClassName)}\n data-testid={`${dataTestId}-button`}\n icon={() => (\n <span className={cn('relative inline-flex items-center justify-center', iconContainerSizeByButtonSize[size])}>\n <span\n aria-hidden={isOpen}\n className={cn('inset-0 absolute flex items-center justify-center transition-[filter,opacity,transform] duration-200 ease-in motion-reduce:transition-none', isOpen ? 'pointer-events-none scale-95 opacity-0 blur-[2px]' : 'blur-0 scale-100 opacity-100')}\n data-icon-state='closed'\n >\n <OpenIcon\n aria-hidden='true'\n className='size-full shrink-0'\n size={iconSize}\n />\n </span>\n\n <span\n aria-hidden={!isOpen}\n className={cn('inset-0 absolute flex items-center justify-center transition-[filter,opacity,transform] duration-200 ease-in motion-reduce:transition-none', isOpen ? 'blur-0 scale-100 opacity-100' : 'pointer-events-none scale-95 opacity-0 blur-[2px]')}\n data-icon-state='open'\n >\n <CloseIconComponent\n aria-hidden='true'\n className='size-full shrink-0'\n size={iconSize}\n />\n </span>\n </span>\n )}\n label={isOpen ? closeLabel : label}\n onClick={handleToggle}\n shape={shape}\n size={size}\n />\n\n <div\n aria-hidden={!isOpen}\n className={cn(\n 'rounded-r-xl pr-3 font-medium pointer-events-none bg-level-three text-text-primary',\n contentHeightBySize[size],\n 'flex items-center overflow-hidden transition-[transform,opacity,clip-path] duration-200 ease-in motion-reduce:transition-none',\n isOpen ? 'translate-x-0 opacity-100 [clip-path:inset(0_0_0_0)]' : '-translate-x-2 opacity-0 [clip-path:inset(0_100%_0_0)]',\n isInlineLayout ? cn('min-w-0 max-w-44 relative z-0', inlineContentMargin, contentLeftPadding) : cn('inset-y-0 max-w-44 absolute z-0 w-max', overlayContentLeftPosition, contentLeftPadding),\n )}\n data-testid={`${dataTestId}-content`}\n id={contentId}\n >\n <span className={cn('leading-5 block max-w-full truncate', fontSizeByButtonSize[size], contentClassName)}>{content}</span>\n </div>\n </div>\n )\n}\n\nButtonIconSlideout.displayName = 'ButtonIconSlideout'\n"],"mappings":";;;;;;;;;;AAWA,MAAM,sBAAoD;CACxD,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,gCAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,yBAAuD;CAC3D,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,uBAAqD;CACzD,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,2BAAyD;CAC7D,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AA6BD,MAAa,sBAAsB,EACjC,iBACA,WACA,aAAa,eACb,SACA,kBACA,aAAa,iCACb,cAAc,OACd,QAAQ,CAAC,WAAW,UAAU,EAC9B,OACA,SAAS,WACT,QAAQ,UACR,OAAO,MACP,SACA,SACA,QACA,cACA,MACA,GAAG,kBAC0B;CAC7B,MAAM,CAAC,QAAQ,aAAa,qBAA8B;EACxD,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAC;CACF,MAAM,YAAY,OAAO;CAEzB,MAAM,gBAAgB,UAAyC;AAC7D,YAAU,MAAM;AAEhB,MAAI,MAAM,iBAAkB;AAE5B,MAAI,OACF,WAAU,MAAM;MAEhB,UAAS,MAAM;AAGjB,aAAW,aAAa,CAAC,SAAS;;CAGpC,MAAM,CAAC,UAAU,sBAAsB;CACvC,MAAM,WAAW,uBAAuB;CACxC,MAAM,iBAAiB,WAAW;CAClC,MAAM,6BACJ,UAAU,WACN;EACE,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,CAAC,QACF;CACN,MAAM,qBACJ,UAAU,WACN;EACE,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,CAAC,QACF;CACN,MAAM,sBAAsB,UAAU,WAAW,yBAAyB,QAAQ;AAElF,QACE,qBAAC,OAAD;EAEE,WAAW,GAAG,iCAAiC,iBAAiB,GAAG,qGAAqG,SAAS,yBAAyB,uBAAuB,GAAG,qBAAqB,UAAU;EACnQ,eAAa;YAHf,CAKE,oBAAC,YAAD;GACE,GAAI;GACJ,iBAAe;GACf,iBAAe;GACf,WAAW,GAAG,iBAAiB,UAAU,6EAA6E,gBAAgB;GACtI,eAAa,GAAG,WAAW;GAC3B,YACE,qBAAC,QAAD;IAAM,WAAW,GAAG,oDAAoD,8BAA8B,MAAM;cAA5G,CACE,oBAAC,QAAD;KACE,eAAa;KACb,WAAW,GAAG,8IAA8I,SAAS,sDAAsD,+BAA+B;KAC1P,mBAAgB;eAEhB,oBAAC,UAAD;MACE,eAAY;MACZ,WAAU;MACV,MAAM;MACN;KACG,GAEP,oBAAC,QAAD;KACE,eAAa,CAAC;KACd,WAAW,GAAG,8IAA8I,SAAS,iCAAiC,oDAAoD;KAC1P,mBAAgB;eAEhB,oBAAC,oBAAD;MACE,eAAY;MACZ,WAAU;MACV,MAAM;MACN;KACG,EACF;;GAET,OAAO,SAAS,aAAa;GAC7B,SAAS;GACF;GACD;GACN,GAEF,oBAAC,OAAD;GACE,eAAa,CAAC;GACd,WAAW,GACT,sFACA,oBAAoB,OACpB,iIACA,SAAS,yDAAyD,0DAClE,iBAAiB,GAAG,iCAAiC,qBAAqB,mBAAmB,GAAG,GAAG,yCAAyC,4BAA4B,mBAAmB,CAC5L;GACD,eAAa,GAAG,WAAW;GAC3B,IAAI;aAEJ,oBAAC,QAAD;IAAM,WAAW,GAAG,uCAAuC,qBAAqB,OAAO,iBAAiB;cAAG;IAAe;GACtH,EACF;;;AAIV,mBAAmB,cAAc"}
1
+ {"version":3,"file":"ButtonIconSlideout.js","names":[],"sources":["../src/components/ButtonIconSlideout/ButtonIconSlideout.tsx"],"sourcesContent":["import { ButtonIcon, type ButtonIconProps } from '@components/ButtonIcon/ButtonIcon'\nimport { CloseIcon, LabelIcon } from '@components/Icons'\nimport { type IconProps } from '@components/Icons/iconTypes'\nimport { useControllableState } from '@hooks/useControllableState'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentType, type MouseEvent, useId } from 'react'\n\ntype SlideoutSize = NonNullable<ButtonIconProps['size']>\ntype SlideoutIcons = [openIcon: ComponentType<IconProps>, closeIcon: ComponentType<IconProps>]\ntype SlideoutLayout = 'overlay' | 'inline'\n\nconst contentHeightBySize: Record<SlideoutSize, string> = {\n sm: 'h-8',\n md: 'h-10',\n lg: 'h-12',\n}\n\nconst iconContainerSizeByButtonSize: Record<SlideoutSize, string> = {\n sm: 'size-4',\n md: 'size-6',\n lg: 'size-8',\n}\n\nconst iconPixelsByButtonSize: Record<SlideoutSize, number> = {\n sm: 16,\n md: 24,\n lg: 32,\n}\n\nconst fontSizeByButtonSize: Record<SlideoutSize, string> = {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n}\n\nconst inlineCircleMarginBySize: Record<SlideoutSize, string> = {\n sm: '-ml-4',\n md: '-ml-5',\n lg: '-ml-6',\n}\n\nexport interface ButtonIconSlideoutProps extends Omit<ButtonIconProps, 'className' | 'content' | 'icon' | 'label' | 'onClick'> {\n buttonClassName?: string\n className?: string\n closeLabel?: string\n content: number | string\n contentClassName?: string\n dataTestId?: string\n defaultOpen?: boolean\n icons?: SlideoutIcons\n label: string\n /**\n * Controls how the slideout panel relates to surrounding layout flow:\n *\n * - `'overlay'` (default): the panel is absolutely positioned and slides over its\n * neighbors. Use when the trigger sits in free space (toolbars, floating actions).\n * - `'inline'`: the panel participates in flex/grid flow and pushes its neighbors as\n * it opens. Use when the trigger sits inside a row alongside other content (such\n * as a header where a title should slide aside).\n */\n layout?: SlideoutLayout\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n onClose?: (event: MouseEvent<HTMLButtonElement>) => void\n onOpen?: (event: MouseEvent<HTMLButtonElement>) => void\n onOpenChange?: (isOpen: boolean) => void\n open?: boolean\n}\n\nexport const ButtonIconSlideout = ({\n buttonClassName,\n className,\n closeLabel = 'Close panel',\n content,\n contentClassName,\n dataTestId = 'spectral-button-icon-slideout',\n defaultOpen = false,\n icons = [LabelIcon, CloseIcon],\n label,\n layout = 'overlay',\n shape = 'square',\n size = 'md',\n onClick,\n onClose,\n onOpen,\n onOpenChange,\n open,\n ...buttonProps\n}: ButtonIconSlideoutProps) => {\n const [isOpen, setIsOpen] = useControllableState<boolean>({\n value: open,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n })\n const contentId = useId()\n\n const handleToggle = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event)\n\n if (event.defaultPrevented) return\n\n if (isOpen) {\n onClose?.(event)\n } else {\n onOpen?.(event)\n }\n\n setIsOpen((previous) => !previous)\n }\n\n const [OpenIcon, CloseIconComponent] = icons\n const iconSize = iconPixelsByButtonSize[size]\n const isInlineLayout = layout === 'inline'\n const overlayContentLeftPosition =\n shape === 'circle'\n ? {\n sm: 'left-[calc(100%-1rem)]',\n md: 'left-[calc(100%-1.25rem)]',\n lg: 'left-[calc(100%-1.5rem)]',\n }[size]\n : 'left-[calc(100%-0.75rem)]'\n const contentLeftPadding =\n shape === 'circle'\n ? {\n sm: 'pl-5',\n md: 'pl-6',\n lg: 'pl-7',\n }[size]\n : 'pl-4'\n const inlineContentMargin = shape === 'circle' ? inlineCircleMarginBySize[size] : '-ml-3'\n\n return (\n <div\n // This is an approved exception to the layout-property animation rule in order to maintain lockstep sibling reflow animation.\n className={cn('relative isolate items-center', isInlineLayout ? cn('inline-grid transition-[grid-template-columns] duration-200 ease-in motion-reduce:transition-none', isOpen ? 'grid-cols-[auto_1fr]' : 'grid-cols-[auto_0fr]') : 'inline-flex w-fit', className)}\n data-testid={dataTestId}\n >\n <ButtonIcon\n {...buttonProps}\n aria-controls={contentId}\n aria-expanded={isOpen}\n className={cn('relative z-10', isOpen && 'bg-level-three shadow-[4px_0_10px_rgb(0_0_0_/_0.18)] hover:bg-level-three', buttonClassName)}\n data-testid={`${dataTestId}-button`}\n icon={() => (\n <span className={cn('relative inline-flex items-center justify-center', iconContainerSizeByButtonSize[size])}>\n <span\n aria-hidden={isOpen}\n className={cn('inset-0 absolute flex items-center justify-center transition-[filter,opacity,transform] duration-200 ease-in motion-reduce:transition-none', isOpen ? 'pointer-events-none scale-95 opacity-0 blur-[2px]' : 'blur-0 scale-100 opacity-100')}\n data-icon-state='closed'\n >\n <OpenIcon\n aria-hidden='true'\n className='size-full shrink-0'\n size={iconSize}\n />\n </span>\n\n <span\n aria-hidden={!isOpen}\n className={cn('inset-0 absolute flex items-center justify-center transition-[filter,opacity,transform] duration-200 ease-in motion-reduce:transition-none', isOpen ? 'blur-0 scale-100 opacity-100' : 'pointer-events-none scale-95 opacity-0 blur-[2px]')}\n data-icon-state='open'\n >\n <CloseIconComponent\n aria-hidden='true'\n className='size-full shrink-0'\n size={iconSize}\n />\n </span>\n </span>\n )}\n label={isOpen ? closeLabel : label}\n onClick={handleToggle}\n shape={shape}\n size={size}\n />\n\n <div\n aria-hidden={!isOpen}\n className={cn(\n 'rounded-r-xl pr-3 font-medium pointer-events-none bg-level-three text-text-primary',\n contentHeightBySize[size],\n 'flex items-center overflow-hidden transition-[transform,opacity,clip-path] duration-200 ease-in motion-reduce:transition-none',\n isOpen ? 'translate-x-0 opacity-100 [clip-path:inset(0_0_0_0)]' : '-translate-x-2 opacity-0 [clip-path:inset(0_100%_0_0)]',\n isInlineLayout ? cn('min-w-0 max-w-44 relative z-0', inlineContentMargin, contentLeftPadding) : cn('inset-y-0 max-w-44 absolute z-0 w-max', overlayContentLeftPosition, contentLeftPadding),\n )}\n data-testid={`${dataTestId}-content`}\n id={contentId}\n >\n <span className={cn('leading-5 block max-w-full truncate', fontSizeByButtonSize[size], contentClassName)}>{content}</span>\n </div>\n </div>\n )\n}\n\nButtonIconSlideout.displayName = 'ButtonIconSlideout'\n"],"mappings":";;;;;;;;;;AAWA,MAAM,sBAAoD;CACxD,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,gCAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,yBAAuD;CAC3D,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,uBAAqD;CACzD,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,2BAAyD;CAC7D,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AA6BA,MAAa,sBAAsB,EACjC,iBACA,WACA,aAAa,eACb,SACA,kBACA,aAAa,iCACb,cAAc,OACd,QAAQ,CAAC,WAAW,UAAU,EAC9B,OACA,SAAS,WACT,QAAQ,UACR,OAAO,MACP,SACA,SACA,QACA,cACA,MACA,GAAG,kBAC0B;CAC7B,MAAM,CAAC,QAAQ,aAAa,qBAA8B;EACxD,OAAO;EACP,cAAc;EACd,UAAU;EACX,CAAA;CACD,MAAM,YAAY,OAAM;CAExB,MAAM,gBAAgB,UAAyC;AAC7D,YAAU,MAAK;AAEf,MAAI,MAAM,iBAAkB;AAE5B,MAAI,OACF,WAAU,MAAK;MAEf,UAAS,MAAK;AAGhB,aAAW,aAAa,CAAC,SAAQ;;CAGnC,MAAM,CAAC,UAAU,sBAAsB;CACvC,MAAM,WAAW,uBAAuB;CACxC,MAAM,iBAAiB,WAAW;CAClC,MAAM,6BACJ,UAAU,WACN;EACE,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,CAAC,QACF;CACN,MAAM,qBACJ,UAAU,WACN;EACE,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,CAAC,QACF;CACN,MAAM,sBAAsB,UAAU,WAAW,yBAAyB,QAAQ;AAElF,QACE,qBAAC,OAAD;EAEE,WAAW,GAAG,iCAAiC,iBAAiB,GAAG,qGAAqG,SAAS,yBAAyB,uBAAuB,GAAG,qBAAqB,UAAU;YAFrQ,CAKE,oBAAC,YAAD;GACE,GAAI;GACJ,iBAAe;GACf,iBAAe;GACf,WAAW,GAAG,iBAAiB,UAAU,6EAA6E,gBAAgB;GAEtI,YACE,qBAAC,QAAD;IAAM,WAAW,GAAG,oDAAoD,8BAA8B,MAAM;cAA5G,CACE,oBAAC,QAAD;KACE,eAAa;KACb,WAAW,GAAG,8IAA8I,SAAS,sDAAsD,+BAA+B;KAC1P,mBAAgB;eAEhB,oBAAC,UAAD;MACE,eAAY;MACZ,WAAU;MACV,MAAM;MACP;KACG,GAEN,oBAAC,QAAD;KACE,eAAa,CAAC;KACd,WAAW,GAAG,8IAA8I,SAAS,iCAAiC,oDAAoD;KAC1P,mBAAgB;eAEhB,oBAAC,oBAAD;MACE,eAAY;MACZ,WAAU;MACV,MAAM;MACP;KACG,EACF;;GAER,OAAO,SAAS,aAAa;GAC7B,SAAS;GACF;GACD;GACP,GAED,oBAAC,OAAD;GACE,eAAa,CAAC;GACd,WAAW,GACT,sFACA,oBAAoB,OACpB,iIACA,SAAS,yDAAyD,0DAClE,iBAAiB,GAAG,iCAAiC,qBAAqB,mBAAmB,GAAG,GAAG,yCAAyC,4BAA4B,mBAAmB,CAC5L;GAED,IAAI;aAEJ,oBAAC,QAAD;IAAM,WAAW,GAAG,uCAAuC,qBAAqB,OAAO,iBAAiB;cAAG;IAAc;GACtH,EACF;;;AAIT,mBAAmB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.d.ts","names":[],"sources":["../src/components/Checkbox/Checkbox.tsx"],"mappings":";;;;;;;UAMiB,aAAA,SAAsB,IAAA,CAAK,wBAAA,QAAgC,YAAA;EAC1E,kBAAA;EACA,YAAA;EACA,OAAA;EACA,QAAA;EACA,YAAA,GAAe,kBAAA;EACf,EAAA;EACA,KAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,eAAA,GAAkB,KAAA;EAClB,QAAA;EACA,KAAA,GAAQ,cAAA;EACR,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAIjB,OAAA;EACA,SAAA;EACA,YAAA;EACA,EAAA;EACA,KAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,eAAA;EACA,GAAA;EACA,QAAA;EACA,KAAA;EACA,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN,SAAA;EAAA,GACX;AAAA,GACF,aAAA;EACD,GAAA,GAAM,GAAA,CAAI,YAAA,QAAoB,YAAA;AAAA,IAC/B,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"Checkbox.d.ts","names":[],"sources":["../src/components/Checkbox/Checkbox.tsx"],"mappings":";;;;;;;UAMiB,aAAA,SAAsB,IAAA,CAAK,wBAAA,QAAgC,YAAA;EAC1E,kBAAA;EACA,YAAA;EACA,OAAA;EACA,QAAA;EACA,YAAA,GAAe,kBAAA;EACf,EAAA;EACA,KAAA;EAEA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,eAAA,GAAkB,KAAA;EAClB,QAAA;EACA,KAAA,GAAQ,cAAA;EACR,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAIjB,OAAA;EACA,SAAA;EACA,YAAA;EACA,EAAA;EACA,KAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EACA,eAAA;EACA,GAAA;EACA,QAAA;EACA,KAAA;EACA,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN,SAAA;EAAA,GACX;AAAA,GACF,aAAA;EACD,GAAA,GAAM,GAAA,CAAI,YAAA,QAAoB,YAAA;AAAA,IAC/B,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
package/dist/Checkbox.js CHANGED
@@ -11,7 +11,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
11
11
  //#region src/components/Checkbox/Checkbox.tsx
12
12
  const Checkbox = ({ checked, className, errorMessage, id, label, labelText, messageReserveLines = 1, messageReserveSpace = false, onCheckedChange, ref, required, state = "default", warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, ...props }) => {
13
13
  const inputId = useFormFieldId(id, props.name);
14
- const resolvedLabelText = labelText ?? label;
14
+ const resolvedLabel = label ?? labelText;
15
15
  const errorMessageId = `${inputId}-error`;
16
16
  const warningMessageId = `${inputId}-warning`;
17
17
  return /* @__PURE__ */ jsxs("div", { children: [
@@ -20,18 +20,16 @@ const Checkbox = ({ checked, className, errorMessage, id, label, labelText, mess
20
20
  children: [/* @__PURE__ */ jsx(CheckboxBase, {
21
21
  "aria-describedby": [state === "error" && errorMessage && errorMessageId ? errorMessageId : state === "warning" && warningMessage && warningMessageId ? warningMessageId : void 0, ariaDescribedBy].filter(Boolean).join(" ") || void 0,
22
22
  "aria-invalid": state === "error" ? true : void 0,
23
- "aria-label": ariaLabel ?? (!resolvedLabelText ? "Checkbox" : void 0),
23
+ "aria-label": ariaLabel ?? (!resolvedLabel ? "Checkbox" : void 0),
24
24
  "aria-required": required ?? void 0,
25
25
  checked,
26
- className: cn("checkbox peer size-5 mt-0.5 border-checkbox-border hover:opacity-80 focus-visible:outline-1 focus-visible:outline-checkbox-border--focus", "data-[state=checked]:border-checkbox-border--checked", className),
26
+ className: cn("checkbox peer size-5 mt-0.5 border-checkbox-border hover:opacity-80 focus-visible:outline-1 focus-visible:outline-checkbox-border--focus data-[state=checked]:border-checkbox-border--checked", className),
27
27
  "data-field-state": state,
28
- "data-testid": "spectral-checkbox",
29
28
  id: inputId,
30
29
  onCheckedChange,
31
30
  ref,
32
31
  ...props,
33
32
  children: /* @__PURE__ */ jsx(CheckboxIndicator, {
34
- "data-testid": "spectral-checkbox-indicator",
35
33
  className: cn("checkbox-indicator flex items-center justify-center text-checkbox-indicator--checked"),
36
34
  children: checked === "indeterminate" ? /* @__PURE__ */ jsx(MinusIcon, {
37
35
  className: "checkbox-indeterminate",
@@ -43,11 +41,10 @@ const Checkbox = ({ checked, className, errorMessage, id, label, labelText, mess
43
41
  strokeWidth: 4
44
42
  })
45
43
  })
46
- }), resolvedLabelText && /* @__PURE__ */ jsx("label", {
44
+ }), resolvedLabel && /* @__PURE__ */ jsx("label", {
47
45
  className: "text-md peer-disabled:text-neutral-400 text-text-primary",
48
- "data-testid": "spectral-checkbox-label",
49
46
  htmlFor: inputId,
50
- children: resolvedLabelText
47
+ children: resolvedLabel
51
48
  })]
52
49
  }),
53
50
  /* @__PURE__ */ jsx(ErrorMessage, {
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.js","names":[],"sources":["../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import { CheckmarkIcon, MinusIcon } from '@components/Icons'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentPropsWithoutRef, type ComponentRef, type Ref } from 'react'\nimport { CheckboxBase, CheckboxIndicator } from './CheckboxBase'\n\nexport interface CheckboxProps extends Omit<ComponentPropsWithoutRef<typeof CheckboxBase>, 'onCheckedChange'> {\n 'aria-describedby'?: string\n 'aria-label'?: string\n checked?: boolean | 'indeterminate'\n disabled?: boolean\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string\n label?: string\n labelText?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n onCheckedChange: (value: boolean | 'indeterminate') => void\n required?: boolean\n state?: FormFieldState\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport const Checkbox = ({\n checked,\n className,\n errorMessage,\n id,\n label,\n labelText,\n messageReserveLines = 1,\n messageReserveSpace = false,\n onCheckedChange,\n ref,\n required,\n state = 'default',\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n ...props\n}: CheckboxProps & {\n ref?: Ref<ComponentRef<typeof CheckboxBase>>\n}) => {\n const inputId = useFormFieldId(id, props.name)\n const resolvedLabelText = labelText ?? label\n const errorMessageId = `${inputId}-error`\n const warningMessageId = `${inputId}-warning`\n const messageId = state === 'error' && errorMessage && errorMessageId ? errorMessageId : state === 'warning' && warningMessage && warningMessageId ? warningMessageId : undefined\n\n return (\n <div>\n <div className='gap-2 flex items-start shrink-0'>\n <CheckboxBase\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (!resolvedLabelText ? 'Checkbox' : undefined)}\n aria-required={required ?? undefined}\n checked={checked}\n className={cn(\n 'checkbox peer size-5 mt-0.5 border-checkbox-border hover:opacity-80 focus-visible:outline-1 focus-visible:outline-checkbox-border--focus',\n 'data-[state=checked]:border-checkbox-border--checked',\n className,\n )}\n data-field-state={state}\n data-testid='spectral-checkbox'\n id={inputId}\n onCheckedChange={onCheckedChange}\n ref={ref}\n {...props}\n >\n <CheckboxIndicator data-testid='spectral-checkbox-indicator' className={cn('checkbox-indicator flex items-center justify-center text-checkbox-indicator--checked')}>\n {checked === 'indeterminate' ? <MinusIcon className='checkbox-indeterminate' size={16} strokeWidth={4} /> : <CheckmarkIcon className='checkbox-check' size={16} strokeWidth={4} />}\n </CheckboxIndicator>\n </CheckboxBase>\n {resolvedLabelText && (\n <label className='text-md peer-disabled:text-neutral-400 text-text-primary' data-testid='spectral-checkbox-label' htmlFor={inputId}>\n {resolvedLabelText}\n </label>\n )}\n </div>\n <ErrorMessage\n dataTestId='spectral-checkbox-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-checkbox-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nCheckbox.displayName = 'Checkbox'\n"],"mappings":";;;;;;;;;;;AAyBA,MAAa,YAAY,EACvB,SACA,WACA,cACA,IACA,OACA,WACA,sBAAsB,GACtB,sBAAsB,OACtB,iBACA,KACA,UACA,QAAQ,WACR,gBACA,oBAAoB,iBACpB,cAAc,WACd,GAAG,YAGC;CACJ,MAAM,UAAU,eAAe,IAAI,MAAM,KAAK;CAC9C,MAAM,oBAAoB,aAAa;CACvC,MAAM,iBAAiB,GAAG,QAAQ;CAClC,MAAM,mBAAmB,GAAG,QAAQ;AAGpC,QACE,qBAAC,OAAD;EACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,cAAD;IACE,oBAAkB,CANR,UAAU,WAAW,gBAAgB,iBAAiB,iBAAiB,UAAU,aAAa,kBAAkB,mBAAmB,mBAAmB,QAMlI,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;IAC5E,gBAAc,UAAU,UAAU,OAAO;IACzC,cAAY,cAAc,CAAC,oBAAoB,aAAa;IAC5D,iBAAe,YAAY;IAClB;IACT,WAAW,GACT,4IACA,wDACA,UACD;IACD,oBAAkB;IAClB,eAAY;IACZ,IAAI;IACa;IACZ;IACL,GAAI;cAEJ,oBAAC,mBAAD;KAAmB,eAAY;KAA8B,WAAW,GAAG,uFAAuF;eAC/J,YAAY,kBAAkB,oBAAC,WAAD;MAAW,WAAU;MAAyB,MAAM;MAAI,aAAa;MAAK,IAAG,oBAAC,eAAD;MAAe,WAAU;MAAiB,MAAM;MAAI,aAAa;MAAK;KAChK;IACP,GACd,qBACC,oBAAC,SAAD;IAAO,WAAU;IAA2D,eAAY;IAA0B,SAAS;cACxH;IACK,EAEN;;EACN,oBAAC,cAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,UAAU,eAAe;GACvB;GACrB,qBAAqB,uBAAuB,UAAU;GACtD;EACF,oBAAC,gBAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,YAAY,iBAAiB;GAC3B;GACrB,qBAAqB,uBAAuB,UAAU;GACtD;EACE;;AAGV,SAAS,cAAc"}
1
+ {"version":3,"file":"Checkbox.js","names":[],"sources":["../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import { CheckmarkIcon, MinusIcon } from '@components/Icons'\nimport { ErrorMessage, WarningMessage, useFormFieldId, type BaseFormFieldProps, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentPropsWithoutRef, type ComponentRef, type Ref } from 'react'\nimport { CheckboxBase, CheckboxIndicator } from './CheckboxBase'\n\nexport interface CheckboxProps extends Omit<ComponentPropsWithoutRef<typeof CheckboxBase>, 'onCheckedChange'> {\n 'aria-describedby'?: string\n 'aria-label'?: string\n checked?: boolean | 'indeterminate'\n disabled?: boolean\n errorMessage?: BaseFormFieldProps['errorMessage']\n id?: string\n label?: string\n /* Deprecated - use label instead */\n labelText?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n onCheckedChange: (value: boolean | 'indeterminate') => void\n required?: boolean\n state?: FormFieldState\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport const Checkbox = ({\n checked,\n className,\n errorMessage,\n id,\n label,\n labelText,\n messageReserveLines = 1,\n messageReserveSpace = false,\n onCheckedChange,\n ref,\n required,\n state = 'default',\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n ...props\n}: CheckboxProps & {\n ref?: Ref<ComponentRef<typeof CheckboxBase>>\n}) => {\n const inputId = useFormFieldId(id, props.name)\n const resolvedLabel = label ?? labelText\n const errorMessageId = `${inputId}-error`\n const warningMessageId = `${inputId}-warning`\n const messageId = state === 'error' && errorMessage && errorMessageId ? errorMessageId : state === 'warning' && warningMessage && warningMessageId ? warningMessageId : undefined\n\n return (\n <div>\n <div className='gap-2 flex items-start shrink-0'>\n <CheckboxBase\n aria-describedby={[messageId, ariaDescribedBy].filter(Boolean).join(' ') || undefined}\n aria-invalid={state === 'error' ? true : undefined}\n aria-label={ariaLabel ?? (!resolvedLabel ? 'Checkbox' : undefined)}\n aria-required={required ?? undefined}\n checked={checked}\n className={cn(\n 'checkbox peer size-5 mt-0.5 border-checkbox-border hover:opacity-80 focus-visible:outline-1 focus-visible:outline-checkbox-border--focus data-[state=checked]:border-checkbox-border--checked',\n className,\n )}\n data-field-state={state}\n data-testid='spectral-checkbox'\n id={inputId}\n onCheckedChange={onCheckedChange}\n ref={ref}\n {...props}\n >\n <CheckboxIndicator data-testid='spectral-checkbox-indicator' className={cn('checkbox-indicator flex items-center justify-center text-checkbox-indicator--checked')}>\n {checked === 'indeterminate' ? <MinusIcon className='checkbox-indeterminate' size={16} strokeWidth={4} /> : <CheckmarkIcon className='checkbox-check' size={16} strokeWidth={4} />}\n </CheckboxIndicator>\n </CheckboxBase>\n {resolvedLabel && (\n <label className='text-md peer-disabled:text-neutral-400 text-text-primary' data-testid='spectral-checkbox-label' htmlFor={inputId}>\n {resolvedLabel}\n </label>\n )}\n </div>\n <ErrorMessage\n dataTestId='spectral-checkbox-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-checkbox-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\n\nCheckbox.displayName = 'Checkbox'\n"],"mappings":";;;;;;;;;;;AA0BA,MAAa,YAAY,EACvB,SACA,WACA,cACA,IACA,OACA,WACA,sBAAsB,GACtB,sBAAsB,OACtB,iBACA,KACA,UACA,QAAQ,WACR,gBACA,oBAAoB,iBACpB,cAAc,WACd,GAAG,YAGC;CACJ,MAAM,UAAU,eAAe,IAAI,MAAM,KAAI;CAC7C,MAAM,gBAAgB,SAAS;CAC/B,MAAM,iBAAiB,GAAG,QAAQ;CAClC,MAAM,mBAAmB,GAAG,QAAQ;AAGpC,QACE,qBAAC,OAAD;EACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,cAAD;IACE,oBAAkB,CANR,UAAU,WAAW,gBAAgB,iBAAiB,iBAAiB,UAAU,aAAa,kBAAkB,mBAAmB,mBAAmB,QAMlI,gBAAgB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;IAC5E,gBAAc,UAAU,UAAU,OAAO;IACzC,cAAY,cAAc,CAAC,gBAAgB,aAAa;IACxD,iBAAe,YAAY;IAClB;IACT,WAAW,GACT,iMACA,UACD;IACD,oBAAkB;IAElB,IAAI;IACa;IACZ;IACL,GAAI;cAEJ,oBAAC,mBAAD;KAA6D,WAAW,GAAG,uFAAuF;eAC/J,YAAY,kBAAkB,oBAAC,WAAD;MAAW,WAAU;MAAyB,MAAM;MAAI,aAAa;MAAK,IAAG,oBAAC,eAAD;MAAe,WAAU;MAAiB,MAAM;MAAI,aAAa;MAAK;KACjK;IACP,GACb,iBACC,oBAAC,SAAD;IAAO,WAAU;IAAiG,SAAS;cACxH;IACI,EAEN;;EACL,oBAAC,cAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,UAAU,eAAe;GACvB;GACrB,qBAAqB,uBAAuB,UAAU;GACvD;EACD,oBAAC,gBAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,YAAY,iBAAiB;GAC3B;GACrB,qBAAqB,uBAAuB,UAAU;GACvD;EACE;;AAIT,SAAS,cAAc"}
@@ -13,6 +13,7 @@ interface ComboboxProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'> {
13
13
  labelClassName?: string;
14
14
  loadingMessage?: string;
15
15
  onChange?: (value: string) => void;
16
+ /** @deprecated Use `onChange` instead. `onValueChange` will be removed in a future release. */
16
17
  onValueChange?: (value: string) => void;
17
18
  options: ComboboxOption[];
18
19
  placeholder?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.d.ts","names":[],"sources":["../src/components/Combobox/Combobox.tsx"],"mappings":";;;;;;KA0BY,cAAA,GAAiB,UAAA;AAAA,UAEZ,aAAA,SAAsB,IAAA,CAAK,kBAAA;EAC1C,SAAA;EACA,YAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,cAAA;EACA,cAAA;EACA,QAAA,IAAY,KAAA;EACZ,aAAA,IAAiB,KAAA;EACjB,OAAA,EAAS,cAAA;EACT,WAAA;EACA,KAAA,GAAQ,OAAA,CAAQ,cAAA;EAChB,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAIjB,SAAA;EACA,QAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,EAAA;EACA,KAAA;EACA,cAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,QAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN;AAAA,GACb,aAAA;EAAkB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"Combobox.d.ts","names":[],"sources":["../src/components/Combobox/Combobox.tsx"],"mappings":";;;;;;KA0BY,cAAA,GAAiB,UAAA;AAAA,UAEZ,aAAA,SAAsB,IAAA,CAAK,kBAAA;EAC1C,SAAA;EACA,YAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,cAAA;EACA,cAAA;EACA,QAAA,IAAY,KAAA;EAPiB;EAS7B,aAAA,IAAiB,KAAA;EACjB,OAAA,EAAS,cAAA;EACT,WAAA;EACA,KAAA,GAAQ,OAAA,CAAQ,cAAA;EAChB,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAIjB,SAAA;EACA,QAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,EAAA;EACA,KAAA;EACA,cAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,aAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,QAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN;AAAA,GACb,aAAA;EAAkB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
package/dist/Combobox.js CHANGED
@@ -74,7 +74,6 @@ const Combobox = ({ className, disabled, defaultValue = "", dropdownWidth = "tri
74
74
  children: [
75
75
  label && /* @__PURE__ */ jsx(Label, {
76
76
  className: cn("mb-2 block text-text-primary", labelClassName, isDisabled && "text-text-secondary"),
77
- "data-testid": "spectral-combobox-label",
78
77
  htmlFor: comboboxId,
79
78
  children: label
80
79
  }),
@@ -100,7 +99,6 @@ const Combobox = ({ className, disabled, defaultValue = "", dropdownWidth = "tri
100
99
  render: /* @__PURE__ */ jsx(InputGroup, {
101
100
  "data-slot": "combobox-content",
102
101
  "data-state": state,
103
- "data-testid": "spectral-combobox-trigger",
104
102
  className: cn(getTriggerClasses(open, state), "ring-0! outline-none focus-within:outline-none has-[[data-slot=input-group-control]:focus-visible]:outline-0", isDisabled && "pointer-events-none cursor-not-allowed", className),
105
103
  onClick: handleTriggerContainerClick,
106
104
  style: getFormFieldCSSProperties()
@@ -134,14 +132,12 @@ const Combobox = ({ className, disabled, defaultValue = "", dropdownWidth = "tri
134
132
  className: cn("p-1 z-50 motion-safe:data-closed:animate-out motion-safe:data-open:animate-in", getDropdownSurfaceClasses(), "motion-safe:data-closed:fade-out-0 motion-safe:data-closed:zoom-out-95 motion-safe:data-open:fade-in-0 motion-safe:data-open:zoom-in-95", "max-h-[min(var(--available-height),18rem)] motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2", "min-w-32 origin-(--transform-origin) overflow-hidden"),
135
133
  "data-dropdown-width-mode": dropdownWidthMode,
136
134
  "data-dropdown-width-value": dropdownWidthMode === "custom" ? dropdownWidth : void 0,
137
- "data-testid": "spectral-combobox-content",
138
135
  style: dropdownWidthStyle,
139
136
  children: isLoading ? /* @__PURE__ */ jsx(LoadingState, { message: loadingMessage }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { message: emptyMessage }) : /* @__PURE__ */ jsx(Combobox$1.List, {
140
137
  className: "max-h-[min(var(--available-height),18rem)] overflow-y-auto",
141
138
  id: listboxId,
142
139
  children: filteredOptions.map((option) => /* @__PURE__ */ jsxs(Combobox$1.Item, {
143
140
  className: cn(getOptionClasses(!!option.disabled, false, value === option.value), "group/command-item relative flex w-full items-center data-highlighted:bg-input-bg--hover"),
144
- "data-testid": "spectral-combobox-item",
145
141
  disabled: option.disabled,
146
142
  value: option,
147
143
  children: [/* @__PURE__ */ jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.js","names":["ComboboxPrimitive"],"sources":["../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import { Combobox as ComboboxPrimitive } from '@base-ui/react'\nimport { CheckmarkIcon, ChevronDownIcon, LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { InputGroup, InputGroupAddon } from '@primitives/input-group'\nimport {\n EmptyState,\n ErrorMessage,\n getAriaProps,\n getDropdownWidthStyles,\n getDropdownSurfaceClasses,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getOptionClasses,\n getTriggerClasses,\n LoadingState,\n WarningMessage,\n useFormFieldId,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useMemo, useRef, useState, type CSSProperties, type MouseEvent, type Ref } from 'react'\n\nexport type ComboboxOption = BaseOption\n\nexport interface ComboboxProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'> {\n className?: string\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n labelClassName?: string\n loadingMessage?: string\n onChange?: (value: string) => void\n onValueChange?: (value: string) => void\n options: ComboboxOption[]\n placeholder?: string\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport const Combobox = ({\n className,\n disabled,\n defaultValue = '',\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found.',\n errorMessage,\n id,\n label,\n labelClassName,\n loadingMessage = 'Loading…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n options,\n placeholder = 'Search…',\n ref,\n required,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n}: ComboboxProps & { ref?: Ref<HTMLDivElement> }) => {\n if (process.env.NODE_ENV !== 'production' && !label && !ariaLabel) {\n console.warn('Combobox: provide either `label` or `aria-label` for an accessible name.')\n }\n\n const comboboxId = useFormFieldId(id, name)\n const listboxId = `${comboboxId}-listbox`\n const errorMessageId = getErrorMessageId(comboboxId)\n const warningMessageId = `${comboboxId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const isInvalid = state === 'error'\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n\n const [open, setOpen] = useState(false)\n const [inputValue, setInputValue] = useState('')\n const inputRef = useRef<HTMLInputElement>(null)\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue,\n onChange: (nextValue) => {\n if (onChange) {\n onChange(nextValue)\n } else {\n onValueChange?.(nextValue)\n }\n },\n })\n\n const selectedOption = useMemo(() => options.find((o) => o.value === value) ?? null, [options, value])\n const filteredOptions = useMemo(() => {\n const query = inputValue.trim().toLowerCase()\n if (!query) return options\n return options.filter((option) => option.label.toLowerCase().includes(query))\n }, [inputValue, options])\n const showsSelectedValueAsPlaceholder = Boolean(selectedOption && inputValue.length === 0)\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--anchor-width)',\n })\n\n const handleValueChange = (nextOption: ComboboxOption | null, eventDetails: { reason?: string }) => {\n const nextValue = nextOption?.value ?? ''\n const shouldClearSelection = eventDetails.reason === 'item-press' && nextValue === value\n setValue(shouldClearSelection ? '' : nextValue)\n setInputValue('')\n setOpen(false)\n }\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (isDisabled || isLoading) {\n setOpen(false)\n return\n }\n\n if (!nextOpen) {\n setInputValue('')\n }\n\n setOpen(nextOpen)\n }\n\n const handleTriggerContainerClick = (event: MouseEvent<HTMLDivElement>) => {\n if (isDisabled || isLoading) return\n\n const target = event.target as HTMLElement\n if (target === inputRef.current) return\n if (target.closest('[data-slot=combobox-trigger-button]')) return\n inputRef.current?.focus()\n setOpen(true)\n }\n\n return (\n <div className='w-full' ref={ref}>\n {label && (\n <Label className={cn('mb-2 block text-text-primary', labelClassName, isDisabled && 'text-text-secondary')} data-testid='spectral-combobox-label' htmlFor={comboboxId}>\n {label}\n </Label>\n )}\n\n <ComboboxPrimitive.Root\n autoHighlight\n disabled={isDisabled || isLoading}\n filter={null}\n inputValue={inputValue}\n itemToStringLabel={(option: ComboboxOption) => option.label}\n itemToStringValue={(option: ComboboxOption) => option.value}\n openOnInputClick\n onInputValueChange={(nextInputValue, eventDetails) => {\n if (eventDetails.reason !== 'input-change' && eventDetails.reason !== 'input-clear') return\n setInputValue(nextInputValue)\n }}\n name={name}\n onOpenChange={handleOpenChange}\n onValueChange={handleValueChange}\n open={open}\n required={required}\n value={selectedOption}\n >\n <ComboboxPrimitive.InputGroup\n render={\n <InputGroup\n data-slot='combobox-content'\n data-state={state}\n data-testid='spectral-combobox-trigger'\n className={cn(getTriggerClasses(open, state), 'ring-0! outline-none focus-within:outline-none has-[[data-slot=input-group-control]:focus-visible]:outline-0', isDisabled && 'pointer-events-none cursor-not-allowed', className)}\n onClick={handleTriggerContainerClick}\n style={getFormFieldCSSProperties() as CSSProperties}\n />\n }\n >\n <ComboboxPrimitive.Input\n aria-controls={listboxId}\n aria-expanded={open}\n aria-label={ariaLabel ?? label}\n autoComplete='off'\n className={cn(\n 'min-w-0 text-base flex-1 truncate overflow-hidden border-0 bg-transparent whitespace-nowrap text-input-text outline-hidden outline-0 placeholder:opacity-100 focus-visible:ring-0 focus-visible:outline-none',\n showsSelectedValueAsPlaceholder ? 'placeholder:text-input-text!' : 'placeholder:text-input-text-placeholder!',\n )}\n data-slot='input-group-control'\n id={comboboxId}\n ref={inputRef}\n placeholder={selectedOption?.label ?? placeholder}\n {...ariaProps}\n />\n <InputGroupAddon align='inline-end' className='cursor-pointer'>\n <ComboboxPrimitive.Trigger\n aria-label='Toggle options'\n className='cursor-pointer'\n data-slot='combobox-trigger-button'\n >\n {isLoading ? <LoaderIcon className='size-5 motion-safe:animate-spin' /> : <ChevronDownIcon className={cn('size-5 shrink-0 transition-transform duration-200', open && 'rotate-180')} />}\n </ComboboxPrimitive.Trigger>\n </InputGroupAddon>\n </ComboboxPrimitive.InputGroup>\n\n <ComboboxPrimitive.Portal>\n <ComboboxPrimitive.Positioner align='start' className='isolate z-50' sideOffset={4}>\n <ComboboxPrimitive.Popup\n className={cn(\n 'p-1 z-50 motion-safe:data-closed:animate-out motion-safe:data-open:animate-in',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-closed:fade-out-0 motion-safe:data-closed:zoom-out-95 motion-safe:data-open:fade-in-0 motion-safe:data-open:zoom-in-95',\n 'max-h-[min(var(--available-height),18rem)] motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2',\n // Keep a single scroll container (the list) to avoid dual scrollbar styles.\n 'min-w-32 origin-(--transform-origin) overflow-hidden',\n )}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-combobox-content'\n style={dropdownWidthStyle}\n >\n {isLoading ? (\n <LoadingState message={loadingMessage} />\n ) : filteredOptions.length === 0 ? (\n <EmptyState message={emptyMessage} />\n ) : (\n <ComboboxPrimitive.List className='max-h-[min(var(--available-height),18rem)] overflow-y-auto' id={listboxId}>\n {filteredOptions.map((option) => (\n <ComboboxPrimitive.Item\n className={cn(getOptionClasses(!!option.disabled, false, value === option.value), 'group/command-item relative flex w-full items-center data-highlighted:bg-input-bg--hover')}\n data-testid='spectral-combobox-item'\n disabled={option.disabled}\n key={option.value}\n value={option}\n >\n <span className='min-w-0 flex-1 truncate whitespace-nowrap'>{option.label}</span>\n <ComboboxPrimitive.ItemIndicator\n render={\n <span className='right-2 h-4 w-4 absolute flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n }\n />\n </ComboboxPrimitive.Item>\n ))}\n </ComboboxPrimitive.List>\n )}\n </ComboboxPrimitive.Popup>\n </ComboboxPrimitive.Positioner>\n </ComboboxPrimitive.Portal>\n </ComboboxPrimitive.Root>\n\n <ErrorMessage\n dataTestId='spectral-combobox-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-combobox-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nCombobox.displayName = 'Combobox'\n"],"mappings":"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"}
1
+ {"version":3,"file":"Combobox.js","names":[],"sources":["../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import { Combobox as ComboboxPrimitive } from '@base-ui/react'\nimport { CheckmarkIcon, ChevronDownIcon, LoaderIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { InputGroup, InputGroupAddon } from '@primitives/input-group'\nimport {\n EmptyState,\n ErrorMessage,\n getAriaProps,\n getDropdownWidthStyles,\n getDropdownSurfaceClasses,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getOptionClasses,\n getTriggerClasses,\n LoadingState,\n WarningMessage,\n useFormFieldId,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useMemo, useRef, useState, type CSSProperties, type MouseEvent, type Ref } from 'react'\n\nexport type ComboboxOption = BaseOption\n\nexport interface ComboboxProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'> {\n className?: string\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n labelClassName?: string\n loadingMessage?: string\n onChange?: (value: string) => void\n /** @deprecated Use `onChange` instead. `onValueChange` will be removed in a future release. */\n onValueChange?: (value: string) => void\n options: ComboboxOption[]\n placeholder?: string\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nexport const Combobox = ({\n className,\n disabled,\n defaultValue = '',\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found.',\n errorMessage,\n id,\n label,\n labelClassName,\n loadingMessage = 'Loading…',\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onValueChange,\n options,\n placeholder = 'Search…',\n ref,\n required,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n}: ComboboxProps & { ref?: Ref<HTMLDivElement> }) => {\n if (process.env.NODE_ENV !== 'production' && !label && !ariaLabel) {\n console.warn('Combobox: provide either `label` or `aria-label` for an accessible name.')\n }\n\n const comboboxId = useFormFieldId(id, name)\n const listboxId = `${comboboxId}-listbox`\n const errorMessageId = getErrorMessageId(comboboxId)\n const warningMessageId = `${comboboxId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const isDisabled = Boolean(disabled)\n const isLoading = state === 'loading'\n const isInvalid = state === 'error'\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n\n const [open, setOpen] = useState(false)\n const [inputValue, setInputValue] = useState('')\n const inputRef = useRef<HTMLInputElement>(null)\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue,\n onChange: (nextValue) => {\n if (onChange) {\n onChange(nextValue)\n } else {\n onValueChange?.(nextValue)\n }\n },\n })\n\n const selectedOption = useMemo(() => options.find((o) => o.value === value) ?? null, [options, value])\n const filteredOptions = useMemo(() => {\n const query = inputValue.trim().toLowerCase()\n if (!query) return options\n return options.filter((option) => option.label.toLowerCase().includes(query))\n }, [inputValue, options])\n const showsSelectedValueAsPlaceholder = Boolean(selectedOption && inputValue.length === 0)\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: 'var(--anchor-width)',\n })\n\n const handleValueChange = (nextOption: ComboboxOption | null, eventDetails: { reason?: string }) => {\n const nextValue = nextOption?.value ?? ''\n const shouldClearSelection = eventDetails.reason === 'item-press' && nextValue === value\n setValue(shouldClearSelection ? '' : nextValue)\n setInputValue('')\n setOpen(false)\n }\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (isDisabled || isLoading) {\n setOpen(false)\n return\n }\n\n if (!nextOpen) {\n setInputValue('')\n }\n\n setOpen(nextOpen)\n }\n\n const handleTriggerContainerClick = (event: MouseEvent<HTMLDivElement>) => {\n if (isDisabled || isLoading) return\n\n const target = event.target as HTMLElement\n if (target === inputRef.current) return\n if (target.closest('[data-slot=combobox-trigger-button]')) return\n inputRef.current?.focus()\n setOpen(true)\n }\n\n return (\n <div className='w-full' ref={ref}>\n {label && (\n <Label className={cn('mb-2 block text-text-primary', labelClassName, isDisabled && 'text-text-secondary')} data-testid='spectral-combobox-label' htmlFor={comboboxId}>\n {label}\n </Label>\n )}\n\n <ComboboxPrimitive.Root\n autoHighlight\n disabled={isDisabled || isLoading}\n filter={null}\n inputValue={inputValue}\n itemToStringLabel={(option: ComboboxOption) => option.label}\n itemToStringValue={(option: ComboboxOption) => option.value}\n openOnInputClick\n onInputValueChange={(nextInputValue, eventDetails) => {\n if (eventDetails.reason !== 'input-change' && eventDetails.reason !== 'input-clear') return\n setInputValue(nextInputValue)\n }}\n name={name}\n onOpenChange={handleOpenChange}\n onValueChange={handleValueChange}\n open={open}\n required={required}\n value={selectedOption}\n >\n <ComboboxPrimitive.InputGroup\n render={\n <InputGroup\n data-slot='combobox-content'\n data-state={state}\n data-testid='spectral-combobox-trigger'\n className={cn(getTriggerClasses(open, state), 'ring-0! outline-none focus-within:outline-none has-[[data-slot=input-group-control]:focus-visible]:outline-0', isDisabled && 'pointer-events-none cursor-not-allowed', className)}\n onClick={handleTriggerContainerClick}\n style={getFormFieldCSSProperties() as CSSProperties}\n />\n }\n >\n <ComboboxPrimitive.Input\n aria-controls={listboxId}\n aria-expanded={open}\n aria-label={ariaLabel ?? label}\n autoComplete='off'\n className={cn(\n 'min-w-0 text-base flex-1 truncate overflow-hidden border-0 bg-transparent whitespace-nowrap text-input-text outline-hidden outline-0 placeholder:opacity-100 focus-visible:ring-0 focus-visible:outline-none',\n showsSelectedValueAsPlaceholder ? 'placeholder:text-input-text!' : 'placeholder:text-input-text-placeholder!',\n )}\n data-slot='input-group-control'\n id={comboboxId}\n ref={inputRef}\n placeholder={selectedOption?.label ?? placeholder}\n {...ariaProps}\n />\n <InputGroupAddon align='inline-end' className='cursor-pointer'>\n <ComboboxPrimitive.Trigger\n aria-label='Toggle options'\n className='cursor-pointer'\n data-slot='combobox-trigger-button'\n >\n {isLoading ? <LoaderIcon className='size-5 motion-safe:animate-spin' /> : <ChevronDownIcon className={cn('size-5 shrink-0 transition-transform duration-200', open && 'rotate-180')} />}\n </ComboboxPrimitive.Trigger>\n </InputGroupAddon>\n </ComboboxPrimitive.InputGroup>\n\n <ComboboxPrimitive.Portal>\n <ComboboxPrimitive.Positioner align='start' className='isolate z-50' sideOffset={4}>\n <ComboboxPrimitive.Popup\n className={cn(\n 'p-1 z-50 motion-safe:data-closed:animate-out motion-safe:data-open:animate-in',\n getDropdownSurfaceClasses(),\n 'motion-safe:data-closed:fade-out-0 motion-safe:data-closed:zoom-out-95 motion-safe:data-open:fade-in-0 motion-safe:data-open:zoom-in-95',\n 'max-h-[min(var(--available-height),18rem)] motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2',\n // Keep a single scroll container (the list) to avoid dual scrollbar styles.\n 'min-w-32 origin-(--transform-origin) overflow-hidden',\n )}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-combobox-content'\n style={dropdownWidthStyle}\n >\n {isLoading ? (\n <LoadingState message={loadingMessage} />\n ) : filteredOptions.length === 0 ? (\n <EmptyState message={emptyMessage} />\n ) : (\n <ComboboxPrimitive.List className='max-h-[min(var(--available-height),18rem)] overflow-y-auto' id={listboxId}>\n {filteredOptions.map((option) => (\n <ComboboxPrimitive.Item\n className={cn(getOptionClasses(!!option.disabled, false, value === option.value), 'group/command-item relative flex w-full items-center data-highlighted:bg-input-bg--hover')}\n data-testid='spectral-combobox-item'\n disabled={option.disabled}\n key={option.value}\n value={option}\n >\n <span className='min-w-0 flex-1 truncate whitespace-nowrap'>{option.label}</span>\n <ComboboxPrimitive.ItemIndicator\n render={\n <span className='right-2 h-4 w-4 absolute flex items-center justify-center'>\n <CheckmarkIcon size={16} />\n </span>\n }\n />\n </ComboboxPrimitive.Item>\n ))}\n </ComboboxPrimitive.List>\n )}\n </ComboboxPrimitive.Popup>\n </ComboboxPrimitive.Positioner>\n </ComboboxPrimitive.Portal>\n </ComboboxPrimitive.Root>\n\n <ErrorMessage\n dataTestId='spectral-combobox-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-combobox-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nCombobox.displayName = 'Combobox'\n"],"mappings":"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"}
@@ -45,7 +45,6 @@ const ControlGroupSelect = ({ amountStep, ariaLabel, captionLayout = "inline", c
45
45
  return /* @__PURE__ */ jsx(ControlGroup, {
46
46
  "aria-label": groupAriaLabel,
47
47
  className,
48
- "data-testid": dataTestId,
49
48
  disabled,
50
49
  errorMessage,
51
50
  id: idPrefix,
@@ -99,7 +98,6 @@ const ControlGroupSelectInner = ({ amountStep, dataTestId, dropdownWidth, inputA
99
98
  "aria-label": inputAccessibleName,
100
99
  "aria-labelledby": useAboveLabels ? inputLabelId : void 0,
101
100
  className: cn(groupedFieldBaseClasses, inputRadiusClasses, getStateClasses(state), type === "number" && numberInputNoSpinner, type === "number" && "tabular-nums"),
102
- "data-testid": `${dataTestId}-input`,
103
101
  disabled: isDisabled,
104
102
  id: useAboveLabels ? inputId : void 0,
105
103
  type: type === "number" ? "number" : "text",
@@ -118,7 +116,6 @@ const ControlGroupSelectInner = ({ amountStep, dataTestId, dropdownWidth, inputA
118
116
  "aria-label": selectTriggerAriaLabel,
119
117
  "aria-labelledby": useAboveLabels ? selectLabelId : void 0,
120
118
  className: cn("text-input-text data-placeholder:text-input-text-placeholder!", selectRadiusClasses, "px-4 w-full justify-between focus-visible:border-input-border--focus focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus", getStateClasses(state)),
121
- "data-testid": `${dataTestId}-select-trigger`,
122
119
  disabled: isDisabled,
123
120
  id: useAboveLabels ? selectTriggerId : void 0,
124
121
  style: selectTriggerMinWidth ? { minWidth: selectTriggerMinWidth } : void 0,
@@ -140,7 +137,6 @@ const ControlGroupSelectInner = ({ amountStep, dataTestId, dropdownWidth, inputA
140
137
  }) : inputElement
141
138
  }), /* @__PURE__ */ jsxs(Select, {
142
139
  ...selectProps,
143
- "data-testid": `${dataTestId}-select-root`,
144
140
  disabled: isDisabled,
145
141
  ...isSelectOpenControlled ? { open: selectProps.open } : {},
146
142
  onOpenChange: handleSelectOpenChange,
@@ -156,7 +152,6 @@ const ControlGroupSelectInner = ({ amountStep, dataTestId, dropdownWidth, inputA
156
152
  }), selectTriggerElement]
157
153
  }) : selectTriggerElement
158
154
  }), /* @__PURE__ */ jsx(SelectContent, {
159
- "data-testid": `${dataTestId}-select-content`,
160
155
  dropdownWidth,
161
156
  children: selectOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, {
162
157
  disabled: option.disabled,
@@ -1 +1 @@
1
- {"version":3,"file":"ControlGroupSelect.js","names":[],"sources":["../../src/components/ControlGroup/ControlGroupSelect.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { Input } from '@primitives/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { getStateClasses, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useId, type ComponentProps } from 'react'\nimport { ControlGroup, ControlGroupItem, useControlGroup, type ControlGroupProps } from './ControlGroup'\n\nconst numberInputNoSpinner = '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\nconst defaultInputLabel = 'Amount'\nconst defaultSelectLabel = 'Select an option'\n\nexport interface SelectOptionType {\n disabled?: boolean\n label: string\n value: string\n}\n\n/** `inline`: `inputPlaceholder` / `selectPlaceholder` show inside the fields. `above`: same strings render as labels above each control (no inner placeholders). */\nexport type ControlGroupSelectCaptionLayout = 'above' | 'inline'\n\ntype ControlGroupSelectInputControlProps =\n | {\n inputValue: ComponentProps<typeof Input>['value']\n onInputChange: ComponentProps<typeof Input>['onChange']\n }\n | {\n inputValue?: undefined\n onInputChange?: undefined\n }\n\ntype ControlGroupSelectBaseProps = ComponentProps<typeof Select> &\n Pick<ControlGroupProps, 'orientation'> & {\n amountStep?: number\n /** Accessible name for the group wrapper (use when there is no visible group heading). */\n ariaLabel?: string\n captionLayout?: ControlGroupSelectCaptionLayout\n className?: string\n dataTestId?: string\n disabled?: boolean\n dropdownWidth?: DropdownWidth\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n /** Class applied to the input `ControlGroupItem` segment for width/split composition. */\n inputItemClassName?: string\n /** When `captionLayout` is `inline`, overrides the input's accessible name (defaults to `inputPlaceholder` when set). */\n inputAriaLabel?: string\n inputPlaceholder?: string\n maxAmount?: number\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: false). */\n messageReserveSpace?: boolean\n minAmount?: number\n selectPlaceholder?: string\n /** When `captionLayout` is `inline` and `selectPlaceholder` is empty, sets the select trigger's accessible name. */\n selectAriaLabel?: string\n /** Class applied to the select `ControlGroupItem` segment for width/split composition. */\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n state?: Exclude<FormFieldState, 'disabled'>\n type?: 'number' | 'text'\n warningMessage?: string | string[] | Record<string, unknown> | null\n }\n\nexport type ControlGroupSelectProps = ControlGroupSelectBaseProps & ControlGroupSelectInputControlProps\n\nconst fieldStackClass = 'flex w-full min-w-0 flex-col gap-1.5'\nconst groupedFieldBaseClasses =\n 'h-12! min-h-12! border-2! border-input-border bg-input-bg text-base text-input-text transition duration-200 placeholder:text-input-text-placeholder hover:border-input-border--hover focus-visible:border-input-border--focus focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus disabled:pointer-events-none disabled:border-input-border--disabled disabled:bg-input-bg--disabled disabled:text-input-text--disabled'\n\nconst getFieldMinWidth = (caption?: string, extraCharacters: number = 0): string | undefined => {\n const normalizedCaption = caption?.trim()\n if (!normalizedCaption) return undefined\n return `${Math.max(normalizedCaption.length + extraCharacters, 8)}ch`\n}\n\nconst getReadableLabel = (label: string | undefined, fallback: string): string => {\n const normalizedLabel = label?.trim()\n return normalizedLabel && normalizedLabel.length > 0 ? normalizedLabel : fallback\n}\n\nexport const ControlGroupSelect = ({\n amountStep,\n ariaLabel,\n captionLayout = 'inline',\n className,\n dataTestId = 'spectral-control-group-select',\n disabled,\n errorMessage,\n id,\n dropdownWidth = 'trigger',\n inputAriaLabel,\n inputPlaceholder,\n inputItemClassName,\n inputValue,\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxAmount = 1000000,\n minAmount = 0,\n onInputChange,\n orientation = 'horizontal',\n selectAriaLabel,\n selectItemClassName,\n selectOptions,\n selectPlaceholder,\n state = 'default',\n type = 'number',\n warningMessage,\n ...selectProps\n}: ControlGroupSelectProps) => {\n const baseId = useId()\n const idPrefix = id ?? baseId\n const inputId = `${idPrefix}-amount`\n const selectTriggerId = `${idPrefix}-select`\n const inputLabelId = `${inputId}-label`\n const selectLabelId = `${selectTriggerId}-label`\n\n const useAboveLabels = captionLayout === 'above'\n const inputCaption = useAboveLabels ? undefined : inputPlaceholder\n const selectCaption = useAboveLabels ? undefined : selectPlaceholder\n const inputLabelText = getReadableLabel(inputPlaceholder, defaultInputLabel)\n const selectLabelText = getReadableLabel(selectPlaceholder, defaultSelectLabel)\n\n const inputAccessibleName = inputAriaLabel ?? (useAboveLabels ? undefined : inputLabelText)\n const selectTriggerAriaLabel = selectAriaLabel ?? (useAboveLabels ? undefined : selectLabelText)\n const inputMinWidth = getFieldMinWidth(inputPlaceholder, 3)\n const selectTriggerMinWidth = getFieldMinWidth(selectPlaceholder, 5)\n const groupAriaLabel = ariaLabel ?? `${inputLabelText} and ${selectLabelText}`\n\n const isDisabled = !!disabled\n const isInputControlled = inputValue !== undefined && onInputChange !== undefined\n\n return (\n <ControlGroup\n aria-label={groupAriaLabel}\n className={className}\n data-testid={dataTestId}\n disabled={disabled}\n errorMessage={errorMessage}\n id={idPrefix}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n orientation={orientation}\n state={state}\n warningMessage={warningMessage}\n >\n <ControlGroupSelectInner\n amountStep={amountStep}\n dataTestId={dataTestId}\n inputAccessibleName={inputAccessibleName}\n inputCaption={inputCaption}\n inputId={inputId}\n inputLabelId={inputLabelId}\n inputLabelText={inputLabelText}\n inputItemClassName={inputItemClassName}\n inputMinWidth={inputMinWidth}\n inputValue={isInputControlled ? inputValue : undefined}\n isDisabled={isDisabled}\n maxAmount={maxAmount}\n minAmount={minAmount}\n onInputChange={isInputControlled ? onInputChange : undefined}\n dropdownWidth={dropdownWidth}\n selectCaption={selectCaption}\n selectOptions={selectOptions}\n selectLabelId={selectLabelId}\n selectLabelText={selectLabelText}\n selectItemClassName={selectItemClassName}\n selectProps={selectProps}\n selectTriggerAriaLabel={selectTriggerAriaLabel}\n selectTriggerId={selectTriggerId}\n selectTriggerMinWidth={selectTriggerMinWidth}\n type={type}\n useAboveLabels={useAboveLabels}\n />\n </ControlGroup>\n )\n}\n\ninterface ControlGroupSelectInnerProps {\n amountStep?: number\n dataTestId: string\n dropdownWidth: DropdownWidth\n inputAccessibleName?: string\n inputCaption?: string\n inputId: string\n inputLabelId: string\n inputLabelText: string\n inputItemClassName?: string\n inputMinWidth?: string\n inputValue?: ComponentProps<typeof Input>['value']\n isDisabled: boolean\n maxAmount: number\n minAmount: number\n onInputChange?: ComponentProps<typeof Input>['onChange']\n selectCaption?: string\n selectLabelId: string\n selectLabelText: string\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n selectProps: Omit<ComponentProps<typeof Select>, 'children'>\n selectTriggerAriaLabel?: string\n selectTriggerId: string\n selectTriggerMinWidth?: string\n type: 'number' | 'text'\n useAboveLabels: boolean\n}\n\nconst ControlGroupSelectInner = ({\n amountStep,\n dataTestId,\n dropdownWidth,\n inputAccessibleName,\n inputCaption,\n inputId,\n inputLabelId,\n inputLabelText,\n inputItemClassName,\n inputMinWidth,\n inputValue,\n isDisabled,\n maxAmount,\n minAmount,\n onInputChange,\n selectCaption,\n selectLabelId,\n selectLabelText,\n selectItemClassName,\n selectOptions,\n selectProps,\n selectTriggerAriaLabel,\n selectTriggerId,\n selectTriggerMinWidth,\n type,\n useAboveLabels,\n}: ControlGroupSelectInnerProps) => {\n const { messageId, orientation, state } = useControlGroup()\n const isSelectOpenControlled = selectProps.open !== undefined\n const handleSelectOpenChange: NonNullable<ComponentProps<typeof Select>['onOpenChange']> = (nextOpen) => {\n selectProps.onOpenChange?.(nextOpen)\n }\n\n const inputRadiusClasses = orientation === 'horizontal' ? 'rounded-s-md rounded-e-none' : 'rounded-ss-md rounded-se-md rounded-es-none rounded-ee-none'\n const selectRadiusClasses = orientation === 'horizontal' ? 'rounded-s-none rounded-e-md' : 'rounded-ss-none rounded-se-none rounded-es-md rounded-ee-md'\n const firstItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0' : 'mbe-0'\n const secondItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0 [&>*:last-child]:-ms-0.5' : 'mbe-0 [&>*:last-child]:-mt-0.5'\n\n const inputElement = (\n <Input\n aria-describedby={messageId}\n aria-label={inputAccessibleName}\n aria-labelledby={useAboveLabels ? inputLabelId : undefined}\n className={cn(groupedFieldBaseClasses, inputRadiusClasses, getStateClasses(state), type === 'number' && numberInputNoSpinner, type === 'number' && 'tabular-nums')}\n data-testid={`${dataTestId}-input`}\n disabled={isDisabled}\n id={useAboveLabels ? inputId : undefined}\n type={type === 'number' ? 'number' : 'text'}\n placeholder={inputCaption}\n style={inputMinWidth ? { minWidth: inputMinWidth } : undefined}\n min={minAmount ?? 0}\n max={maxAmount ?? 1000000}\n {...(inputValue !== undefined && onInputChange !== undefined ? { value: inputValue, onChange: onInputChange } : {})}\n step={amountStep ?? 1}\n />\n )\n\n const selectTriggerElement = (\n <SelectTrigger\n aria-describedby={messageId}\n aria-label={selectTriggerAriaLabel}\n aria-labelledby={useAboveLabels ? selectLabelId : undefined}\n className={cn(\n 'text-input-text data-placeholder:text-input-text-placeholder!',\n selectRadiusClasses,\n 'px-4 w-full justify-between focus-visible:border-input-border--focus focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus',\n getStateClasses(state),\n )}\n data-testid={`${dataTestId}-select-trigger`}\n disabled={isDisabled}\n id={useAboveLabels ? selectTriggerId : undefined}\n style={selectTriggerMinWidth ? { minWidth: selectTriggerMinWidth } : undefined}\n >\n <SelectValue className='min-w-0 block max-w-full truncate text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder!' placeholder={selectCaption} />\n </SelectTrigger>\n )\n\n return (\n <>\n <ControlGroupItem className={cn(useAboveLabels ? firstItemAboveLabelClasses : undefined, inputItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={inputId} id={inputLabelId}>\n {inputLabelText}\n </Label>\n {inputElement}\n </div>\n ) : (\n inputElement\n )}\n </ControlGroupItem>\n <Select {...selectProps} data-testid={`${dataTestId}-select-root`} disabled={isDisabled} {...(isSelectOpenControlled ? { open: selectProps.open } : {})} onOpenChange={handleSelectOpenChange}>\n <ControlGroupItem className={cn(useAboveLabels ? secondItemAboveLabelClasses : undefined, selectItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={selectTriggerId} id={selectLabelId}>\n {selectLabelText}\n </Label>\n {selectTriggerElement}\n </div>\n ) : (\n selectTriggerElement\n )}\n </ControlGroupItem>\n <SelectContent data-testid={`${dataTestId}-select-content`} dropdownWidth={dropdownWidth}>\n {selectOptions.map((option) => (\n <SelectItem disabled={option.disabled} key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ControlGroupSelect.js","names":[],"sources":["../../src/components/ControlGroup/ControlGroupSelect.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { Input } from '@primitives/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { getStateClasses, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useId, type ComponentProps } from 'react'\nimport { ControlGroup, ControlGroupItem, useControlGroup, type ControlGroupProps } from './ControlGroup'\n\nconst numberInputNoSpinner = '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\nconst defaultInputLabel = 'Amount'\nconst defaultSelectLabel = 'Select an option'\n\nexport interface SelectOptionType {\n disabled?: boolean\n label: string\n value: string\n}\n\n/** `inline`: `inputPlaceholder` / `selectPlaceholder` show inside the fields. `above`: same strings render as labels above each control (no inner placeholders). */\nexport type ControlGroupSelectCaptionLayout = 'above' | 'inline'\n\ntype ControlGroupSelectInputControlProps =\n | {\n inputValue: ComponentProps<typeof Input>['value']\n onInputChange: ComponentProps<typeof Input>['onChange']\n }\n | {\n inputValue?: undefined\n onInputChange?: undefined\n }\n\ntype ControlGroupSelectBaseProps = ComponentProps<typeof Select> &\n Pick<ControlGroupProps, 'orientation'> & {\n amountStep?: number\n /** Accessible name for the group wrapper (use when there is no visible group heading). */\n ariaLabel?: string\n captionLayout?: ControlGroupSelectCaptionLayout\n className?: string\n dataTestId?: string\n disabled?: boolean\n dropdownWidth?: DropdownWidth\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n /** Class applied to the input `ControlGroupItem` segment for width/split composition. */\n inputItemClassName?: string\n /** When `captionLayout` is `inline`, overrides the input's accessible name (defaults to `inputPlaceholder` when set). */\n inputAriaLabel?: string\n inputPlaceholder?: string\n maxAmount?: number\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: false). */\n messageReserveSpace?: boolean\n minAmount?: number\n selectPlaceholder?: string\n /** When `captionLayout` is `inline` and `selectPlaceholder` is empty, sets the select trigger's accessible name. */\n selectAriaLabel?: string\n /** Class applied to the select `ControlGroupItem` segment for width/split composition. */\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n state?: Exclude<FormFieldState, 'disabled'>\n type?: 'number' | 'text'\n warningMessage?: string | string[] | Record<string, unknown> | null\n }\n\nexport type ControlGroupSelectProps = ControlGroupSelectBaseProps & ControlGroupSelectInputControlProps\n\nconst fieldStackClass = 'flex w-full min-w-0 flex-col gap-1.5'\nconst groupedFieldBaseClasses =\n 'h-12! min-h-12! border-2! border-input-border bg-input-bg text-base text-input-text transition duration-200 placeholder:text-input-text-placeholder hover:border-input-border--hover focus-visible:border-input-border--focus focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus disabled:pointer-events-none disabled:border-input-border--disabled disabled:bg-input-bg--disabled disabled:text-input-text--disabled'\n\nconst getFieldMinWidth = (caption?: string, extraCharacters: number = 0): string | undefined => {\n const normalizedCaption = caption?.trim()\n if (!normalizedCaption) return undefined\n return `${Math.max(normalizedCaption.length + extraCharacters, 8)}ch`\n}\n\nconst getReadableLabel = (label: string | undefined, fallback: string): string => {\n const normalizedLabel = label?.trim()\n return normalizedLabel && normalizedLabel.length > 0 ? normalizedLabel : fallback\n}\n\nexport const ControlGroupSelect = ({\n amountStep,\n ariaLabel,\n captionLayout = 'inline',\n className,\n dataTestId = 'spectral-control-group-select',\n disabled,\n errorMessage,\n id,\n dropdownWidth = 'trigger',\n inputAriaLabel,\n inputPlaceholder,\n inputItemClassName,\n inputValue,\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxAmount = 1000000,\n minAmount = 0,\n onInputChange,\n orientation = 'horizontal',\n selectAriaLabel,\n selectItemClassName,\n selectOptions,\n selectPlaceholder,\n state = 'default',\n type = 'number',\n warningMessage,\n ...selectProps\n}: ControlGroupSelectProps) => {\n const baseId = useId()\n const idPrefix = id ?? baseId\n const inputId = `${idPrefix}-amount`\n const selectTriggerId = `${idPrefix}-select`\n const inputLabelId = `${inputId}-label`\n const selectLabelId = `${selectTriggerId}-label`\n\n const useAboveLabels = captionLayout === 'above'\n const inputCaption = useAboveLabels ? undefined : inputPlaceholder\n const selectCaption = useAboveLabels ? undefined : selectPlaceholder\n const inputLabelText = getReadableLabel(inputPlaceholder, defaultInputLabel)\n const selectLabelText = getReadableLabel(selectPlaceholder, defaultSelectLabel)\n\n const inputAccessibleName = inputAriaLabel ?? (useAboveLabels ? undefined : inputLabelText)\n const selectTriggerAriaLabel = selectAriaLabel ?? (useAboveLabels ? undefined : selectLabelText)\n const inputMinWidth = getFieldMinWidth(inputPlaceholder, 3)\n const selectTriggerMinWidth = getFieldMinWidth(selectPlaceholder, 5)\n const groupAriaLabel = ariaLabel ?? `${inputLabelText} and ${selectLabelText}`\n\n const isDisabled = !!disabled\n const isInputControlled = inputValue !== undefined && onInputChange !== undefined\n\n return (\n <ControlGroup\n aria-label={groupAriaLabel}\n className={className}\n data-testid={dataTestId}\n disabled={disabled}\n errorMessage={errorMessage}\n id={idPrefix}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n orientation={orientation}\n state={state}\n warningMessage={warningMessage}\n >\n <ControlGroupSelectInner\n amountStep={amountStep}\n dataTestId={dataTestId}\n inputAccessibleName={inputAccessibleName}\n inputCaption={inputCaption}\n inputId={inputId}\n inputLabelId={inputLabelId}\n inputLabelText={inputLabelText}\n inputItemClassName={inputItemClassName}\n inputMinWidth={inputMinWidth}\n inputValue={isInputControlled ? inputValue : undefined}\n isDisabled={isDisabled}\n maxAmount={maxAmount}\n minAmount={minAmount}\n onInputChange={isInputControlled ? onInputChange : undefined}\n dropdownWidth={dropdownWidth}\n selectCaption={selectCaption}\n selectOptions={selectOptions}\n selectLabelId={selectLabelId}\n selectLabelText={selectLabelText}\n selectItemClassName={selectItemClassName}\n selectProps={selectProps}\n selectTriggerAriaLabel={selectTriggerAriaLabel}\n selectTriggerId={selectTriggerId}\n selectTriggerMinWidth={selectTriggerMinWidth}\n type={type}\n useAboveLabels={useAboveLabels}\n />\n </ControlGroup>\n )\n}\n\ninterface ControlGroupSelectInnerProps {\n amountStep?: number\n dataTestId: string\n dropdownWidth: DropdownWidth\n inputAccessibleName?: string\n inputCaption?: string\n inputId: string\n inputLabelId: string\n inputLabelText: string\n inputItemClassName?: string\n inputMinWidth?: string\n inputValue?: ComponentProps<typeof Input>['value']\n isDisabled: boolean\n maxAmount: number\n minAmount: number\n onInputChange?: ComponentProps<typeof Input>['onChange']\n selectCaption?: string\n selectLabelId: string\n selectLabelText: string\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n selectProps: Omit<ComponentProps<typeof Select>, 'children'>\n selectTriggerAriaLabel?: string\n selectTriggerId: string\n selectTriggerMinWidth?: string\n type: 'number' | 'text'\n useAboveLabels: boolean\n}\n\nconst ControlGroupSelectInner = ({\n amountStep,\n dataTestId,\n dropdownWidth,\n inputAccessibleName,\n inputCaption,\n inputId,\n inputLabelId,\n inputLabelText,\n inputItemClassName,\n inputMinWidth,\n inputValue,\n isDisabled,\n maxAmount,\n minAmount,\n onInputChange,\n selectCaption,\n selectLabelId,\n selectLabelText,\n selectItemClassName,\n selectOptions,\n selectProps,\n selectTriggerAriaLabel,\n selectTriggerId,\n selectTriggerMinWidth,\n type,\n useAboveLabels,\n}: ControlGroupSelectInnerProps) => {\n const { messageId, orientation, state } = useControlGroup()\n const isSelectOpenControlled = selectProps.open !== undefined\n const handleSelectOpenChange: NonNullable<ComponentProps<typeof Select>['onOpenChange']> = (nextOpen) => {\n selectProps.onOpenChange?.(nextOpen)\n }\n\n const inputRadiusClasses = orientation === 'horizontal' ? 'rounded-s-md rounded-e-none' : 'rounded-ss-md rounded-se-md rounded-es-none rounded-ee-none'\n const selectRadiusClasses = orientation === 'horizontal' ? 'rounded-s-none rounded-e-md' : 'rounded-ss-none rounded-se-none rounded-es-md rounded-ee-md'\n const firstItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0' : 'mbe-0'\n const secondItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0 [&>*:last-child]:-ms-0.5' : 'mbe-0 [&>*:last-child]:-mt-0.5'\n\n const inputElement = (\n <Input\n aria-describedby={messageId}\n aria-label={inputAccessibleName}\n aria-labelledby={useAboveLabels ? inputLabelId : undefined}\n className={cn(groupedFieldBaseClasses, inputRadiusClasses, getStateClasses(state), type === 'number' && numberInputNoSpinner, type === 'number' && 'tabular-nums')}\n data-testid={`${dataTestId}-input`}\n disabled={isDisabled}\n id={useAboveLabels ? inputId : undefined}\n type={type === 'number' ? 'number' : 'text'}\n placeholder={inputCaption}\n style={inputMinWidth ? { minWidth: inputMinWidth } : undefined}\n min={minAmount ?? 0}\n max={maxAmount ?? 1000000}\n {...(inputValue !== undefined && onInputChange !== undefined ? { value: inputValue, onChange: onInputChange } : {})}\n step={amountStep ?? 1}\n />\n )\n\n const selectTriggerElement = (\n <SelectTrigger\n aria-describedby={messageId}\n aria-label={selectTriggerAriaLabel}\n aria-labelledby={useAboveLabels ? selectLabelId : undefined}\n className={cn(\n 'text-input-text data-placeholder:text-input-text-placeholder!',\n selectRadiusClasses,\n 'px-4 w-full justify-between focus-visible:border-input-border--focus focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus',\n getStateClasses(state),\n )}\n data-testid={`${dataTestId}-select-trigger`}\n disabled={isDisabled}\n id={useAboveLabels ? selectTriggerId : undefined}\n style={selectTriggerMinWidth ? { minWidth: selectTriggerMinWidth } : undefined}\n >\n <SelectValue className='min-w-0 block max-w-full truncate text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder!' placeholder={selectCaption} />\n </SelectTrigger>\n )\n\n return (\n <>\n <ControlGroupItem className={cn(useAboveLabels ? firstItemAboveLabelClasses : undefined, inputItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={inputId} id={inputLabelId}>\n {inputLabelText}\n </Label>\n {inputElement}\n </div>\n ) : (\n inputElement\n )}\n </ControlGroupItem>\n <Select {...selectProps} data-testid={`${dataTestId}-select-root`} disabled={isDisabled} {...(isSelectOpenControlled ? { open: selectProps.open } : {})} onOpenChange={handleSelectOpenChange}>\n <ControlGroupItem className={cn(useAboveLabels ? secondItemAboveLabelClasses : undefined, selectItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={selectTriggerId} id={selectLabelId}>\n {selectLabelText}\n </Label>\n {selectTriggerElement}\n </div>\n ) : (\n selectTriggerElement\n )}\n </ControlGroupItem>\n <SelectContent data-testid={`${dataTestId}-select-content`} dropdownWidth={dropdownWidth}>\n {selectOptions.map((option) => (\n <SelectItem disabled={option.disabled} key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )\n}\n"],"mappings":"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"}
@@ -9,7 +9,6 @@ const cardClasses = "text-text-primary flex flex-col w-full card-effects p-3 gap
9
9
  const CardBase = ({ ...props }) => {
10
10
  return /* @__PURE__ */ jsx("div", {
11
11
  "data-slot": "card",
12
- "data-testid": "spectral-card",
13
12
  ...props
14
13
  });
15
14
  };
@@ -17,7 +16,6 @@ const CardHeader = ({ className, ...props }) => {
17
16
  return /* @__PURE__ */ jsx("div", {
18
17
  className: cn("pb-4 @container/card-header flex items-center justify-between", className),
19
18
  "data-slot": "card-header",
20
- "data-testid": "spectral-card-header",
21
19
  ...props
22
20
  });
23
21
  };
@@ -25,7 +23,6 @@ const CardTitle = ({ className, asChild = false, ...props }) => {
25
23
  return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
26
24
  className: cn("font-semibold text-xl", className),
27
25
  "data-slot": "card-title",
28
- "data-testid": "spectral-card-title",
29
26
  ...props
30
27
  });
31
28
  };
@@ -33,7 +30,6 @@ const CardHeaderEndSlot = ({ className, asChild = false, ...props }) => {
33
30
  return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
34
31
  className: cn("justify-self-end", className),
35
32
  "data-slot": "card-action",
36
- "data-testid": "spectral-card-action",
37
33
  ...props
38
34
  });
39
35
  };
@@ -41,7 +37,6 @@ const CardContent = ({ className, ...props }) => {
41
37
  return /* @__PURE__ */ jsx("div", {
42
38
  className,
43
39
  "data-slot": "card-content",
44
- "data-testid": "spectral-card-content",
45
40
  ...props
46
41
  });
47
42
  };
@@ -49,7 +44,6 @@ const Card = ({ asChild = false, children, className, ...props }) => {
49
44
  return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
50
45
  className: cn(cardClasses, className),
51
46
  "data-slot": "card",
52
- "data-testid": "spectral-card",
53
47
  ...props,
54
48
  children
55
49
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Card.js","names":[],"sources":["../../src/components/DataCard/Card.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type CardProps = ComponentProps<'div'> & { asChild?: boolean }\n\nconst cardClasses = 'text-text-primary flex flex-col w-full card-effects p-3 gap-6 rounded-xl'\n\nexport const CardBase = ({ ...props }: CardProps) => {\n return <div data-slot='card' data-testid='spectral-card' {...props} />\n}\n\nexport const CardHeader = ({ className, ...props }: CardProps) => {\n return <div className={cn('pb-4 @container/card-header flex items-center justify-between', className)} data-slot='card-header' data-testid='spectral-card-header' {...props} />\n}\n\nexport const CardTitle = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return <Comp className={cn('font-semibold text-xl', className)} data-slot='card-title' data-testid='spectral-card-title' {...props} />\n}\n\nexport const CardHeaderEndSlot = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return <Comp className={cn('justify-self-end', className)} data-slot='card-action' data-testid='spectral-card-action' {...props} />\n}\n\nexport const CardContent = ({ className, ...props }: CardProps) => {\n return <div className={className} data-slot='card-content' data-testid='spectral-card-content' {...props} />\n}\n\nexport const Card = ({ asChild = false, children, className, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return (\n <Comp className={cn(cardClasses, className)} data-slot='card' data-testid='spectral-card' {...props}>\n {children}\n </Comp>\n )\n}\n"],"mappings":";;;;;;;AAMA,MAAM,cAAc;AAEpB,MAAa,YAAY,EAAE,GAAG,YAAuB;AACnD,QAAO,oBAAC,OAAD;EAAK,aAAU;EAAO,eAAY;EAAgB,GAAI;EAAS;;AAGxE,MAAa,cAAc,EAAE,WAAW,GAAG,YAAuB;AAChE,QAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,iEAAiE,UAAU;EAAE,aAAU;EAAc,eAAY;EAAuB,GAAI;EAAS;;AAGjL,MAAa,aAAa,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGhF,QAAO,oBAFM,UAAU,OAAO,OAEvB;EAAM,WAAW,GAAG,yBAAyB,UAAU;EAAE,aAAU;EAAa,eAAY;EAAsB,GAAI;EAAS;;AAGxI,MAAa,qBAAqB,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGxF,QAAO,oBAFM,UAAU,OAAO,OAEvB;EAAM,WAAW,GAAG,oBAAoB,UAAU;EAAE,aAAU;EAAc,eAAY;EAAuB,GAAI;EAAS;;AAGrI,MAAa,eAAe,EAAE,WAAW,GAAG,YAAuB;AACjE,QAAO,oBAAC,OAAD;EAAgB;EAAW,aAAU;EAAe,eAAY;EAAwB,GAAI;EAAS;;AAG9G,MAAa,QAAQ,EAAE,UAAU,OAAO,UAAU,WAAW,GAAG,YAAuB;AAGrF,QACE,oBAHW,UAAU,OAAO,OAG5B;EAAM,WAAW,GAAG,aAAa,UAAU;EAAE,aAAU;EAAO,eAAY;EAAgB,GAAI;EAC3F;EACI"}
1
+ {"version":3,"file":"Card.js","names":[],"sources":["../../src/components/DataCard/Card.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type CardProps = ComponentProps<'div'> & { asChild?: boolean }\n\nconst cardClasses = 'text-text-primary flex flex-col w-full card-effects p-3 gap-6 rounded-xl'\n\nexport const CardBase = ({ ...props }: CardProps) => {\n return <div data-slot='card' data-testid='spectral-card' {...props} />\n}\n\nexport const CardHeader = ({ className, ...props }: CardProps) => {\n return <div className={cn('pb-4 @container/card-header flex items-center justify-between', className)} data-slot='card-header' data-testid='spectral-card-header' {...props} />\n}\n\nexport const CardTitle = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return <Comp className={cn('font-semibold text-xl', className)} data-slot='card-title' data-testid='spectral-card-title' {...props} />\n}\n\nexport const CardHeaderEndSlot = ({ className, asChild = false, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return <Comp className={cn('justify-self-end', className)} data-slot='card-action' data-testid='spectral-card-action' {...props} />\n}\n\nexport const CardContent = ({ className, ...props }: CardProps) => {\n return <div className={className} data-slot='card-content' data-testid='spectral-card-content' {...props} />\n}\n\nexport const Card = ({ asChild = false, children, className, ...props }: CardProps) => {\n const Comp = asChild ? Slot : 'div'\n\n return (\n <Comp className={cn(cardClasses, className)} data-slot='card' data-testid='spectral-card' {...props}>\n {children}\n </Comp>\n )\n}\n"],"mappings":";;;;;;;AAMA,MAAM,cAAc;AAEpB,MAAa,YAAY,EAAE,GAAG,YAAuB;AACnD,QAAO,oBAAC,OAAD;EAAK,aAAU;EAAmC,GAAI;EAAQ;;AAGvE,MAAa,cAAc,EAAE,WAAW,GAAG,YAAuB;AAChE,QAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,iEAAiE,UAAU;EAAE,aAAU;EAAiD,GAAI;EAAQ;;AAGhL,MAAa,aAAa,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGhF,QAAO,oBAFM,UAAU,OAAO,OAEvB;EAAM,WAAW,GAAG,yBAAyB,UAAU;EAAE,aAAU;EAA+C,GAAI;EAAQ;;AAGvI,MAAa,qBAAqB,EAAE,WAAW,UAAU,OAAO,GAAG,YAAuB;AAGxF,QAAO,oBAFM,UAAU,OAAO,OAEvB;EAAM,WAAW,GAAG,oBAAoB,UAAU;EAAE,aAAU;EAAiD,GAAI;EAAQ;;AAGpI,MAAa,eAAe,EAAE,WAAW,GAAG,YAAuB;AACjE,QAAO,oBAAC,OAAD;EAAgB;EAAW,aAAU;EAAmD,GAAI;EAAQ;;AAG7G,MAAa,QAAQ,EAAE,UAAU,OAAO,UAAU,WAAW,GAAG,YAAuB;AAGrF,QACE,oBAHW,UAAU,OAAO,OAG5B;EAAM,WAAW,GAAG,aAAa,UAAU;EAAE,aAAU;EAAmC,GAAI;EAC3F;EACG"}
package/dist/DataCard.js CHANGED
@@ -7,31 +7,25 @@ import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/components/DataCard/DataCard.tsx
8
8
  const DataCard = ({ accentColor, cardHeaderEndSlot, className, dataDescription, dataValue, title, ...props }) => {
9
9
  return /* @__PURE__ */ jsxs(Card, {
10
- className: cn("gap-4 card-effects", className),
10
+ className: cn("gap-4 card-effects-medium", className),
11
11
  ...props,
12
- "data-testid": "spectral-datacard",
13
12
  children: [/* @__PURE__ */ jsxs(CardHeader, {
14
13
  className: "pb-0",
15
- "data-testid": "spectral-datacard-header",
16
14
  children: [/* @__PURE__ */ jsx(CardTitle, {
17
15
  className: "text-sm font-bold uppercase",
18
- "data-testid": "spectral-datacard-title",
19
16
  children: title
20
17
  }), /* @__PURE__ */ jsx("div", {
21
18
  style: { color: accentColor },
22
- "data-testid": "spectral-datacard-end-slot",
23
19
  children: cardHeaderEndSlot
24
20
  })]
25
21
  }), /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs("div", {
26
22
  className: "gap-4 flex flex-col",
27
23
  children: [/* @__PURE__ */ jsx("div", {
28
24
  className: "text-4xl font-bold tabular-nums",
29
- "data-testid": "spectral-datacard-data-value",
30
25
  style: { color: accentColor },
31
26
  children: dataValue
32
27
  }), /* @__PURE__ */ jsx("div", {
33
28
  className: "text-xs text-data-card-description",
34
- "data-testid": "spectral-datacard-data-description",
35
29
  children: dataDescription
36
30
  })]
37
31
  }) })]
@@ -1 +1 @@
1
- {"version":3,"file":"DataCard.js","names":[],"sources":["../src/components/DataCard/DataCard.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Card, CardContent, CardHeader, CardTitle, type CardProps } from './Card'\n\nexport type DataCardProps = CardProps & {\n accentColor: string\n cardHeaderEndSlot: ReactNode\n dataDescription: string\n dataValue: string | number\n title: string\n}\n\nexport const DataCard = ({ accentColor, cardHeaderEndSlot, className, dataDescription, dataValue, title, ...props }: DataCardProps) => {\n return (\n <Card className={cn('gap-4 card-effects', className)} {...props} data-testid='spectral-datacard'>\n <CardHeader className='pb-0' data-testid='spectral-datacard-header'>\n <CardTitle className='text-sm font-bold uppercase' data-testid='spectral-datacard-title'>\n {title}\n </CardTitle>\n <div style={{ color: accentColor }} data-testid='spectral-datacard-end-slot'>\n {cardHeaderEndSlot}\n </div>\n </CardHeader>\n <CardContent>\n <div className='gap-4 flex flex-col'>\n <div className='text-4xl font-bold tabular-nums' data-testid='spectral-datacard-data-value' style={{ color: accentColor }}>\n {dataValue}\n </div>\n <div className='text-xs text-data-card-description' data-testid='spectral-datacard-data-description'>\n {dataDescription}\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":";;;;;;;AAYA,MAAa,YAAY,EAAE,aAAa,mBAAmB,WAAW,iBAAiB,WAAW,OAAO,GAAG,YAA2B;AACrI,QACE,qBAAC,MAAD;EAAM,WAAW,GAAG,sBAAsB,UAAU;EAAE,GAAI;EAAO,eAAY;YAA7E,CACE,qBAAC,YAAD;GAAY,WAAU;GAAO,eAAY;aAAzC,CACE,oBAAC,WAAD;IAAW,WAAU;IAA8B,eAAY;cAC5D;IACS,GACZ,oBAAC,OAAD;IAAK,OAAO,EAAE,OAAO,aAAa;IAAE,eAAY;cAC7C;IACG,EACK;MACb,oBAAC,aAAD,YACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IAAK,WAAU;IAAkC,eAAY;IAA+B,OAAO,EAAE,OAAO,aAAa;cACtH;IACG,GACN,oBAAC,OAAD;IAAK,WAAU;IAAqC,eAAY;cAC7D;IACG,EACF;MACM,EACT"}
1
+ {"version":3,"file":"DataCard.js","names":[],"sources":["../src/components/DataCard/DataCard.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Card, CardContent, CardHeader, CardTitle, type CardProps } from './Card'\n\nexport type DataCardProps = CardProps & {\n accentColor: string\n cardHeaderEndSlot: ReactNode\n dataDescription: string\n dataValue: string | number\n title: string\n}\n\nexport const DataCard = ({ accentColor, cardHeaderEndSlot, className, dataDescription, dataValue, title, ...props }: DataCardProps) => {\n return (\n <Card className={cn('gap-4 card-effects-medium', className)} {...props} data-testid='spectral-datacard'>\n <CardHeader className='pb-0' data-testid='spectral-datacard-header'>\n <CardTitle className='text-sm font-bold uppercase' data-testid='spectral-datacard-title'>\n {title}\n </CardTitle>\n <div style={{ color: accentColor }} data-testid='spectral-datacard-end-slot'>\n {cardHeaderEndSlot}\n </div>\n </CardHeader>\n <CardContent>\n <div className='gap-4 flex flex-col'>\n <div className='text-4xl font-bold tabular-nums' data-testid='spectral-datacard-data-value' style={{ color: accentColor }}>\n {dataValue}\n </div>\n <div className='text-xs text-data-card-description' data-testid='spectral-datacard-data-description'>\n {dataDescription}\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n"],"mappings":";;;;;;;AAYA,MAAa,YAAY,EAAE,aAAa,mBAAmB,WAAW,iBAAiB,WAAW,OAAO,GAAG,YAA2B;AACrI,QACE,qBAAC,MAAD;EAAM,WAAW,GAAG,6BAA6B,UAAU;EAAE,GAAI;YAAjE,CACE,qBAAC,YAAD;GAAY,WAAU;aAAtB,CACE,oBAAC,WAAD;IAAW,WAAU;cAClB;IACQ,GACX,oBAAC,OAAD;IAAK,OAAO,EAAE,OAAO,aAAa;cAC/B;IACE,EACK;MACZ,oBAAC,aAAD,YACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IAAK,WAAU;IAA6E,OAAO,EAAE,OAAO,aAAa;cACtH;IACE,GACL,oBAAC,OAAD;IAAK,WAAU;cACZ;IACE,EACF;MACM,EACT"}
@@ -40,7 +40,6 @@ const Calendar = ({ classNames, disabled, disablePastDates = true, fixedWeeks, l
40
40
  className: cn("size-4", orientation === "left" && "rotate-90", orientation === "right" && "-rotate-90")
41
41
  }) },
42
42
  "data-slot": "calendar",
43
- "data-testid": "spectral-calendar",
44
43
  disabled: combinedDisabled.length > 0 ? combinedDisabled : void 0,
45
44
  fixedWeeks,
46
45
  locale,
@@ -1 +1 @@
1
- {"version":3,"file":"Calendar.js","names":[],"sources":["../../src/components/DateTimePicker/Calendar.tsx"],"sourcesContent":["import { ChevronDownIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { useMemo } from 'react'\nimport { DayPicker, type DayPickerProps, type Matcher, type Locale } from 'react-day-picker'\n\nexport type CalendarProps = DayPickerProps & {\n disabled?: Matcher | Matcher[]\n disablePastDates?: boolean\n fixedWeeks?: boolean\n /** The locale object used to localize dates. Import from 'react-day-picker/locale'. */\n locale?: Partial<Locale>\n}\n\nexport const Calendar = ({ classNames, disabled, disablePastDates = true, fixedWeeks, locale, showOutsideDays = true, ...props }: CalendarProps) => {\n // Memoize today's date to avoid creating new Date objects on every render\n const today = useMemo(() => new Date(), [])\n\n // Combine user-provided disabled dates with past dates if enabled\n const combinedDisabled: Matcher[] = [...(disablePastDates ? [{ before: today }] : []), ...(Array.isArray(disabled) ? disabled : disabled ? [disabled] : [])]\n\n return (\n <DayPicker\n {...props}\n classNames={{\n months: cn('months relative flex'),\n month: cn('month'),\n caption: cn('calendar-header'),\n caption_label: cn('month-title'),\n nav: cn('rdp-nav flex w-full items-center'),\n nav_button: cn('nav-button h-7 w-7 p-0 bg-transparent opacity-50 hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent'),\n button_previous: cn('nav-prev left-1 top-0 absolute'),\n button_next: cn('nav-next right-1 top-0 absolute'),\n table: cn('table w-full border-collapse'),\n head_row: cn('day-head-row flex'),\n head_cell: cn('days-of-week'),\n row: cn('day-row mt-2 flex w-full'),\n cell: cn('day-cell'),\n day: cn('day'),\n day_range_start: cn('day-range-start'),\n day_range_middle: cn('day-range-middle'),\n day_range_end: cn('day-range-end'),\n day_selected: cn('day-selected'),\n day_outside: cn('day-outside'),\n day_disabled: cn('day-disabled'),\n hidden: cn('hidden'),\n ...classNames,\n }}\n components={{\n Chevron: ({ orientation }) => <ChevronDownIcon aria-hidden='true' className={cn('size-4', orientation === 'left' && 'rotate-90', orientation === 'right' && '-rotate-90')} />,\n }}\n data-slot='calendar'\n data-testid='spectral-calendar'\n disabled={combinedDisabled.length > 0 ? combinedDisabled : undefined}\n fixedWeeks={fixedWeeks}\n locale={locale}\n showOutsideDays={showOutsideDays}\n />\n )\n}\n\nCalendar.displayName = 'Calendar'\n"],"mappings":";;;;;;;;AAaA,MAAa,YAAY,EAAE,YAAY,UAAU,mBAAmB,MAAM,YAAY,QAAQ,kBAAkB,MAAM,GAAG,YAA2B;CAElJ,MAAM,QAAQ,8BAAc,IAAI,MAAM,EAAE,EAAE,CAAC;CAG3C,MAAM,mBAA8B,CAAC,GAAI,mBAAmB,CAAC,EAAE,QAAQ,OAAO,CAAC,GAAG,EAAE,EAAG,GAAI,MAAM,QAAQ,SAAS,GAAG,WAAW,WAAW,CAAC,SAAS,GAAG,EAAE,CAAE;AAE5J,QACE,oBAAC,WAAD;EACE,GAAI;EACJ,YAAY;GACV,QAAQ,GAAG,uBAAuB;GAClC,OAAO,GAAG,QAAQ;GAClB,SAAS,GAAG,kBAAkB;GAC9B,eAAe,GAAG,cAAc;GAChC,KAAK,GAAG,mCAAmC;GAC3C,YAAY,GAAG,mLAAmL;GAClM,iBAAiB,GAAG,iCAAiC;GACrD,aAAa,GAAG,kCAAkC;GAClD,OAAO,GAAG,+BAA+B;GACzC,UAAU,GAAG,oBAAoB;GACjC,WAAW,GAAG,eAAe;GAC7B,KAAK,GAAG,2BAA2B;GACnC,MAAM,GAAG,WAAW;GACpB,KAAK,GAAG,MAAM;GACd,iBAAiB,GAAG,kBAAkB;GACtC,kBAAkB,GAAG,mBAAmB;GACxC,eAAe,GAAG,gBAAgB;GAClC,cAAc,GAAG,eAAe;GAChC,aAAa,GAAG,cAAc;GAC9B,cAAc,GAAG,eAAe;GAChC,QAAQ,GAAG,SAAS;GACpB,GAAG;GACJ;EACD,YAAY,EACV,UAAU,EAAE,kBAAkB,oBAAC,iBAAD;GAAiB,eAAY;GAAO,WAAW,GAAG,UAAU,gBAAgB,UAAU,aAAa,gBAAgB,WAAW,aAAa;GAAI,GAC9K;EACD,aAAU;EACV,eAAY;EACZ,UAAU,iBAAiB,SAAS,IAAI,mBAAmB;EAC/C;EACJ;EACS;EACjB;;AAIN,SAAS,cAAc"}
1
+ {"version":3,"file":"Calendar.js","names":[],"sources":["../../src/components/DateTimePicker/Calendar.tsx"],"sourcesContent":["import { ChevronDownIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { useMemo } from 'react'\nimport { DayPicker, type DayPickerProps, type Matcher, type Locale } from 'react-day-picker'\n\nexport type CalendarProps = DayPickerProps & {\n disabled?: Matcher | Matcher[]\n disablePastDates?: boolean\n fixedWeeks?: boolean\n /** The locale object used to localize dates. Import from 'react-day-picker/locale'. */\n locale?: Partial<Locale>\n}\n\nexport const Calendar = ({ classNames, disabled, disablePastDates = true, fixedWeeks, locale, showOutsideDays = true, ...props }: CalendarProps) => {\n // Memoize today's date to avoid creating new Date objects on every render\n const today = useMemo(() => new Date(), [])\n\n // Combine user-provided disabled dates with past dates if enabled\n const combinedDisabled: Matcher[] = [...(disablePastDates ? [{ before: today }] : []), ...(Array.isArray(disabled) ? disabled : disabled ? [disabled] : [])]\n\n return (\n <DayPicker\n {...props}\n classNames={{\n months: cn('months relative flex'),\n month: cn('month'),\n caption: cn('calendar-header'),\n caption_label: cn('month-title'),\n nav: cn('rdp-nav flex w-full items-center'),\n nav_button: cn('nav-button h-7 w-7 p-0 bg-transparent opacity-50 hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent'),\n button_previous: cn('nav-prev left-1 top-0 absolute'),\n button_next: cn('nav-next right-1 top-0 absolute'),\n table: cn('table w-full border-collapse'),\n head_row: cn('day-head-row flex'),\n head_cell: cn('days-of-week'),\n row: cn('day-row mt-2 flex w-full'),\n cell: cn('day-cell'),\n day: cn('day'),\n day_range_start: cn('day-range-start'),\n day_range_middle: cn('day-range-middle'),\n day_range_end: cn('day-range-end'),\n day_selected: cn('day-selected'),\n day_outside: cn('day-outside'),\n day_disabled: cn('day-disabled'),\n hidden: cn('hidden'),\n ...classNames,\n }}\n components={{\n Chevron: ({ orientation }) => <ChevronDownIcon aria-hidden='true' className={cn('size-4', orientation === 'left' && 'rotate-90', orientation === 'right' && '-rotate-90')} />,\n }}\n data-slot='calendar'\n data-testid='spectral-calendar'\n disabled={combinedDisabled.length > 0 ? combinedDisabled : undefined}\n fixedWeeks={fixedWeeks}\n locale={locale}\n showOutsideDays={showOutsideDays}\n />\n )\n}\n\nCalendar.displayName = 'Calendar'\n"],"mappings":";;;;;;;;AAaA,MAAa,YAAY,EAAE,YAAY,UAAU,mBAAmB,MAAM,YAAY,QAAQ,kBAAkB,MAAM,GAAG,YAA2B;CAElJ,MAAM,QAAQ,8BAAc,IAAI,MAAM,EAAE,EAAE,CAAA;CAG1C,MAAM,mBAA8B,CAAC,GAAI,mBAAmB,CAAC,EAAE,QAAQ,OAAO,CAAC,GAAG,EAAE,EAAG,GAAI,MAAM,QAAQ,SAAS,GAAG,WAAW,WAAW,CAAC,SAAS,GAAG,EAAE,CAAC;AAE3J,QACE,oBAAC,WAAD;EACE,GAAI;EACJ,YAAY;GACV,QAAQ,GAAG,uBAAuB;GAClC,OAAO,GAAG,QAAQ;GAClB,SAAS,GAAG,kBAAkB;GAC9B,eAAe,GAAG,cAAc;GAChC,KAAK,GAAG,mCAAmC;GAC3C,YAAY,GAAG,mLAAmL;GAClM,iBAAiB,GAAG,iCAAiC;GACrD,aAAa,GAAG,kCAAkC;GAClD,OAAO,GAAG,+BAA+B;GACzC,UAAU,GAAG,oBAAoB;GACjC,WAAW,GAAG,eAAe;GAC7B,KAAK,GAAG,2BAA2B;GACnC,MAAM,GAAG,WAAW;GACpB,KAAK,GAAG,MAAM;GACd,iBAAiB,GAAG,kBAAkB;GACtC,kBAAkB,GAAG,mBAAmB;GACxC,eAAe,GAAG,gBAAgB;GAClC,cAAc,GAAG,eAAe;GAChC,aAAa,GAAG,cAAc;GAC9B,cAAc,GAAG,eAAe;GAChC,QAAQ,GAAG,SAAS;GACpB,GAAG;GACJ;EACD,YAAY,EACV,UAAU,EAAE,kBAAkB,oBAAC,iBAAD;GAAiB,eAAY;GAAO,WAAW,GAAG,UAAU,gBAAgB,UAAU,aAAa,gBAAgB,WAAW,aAAa;GAAI,GAC9K;EACD,aAAU;EAEV,UAAU,iBAAiB,SAAS,IAAI,mBAAmB;EAC/C;EACJ;EACS;EAClB;;AAIL,SAAS,cAAc"}
@@ -163,7 +163,6 @@ const DateTimeInput = ({ className, date, disabled, id, locale, name, onKeyDown,
163
163
  return /* @__PURE__ */ jsx(Input, {
164
164
  className: cn("text-center tabular-nums", className),
165
165
  "data-slot": "datetime-input",
166
- "data-testid": `spectral-datetime-input-${picker}`,
167
166
  defaultValue: displayValue,
168
167
  disabled,
169
168
  id: id ?? picker,