@spear-ai/spectral 1.15.1 → 1.15.3

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 (58) hide show
  1. package/dist/Accordion.js +3 -3
  2. package/dist/Accordion.js.map +1 -1
  3. package/dist/Alert/AlertBase.js +1 -1
  4. package/dist/Alert/AlertBase.js.map +1 -1
  5. package/dist/Alert.js +3 -3
  6. package/dist/Alert.js.map +1 -1
  7. package/dist/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar.js +17 -10
  9. package/dist/Avatar.js.map +1 -1
  10. package/dist/ButtonGroup/ButtonGroupButton.js +1 -1
  11. package/dist/ButtonGroup/ButtonGroupButton.js.map +1 -1
  12. package/dist/ControlGroup.js +1 -1
  13. package/dist/ControlGroup.js.map +1 -1
  14. package/dist/DateTimePicker/Calendar.js +1 -1
  15. package/dist/DateTimePicker/Calendar.js.map +1 -1
  16. package/dist/Dialog.d.ts +1 -0
  17. package/dist/Dialog.d.ts.map +1 -1
  18. package/dist/Dialog.js +7 -6
  19. package/dist/Dialog.js.map +1 -1
  20. package/dist/Drawer.d.ts.map +1 -1
  21. package/dist/Drawer.js +27 -23
  22. package/dist/Drawer.js.map +1 -1
  23. package/dist/Icons/SyncIcon.d.ts +18 -0
  24. package/dist/Icons/SyncIcon.d.ts.map +1 -0
  25. package/dist/Icons/SyncIcon.js +33 -0
  26. package/dist/Icons/SyncIcon.js.map +1 -0
  27. package/dist/Icons/SyncOffIcon.d.ts +18 -0
  28. package/dist/Icons/SyncOffIcon.d.ts.map +1 -0
  29. package/dist/Icons/SyncOffIcon.js +43 -0
  30. package/dist/Icons/SyncOffIcon.js.map +1 -0
  31. package/dist/Icons.d.ts +3 -1
  32. package/dist/Icons.js +3 -1
  33. package/dist/Input.js +1 -1
  34. package/dist/Input.js.map +1 -1
  35. package/dist/MultiSelect/MultiSelectBase.js +3 -2
  36. package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
  37. package/dist/RadioGroup.js +1 -1
  38. package/dist/RadioGroup.js.map +1 -1
  39. package/dist/Switch.js +4 -4
  40. package/dist/Switch.js.map +1 -1
  41. package/dist/Tabs/TabsBase.d.ts.map +1 -1
  42. package/dist/Tabs/TabsBase.js +10 -56
  43. package/dist/Tabs/TabsBase.js.map +1 -1
  44. package/dist/Tabs.js +1 -1
  45. package/dist/Tabs.js.map +1 -1
  46. package/dist/ToggleGroup/ToggleGroupItem.js +1 -1
  47. package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
  48. package/dist/Tooltip.js +1 -1
  49. package/dist/Tooltip.js.map +1 -1
  50. package/dist/Tray.d.ts.map +1 -1
  51. package/dist/Tray.js +11 -49
  52. package/dist/Tray.js.map +1 -1
  53. package/dist/index.d.ts +3 -1
  54. package/dist/index.js +3 -1
  55. package/dist/styles/horizon/base.css +18 -7
  56. package/dist/styles/horizon/colors.css +3 -1
  57. package/dist/styles/spectral.css +1 -1
  58. package/package.json +1 -1
package/dist/Accordion.js CHANGED
@@ -10,7 +10,7 @@ import * as AccordionPrimitive from "@radix-ui/react-accordion";
10
10
  const variantStyles = {
11
11
  default: "shadow-none",
12
12
  contained: "rounded-md border border-level-four",
13
- separated: "rounded-none space-y-2"
13
+ separated: "rounded-none gap-2"
14
14
  };
15
15
  const itemStyles = {
16
16
  default: "w-full py-4",
@@ -69,14 +69,14 @@ const AccordionTrigger = ({ ref, className, title, subtitle, ...props }) => {
69
69
  return /* @__PURE__ */ jsx(AccordionPrimitive.Header, {
70
70
  className: "m-0 flex",
71
71
  children: /* @__PURE__ */ jsxs(AccordionPrimitive.Trigger, {
72
- className: cn("text-sm font-normal flex flex-1 items-center justify-between text-text-primary transition-all hover:no-underline", "disabled:cursor-not-allowed [&[data-state=open]>svg]:rotate-180", className),
72
+ className: cn("text-sm font-normal flex flex-1 items-center justify-between text-text-primary transition-colors hover:no-underline", "disabled:cursor-not-allowed [&[data-state=open]>svg]:rotate-180", className),
73
73
  "data-slot": "accordion-trigger",
74
74
  "data-testid": "spectral-accordion-trigger",
75
75
  onClick: handleAccordionOpen,
76
76
  ref: useMergedRef,
77
77
  ...props,
78
78
  children: [/* @__PURE__ */ jsxs("div", {
79
- className: "space-y-0.5 flex w-full flex-col text-start",
79
+ className: "gap-0.5 flex w-full flex-col text-start",
80
80
  children: [/* @__PURE__ */ jsx("div", {
81
81
  className: "text-base font-medium text-text-primary",
82
82
  children: title
@@ -1 +1 @@
1
- {"version":3,"file":"Accordion.js","names":[],"sources":["../src/components/Accordion/Accordion.tsx"],"sourcesContent":["import { ChevronDownIcon } from '@components/Icons'\nimport { useAccordionAutoScroll } from '@hooks/useAccordionAutoScroll'\nimport * as AccordionPrimitive from '@radix-ui/react-accordion'\nimport { cn } from '@utils/twUtils'\nimport { Children, cloneElement, createContext, isValidElement, useCallback, useContext, useRef, type ComponentPropsWithoutRef, type ComponentRef, type ReactNode, type Ref } from 'react'\n\nexport type AutoScrollBehavior = 'never' | 'mobile' | 'always'\n\ninterface BaseAccordionProps {\n autoScroll?: AutoScrollBehavior\n children?: ReactNode\n className?: string\n scrollPadding?: number\n variant?: 'default' | 'contained' | 'separated'\n}\n\nexport interface AccordionSingleProps extends BaseAccordionProps {\n collapsible?: boolean\n defaultValue?: string\n onValueChange?: (value: string) => void\n type: 'single'\n value?: string\n}\n\nexport interface AccordionMultipleProps extends BaseAccordionProps {\n defaultValue?: string[]\n onValueChange?: (value: string[]) => void\n type: 'multiple'\n value?: string[]\n}\n\nexport type AccordionProps = AccordionSingleProps | AccordionMultipleProps\n\ntype AccordionComponent = (props: AccordionProps & { ref?: Ref<HTMLDivElement> }) => ReactNode\n\ntype AccordionType = AccordionComponent & {\n Content: typeof AccordionContent\n Item: typeof AccordionItem\n Trigger: typeof AccordionTrigger\n}\n\ninterface ScrollOptions {\n autoScroll: AutoScrollBehavior\n scrollPadding: number\n}\n\nconst variantStyles = {\n default: 'shadow-none',\n contained: 'rounded-md border border-level-four',\n separated: 'rounded-none space-y-2',\n}\n\nconst itemStyles = {\n default: 'w-full py-4',\n contained: 'not-last:border-b border-level-four p-4',\n separated: 'border border-level-four rounded-md p-4',\n}\n\nconst AccordionContext = createContext<{ variant: BaseAccordionProps['variant'] }>({ variant: 'default' })\n\nconst AccordionRoot = ({\n className,\n ref,\n variant = 'default',\n ...props\n}: AccordionProps & {\n ref?: Ref<HTMLDivElement>\n}) => {\n const { autoScroll = 'never', scrollPadding = -20, children, ...rest } = props\n\n const accordionContext: ScrollOptions = {\n autoScroll,\n scrollPadding,\n }\n\n const rootProps = {\n ...rest,\n ref,\n }\n\n return (\n <AccordionContext.Provider value={{ variant }}>\n <AccordionPrimitive.Root\n {...rootProps}\n className={cn('accordion-wrapper flex flex-col', variantStyles[variant], className)}\n data-auto-scroll={autoScroll}\n data-scroll-options={JSON.stringify(accordionContext)}\n data-scroll-padding={scrollPadding}\n data-slot='accordion'\n data-testid='spectral-accordion'\n {...(props.type === 'single' ? { collapsible: true } : {})}\n >\n {Children.map(children, (child: ReactNode) => {\n if (isValidElement(child)) {\n return cloneElement(child, { variant } as { variant: typeof variant })\n }\n return child\n })}\n </AccordionPrimitive.Root>\n </AccordionContext.Provider>\n )\n}\nAccordionRoot.displayName = 'Accordion'\n\nexport const AccordionItem = ({\n className,\n ref,\n ...props\n}: ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> & {\n ref?: Ref<ComponentRef<typeof AccordionPrimitive.Item>>\n}) => {\n const { variant = 'default' } = useContext(AccordionContext)\n\n return (\n <AccordionPrimitive.Item\n className={cn('w-full', itemStyles[variant], className)}\n data-slot='accordion-item'\n data-testid='spectral-accordion-item'\n ref={ref}\n {...props}\n />\n )\n}\nAccordionItem.displayName = 'AccordionItem'\n\nexport const AccordionTrigger = ({\n ref,\n className,\n title,\n subtitle,\n ...props\n}: ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> & {\n ref?: Ref<HTMLButtonElement>\n subtitle?: ReactNode\n title: ReactNode\n}) => {\n const triggerRef = useRef<HTMLButtonElement>(null)\n const handleAccordionOpen = useAccordionAutoScroll(triggerRef)\n\n const useMergedRef = useCallback(\n (element: HTMLButtonElement) => {\n if (typeof ref === 'function') {\n ref(element)\n } else if (ref) {\n ref.current = element\n }\n triggerRef.current = element\n },\n [ref],\n )\n\n return (\n <AccordionPrimitive.Header className='m-0 flex'>\n <AccordionPrimitive.Trigger\n className={cn('text-sm font-normal flex flex-1 items-center justify-between text-text-primary transition-all hover:no-underline', 'disabled:cursor-not-allowed [&[data-state=open]>svg]:rotate-180', className)}\n data-slot='accordion-trigger'\n data-testid='spectral-accordion-trigger'\n onClick={handleAccordionOpen}\n ref={useMergedRef}\n {...props}\n >\n <div className='space-y-0.5 flex w-full flex-col text-start'>\n <div className='text-base font-medium text-text-primary'>{title}</div>\n {subtitle && <div className='text-sm font-normal text-text-secondary'>{subtitle}</div>}\n </div>\n <ChevronDownIcon className='shrink-0 transition-transform duration-200' />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\nAccordionTrigger.displayName = 'AccordionTrigger'\n\nexport const AccordionContent = ({\n ref,\n className,\n children,\n ...props\n}: ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> & {\n ref?: Ref<ComponentRef<typeof AccordionPrimitive.Content>>\n}) => (\n <AccordionPrimitive.Content\n className={cn('pt-4 text-sm overflow-hidden motion-safe:data-[state=closed]:animate-accordion-up motion-safe:data-[state=open]:animate-accordion-down', className)}\n data-slot='accordion-content'\n data-testid='spectral-accordion-content'\n ref={ref}\n {...props}\n >\n <div\n className='px-1 pb-4 pt-0'\n data-slot='accordion-content-inner'\n >\n {children}\n </div>\n </AccordionPrimitive.Content>\n)\nAccordionContent.displayName = 'AccordionContent'\n\nexport const Accordion: AccordionType = Object.assign(AccordionRoot, {\n Content: AccordionContent,\n Item: AccordionItem,\n Trigger: AccordionTrigger,\n})\n"],"mappings":";;;;;;;;;AA8CA,MAAM,gBAAgB;CACpB,SAAS;CACT,WAAW;CACX,WAAW;CACZ;AAED,MAAM,aAAa;CACjB,SAAS;CACT,WAAW;CACX,WAAW;CACZ;AAED,MAAM,mBAAmB,cAA0D,EAAE,SAAS,WAAW,CAAC;AAE1G,MAAM,iBAAiB,EACrB,WACA,KACA,UAAU,WACV,GAAG,YAGC;CACJ,MAAM,EAAE,aAAa,SAAS,gBAAgB,KAAK,UAAU,GAAG,SAAS;CAEzE,MAAM,mBAAkC;EACtC;EACA;EACD;CAED,MAAM,YAAY;EAChB,GAAG;EACH;EACD;AAED,QACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO,EAAE,SAAS;YAC3C,oBAAC,mBAAmB,MAApB;GACE,GAAI;GACJ,WAAW,GAAG,mCAAmC,cAAc,UAAU,UAAU;GACnF,oBAAkB;GAClB,uBAAqB,KAAK,UAAU,iBAAiB;GACrD,uBAAqB;GACrB,aAAU;GACV,eAAY;GACZ,GAAK,MAAM,SAAS,WAAW,EAAE,aAAa,MAAM,GAAG,EAAE;aAExD,SAAS,IAAI,WAAW,UAAqB;AAC5C,QAAI,eAAe,MAAM,CACvB,QAAO,aAAa,OAAO,EAAE,SAAS,CAAgC;AAExE,WAAO;KACP;GACsB;EACA;;AAGhC,cAAc,cAAc;AAE5B,MAAa,iBAAiB,EAC5B,WACA,KACA,GAAG,YAGC;CACJ,MAAM,EAAE,UAAU,cAAc,WAAW,iBAAiB;AAE5D,QACE,oBAAC,mBAAmB,MAApB;EACE,WAAW,GAAG,UAAU,WAAW,UAAU,UAAU;EACvD,aAAU;EACV,eAAY;EACP;EACL,GAAI;EACJ;;AAGN,cAAc,cAAc;AAE5B,MAAa,oBAAoB,EAC/B,KACA,WACA,OACA,UACA,GAAG,YAKC;CACJ,MAAM,aAAa,OAA0B,KAAK;CAClD,MAAM,sBAAsB,uBAAuB,WAAW;CAE9D,MAAM,eAAe,aAClB,YAA+B;AAC9B,MAAI,OAAO,QAAQ,WACjB,KAAI,QAAQ;WACH,IACT,KAAI,UAAU;AAEhB,aAAW,UAAU;IAEvB,CAAC,IAAI,CACN;AAED,QACE,oBAAC,mBAAmB,QAApB;EAA2B,WAAU;YACnC,qBAAC,mBAAmB,SAApB;GACE,WAAW,GAAG,oHAAoH,mEAAmE,UAAU;GAC/M,aAAU;GACV,eAAY;GACZ,SAAS;GACT,KAAK;GACL,GAAI;aANN,CAQE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eAA2C;KAAY,GACrE,YAAY,oBAAC,OAAD;KAAK,WAAU;eAA2C;KAAe,EAClF;OACN,oBAAC,iBAAD,EAAiB,WAAU,8CAA+C,EAC/C;;EACH;;AAGhC,iBAAiB,cAAc;AAE/B,MAAa,oBAAoB,EAC/B,KACA,WACA,UACA,GAAG,YAIH,oBAAC,mBAAmB,SAApB;CACE,WAAW,GAAG,0IAA0I,UAAU;CAClK,aAAU;CACV,eAAY;CACP;CACL,GAAI;WAEJ,oBAAC,OAAD;EACE,WAAU;EACV,aAAU;EAET;EACG;CACqB;AAE/B,iBAAiB,cAAc;AAE/B,MAAa,YAA2B,OAAO,OAAO,eAAe;CACnE,SAAS;CACT,MAAM;CACN,SAAS;CACV,CAAC"}
1
+ {"version":3,"file":"Accordion.js","names":[],"sources":["../src/components/Accordion/Accordion.tsx"],"sourcesContent":["import { ChevronDownIcon } from '@components/Icons'\nimport { useAccordionAutoScroll } from '@hooks/useAccordionAutoScroll'\nimport * as AccordionPrimitive from '@radix-ui/react-accordion'\nimport { cn } from '@utils/twUtils'\nimport { Children, cloneElement, createContext, isValidElement, useCallback, useContext, useRef, type ComponentPropsWithoutRef, type ComponentRef, type ReactNode, type Ref } from 'react'\n\nexport type AutoScrollBehavior = 'never' | 'mobile' | 'always'\n\ninterface BaseAccordionProps {\n autoScroll?: AutoScrollBehavior\n children?: ReactNode\n className?: string\n scrollPadding?: number\n variant?: 'default' | 'contained' | 'separated'\n}\n\nexport interface AccordionSingleProps extends BaseAccordionProps {\n collapsible?: boolean\n defaultValue?: string\n onValueChange?: (value: string) => void\n type: 'single'\n value?: string\n}\n\nexport interface AccordionMultipleProps extends BaseAccordionProps {\n defaultValue?: string[]\n onValueChange?: (value: string[]) => void\n type: 'multiple'\n value?: string[]\n}\n\nexport type AccordionProps = AccordionSingleProps | AccordionMultipleProps\n\ntype AccordionComponent = (props: AccordionProps & { ref?: Ref<HTMLDivElement> }) => ReactNode\n\ntype AccordionType = AccordionComponent & {\n Content: typeof AccordionContent\n Item: typeof AccordionItem\n Trigger: typeof AccordionTrigger\n}\n\ninterface ScrollOptions {\n autoScroll: AutoScrollBehavior\n scrollPadding: number\n}\n\nconst variantStyles = {\n default: 'shadow-none',\n contained: 'rounded-md border border-level-four',\n separated: 'rounded-none gap-2',\n}\n\nconst itemStyles = {\n default: 'w-full py-4',\n contained: 'not-last:border-b border-level-four p-4',\n separated: 'border border-level-four rounded-md p-4',\n}\n\nconst AccordionContext = createContext<{ variant: BaseAccordionProps['variant'] }>({ variant: 'default' })\n\nconst AccordionRoot = ({\n className,\n ref,\n variant = 'default',\n ...props\n}: AccordionProps & {\n ref?: Ref<HTMLDivElement>\n}) => {\n const { autoScroll = 'never', scrollPadding = -20, children, ...rest } = props\n\n const accordionContext: ScrollOptions = {\n autoScroll,\n scrollPadding,\n }\n\n const rootProps = {\n ...rest,\n ref,\n }\n\n return (\n <AccordionContext.Provider value={{ variant }}>\n <AccordionPrimitive.Root\n {...rootProps}\n className={cn('accordion-wrapper flex flex-col', variantStyles[variant], className)}\n data-auto-scroll={autoScroll}\n data-scroll-options={JSON.stringify(accordionContext)}\n data-scroll-padding={scrollPadding}\n data-slot='accordion'\n data-testid='spectral-accordion'\n {...(props.type === 'single' ? { collapsible: true } : {})}\n >\n {Children.map(children, (child: ReactNode) => {\n if (isValidElement(child)) {\n return cloneElement(child, { variant } as { variant: typeof variant })\n }\n return child\n })}\n </AccordionPrimitive.Root>\n </AccordionContext.Provider>\n )\n}\nAccordionRoot.displayName = 'Accordion'\n\nexport const AccordionItem = ({\n className,\n ref,\n ...props\n}: ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> & {\n ref?: Ref<ComponentRef<typeof AccordionPrimitive.Item>>\n}) => {\n const { variant = 'default' } = useContext(AccordionContext)\n\n return (\n <AccordionPrimitive.Item\n className={cn('w-full', itemStyles[variant], className)}\n data-slot='accordion-item'\n data-testid='spectral-accordion-item'\n ref={ref}\n {...props}\n />\n )\n}\nAccordionItem.displayName = 'AccordionItem'\n\nexport const AccordionTrigger = ({\n ref,\n className,\n title,\n subtitle,\n ...props\n}: ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> & {\n ref?: Ref<HTMLButtonElement>\n subtitle?: ReactNode\n title: ReactNode\n}) => {\n const triggerRef = useRef<HTMLButtonElement>(null)\n const handleAccordionOpen = useAccordionAutoScroll(triggerRef)\n\n const useMergedRef = useCallback(\n (element: HTMLButtonElement) => {\n if (typeof ref === 'function') {\n ref(element)\n } else if (ref) {\n ref.current = element\n }\n triggerRef.current = element\n },\n [ref],\n )\n\n return (\n <AccordionPrimitive.Header className='m-0 flex'>\n <AccordionPrimitive.Trigger\n className={cn('text-sm font-normal flex flex-1 items-center justify-between text-text-primary transition-colors hover:no-underline', 'disabled:cursor-not-allowed [&[data-state=open]>svg]:rotate-180', className)}\n data-slot='accordion-trigger'\n data-testid='spectral-accordion-trigger'\n onClick={handleAccordionOpen}\n ref={useMergedRef}\n {...props}\n >\n <div className='gap-0.5 flex w-full flex-col text-start'>\n <div className='text-base font-medium text-text-primary'>{title}</div>\n {subtitle && <div className='text-sm font-normal text-text-secondary'>{subtitle}</div>}\n </div>\n <ChevronDownIcon className='shrink-0 transition-transform duration-200' />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\nAccordionTrigger.displayName = 'AccordionTrigger'\n\nexport const AccordionContent = ({\n ref,\n className,\n children,\n ...props\n}: ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> & {\n ref?: Ref<ComponentRef<typeof AccordionPrimitive.Content>>\n}) => (\n <AccordionPrimitive.Content\n className={cn('pt-4 text-sm overflow-hidden motion-safe:data-[state=closed]:animate-accordion-up motion-safe:data-[state=open]:animate-accordion-down', className)}\n data-slot='accordion-content'\n data-testid='spectral-accordion-content'\n ref={ref}\n {...props}\n >\n <div\n className='px-1 pb-4 pt-0'\n data-slot='accordion-content-inner'\n >\n {children}\n </div>\n </AccordionPrimitive.Content>\n)\nAccordionContent.displayName = 'AccordionContent'\n\nexport const Accordion: AccordionType = Object.assign(AccordionRoot, {\n Content: AccordionContent,\n Item: AccordionItem,\n Trigger: AccordionTrigger,\n})\n"],"mappings":";;;;;;;;;AA8CA,MAAM,gBAAgB;CACpB,SAAS;CACT,WAAW;CACX,WAAW;CACZ;AAED,MAAM,aAAa;CACjB,SAAS;CACT,WAAW;CACX,WAAW;CACZ;AAED,MAAM,mBAAmB,cAA0D,EAAE,SAAS,WAAW,CAAC;AAE1G,MAAM,iBAAiB,EACrB,WACA,KACA,UAAU,WACV,GAAG,YAGC;CACJ,MAAM,EAAE,aAAa,SAAS,gBAAgB,KAAK,UAAU,GAAG,SAAS;CAEzE,MAAM,mBAAkC;EACtC;EACA;EACD;CAED,MAAM,YAAY;EAChB,GAAG;EACH;EACD;AAED,QACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO,EAAE,SAAS;YAC3C,oBAAC,mBAAmB,MAApB;GACE,GAAI;GACJ,WAAW,GAAG,mCAAmC,cAAc,UAAU,UAAU;GACnF,oBAAkB;GAClB,uBAAqB,KAAK,UAAU,iBAAiB;GACrD,uBAAqB;GACrB,aAAU;GACV,eAAY;GACZ,GAAK,MAAM,SAAS,WAAW,EAAE,aAAa,MAAM,GAAG,EAAE;aAExD,SAAS,IAAI,WAAW,UAAqB;AAC5C,QAAI,eAAe,MAAM,CACvB,QAAO,aAAa,OAAO,EAAE,SAAS,CAAgC;AAExE,WAAO;KACP;GACsB;EACA;;AAGhC,cAAc,cAAc;AAE5B,MAAa,iBAAiB,EAC5B,WACA,KACA,GAAG,YAGC;CACJ,MAAM,EAAE,UAAU,cAAc,WAAW,iBAAiB;AAE5D,QACE,oBAAC,mBAAmB,MAApB;EACE,WAAW,GAAG,UAAU,WAAW,UAAU,UAAU;EACvD,aAAU;EACV,eAAY;EACP;EACL,GAAI;EACJ;;AAGN,cAAc,cAAc;AAE5B,MAAa,oBAAoB,EAC/B,KACA,WACA,OACA,UACA,GAAG,YAKC;CACJ,MAAM,aAAa,OAA0B,KAAK;CAClD,MAAM,sBAAsB,uBAAuB,WAAW;CAE9D,MAAM,eAAe,aAClB,YAA+B;AAC9B,MAAI,OAAO,QAAQ,WACjB,KAAI,QAAQ;WACH,IACT,KAAI,UAAU;AAEhB,aAAW,UAAU;IAEvB,CAAC,IAAI,CACN;AAED,QACE,oBAAC,mBAAmB,QAApB;EAA2B,WAAU;YACnC,qBAAC,mBAAmB,SAApB;GACE,WAAW,GAAG,uHAAuH,mEAAmE,UAAU;GAClN,aAAU;GACV,eAAY;GACZ,SAAS;GACT,KAAK;GACL,GAAI;aANN,CAQE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eAA2C;KAAY,GACrE,YAAY,oBAAC,OAAD;KAAK,WAAU;eAA2C;KAAe,EAClF;OACN,oBAAC,iBAAD,EAAiB,WAAU,8CAA+C,EAC/C;;EACH;;AAGhC,iBAAiB,cAAc;AAE/B,MAAa,oBAAoB,EAC/B,KACA,WACA,UACA,GAAG,YAIH,oBAAC,mBAAmB,SAApB;CACE,WAAW,GAAG,0IAA0I,UAAU;CAClK,aAAU;CACV,eAAY;CACP;CACL,GAAI;WAEJ,oBAAC,OAAD;EACE,WAAU;EACV,aAAU;EAET;EACG;CACqB;AAE/B,iBAAiB,cAAc;AAE/B,MAAa,YAA2B,OAAO,OAAO,eAAe;CACnE,SAAS;CACT,MAAM;CACN,SAAS;CACV,CAAC"}
@@ -7,7 +7,7 @@ import { cva } from "class-variance-authority";
7
7
  import { createPortal } from "react-dom";
8
8
 
9
9
  //#region src/components/Alert/AlertBase.tsx
10
- const alertVariants = cva(`top-2 max-w-md rounded-md px-4 py-3 text-sm gap-y-1 translate-y-0 fixed left-1/2 z-50 flex w-full -translate-x-1/2 scale-100 transform flex-col border opacity-100 transition-all duration-300 ease-in-out motion-safe:duration-300 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-full`, {
10
+ const alertVariants = cva(`top-2 max-w-md rounded-md px-4 py-3 text-sm gap-y-1 translate-y-0 fixed left-1/2 z-50 flex w-full -translate-x-1/2 scale-100 transform flex-col border opacity-100 transition-opacity duration-200 ease-out motion-safe:duration-200 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-full`, {
11
11
  variants: { variant: {
12
12
  default: "border-alert-border bg-alert-bg",
13
13
  success: "border-alert-success-border bg-alert-success-bg",
@@ -1 +1 @@
1
- {"version":3,"file":"AlertBase.js","names":[],"sources":["../../src/components/Alert/AlertBase.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { useEffect, useState, type HTMLAttributes, type ReactNode, type Ref } from 'react'\nimport { createPortal } from 'react-dom'\n\nconst alertVariants = cva(\n `top-2 max-w-md rounded-md px-4 py-3 text-sm gap-y-1 translate-y-0 fixed left-1/2 z-50 flex w-full -translate-x-1/2 scale-100 transform flex-col border opacity-100 transition-all duration-300 ease-in-out motion-safe:duration-300 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-full`,\n {\n variants: {\n variant: {\n default: 'border-alert-border bg-alert-bg',\n success: 'border-alert-success-border bg-alert-success-bg',\n warning: 'border-alert-warning-border bg-alert-warning-bg',\n danger: 'border-alert-danger-border bg-alert-danger-bg',\n info: 'border-alert-info-border bg-alert-info-bg',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n)\n\nconst variantColors = {\n success: 'text-alert-success-text [&_p]:text-alert-success-text',\n warning: 'text-alert-warning-text [&_p]:text-alert-warning-text',\n danger: 'text-alert-danger-text [&_p]:text-alert-danger-text',\n info: 'text-alert-info-text [&_p]:text-alert-info-text',\n default: 'text-alert-text [&_p]:text-alert-text',\n}\n\ntype AlertVariant = 'default' | 'success' | 'warning' | 'danger' | 'info'\n\nexport const AlertBase = ({\n ref,\n className,\n variant,\n ...props\n}: HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof alertVariants> & {\n ref?: Ref<HTMLDivElement>\n }) => (\n <div\n className={cn(alertVariants({ variant }), className)}\n data-slot='alert'\n data-testid='spectral-alert'\n ref={ref}\n role='alert'\n {...props}\n />\n)\nAlertBase.displayName = 'AlertBase'\n\nexport const AlertHeader = ({\n className,\n ref,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n}) => (\n <div\n className={cn('gap-2 [&>svg]:size-6 flex items-center [&>svg]:shrink-0', className)}\n data-slot='alert-header'\n ref={ref}\n {...props}\n />\n)\nAlertHeader.displayName = 'AlertHeader'\n\nexport const AlertTitle = ({\n className,\n ref,\n variant,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n variant: AlertVariant\n}) => (\n <div\n className={cn(variantColors[variant], 'font-semibold text-base tracking-tight line-clamp-1 flex-1', className)}\n data-slot='alert-title'\n data-testid='spectral-alert-title'\n ref={ref}\n {...props}\n />\n)\nAlertTitle.displayName = 'AlertTitle'\n\nexport const AlertDescription = ({\n className,\n ref,\n variant,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n variant: AlertVariant\n}) => (\n <div\n className={cn(variantColors[variant], 'gap-1 text-sm [&_p]:leading-relaxed grid justify-items-start', className)}\n data-slot='alert-description'\n data-testid='spectral-alert-description'\n ref={ref}\n {...props}\n />\n)\nAlertDescription.displayName = 'AlertDescription'\n\nexport const AlertCloseButton = ({\n className,\n ref,\n variant,\n ...props\n}: HTMLAttributes<SVGSVGElement> & {\n ref?: Ref<SVGSVGElement>\n variant: AlertVariant\n}) => (\n <CloseIcon\n aria-label='Close alert'\n className={cn(variantColors[variant], 'rounded shrink-0 cursor-pointer outline-transparent focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-text-secondary', className)}\n data-slot='close-icon'\n data-testid='spectral-alert-close-button'\n ref={ref}\n size={20}\n tabIndex={0}\n {...props}\n />\n)\nAlertCloseButton.displayName = 'AlertCloseButton'\n\ninterface AlertPortalProps {\n children: ReactNode\n container?: Element | DocumentFragment\n}\n\nexport const AlertPortal = ({ children, container }: AlertPortalProps) => {\n const [mounted, setMounted] = useState(false)\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n if (!mounted) return null\n\n return createPortal(children, container ?? document.body)\n}\n"],"mappings":";;;;;;;;;AAMA,MAAM,gBAAgB,IACpB,qTACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,SAAS;EACT,SAAS;EACT,QAAQ;EACR,MAAM;EACP,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CACF;AAED,MAAM,gBAAgB;CACpB,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,SAAS;CACV;AAID,MAAa,aAAa,EACxB,KACA,WACA,SACA,GAAG,YAKH,oBAAC,OAAD;CACE,WAAW,GAAG,cAAc,EAAE,SAAS,CAAC,EAAE,UAAU;CACpD,aAAU;CACV,eAAY;CACP;CACL,MAAK;CACL,GAAI;CACJ;AAEJ,UAAU,cAAc;AAExB,MAAa,eAAe,EAC1B,WACA,KACA,GAAG,YAIH,oBAAC,OAAD;CACE,WAAW,GAAG,2DAA2D,UAAU;CACnF,aAAU;CACL;CACL,GAAI;CACJ;AAEJ,YAAY,cAAc;AAE1B,MAAa,cAAc,EACzB,WACA,KACA,SACA,GAAG,YAKH,oBAAC,OAAD;CACE,WAAW,GAAG,cAAc,UAAU,8DAA8D,UAAU;CAC9G,aAAU;CACV,eAAY;CACP;CACL,GAAI;CACJ;AAEJ,WAAW,cAAc;AAEzB,MAAa,oBAAoB,EAC/B,WACA,KACA,SACA,GAAG,YAKH,oBAAC,OAAD;CACE,WAAW,GAAG,cAAc,UAAU,gEAAgE,UAAU;CAChH,aAAU;CACV,eAAY;CACP;CACL,GAAI;CACJ;AAEJ,iBAAiB,cAAc;AAE/B,MAAa,oBAAoB,EAC/B,WACA,KACA,SACA,GAAG,YAKH,oBAAC,WAAD;CACE,cAAW;CACX,WAAW,GAAG,cAAc,UAAU,mJAAmJ,UAAU;CACnM,aAAU;CACV,eAAY;CACP;CACL,MAAM;CACN,UAAU;CACV,GAAI;CACJ;AAEJ,iBAAiB,cAAc;AAO/B,MAAa,eAAe,EAAE,UAAU,gBAAkC;CACxE,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;AAE7C,iBAAgB;AACd,aAAW,KAAK;AAChB,eAAa,WAAW,MAAM;IAC7B,EAAE,CAAC;AAEN,KAAI,CAAC,QAAS,QAAO;AAErB,QAAO,aAAa,UAAU,aAAa,SAAS,KAAK"}
1
+ {"version":3,"file":"AlertBase.js","names":[],"sources":["../../src/components/Alert/AlertBase.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { useEffect, useState, type HTMLAttributes, type ReactNode, type Ref } from 'react'\nimport { createPortal } from 'react-dom'\n\nconst alertVariants = cva(\n `top-2 max-w-md rounded-md px-4 py-3 text-sm gap-y-1 translate-y-0 fixed left-1/2 z-50 flex w-full -translate-x-1/2 scale-100 transform flex-col border opacity-100 transition-opacity duration-200 ease-out motion-safe:duration-200 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-full`,\n {\n variants: {\n variant: {\n default: 'border-alert-border bg-alert-bg',\n success: 'border-alert-success-border bg-alert-success-bg',\n warning: 'border-alert-warning-border bg-alert-warning-bg',\n danger: 'border-alert-danger-border bg-alert-danger-bg',\n info: 'border-alert-info-border bg-alert-info-bg',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n)\n\nconst variantColors = {\n success: 'text-alert-success-text [&_p]:text-alert-success-text',\n warning: 'text-alert-warning-text [&_p]:text-alert-warning-text',\n danger: 'text-alert-danger-text [&_p]:text-alert-danger-text',\n info: 'text-alert-info-text [&_p]:text-alert-info-text',\n default: 'text-alert-text [&_p]:text-alert-text',\n}\n\ntype AlertVariant = 'default' | 'success' | 'warning' | 'danger' | 'info'\n\nexport const AlertBase = ({\n ref,\n className,\n variant,\n ...props\n}: HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof alertVariants> & {\n ref?: Ref<HTMLDivElement>\n }) => (\n <div\n className={cn(alertVariants({ variant }), className)}\n data-slot='alert'\n data-testid='spectral-alert'\n ref={ref}\n role='alert'\n {...props}\n />\n)\nAlertBase.displayName = 'AlertBase'\n\nexport const AlertHeader = ({\n className,\n ref,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n}) => (\n <div\n className={cn('gap-2 [&>svg]:size-6 flex items-center [&>svg]:shrink-0', className)}\n data-slot='alert-header'\n ref={ref}\n {...props}\n />\n)\nAlertHeader.displayName = 'AlertHeader'\n\nexport const AlertTitle = ({\n className,\n ref,\n variant,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n variant: AlertVariant\n}) => (\n <div\n className={cn(variantColors[variant], 'font-semibold text-base tracking-tight line-clamp-1 flex-1', className)}\n data-slot='alert-title'\n data-testid='spectral-alert-title'\n ref={ref}\n {...props}\n />\n)\nAlertTitle.displayName = 'AlertTitle'\n\nexport const AlertDescription = ({\n className,\n ref,\n variant,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n variant: AlertVariant\n}) => (\n <div\n className={cn(variantColors[variant], 'gap-1 text-sm [&_p]:leading-relaxed grid justify-items-start', className)}\n data-slot='alert-description'\n data-testid='spectral-alert-description'\n ref={ref}\n {...props}\n />\n)\nAlertDescription.displayName = 'AlertDescription'\n\nexport const AlertCloseButton = ({\n className,\n ref,\n variant,\n ...props\n}: HTMLAttributes<SVGSVGElement> & {\n ref?: Ref<SVGSVGElement>\n variant: AlertVariant\n}) => (\n <CloseIcon\n aria-label='Close alert'\n className={cn(variantColors[variant], 'rounded shrink-0 cursor-pointer outline-transparent focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-text-secondary', className)}\n data-slot='close-icon'\n data-testid='spectral-alert-close-button'\n ref={ref}\n size={20}\n tabIndex={0}\n {...props}\n />\n)\nAlertCloseButton.displayName = 'AlertCloseButton'\n\ninterface AlertPortalProps {\n children: ReactNode\n container?: Element | DocumentFragment\n}\n\nexport const AlertPortal = ({ children, container }: AlertPortalProps) => {\n const [mounted, setMounted] = useState(false)\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n if (!mounted) return null\n\n return createPortal(children, container ?? document.body)\n}\n"],"mappings":";;;;;;;;;AAMA,MAAM,gBAAgB,IACpB,sTACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,SAAS;EACT,SAAS;EACT,QAAQ;EACR,MAAM;EACP,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CACF;AAED,MAAM,gBAAgB;CACpB,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,SAAS;CACV;AAID,MAAa,aAAa,EACxB,KACA,WACA,SACA,GAAG,YAKH,oBAAC,OAAD;CACE,WAAW,GAAG,cAAc,EAAE,SAAS,CAAC,EAAE,UAAU;CACpD,aAAU;CACV,eAAY;CACP;CACL,MAAK;CACL,GAAI;CACJ;AAEJ,UAAU,cAAc;AAExB,MAAa,eAAe,EAC1B,WACA,KACA,GAAG,YAIH,oBAAC,OAAD;CACE,WAAW,GAAG,2DAA2D,UAAU;CACnF,aAAU;CACL;CACL,GAAI;CACJ;AAEJ,YAAY,cAAc;AAE1B,MAAa,cAAc,EACzB,WACA,KACA,SACA,GAAG,YAKH,oBAAC,OAAD;CACE,WAAW,GAAG,cAAc,UAAU,8DAA8D,UAAU;CAC9G,aAAU;CACV,eAAY;CACP;CACL,GAAI;CACJ;AAEJ,WAAW,cAAc;AAEzB,MAAa,oBAAoB,EAC/B,WACA,KACA,SACA,GAAG,YAKH,oBAAC,OAAD;CACE,WAAW,GAAG,cAAc,UAAU,gEAAgE,UAAU;CAChH,aAAU;CACV,eAAY;CACP;CACL,GAAI;CACJ;AAEJ,iBAAiB,cAAc;AAE/B,MAAa,oBAAoB,EAC/B,WACA,KACA,SACA,GAAG,YAKH,oBAAC,WAAD;CACE,cAAW;CACX,WAAW,GAAG,cAAc,UAAU,mJAAmJ,UAAU;CACnM,aAAU;CACV,eAAY;CACP;CACL,MAAM;CACN,UAAU;CACV,GAAI;CACJ;AAEJ,iBAAiB,cAAc;AAO/B,MAAa,eAAe,EAAE,UAAU,gBAAkC;CACxE,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;AAE7C,iBAAgB;AACd,aAAW,KAAK;AAChB,eAAa,WAAW,MAAM;IAC7B,EAAE,CAAC;AAEN,KAAI,CAAC,QAAS,QAAO;AAErB,QAAO,aAAa,UAAU,aAAa,SAAS,KAAK"}
package/dist/Alert.js CHANGED
@@ -24,7 +24,7 @@ const Alert = ({ className, description, icon, id, onClose, title, variant = "de
24
24
  setTimeout(() => {
25
25
  if (wrapperRef.current) wrapperRef.current.style.display = "none";
26
26
  onClose?.();
27
- }, 300);
27
+ }, 200);
28
28
  }
29
29
  }, [onClose]);
30
30
  useEffect(() => {
@@ -43,8 +43,8 @@ const Alert = ({ className, description, icon, id, onClose, title, variant = "de
43
43
  closeAlert();
44
44
  }, [closeAlert]);
45
45
  return /* @__PURE__ */ jsx(AlertPortal, { children: /* @__PURE__ */ jsxs(AlertBase, {
46
- "aria-live": new Set(["danger", "warning"]).has(variant) ? "assertive" : "polite",
47
- className: cn("alert-wrapper transition-opacity duration-300", className),
46
+ "aria-live": variant === "warning" || variant === "danger" ? "assertive" : "polite",
47
+ className: cn("alert-wrapper transition-opacity duration-200 ease-out", className),
48
48
  "data-slot": "alert",
49
49
  "data-variant": variant,
50
50
  id,
package/dist/Alert.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Alert.js","names":[],"sources":["../src/components/Alert/Alert.tsx"],"sourcesContent":["import { CheckSquareIcon, CloseCircleIcon, InfoIcon, WarningIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { type ReactNode, useCallback, useEffect, useRef } from 'react'\nimport { AlertBase, AlertCloseButton, AlertDescription, AlertHeader, AlertPortal, AlertTitle } from './AlertBase'\n\nexport interface AlertProps {\n className?: string\n description: string | ReactNode | undefined\n icon?: ReactNode\n id: string | undefined\n onClose?: () => void\n title: string | undefined\n variant?: 'default' | 'info' | 'success' | 'warning' | 'danger'\n}\n\nexport const Alert = ({ className, description, icon, id, onClose, title, variant = 'default' }: AlertProps) => {\n const wrapperRef = useRef<HTMLDivElement | null>(null)\n\n const variantIconMap = {\n info: <InfoIcon className='text-alert-info-text' />,\n success: <CheckSquareIcon className='text-alert-success-text' />,\n warning: <WarningIcon className='text-alert-warning-text' />,\n danger: <CloseCircleIcon className='text-alert-danger-text' />,\n default: null,\n } as const\n\n const displayIcon = icon ?? variantIconMap[variant]\n\n const closeAlert = useCallback(() => {\n if (wrapperRef.current) {\n wrapperRef.current.style.opacity = '0'\n setTimeout(() => {\n if (wrapperRef.current) {\n wrapperRef.current.style.display = 'none'\n }\n onClose?.()\n }, 300)\n }\n }, [onClose])\n\n useEffect(() => {\n const handleEscapeKey = (e: globalThis.KeyboardEvent) => {\n if (e.key === 'Escape' && wrapperRef.current) {\n e.preventDefault()\n closeAlert()\n }\n }\n\n document.addEventListener('keydown', handleEscapeKey)\n\n return () => {\n document.removeEventListener('keydown', handleEscapeKey)\n }\n }, [closeAlert])\n\n const handleClose = useCallback(() => {\n closeAlert()\n }, [closeAlert])\n\n const URGENT_VARIANTS = new Set(['danger', 'warning'])\n const ariaLive = URGENT_VARIANTS.has(variant) ? 'assertive' : 'polite'\n\n return (\n <AlertPortal>\n <AlertBase\n aria-live={ariaLive}\n className={cn('alert-wrapper transition-opacity duration-300', className)}\n data-slot='alert'\n data-variant={variant}\n id={id}\n ref={wrapperRef}\n variant={variant}\n >\n <AlertHeader>\n {displayIcon}\n <AlertTitle variant={variant}>{title}</AlertTitle>\n <AlertCloseButton\n onClick={handleClose}\n variant={variant}\n />\n </AlertHeader>\n {description && (\n <AlertDescription\n className={displayIcon ? 'ml-8' : undefined}\n variant={variant}\n >\n {description}\n </AlertDescription>\n )}\n </AlertBase>\n </AlertPortal>\n )\n}\n"],"mappings":";;;;;;;;;;;AAeA,MAAa,SAAS,EAAE,WAAW,aAAa,MAAM,IAAI,SAAS,OAAO,UAAU,gBAA4B;CAC9G,MAAM,aAAa,OAA8B,KAAK;CAUtD,MAAM,cAAc,QAAQ;EAP1B,MAAM,oBAAC,UAAD,EAAU,WAAU,wBAAyB;EACnD,SAAS,oBAAC,iBAAD,EAAiB,WAAU,2BAA4B;EAChE,SAAS,oBAAC,aAAD,EAAa,WAAU,2BAA4B;EAC5D,QAAQ,oBAAC,iBAAD,EAAiB,WAAU,0BAA2B;EAC9D,SAAS;EAG+B,CAAC;CAE3C,MAAM,aAAa,kBAAkB;AACnC,MAAI,WAAW,SAAS;AACtB,cAAW,QAAQ,MAAM,UAAU;AACnC,oBAAiB;AACf,QAAI,WAAW,QACb,YAAW,QAAQ,MAAM,UAAU;AAErC,eAAW;MACV,IAAI;;IAER,CAAC,QAAQ,CAAC;AAEb,iBAAgB;EACd,MAAM,mBAAmB,MAAgC;AACvD,OAAI,EAAE,QAAQ,YAAY,WAAW,SAAS;AAC5C,MAAE,gBAAgB;AAClB,gBAAY;;;AAIhB,WAAS,iBAAiB,WAAW,gBAAgB;AAErD,eAAa;AACX,YAAS,oBAAoB,WAAW,gBAAgB;;IAEzD,CAAC,WAAW,CAAC;CAEhB,MAAM,cAAc,kBAAkB;AACpC,cAAY;IACX,CAAC,WAAW,CAAC;AAKhB,QACE,oBAAC,aAAD,YACE,qBAAC,WAAD;EACE,aALW,IADW,IAAI,CAAC,UAAU,UAAU,CACrB,CAAC,IAAI,QAAQ,GAAG,cAAc;EAMxD,WAAW,GAAG,iDAAiD,UAAU;EACzE,aAAU;EACV,gBAAc;EACV;EACJ,KAAK;EACI;YAPX,CASE,qBAAC,aAAD;GACG;GACD,oBAAC,YAAD;IAAqB;cAAU;IAAmB;GAClD,oBAAC,kBAAD;IACE,SAAS;IACA;IACT;GACU,KACb,eACC,oBAAC,kBAAD;GACE,WAAW,cAAc,SAAS;GACzB;aAER;GACgB,EAEX;KACA"}
1
+ {"version":3,"file":"Alert.js","names":[],"sources":["../src/components/Alert/Alert.tsx"],"sourcesContent":["import { CheckSquareIcon, CloseCircleIcon, InfoIcon, WarningIcon } from '@components/Icons'\nimport { cn } from '@utils/twUtils'\nimport { type ReactNode, useCallback, useEffect, useRef } from 'react'\nimport { AlertBase, AlertCloseButton, AlertDescription, AlertHeader, AlertPortal, AlertTitle } from './AlertBase'\n\nexport interface AlertProps {\n className?: string\n description: string | ReactNode | undefined\n icon?: ReactNode\n id: string | undefined\n onClose?: () => void\n title: string | undefined\n variant?: 'default' | 'info' | 'success' | 'warning' | 'danger'\n}\n\nexport const Alert = ({ className, description, icon, id, onClose, title, variant = 'default' }: AlertProps) => {\n const wrapperRef = useRef<HTMLDivElement | null>(null)\n\n const variantIconMap = {\n info: <InfoIcon className='text-alert-info-text' />,\n success: <CheckSquareIcon className='text-alert-success-text' />,\n warning: <WarningIcon className='text-alert-warning-text' />,\n danger: <CloseCircleIcon className='text-alert-danger-text' />,\n default: null,\n } as const\n\n const displayIcon = icon ?? variantIconMap[variant]\n\n const closeAlert = useCallback(() => {\n if (wrapperRef.current) {\n wrapperRef.current.style.opacity = '0'\n setTimeout(() => {\n if (wrapperRef.current) {\n wrapperRef.current.style.display = 'none'\n }\n onClose?.()\n }, 200)\n }\n }, [onClose])\n\n useEffect(() => {\n const handleEscapeKey = (e: globalThis.KeyboardEvent) => {\n if (e.key === 'Escape' && wrapperRef.current) {\n e.preventDefault()\n closeAlert()\n }\n }\n\n document.addEventListener('keydown', handleEscapeKey)\n\n return () => {\n document.removeEventListener('keydown', handleEscapeKey)\n }\n }, [closeAlert])\n\n const handleClose = useCallback(() => {\n closeAlert()\n }, [closeAlert])\n\n const ariaLive = variant === 'warning' || variant === 'danger' ? 'assertive' : 'polite'\n\n return (\n <AlertPortal>\n <AlertBase\n aria-live={ariaLive}\n className={cn('alert-wrapper transition-opacity duration-200 ease-out', className)}\n data-slot='alert'\n data-variant={variant}\n id={id}\n ref={wrapperRef}\n variant={variant}\n >\n <AlertHeader>\n {displayIcon}\n <AlertTitle variant={variant}>{title}</AlertTitle>\n <AlertCloseButton\n onClick={handleClose}\n variant={variant}\n />\n </AlertHeader>\n {description && (\n <AlertDescription\n className={displayIcon ? 'ml-8' : undefined}\n variant={variant}\n >\n {description}\n </AlertDescription>\n )}\n </AlertBase>\n </AlertPortal>\n )\n}\n"],"mappings":";;;;;;;;;;;AAeA,MAAa,SAAS,EAAE,WAAW,aAAa,MAAM,IAAI,SAAS,OAAO,UAAU,gBAA4B;CAC9G,MAAM,aAAa,OAA8B,KAAK;CAUtD,MAAM,cAAc,QAAQ;EAP1B,MAAM,oBAAC,UAAD,EAAU,WAAU,wBAAyB;EACnD,SAAS,oBAAC,iBAAD,EAAiB,WAAU,2BAA4B;EAChE,SAAS,oBAAC,aAAD,EAAa,WAAU,2BAA4B;EAC5D,QAAQ,oBAAC,iBAAD,EAAiB,WAAU,0BAA2B;EAC9D,SAAS;EAG+B,CAAC;CAE3C,MAAM,aAAa,kBAAkB;AACnC,MAAI,WAAW,SAAS;AACtB,cAAW,QAAQ,MAAM,UAAU;AACnC,oBAAiB;AACf,QAAI,WAAW,QACb,YAAW,QAAQ,MAAM,UAAU;AAErC,eAAW;MACV,IAAI;;IAER,CAAC,QAAQ,CAAC;AAEb,iBAAgB;EACd,MAAM,mBAAmB,MAAgC;AACvD,OAAI,EAAE,QAAQ,YAAY,WAAW,SAAS;AAC5C,MAAE,gBAAgB;AAClB,gBAAY;;;AAIhB,WAAS,iBAAiB,WAAW,gBAAgB;AAErD,eAAa;AACX,YAAS,oBAAoB,WAAW,gBAAgB;;IAEzD,CAAC,WAAW,CAAC;CAEhB,MAAM,cAAc,kBAAkB;AACpC,cAAY;IACX,CAAC,WAAW,CAAC;AAIhB,QACE,oBAAC,aAAD,YACE,qBAAC,WAAD;EACE,aALW,YAAY,aAAa,YAAY,WAAW,cAAc;EAMzE,WAAW,GAAG,0DAA0D,UAAU;EAClF,aAAU;EACV,gBAAc;EACV;EACJ,KAAK;EACI;YAPX,CASE,qBAAC,aAAD;GACG;GACD,oBAAC,YAAD;IAAqB;cAAU;IAAmB;GAClD,oBAAC,kBAAD;IACE,SAAS;IACA;IACT;GACU,KACb,eACC,oBAAC,kBAAD;GACE,WAAW,cAAc,SAAS;GACzB;aAER;GACgB,EAEX;KACA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.d.ts","names":[],"sources":["../src/components/Avatar/Avatar.tsx"],"mappings":";;;;;KAIK,UAAA;AAAA,UAEY,WAAA;EACf,GAAA;EACA,SAAA;EACA,QAAA,GAAW,SAAA;EACX,IAAA,GAAO,YAAA;EACP,WAAA;EACA,IAAA,GAAO,UAAA;EACP,YAAA;AAAA;AAAA,cAiCW,MAAA;EAAM,GAAA;EAAA,SAAA;EAAA,QAAA;EAAA,IAAA;EAAA,WAAA;EAAA,IAAA;EAAA;AAAA,GAAgF,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Avatar.d.ts","names":[],"sources":["../src/components/Avatar/Avatar.tsx"],"mappings":";;;;;KAIK,UAAA;AAAA,UAEY,WAAA;EACf,GAAA;EACA,SAAA;EACA,QAAA,GAAW,SAAA;EACX,IAAA,GAAO,YAAA;EACP,WAAA;EACA,IAAA,GAAO,UAAA;EACP,YAAA;AAAA;AAAA,cAuCW,MAAA;EAAM,GAAA;EAAA,SAAA;EAAA,QAAA;EAAA,IAAA;EAAA,WAAA;EAAA,IAAA;EAAA;AAAA,GAAgF,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/Avatar.js CHANGED
@@ -6,9 +6,14 @@ import { jsx } from "react/jsx-runtime";
6
6
 
7
7
  //#region src/components/Avatar/Avatar.tsx
8
8
  const sizeClasses = {
9
- sm: "h-8 w-8",
10
- md: "h-10 w-10",
11
- lg: "h-12 w-12"
9
+ sm: "size-8",
10
+ md: "size-10",
11
+ lg: "size-12"
12
+ };
13
+ const imageDimensions = {
14
+ sm: 32,
15
+ md: 40,
16
+ lg: 48
12
17
  };
13
18
  const textSizeClasses = {
14
19
  sm: "text-xs",
@@ -45,14 +50,14 @@ const Avatar = ({ alt, className, fallback, icon, imageSource, size = "md", user
45
50
  const renderContent = () => {
46
51
  if (userFullName) return /* @__PURE__ */ jsx("span", {
47
52
  "aria-label": userFullName + " avatar",
48
- className: cn("font-bold tracking-tighter flex h-full w-full items-center justify-center text-text-primary font-stretch-condensed", textSizeClasses[size]),
53
+ className: cn("font-bold tracking-tighter flex size-full items-center justify-center text-text-primary font-stretch-condensed", textSizeClasses[size]),
49
54
  "data-testid": "spectral-avatar-initials",
50
55
  children: getInitials(userFullName)
51
56
  });
52
57
  if (icon) {
53
58
  const iconSize = iconSizes[size];
54
59
  return /* @__PURE__ */ jsx("span", {
55
- className: "flex h-full w-full items-center justify-center",
60
+ className: "flex size-full items-center justify-center",
56
61
  children: isValidElement(icon) ? (() => {
57
62
  const baseIconProps = {
58
63
  className: cn("shrink-0", icon.props.className),
@@ -69,23 +74,25 @@ const Avatar = ({ alt, className, fallback, icon, imageSource, size = "md", user
69
74
  if (imageSource && imageStatus === "loaded") return /* @__PURE__ */ jsx("img", {
70
75
  alt: alt ?? "Avatar",
71
76
  "aria-label": alt ?? "Avatar",
72
- className: "inset-0 absolute h-full w-full rounded-full object-cover",
77
+ className: "inset-0 absolute size-full rounded-full object-cover",
73
78
  "data-testid": "spectral-avatar-image",
79
+ height: imageDimensions[size],
74
80
  role: "img",
75
- src: imageSource
81
+ src: imageSource,
82
+ width: imageDimensions[size]
76
83
  });
77
84
  if (imageSource && imageStatus === "error" && fallback) return /* @__PURE__ */ jsx("span", {
78
- className: "flex h-full w-full items-center justify-center",
85
+ className: "flex size-full items-center justify-center",
79
86
  "data-testid": "spectral-avatar-img-error-fallback",
80
87
  children: fallback
81
88
  });
82
89
  if (fallback) return /* @__PURE__ */ jsx("span", {
83
- className: cn("flex h-full w-full items-center justify-center text-text-primary", textSizeClasses[size]),
90
+ className: cn("flex size-full items-center justify-center text-text-primary", textSizeClasses[size]),
84
91
  "data-testid": "spectral-avatar-fallback",
85
92
  children: fallback
86
93
  });
87
94
  if (imageSource && imageStatus === "loading") return /* @__PURE__ */ jsx("span", {
88
- className: "motion-safe:animate-pulse flex h-full w-full items-center justify-center",
95
+ className: "motion-safe:animate-pulse flex size-full items-center justify-center",
89
96
  "data-testid": "spectral-avatar-loading"
90
97
  });
91
98
  return /* @__PURE__ */ jsx(UserIcon, {});
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.js","names":[],"sources":["../src/components/Avatar/Avatar.tsx"],"sourcesContent":["import { UserIcon } from '@components/Icons/UserIcon'\nimport { cn } from '@utils/twUtils'\nimport { cloneElement, isValidElement, useEffect, useState, type ComponentType, type ReactElement, type ReactNode } from 'react'\n\ntype AvatarSize = 'sm' | 'md' | 'lg'\n\nexport interface AvatarProps {\n alt?: string\n className?: string\n fallback?: ReactNode | string\n icon?: ReactElement\n imageSource?: string\n size?: AvatarSize\n userFullName?: string\n}\n\nconst sizeClasses = {\n sm: 'h-8 w-8',\n md: 'h-10 w-10',\n lg: 'h-12 w-12',\n}\n\nconst textSizeClasses = {\n sm: 'text-xs',\n md: 'text-base',\n lg: 'text-xl',\n}\n\nconst iconSizes = {\n sm: 24,\n md: 32,\n lg: 40,\n}\n\nconst getInitials = (name: string): string => {\n const trimmed = name.trim()\n if (!trimmed) return '?'\n\n const words = trimmed.split(/\\s+/).filter(Boolean)\n\n if (words.length === 0) return '?'\n if (words.length === 1) return words[0].charAt(0).toUpperCase()\n\n return (words[0].charAt(0) + words[words.length - 1].charAt(0)).toUpperCase()\n}\n\nexport const Avatar = ({ alt, className, fallback, icon, imageSource, size = 'md', userFullName }: AvatarProps) => {\n const [imageStatus, setImageStatus] = useState<'loading' | 'loaded' | 'error'>('loading')\n\n useEffect(() => {\n if (!imageSource) return\n\n setImageStatus('loading')\n\n const img = new Image()\n img.src = imageSource\n\n img.onload = () => setImageStatus('loaded')\n img.onerror = () => setImageStatus('error')\n\n return () => {\n img.onload = null\n img.onerror = null\n }\n }, [imageSource])\n\n const renderContent = () => {\n if (userFullName) {\n return (\n <span\n // cannot use template literals in aria-label or oxlint validation fails: https://www.w3.org/WAI/ARIA/apg/patterns/img/#labeling\n aria-label={userFullName + ' avatar'}\n className={cn('font-bold tracking-tighter flex h-full w-full items-center justify-center text-text-primary font-stretch-condensed', textSizeClasses[size as keyof typeof textSizeClasses])}\n data-testid='spectral-avatar-initials'\n >\n {getInitials(userFullName)}\n </span>\n )\n }\n\n if (icon) {\n const iconSize = iconSizes[size as keyof typeof iconSizes]\n\n return (\n <span className='flex h-full w-full items-center justify-center'>\n {isValidElement(icon)\n ? (() => {\n const baseIconProps = {\n className: cn('shrink-0', (icon.props as { className?: string }).className),\n 'aria-hidden': 'true' as const,\n }\n\n // Check if this is an icon component that accepts size prop\n const componentType = icon.type as ComponentType<unknown> & { displayName?: string }\n const isIconComponent = componentType.displayName?.includes('Icon') ?? false\n\n if (isIconComponent) {\n const iconPropsWithSize = {\n ...baseIconProps,\n size: iconSize,\n }\n return cloneElement(icon, iconPropsWithSize)\n }\n\n return cloneElement(icon, baseIconProps)\n })()\n : icon}\n </span>\n )\n }\n\n if (imageSource && imageStatus === 'loaded') {\n return (\n <img\n alt={alt ?? 'Avatar'}\n aria-label={alt ?? 'Avatar'}\n className='inset-0 absolute h-full w-full rounded-full object-cover'\n data-testid='spectral-avatar-image'\n role='img'\n src={imageSource}\n />\n )\n }\n\n if (imageSource && imageStatus === 'error' && fallback) {\n return (\n <span\n className='flex h-full w-full items-center justify-center'\n data-testid='spectral-avatar-img-error-fallback'\n >\n {fallback}\n </span>\n )\n }\n\n // Show fallback while image is loading or if no image provided\n if (fallback) {\n return (\n <span\n className={cn('flex h-full w-full items-center justify-center text-text-primary', textSizeClasses[size as keyof typeof textSizeClasses])}\n data-testid='spectral-avatar-fallback'\n >\n {fallback}\n </span>\n )\n }\n\n // Show empty/skeleton state while image is loading\n if (imageSource && imageStatus === 'loading') {\n return (\n <span\n className='motion-safe:animate-pulse flex h-full w-full items-center justify-center'\n data-testid='spectral-avatar-loading'\n />\n )\n }\n\n // Last resort: (only when no imageSource and no fallback)\n return <UserIcon />\n }\n\n return (\n <div\n className={cn('relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-level-two', sizeClasses[size as keyof typeof sizeClasses], className)}\n data-slot='avatar'\n data-testid='spectral-avatar'\n >\n {renderContent()}\n </div>\n )\n}\n"],"mappings":";;;;;;;AAgBA,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,kBAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,YAAY;CAChB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,eAAe,SAAyB;CAC5C,MAAM,UAAU,KAAK,MAAM;AAC3B,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,OAAO,QAAQ;AAElD,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,KAAI,MAAM,WAAW,EAAG,QAAO,MAAM,GAAG,OAAO,EAAE,CAAC,aAAa;AAE/D,SAAQ,MAAM,GAAG,OAAO,EAAE,GAAG,MAAM,MAAM,SAAS,GAAG,OAAO,EAAE,EAAE,aAAa;;AAG/E,MAAa,UAAU,EAAE,KAAK,WAAW,UAAU,MAAM,aAAa,OAAO,MAAM,mBAAgC;CACjH,MAAM,CAAC,aAAa,kBAAkB,SAAyC,UAAU;AAEzF,iBAAgB;AACd,MAAI,CAAC,YAAa;AAElB,iBAAe,UAAU;EAEzB,MAAM,MAAM,IAAI,OAAO;AACvB,MAAI,MAAM;AAEV,MAAI,eAAe,eAAe,SAAS;AAC3C,MAAI,gBAAgB,eAAe,QAAQ;AAE3C,eAAa;AACX,OAAI,SAAS;AACb,OAAI,UAAU;;IAEf,CAAC,YAAY,CAAC;CAEjB,MAAM,sBAAsB;AAC1B,MAAI,aACF,QACE,oBAAC,QAAD;GAEE,cAAY,eAAe;GAC3B,WAAW,GAAG,sHAAsH,gBAAgB,MAAsC;GAC1L,eAAY;aAEX,YAAY,aAAa;GACrB;AAIX,MAAI,MAAM;GACR,MAAM,WAAW,UAAU;AAE3B,UACE,oBAAC,QAAD;IAAM,WAAU;cACb,eAAe,KAAK,UACV;KACL,MAAM,gBAAgB;MACpB,WAAW,GAAG,YAAa,KAAK,MAAiC,UAAU;MAC3E,eAAe;MAChB;AAMD,SAHsB,KAAK,KACW,aAAa,SAAS,OAAO,IAAI,MAOrE,QAAO,aAAa,MAAM;MAHxB,GAAG;MACH,MAAM;MAEmC,CAAC;AAG9C,YAAO,aAAa,MAAM,cAAc;QACtC,GACJ;IACC;;AAIX,MAAI,eAAe,gBAAgB,SACjC,QACE,oBAAC,OAAD;GACE,KAAK,OAAO;GACZ,cAAY,OAAO;GACnB,WAAU;GACV,eAAY;GACZ,MAAK;GACL,KAAK;GACL;AAIN,MAAI,eAAe,gBAAgB,WAAW,SAC5C,QACE,oBAAC,QAAD;GACE,WAAU;GACV,eAAY;aAEX;GACI;AAKX,MAAI,SACF,QACE,oBAAC,QAAD;GACE,WAAW,GAAG,oEAAoE,gBAAgB,MAAsC;GACxI,eAAY;aAEX;GACI;AAKX,MAAI,eAAe,gBAAgB,UACjC,QACE,oBAAC,QAAD;GACE,WAAU;GACV,eAAY;GACZ;AAKN,SAAO,oBAAC,UAAD,EAAY;;AAGrB,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,uGAAuG,YAAY,OAAmC,UAAU;EAC9K,aAAU;EACV,eAAY;YAEX,eAAe;EACZ"}
1
+ {"version":3,"file":"Avatar.js","names":[],"sources":["../src/components/Avatar/Avatar.tsx"],"sourcesContent":["import { UserIcon } from '@components/Icons/UserIcon'\nimport { cn } from '@utils/twUtils'\nimport { cloneElement, isValidElement, useEffect, useState, type ComponentType, type ReactElement, type ReactNode } from 'react'\n\ntype AvatarSize = 'sm' | 'md' | 'lg'\n\nexport interface AvatarProps {\n alt?: string\n className?: string\n fallback?: ReactNode | string\n icon?: ReactElement\n imageSource?: string\n size?: AvatarSize\n userFullName?: string\n}\n\nconst sizeClasses = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n}\n\nconst imageDimensions = {\n sm: 32,\n md: 40,\n lg: 48,\n}\n\nconst textSizeClasses = {\n sm: 'text-xs',\n md: 'text-base',\n lg: 'text-xl',\n}\n\nconst iconSizes = {\n sm: 24,\n md: 32,\n lg: 40,\n}\n\nconst getInitials = (name: string): string => {\n const trimmed = name.trim()\n if (!trimmed) return '?'\n\n const words = trimmed.split(/\\s+/).filter(Boolean)\n\n if (words.length === 0) return '?'\n if (words.length === 1) return words[0].charAt(0).toUpperCase()\n\n return (words[0].charAt(0) + words[words.length - 1].charAt(0)).toUpperCase()\n}\n\nexport const Avatar = ({ alt, className, fallback, icon, imageSource, size = 'md', userFullName }: AvatarProps) => {\n const [imageStatus, setImageStatus] = useState<'loading' | 'loaded' | 'error'>('loading')\n\n useEffect(() => {\n if (!imageSource) return\n\n setImageStatus('loading')\n\n const img = new Image()\n img.src = imageSource\n\n img.onload = () => setImageStatus('loaded')\n img.onerror = () => setImageStatus('error')\n\n return () => {\n img.onload = null\n img.onerror = null\n }\n }, [imageSource])\n\n const renderContent = () => {\n if (userFullName) {\n return (\n <span\n // cannot use template literals in aria-label or oxlint validation fails: https://www.w3.org/WAI/ARIA/apg/patterns/img/#labeling\n aria-label={userFullName + ' avatar'}\n className={cn('font-bold tracking-tighter flex size-full items-center justify-center text-text-primary font-stretch-condensed', textSizeClasses[size as keyof typeof textSizeClasses])}\n data-testid='spectral-avatar-initials'\n >\n {getInitials(userFullName)}\n </span>\n )\n }\n\n if (icon) {\n const iconSize = iconSizes[size as keyof typeof iconSizes]\n\n return (\n <span className='flex size-full items-center justify-center'>\n {isValidElement(icon)\n ? (() => {\n const baseIconProps = {\n className: cn('shrink-0', (icon.props as { className?: string }).className),\n 'aria-hidden': 'true' as const,\n }\n\n // Check if this is an icon component that accepts size prop\n const componentType = icon.type as ComponentType<unknown> & { displayName?: string }\n const isIconComponent = componentType.displayName?.includes('Icon') ?? false\n\n if (isIconComponent) {\n const iconPropsWithSize = {\n ...baseIconProps,\n size: iconSize,\n }\n return cloneElement(icon, iconPropsWithSize)\n }\n\n return cloneElement(icon, baseIconProps)\n })()\n : icon}\n </span>\n )\n }\n\n if (imageSource && imageStatus === 'loaded') {\n return (\n <img\n alt={alt ?? 'Avatar'}\n aria-label={alt ?? 'Avatar'}\n className='inset-0 absolute size-full rounded-full object-cover'\n data-testid='spectral-avatar-image'\n height={imageDimensions[size as keyof typeof imageDimensions]}\n role='img'\n src={imageSource}\n width={imageDimensions[size as keyof typeof imageDimensions]}\n />\n )\n }\n\n if (imageSource && imageStatus === 'error' && fallback) {\n return (\n <span\n className='flex size-full items-center justify-center'\n data-testid='spectral-avatar-img-error-fallback'\n >\n {fallback}\n </span>\n )\n }\n\n // Show fallback while image is loading or if no image provided\n if (fallback) {\n return (\n <span\n className={cn('flex size-full items-center justify-center text-text-primary', textSizeClasses[size as keyof typeof textSizeClasses])}\n data-testid='spectral-avatar-fallback'\n >\n {fallback}\n </span>\n )\n }\n\n // Show empty/skeleton state while image is loading\n if (imageSource && imageStatus === 'loading') {\n return (\n <span\n className='motion-safe:animate-pulse flex size-full items-center justify-center'\n data-testid='spectral-avatar-loading'\n />\n )\n }\n\n // Last resort: (only when no imageSource and no fallback)\n return <UserIcon />\n }\n\n return (\n <div\n className={cn('relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-level-two', sizeClasses[size as keyof typeof sizeClasses], className)}\n data-slot='avatar'\n data-testid='spectral-avatar'\n >\n {renderContent()}\n </div>\n )\n}\n"],"mappings":";;;;;;;AAgBA,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,kBAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,kBAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,YAAY;CAChB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,eAAe,SAAyB;CAC5C,MAAM,UAAU,KAAK,MAAM;AAC3B,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,OAAO,QAAQ;AAElD,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,KAAI,MAAM,WAAW,EAAG,QAAO,MAAM,GAAG,OAAO,EAAE,CAAC,aAAa;AAE/D,SAAQ,MAAM,GAAG,OAAO,EAAE,GAAG,MAAM,MAAM,SAAS,GAAG,OAAO,EAAE,EAAE,aAAa;;AAG/E,MAAa,UAAU,EAAE,KAAK,WAAW,UAAU,MAAM,aAAa,OAAO,MAAM,mBAAgC;CACjH,MAAM,CAAC,aAAa,kBAAkB,SAAyC,UAAU;AAEzF,iBAAgB;AACd,MAAI,CAAC,YAAa;AAElB,iBAAe,UAAU;EAEzB,MAAM,MAAM,IAAI,OAAO;AACvB,MAAI,MAAM;AAEV,MAAI,eAAe,eAAe,SAAS;AAC3C,MAAI,gBAAgB,eAAe,QAAQ;AAE3C,eAAa;AACX,OAAI,SAAS;AACb,OAAI,UAAU;;IAEf,CAAC,YAAY,CAAC;CAEjB,MAAM,sBAAsB;AAC1B,MAAI,aACF,QACE,oBAAC,QAAD;GAEE,cAAY,eAAe;GAC3B,WAAW,GAAG,kHAAkH,gBAAgB,MAAsC;GACtL,eAAY;aAEX,YAAY,aAAa;GACrB;AAIX,MAAI,MAAM;GACR,MAAM,WAAW,UAAU;AAE3B,UACE,oBAAC,QAAD;IAAM,WAAU;cACb,eAAe,KAAK,UACV;KACL,MAAM,gBAAgB;MACpB,WAAW,GAAG,YAAa,KAAK,MAAiC,UAAU;MAC3E,eAAe;MAChB;AAMD,SAHsB,KAAK,KACW,aAAa,SAAS,OAAO,IAAI,MAOrE,QAAO,aAAa,MAAM;MAHxB,GAAG;MACH,MAAM;MAEmC,CAAC;AAG9C,YAAO,aAAa,MAAM,cAAc;QACtC,GACJ;IACC;;AAIX,MAAI,eAAe,gBAAgB,SACjC,QACE,oBAAC,OAAD;GACE,KAAK,OAAO;GACZ,cAAY,OAAO;GACnB,WAAU;GACV,eAAY;GACZ,QAAQ,gBAAgB;GACxB,MAAK;GACL,KAAK;GACL,OAAO,gBAAgB;GACvB;AAIN,MAAI,eAAe,gBAAgB,WAAW,SAC5C,QACE,oBAAC,QAAD;GACE,WAAU;GACV,eAAY;aAEX;GACI;AAKX,MAAI,SACF,QACE,oBAAC,QAAD;GACE,WAAW,GAAG,gEAAgE,gBAAgB,MAAsC;GACpI,eAAY;aAEX;GACI;AAKX,MAAI,eAAe,gBAAgB,UACjC,QACE,oBAAC,QAAD;GACE,WAAU;GACV,eAAY;GACZ;AAKN,SAAO,oBAAC,UAAD,EAAY;;AAGrB,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,uGAAuG,YAAY,OAAmC,UAAU;EAC9K,aAAU;EACV,eAAY;YAEX,eAAe;EACZ"}
@@ -6,7 +6,7 @@ import { jsx } from "react/jsx-runtime";
6
6
  import { cva } from "class-variance-authority";
7
7
 
8
8
  //#region src/components/ButtonGroup/ButtonGroupButton.tsx
9
- const buttonVariants = cva(`gap-2 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 aria-invalid:ring-destructive/20 aria-invalid:border-destructive inline-flex shrink-0 cursor-pointer items-center justify-center rounded-[var(--radius,0.375rem)] bg-level-one whitespace-nowrap text-text-primary transition-all outline-none hover:bg-level-two focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent active:bg-accent active:text-text-inverted disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0`, {
9
+ const buttonVariants = cva(`gap-2 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 aria-invalid:ring-destructive/20 aria-invalid:border-destructive inline-flex shrink-0 cursor-pointer items-center justify-center rounded-[var(--radius,0.375rem)] bg-level-one whitespace-nowrap text-text-primary transition-colors outline-none hover:bg-level-two focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent active:bg-accent active:text-text-inverted disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0`, {
10
10
  variants: {
11
11
  variant: {
12
12
  default: "",
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonGroupButton.js","names":[],"sources":["../../src/components/ButtonGroup/ButtonGroupButton.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { type ComponentProps } from 'react'\n\nexport const buttonVariants = cva(\n `gap-2 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 aria-invalid:ring-destructive/20 aria-invalid:border-destructive inline-flex shrink-0 cursor-pointer items-center justify-center rounded-[var(--radius,0.375rem)] bg-level-one whitespace-nowrap text-text-primary transition-all outline-none hover:bg-level-two focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent active:bg-accent active:text-text-inverted disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0`,\n {\n variants: {\n variant: {\n default: '',\n outline: 'border border-level-three',\n },\n size: {\n md: 'h-9 px-4 py-2 has-[>svg]:px-3',\n sm: 'h-8 gap-1.5 px-3 has-[>svg]:px-2.5',\n lg: 'h-10 px-6 has-[>svg]:px-4',\n 'icon-md': 'size-9',\n 'icon-sm': 'size-8',\n 'icon-lg': 'size-10',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'md',\n },\n },\n)\n\nexport const ButtonGroupButton = ({\n asChild = false,\n className,\n size,\n variant,\n ...props\n}: ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) => {\n const Comp = asChild ? Slot : 'button'\n\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n data-size={size}\n data-slot='button-group-item'\n data-variant={variant}\n {...props}\n />\n )\n}\nButtonGroupButton.displayName = 'ButtonGroupButton'\n"],"mappings":";;;;;;;;AAKA,MAAa,iBAAiB,IAC5B,6jBACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,SAAS;GACV;EACD,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,WAAW;GACX,WAAW;GACX,WAAW;GACZ;EACF;CACD,iBAAiB;EACf,SAAS;EACT,MAAM;EACP;CACF,CACF;AAED,MAAa,qBAAqB,EAChC,UAAU,OACV,WACA,MACA,SACA,GAAG,YAIG;AAGN,QACE,oBAHW,UAAU,OAAO,UAG5B;EACE,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;GAAW,CAAC,CAAC;EAC3D,aAAW;EACX,aAAU;EACV,gBAAc;EACd,GAAI;EACJ;;AAGN,kBAAkB,cAAc"}
1
+ {"version":3,"file":"ButtonGroupButton.js","names":[],"sources":["../../src/components/ButtonGroup/ButtonGroupButton.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { type ComponentProps } from 'react'\n\nexport const buttonVariants = cva(\n `gap-2 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 aria-invalid:ring-destructive/20 aria-invalid:border-destructive inline-flex shrink-0 cursor-pointer items-center justify-center rounded-[var(--radius,0.375rem)] bg-level-one whitespace-nowrap text-text-primary transition-colors outline-none hover:bg-level-two focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent active:bg-accent active:text-text-inverted disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0`,\n {\n variants: {\n variant: {\n default: '',\n outline: 'border border-level-three',\n },\n size: {\n md: 'h-9 px-4 py-2 has-[>svg]:px-3',\n sm: 'h-8 gap-1.5 px-3 has-[>svg]:px-2.5',\n lg: 'h-10 px-6 has-[>svg]:px-4',\n 'icon-md': 'size-9',\n 'icon-sm': 'size-8',\n 'icon-lg': 'size-10',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'md',\n },\n },\n)\n\nexport const ButtonGroupButton = ({\n asChild = false,\n className,\n size,\n variant,\n ...props\n}: ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) => {\n const Comp = asChild ? Slot : 'button'\n\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n data-size={size}\n data-slot='button-group-item'\n data-variant={variant}\n {...props}\n />\n )\n}\nButtonGroupButton.displayName = 'ButtonGroupButton'\n"],"mappings":";;;;;;;;AAKA,MAAa,iBAAiB,IAC5B,gkBACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,SAAS;GACV;EACD,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,WAAW;GACX,WAAW;GACX,WAAW;GACZ;EACF;CACD,iBAAiB;EACf,SAAS;EACT,MAAM;EACP;CACF,CACF;AAED,MAAa,qBAAqB,EAChC,UAAU,OACV,WACA,MACA,SACA,GAAG,YAIG;AAGN,QACE,oBAHW,UAAU,OAAO,UAG5B;EACE,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;GAAW,CAAC,CAAC;EAC3D,aAAW;EACX,aAAU;EACV,gBAAc;EACd,GAAI;EACJ;;AAGN,kBAAkB,cAAc"}
@@ -30,7 +30,7 @@ const ControlGroup = ({ className, disabled, errorMessage, id, messageReserveLin
30
30
  },
31
31
  children: /* @__PURE__ */ jsxs("div", {
32
32
  "data-slot": "control-group-field",
33
- className: "space-y-1.5 w-full",
33
+ className: "gap-1.5 flex w-full flex-col",
34
34
  children: [
35
35
  /* @__PURE__ */ jsx("div", {
36
36
  "data-slot": "control-group",
@@ -1 +1 @@
1
- {"version":3,"file":"ControlGroup.js","names":[],"sources":["../src/components/ControlGroup/ControlGroup.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId, useFormFieldState, WarningMessage, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { createContext, useContext, type ComponentProps } from 'react'\n\ninterface ControlGroupContextValue {\n messageId?: string\n isDisabled: boolean\n isInvalid: boolean\n isLoading: boolean\n orientation: 'horizontal' | 'vertical'\n state: FormFieldState\n}\n\nconst ControlGroupContext = createContext<ControlGroupContextValue | null>(null)\n\nexport const useControlGroup = () => {\n const context = useContext(ControlGroupContext)\n if (context === null) {\n throw new Error('useControlGroup must be used within a ControlGroup')\n }\n return context\n}\n\nexport interface ControlGroupProps extends ComponentProps<'div'> {\n disabled?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n orientation?: 'horizontal' | 'vertical'\n state?: FormFieldState\n warningMessage?: string | string[] | Record<string, unknown> | null\n}\n\nexport const ControlGroup = ({ className, disabled, errorMessage, id, messageReserveLines = 1, messageReserveSpace = false, name, orientation = 'horizontal', state = 'default', warningMessage, ...props }: ControlGroupProps) => {\n const groupId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(groupId)\n const warningMessageId = `${groupId}-warning`\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n\n return (\n <ControlGroupContext.Provider value={{ messageId, isDisabled, isInvalid, isLoading, orientation, state }}>\n <div\n data-slot='control-group-field'\n className='space-y-1.5 w-full'\n >\n <div\n data-slot='control-group'\n data-orientation={orientation}\n data-state={state}\n id={groupId}\n role='group'\n aria-describedby={messageId}\n className={cn('group flex w-full', orientation === 'vertical' && 'flex-col', isDisabled && 'pointer-events-none opacity-50', className)}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-control-group-error-message'\n id={errorMessageId}\n message={isInvalid ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-control-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </ControlGroupContext.Provider>\n )\n}\n\nexport const ControlGroupItem = ({ className, ...props }: ComponentProps<typeof Slot>) => {\n const { orientation } = useControlGroup()\n\n return (\n <Slot\n data-slot='control-group-item'\n className={cn(\n 'rounded-none focus-within:z-10 hover:z-10',\n orientation === 'horizontal' && 'first:rounded-s-md last:me-0 last:rounded-e-md -me-0.5 h-auto',\n orientation === 'vertical' && 'first:rounded-ss-md first:rounded-se-md last:rounded-ee-md last:rounded-es-md last:mbe-0 -mbe-0.5 w-auto',\n className,\n )}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;;;;AAcA,MAAM,sBAAsB,cAA+C,KAAK;AAEhF,MAAa,wBAAwB;CACnC,MAAM,UAAU,WAAW,oBAAoB;AAC/C,KAAI,YAAY,KACd,OAAM,IAAI,MAAM,qDAAqD;AAEvE,QAAO;;AAeT,MAAa,gBAAgB,EAAE,WAAW,UAAU,cAAc,IAAI,sBAAsB,GAAG,sBAAsB,OAAO,MAAM,cAAc,cAAc,QAAQ,WAAW,gBAAgB,GAAG,YAA+B;CACjO,MAAM,UAAU,eAAe,IAAI,KAAK;CACxC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,mBAAmB,GAAG,QAAQ;CACpC,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAkB,UAAU,MAAM;CAC/E,MAAM,YAAY,UAAU,WAAW,eAAe,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;AAElI,QACE,oBAAC,oBAAoB,UAArB;EAA8B,OAAO;GAAE;GAAW;GAAY;GAAW;GAAW;GAAa;GAAO;YACtG,qBAAC,OAAD;GACE,aAAU;GACV,WAAU;aAFZ;IAIE,oBAAC,OAAD;KACE,aAAU;KACV,oBAAkB;KAClB,cAAY;KACZ,IAAI;KACJ,MAAK;KACL,oBAAkB;KAClB,WAAW,GAAG,qBAAqB,gBAAgB,cAAc,YAAY,cAAc,kCAAkC,UAAU;KACvI,GAAI;KACJ;IACF,oBAAC,cAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,YAAY,eAAe;KACf;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACF,oBAAC,gBAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,UAAU,YAAY,iBAAiB;KAC3B;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACE;;EACuB;;AAInC,MAAa,oBAAoB,EAAE,WAAW,GAAG,YAAyC;CACxF,MAAM,EAAE,gBAAgB,iBAAiB;AAEzC,QACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GACT,6CACA,gBAAgB,gBAAgB,iEAChC,gBAAgB,cAAc,4GAC9B,UACD;EACD,GAAI;EACJ"}
1
+ {"version":3,"file":"ControlGroup.js","names":[],"sources":["../src/components/ControlGroup/ControlGroup.tsx"],"sourcesContent":["import { Slot } from '@primitives/slot'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId, useFormFieldState, WarningMessage, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { createContext, useContext, type ComponentProps } from 'react'\n\ninterface ControlGroupContextValue {\n messageId?: string\n isDisabled: boolean\n isInvalid: boolean\n isLoading: boolean\n orientation: 'horizontal' | 'vertical'\n state: FormFieldState\n}\n\nconst ControlGroupContext = createContext<ControlGroupContextValue | null>(null)\n\nexport const useControlGroup = () => {\n const context = useContext(ControlGroupContext)\n if (context === null) {\n throw new Error('useControlGroup must be used within a ControlGroup')\n }\n return context\n}\n\nexport interface ControlGroupProps extends ComponentProps<'div'> {\n disabled?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n messageReserveLines?: number\n messageReserveSpace?: boolean\n name?: string\n orientation?: 'horizontal' | 'vertical'\n state?: FormFieldState\n warningMessage?: string | string[] | Record<string, unknown> | null\n}\n\nexport const ControlGroup = ({ className, disabled, errorMessage, id, messageReserveLines = 1, messageReserveSpace = false, name, orientation = 'horizontal', state = 'default', warningMessage, ...props }: ControlGroupProps) => {\n const groupId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(groupId)\n const warningMessageId = `${groupId}-warning`\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const messageId = state === 'error' && errorMessage ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n\n return (\n <ControlGroupContext.Provider value={{ messageId, isDisabled, isInvalid, isLoading, orientation, state }}>\n <div\n data-slot='control-group-field'\n className='gap-1.5 flex w-full flex-col'\n >\n <div\n data-slot='control-group'\n data-orientation={orientation}\n data-state={state}\n id={groupId}\n role='group'\n aria-describedby={messageId}\n className={cn('group flex w-full', orientation === 'vertical' && 'flex-col', isDisabled && 'pointer-events-none opacity-50', className)}\n {...props}\n />\n <ErrorMessage\n dataTestId='spectral-control-group-error-message'\n id={errorMessageId}\n message={isInvalid ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-control-group-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n </ControlGroupContext.Provider>\n )\n}\n\nexport const ControlGroupItem = ({ className, ...props }: ComponentProps<typeof Slot>) => {\n const { orientation } = useControlGroup()\n\n return (\n <Slot\n data-slot='control-group-item'\n className={cn(\n 'rounded-none focus-within:z-10 hover:z-10',\n orientation === 'horizontal' && 'first:rounded-s-md last:me-0 last:rounded-e-md -me-0.5 h-auto',\n orientation === 'vertical' && 'first:rounded-ss-md first:rounded-se-md last:rounded-ee-md last:rounded-es-md last:mbe-0 -mbe-0.5 w-auto',\n className,\n )}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;;;;AAcA,MAAM,sBAAsB,cAA+C,KAAK;AAEhF,MAAa,wBAAwB;CACnC,MAAM,UAAU,WAAW,oBAAoB;AAC/C,KAAI,YAAY,KACd,OAAM,IAAI,MAAM,qDAAqD;AAEvE,QAAO;;AAeT,MAAa,gBAAgB,EAAE,WAAW,UAAU,cAAc,IAAI,sBAAsB,GAAG,sBAAsB,OAAO,MAAM,cAAc,cAAc,QAAQ,WAAW,gBAAgB,GAAG,YAA+B;CACjO,MAAM,UAAU,eAAe,IAAI,KAAK;CACxC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,mBAAmB,GAAG,QAAQ;CACpC,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAkB,UAAU,MAAM;CAC/E,MAAM,YAAY,UAAU,WAAW,eAAe,iBAAiB,UAAU,aAAa,iBAAiB,mBAAmB;AAElI,QACE,oBAAC,oBAAoB,UAArB;EAA8B,OAAO;GAAE;GAAW;GAAY;GAAW;GAAW;GAAa;GAAO;YACtG,qBAAC,OAAD;GACE,aAAU;GACV,WAAU;aAFZ;IAIE,oBAAC,OAAD;KACE,aAAU;KACV,oBAAkB;KAClB,cAAY;KACZ,IAAI;KACJ,MAAK;KACL,oBAAkB;KAClB,WAAW,GAAG,qBAAqB,gBAAgB,cAAc,YAAY,cAAc,kCAAkC,UAAU;KACvI,GAAI;KACJ;IACF,oBAAC,cAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,YAAY,eAAe;KACf;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACF,oBAAC,gBAAD;KACE,YAAW;KACX,IAAI;KACJ,SAAS,UAAU,YAAY,iBAAiB;KAC3B;KACrB,qBAAqB,uBAAuB,UAAU;KACtD;IACE;;EACuB;;AAInC,MAAa,oBAAoB,EAAE,WAAW,GAAG,YAAyC;CACxF,MAAM,EAAE,gBAAgB,iBAAiB;AAEzC,QACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GACT,6CACA,gBAAgB,gBAAgB,iEAChC,gBAAgB,cAAc,4GAC9B,UACD;EACD,GAAI;EACJ"}
@@ -20,7 +20,7 @@ const Calendar = ({ classNames, disabled, disablePastDates = true, fixedWeeks, l
20
20
  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"),
21
21
  button_previous: cn("nav-prev left-1 top-0 absolute"),
22
22
  button_next: cn("nav-next right-1 top-0 absolute"),
23
- table: cn("space-y-1 table w-full border-collapse"),
23
+ table: cn("table w-full border-collapse"),
24
24
  head_row: cn("day-head-row flex"),
25
25
  head_cell: cn("days-of-week"),
26
26
  row: cn("day-row mt-2 flex w-full"),
@@ -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('space-y-1 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 }) => (\n <ChevronDownIcon\n aria-hidden='true'\n className={cn('size-4', orientation === 'left' && 'rotate-90', orientation === 'right' && '-rotate-90')}\n />\n ),\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,yCAAyC;GACnD,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,kBACV,oBAAC,iBAAD;GACE,eAAY;GACZ,WAAW,GAAG,UAAU,gBAAgB,UAAU,aAAa,gBAAgB,WAAW,aAAa;GACvG,GAEL;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 }) => (\n <ChevronDownIcon\n aria-hidden='true'\n className={cn('size-4', orientation === 'left' && 'rotate-90', orientation === 'right' && '-rotate-90')}\n />\n ),\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,kBACV,oBAAC,iBAAD;GACE,eAAY;GACZ,WAAW,GAAG,UAAU,gBAAgB,UAAU,aAAa,gBAAgB,WAAW,aAAa;GACvG,GAEL;EACD,aAAU;EACV,eAAY;EACZ,UAAU,iBAAiB,SAAS,IAAI,mBAAmB;EAC/C;EACJ;EACS;EACjB;;AAIN,SAAS,cAAc"}
package/dist/Dialog.d.ts CHANGED
@@ -19,6 +19,7 @@ declare const DialogPortal: ({
19
19
  ...props
20
20
  }: ComponentProps<typeof DialogPrimitive.Portal>) => _$react_jsx_runtime0.JSX.Element;
21
21
  declare const DialogClose: ({
22
+ className,
22
23
  ...props
23
24
  }: ComponentProps<typeof DialogPrimitive.Close>) => _$react_jsx_runtime0.JSX.Element;
24
25
  declare const DialogOverlay: ({
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"mappings":";;;;;;cAMM,MAAA;EAAM,MAAA;EAAA,KAAA;EAAA,GAAA;AAAA,GAIT,IAAA,CAAK,cAAA,QAAsB,eAAA,CAAgB,IAAA;EAC5C,MAAA;EACA,aAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYK,aAAA;EAAA,GAAa;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAU7E,YAAA;EAAA,GAAY;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,MAAA,MAAO,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAU3E,WAAA;EAAA,GAAW;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWzE,aAAA;EAAa,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWxF,aAAA;EAAa,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,eAAA;EAAA,iBAAA;EAAA,oBAAA;EAAA,eAAA;EAAA,GAAA;AAAA,GAShB,cAAA,QAAsB,eAAA,CAAgB,OAAA;EACvC,aAAA;EACA,eAAA,IAAmB,KAAA,EAAO,aAAA;EAC1B,iBAAA,IAAqB,KAAA,EAAO,YAAA,GAAe,UAAA;EAC3C,oBAAA,IAAwB,KAAA,EAAO,YAAA;EAC/B,eAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAsCK,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAW9D,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAW9D,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWpF,iBAAA;EAAiB,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,WAAA,MAAY,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Dialog.d.ts","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"mappings":";;;;;;cAMM,MAAA;EAAM,MAAA;EAAA,KAAA;EAAA,GAAA;AAAA,GAIT,IAAA,CAAK,cAAA,QAAsB,eAAA,CAAgB,IAAA;EAC5C,MAAA;EACA,aAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYK,aAAA;EAAA,GAAa;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAU7E,YAAA;EAAA,GAAY;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,MAAA,MAAO,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAU3E,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYpF,aAAA;EAAa,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWxF,aAAA;EAAa,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,eAAA;EAAA,iBAAA;EAAA,oBAAA;EAAA,eAAA;EAAA,GAAA;AAAA,GAShB,cAAA,QAAsB,eAAA,CAAgB,OAAA;EACvC,aAAA;EACA,eAAA,IAAmB,KAAA,EAAO,aAAA;EAC1B,iBAAA,IAAqB,KAAA,EAAO,YAAA,GAAe,UAAA;EAC3C,oBAAA,IAAwB,KAAA,EAAO,YAAA;EAC/B,eAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAsCK,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAW9D,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAW9D,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAWpF,iBAAA;EAAiB,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,WAAA,MAAY,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/Dialog.js CHANGED
@@ -30,17 +30,18 @@ const DialogPortal = ({ ...props }) => {
30
30
  ...props
31
31
  });
32
32
  };
33
- const DialogClose = ({ ...props }) => {
33
+ const DialogClose = ({ className, ...props }) => {
34
34
  return /* @__PURE__ */ jsx(DialogPrimitive.Close, {
35
35
  asChild: true,
36
36
  "data-slot": "dialog-close",
37
37
  "data-testid": "spectral-dialog-close",
38
- ...props
38
+ ...props,
39
+ className: cn("hover:cursor-pointer", className)
39
40
  });
40
41
  };
41
42
  const DialogOverlay = ({ className, ...props }) => {
42
43
  return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, {
43
- className: cn("inset-0 bg-black/50 backdrop-blur-sm fixed z-50", "motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0", "motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0", className),
44
+ className: cn("inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0", "motion-safe:data-[state=closed]:fade-out-0", className),
44
45
  "data-slot": "dialog-overlay",
45
46
  "data-testid": "spectral-dialog-overlay",
46
47
  ...props
@@ -51,7 +52,7 @@ const DialogContent = ({ children, className, dialogOverlay = true, onEscapeKeyD
51
52
  "data-slot": "dialog-portal",
52
53
  "data-testid": "spectral-dialog-portal",
53
54
  children: [dialogOverlay && /* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(DialogPrimitive.Content, {
54
- className: cn("max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg", "motion-safe:data-[state=open]:duration-600 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!", "motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95", RemoveScroll.classNames.fullWidth, className),
55
+ className: cn("max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg", "motion-safe:data-[state=open]:duration-200 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!", "motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95", RemoveScroll.classNames.fullWidth, className),
55
56
  "data-slot": "dialog-content",
56
57
  "data-testid": "spectral-dialog-content",
57
58
  onEscapeKeyDown,
@@ -59,10 +60,10 @@ const DialogContent = ({ children, className, dialogOverlay = true, onEscapeKeyD
59
60
  onPointerDownOutside,
60
61
  ...props,
61
62
  children: [children, showCloseButton && /* @__PURE__ */ jsxs(DialogPrimitive.Close, {
62
- className: `focus:ring-ring data-[state=open]:text-muted-foreground top-4 right-4 rounded-xs absolute opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:shrink-0`,
63
+ className: `top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:cursor-pointer hover:opacity-100 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-text-primary [&_svg]:pointer-events-none [&_svg]:shrink-0`,
63
64
  "data-slot": "dialog-close",
64
65
  "data-testid": "spectral-dialog-close",
65
- children: [/* @__PURE__ */ jsx(CloseIcon, { size: 16 }), /* @__PURE__ */ jsx("span", {
66
+ children: [/* @__PURE__ */ jsx(CloseIcon, { size: 18 }), /* @__PURE__ */ jsx("span", {
66
67
  className: "sr-only",
67
68
  children: "Close dialog"
68
69
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.js","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons/CloseIcon'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\nimport { RemoveScroll } from 'react-remove-scroll'\n\nconst Dialog = ({\n isOpen,\n modal = false,\n ...props\n}: Omit<ComponentProps<typeof DialogPrimitive.Root>, 'open'> & {\n isOpen?: boolean\n dialogOverlay?: boolean\n}) => {\n return (\n <DialogPrimitive.Root\n open={isOpen}\n modal={modal}\n data-slot='dialog'\n data-testid='spectral-dialog'\n {...props}\n />\n )\n}\n\nconst DialogTrigger = ({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) => {\n return (\n <DialogPrimitive.Trigger\n asChild\n data-testid='spectral-dialog-trigger'\n {...props}\n />\n )\n}\n\nconst DialogPortal = ({ ...props }: ComponentProps<typeof DialogPrimitive.Portal>) => {\n return (\n <DialogPrimitive.Portal\n data-slot='dialog-portal'\n data-testid='dialog-portal'\n {...props}\n />\n )\n}\n\nconst DialogClose = ({ ...props }: ComponentProps<typeof DialogPrimitive.Close>) => {\n return (\n <DialogPrimitive.Close\n asChild\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n {...props}\n />\n )\n}\n\nconst DialogOverlay = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) => {\n return (\n <DialogPrimitive.Overlay\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-50', 'motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0', 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0', className)}\n data-slot='dialog-overlay'\n data-testid='spectral-dialog-overlay'\n {...props}\n />\n )\n}\n\nconst DialogContent = ({\n children,\n className,\n dialogOverlay = true,\n onEscapeKeyDown,\n onInteractOutside,\n onPointerDownOutside,\n showCloseButton = true,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n dialogOverlay?: boolean\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void\n onPointerDownOutside?: (event: PointerEvent) => void\n showCloseButton?: boolean\n}) => {\n return (\n <DialogPortal\n data-slot='dialog-portal'\n data-testid='spectral-dialog-portal'\n >\n {dialogOverlay && <DialogOverlay />}\n <DialogPrimitive.Content\n className={cn(\n 'max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg',\n 'motion-safe:data-[state=open]:duration-600 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!',\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95',\n RemoveScroll.classNames.fullWidth,\n className,\n )}\n data-slot='dialog-content'\n data-testid='spectral-dialog-content'\n onEscapeKeyDown={onEscapeKeyDown}\n onInteractOutside={onInteractOutside}\n onPointerDownOutside={onPointerDownOutside}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n className={`focus:ring-ring data-[state=open]:text-muted-foreground top-4 right-4 rounded-xs absolute opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:shrink-0`}\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n >\n <CloseIcon size={16} />\n <span className='sr-only'>Close dialog</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nconst DialogHeader = ({ className, ...props }: ComponentProps<'div'>) => {\n return (\n <div\n className={cn('gap-2 sm:text-left flex flex-col text-center', className)}\n data-slot='dialog-header'\n data-testid='spectral-dialog-header'\n {...props}\n />\n )\n}\n\nconst DialogFooter = ({ className, ...props }: ComponentProps<'div'>) => {\n return (\n <div\n className={cn('gap-2 sm:flex-row sm:justify-end bottom-0 py-4 px-6 -mx-6 sticky z-10 flex flex-col-reverse bg-dialog-bg/85', className)}\n data-slot='dialog-footer'\n data-testid='spectral-dialog-footer'\n {...props}\n />\n )\n}\n\nconst DialogTitle = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) => {\n return (\n <DialogPrimitive.Title\n className={cn('text-2xl font-semibold leading-none', className)}\n data-slot='dialog-title'\n data-testid='spectral-dialog-title'\n {...props}\n />\n )\n}\n\nconst DialogDescription = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Description>) => {\n return (\n <DialogPrimitive.Description\n className={cn('text-muted-foreground text-sm', className)}\n data-slot='dialog-description'\n data-testid='spectral-dialog-description'\n {...props}\n />\n )\n}\n\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger }\n"],"mappings":";;;;;;;;;AAMA,MAAM,UAAU,EACd,QACA,QAAQ,OACR,GAAG,YAIC;AACJ,QACE,oBAAC,gBAAgB,MAAjB;EACE,MAAM;EACC;EACP,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EAAE,GAAG,YAA4D;AACtF,QACE,oBAAC,gBAAgB,SAAjB;EACE;EACA,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,gBAAgB,EAAE,GAAG,YAA2D;AACpF,QACE,oBAAC,gBAAgB,QAAjB;EACE,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,eAAe,EAAE,GAAG,YAA0D;AAClF,QACE,oBAAC,gBAAgB,OAAjB;EACE;EACA,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EAAE,WAAW,GAAG,YAA4D;AACjG,QACE,oBAAC,gBAAgB,SAAjB;EACE,WAAW,GAAG,mDAAmD,oFAAoF,0FAA0F,UAAU;EACzP,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EACrB,UACA,WACA,gBAAgB,MAChB,iBACA,mBACA,sBACA,kBAAkB,MAClB,GAAG,YAOC;AACJ,QACE,qBAAC,cAAD;EACE,aAAU;EACV,eAAY;YAFd,CAIG,iBAAiB,oBAAC,eAAD,EAAiB,GACnC,qBAAC,gBAAgB,SAAjB;GACE,WAAW,GACT,oOACA,wLACA,sIACA,aAAa,WAAW,WACxB,UACD;GACD,aAAU;GACV,eAAY;GACK;GACE;GACG;GACtB,GAAI;aAbN,CAeG,UACA,mBACC,qBAAC,gBAAgB,OAAjB;IACE,WAAW;IACX,aAAU;IACV,eAAY;cAHd,CAKE,oBAAC,WAAD,EAAW,MAAM,IAAM,GACvB,oBAAC,QAAD;KAAM,WAAU;eAAU;KAAmB,EACvB;MAEF;KACb;;;AAInB,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,gDAAgD,UAAU;EACxE,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,+GAA+G,UAAU;EACvI,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QACE,oBAAC,gBAAgB,OAAjB;EACE,WAAW,GAAG,uCAAuC,UAAU;EAC/D,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,qBAAqB,EAAE,WAAW,GAAG,YAAgE;AACzG,QACE,oBAAC,gBAAgB,aAAjB;EACE,WAAW,GAAG,iCAAiC,UAAU;EACzD,aAAU;EACV,eAAY;EACZ,GAAI;EACJ"}
1
+ {"version":3,"file":"Dialog.js","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons/CloseIcon'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\nimport { RemoveScroll } from 'react-remove-scroll'\n\nconst Dialog = ({\n isOpen,\n modal = false,\n ...props\n}: Omit<ComponentProps<typeof DialogPrimitive.Root>, 'open'> & {\n isOpen?: boolean\n dialogOverlay?: boolean\n}) => {\n return (\n <DialogPrimitive.Root\n open={isOpen}\n modal={modal}\n data-slot='dialog'\n data-testid='spectral-dialog'\n {...props}\n />\n )\n}\n\nconst DialogTrigger = ({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) => {\n return (\n <DialogPrimitive.Trigger\n asChild\n data-testid='spectral-dialog-trigger'\n {...props}\n />\n )\n}\n\nconst DialogPortal = ({ ...props }: ComponentProps<typeof DialogPrimitive.Portal>) => {\n return (\n <DialogPrimitive.Portal\n data-slot='dialog-portal'\n data-testid='dialog-portal'\n {...props}\n />\n )\n}\n\nconst DialogClose = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Close>) => {\n return (\n <DialogPrimitive.Close\n asChild\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n {...props}\n className={cn('hover:cursor-pointer', className)}\n />\n )\n}\n\nconst DialogOverlay = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) => {\n return (\n <DialogPrimitive.Overlay\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0', 'motion-safe:data-[state=closed]:fade-out-0', className)}\n data-slot='dialog-overlay'\n data-testid='spectral-dialog-overlay'\n {...props}\n />\n )\n}\n\nconst DialogContent = ({\n children,\n className,\n dialogOverlay = true,\n onEscapeKeyDown,\n onInteractOutside,\n onPointerDownOutside,\n showCloseButton = true,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n dialogOverlay?: boolean\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void\n onPointerDownOutside?: (event: PointerEvent) => void\n showCloseButton?: boolean\n}) => {\n return (\n <DialogPortal\n data-slot='dialog-portal'\n data-testid='spectral-dialog-portal'\n >\n {dialogOverlay && <DialogOverlay />}\n <DialogPrimitive.Content\n className={cn(\n 'max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg',\n 'motion-safe:data-[state=open]:duration-200 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!',\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95',\n RemoveScroll.classNames.fullWidth,\n className,\n )}\n data-slot='dialog-content'\n data-testid='spectral-dialog-content'\n onEscapeKeyDown={onEscapeKeyDown}\n onInteractOutside={onInteractOutside}\n onPointerDownOutside={onPointerDownOutside}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n className={`top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:cursor-pointer hover:opacity-100 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-text-primary [&_svg]:pointer-events-none [&_svg]:shrink-0`}\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n >\n <CloseIcon size={18} />\n <span className='sr-only'>Close dialog</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nconst DialogHeader = ({ className, ...props }: ComponentProps<'div'>) => {\n return (\n <div\n className={cn('gap-2 sm:text-left flex flex-col text-center', className)}\n data-slot='dialog-header'\n data-testid='spectral-dialog-header'\n {...props}\n />\n )\n}\n\nconst DialogFooter = ({ className, ...props }: ComponentProps<'div'>) => {\n return (\n <div\n className={cn('gap-2 sm:flex-row sm:justify-end bottom-0 py-4 px-6 -mx-6 sticky z-10 flex flex-col-reverse bg-dialog-bg/85', className)}\n data-slot='dialog-footer'\n data-testid='spectral-dialog-footer'\n {...props}\n />\n )\n}\n\nconst DialogTitle = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) => {\n return (\n <DialogPrimitive.Title\n className={cn('text-2xl font-semibold leading-none', className)}\n data-slot='dialog-title'\n data-testid='spectral-dialog-title'\n {...props}\n />\n )\n}\n\nconst DialogDescription = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Description>) => {\n return (\n <DialogPrimitive.Description\n className={cn('text-muted-foreground text-sm', className)}\n data-slot='dialog-description'\n data-testid='spectral-dialog-description'\n {...props}\n />\n )\n}\n\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger }\n"],"mappings":";;;;;;;;;AAMA,MAAM,UAAU,EACd,QACA,QAAQ,OACR,GAAG,YAIC;AACJ,QACE,oBAAC,gBAAgB,MAAjB;EACE,MAAM;EACC;EACP,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EAAE,GAAG,YAA4D;AACtF,QACE,oBAAC,gBAAgB,SAAjB;EACE;EACA,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,gBAAgB,EAAE,GAAG,YAA2D;AACpF,QACE,oBAAC,gBAAgB,QAAjB;EACE,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QACE,oBAAC,gBAAgB,OAAjB;EACE;EACA,aAAU;EACV,eAAY;EACZ,GAAI;EACJ,WAAW,GAAG,wBAAwB,UAAU;EAChD;;AAIN,MAAM,iBAAiB,EAAE,WAAW,GAAG,YAA4D;AACjG,QACE,oBAAC,gBAAgB,SAAjB;EACE,WAAW,GAAG,gLAAgL,8CAA8C,UAAU;EACtP,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EACrB,UACA,WACA,gBAAgB,MAChB,iBACA,mBACA,sBACA,kBAAkB,MAClB,GAAG,YAOC;AACJ,QACE,qBAAC,cAAD;EACE,aAAU;EACV,eAAY;YAFd,CAIG,iBAAiB,oBAAC,eAAD,EAAiB,GACnC,qBAAC,gBAAgB,SAAjB;GACE,WAAW,GACT,oOACA,wLACA,sIACA,aAAa,WAAW,WACxB,UACD;GACD,aAAU;GACV,eAAY;GACK;GACE;GACG;GACtB,GAAI;aAbN,CAeG,UACA,mBACC,qBAAC,gBAAgB,OAAjB;IACE,WAAW;IACX,aAAU;IACV,eAAY;cAHd,CAKE,oBAAC,WAAD,EAAW,MAAM,IAAM,GACvB,oBAAC,QAAD;KAAM,WAAU;eAAU;KAAmB,EACvB;MAEF;KACb;;;AAInB,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,gDAAgD,UAAU;EACxE,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,+GAA+G,UAAU;EACvI,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QACE,oBAAC,gBAAgB,OAAjB;EACE,WAAW,GAAG,uCAAuC,UAAU;EAC/D,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,qBAAqB,EAAE,WAAW,GAAG,YAAgE;AACzG,QACE,oBAAC,gBAAgB,aAAjB;EACE,WAAW,GAAG,iCAAiC,UAAU;EACzD,aAAU;EACV,eAAY;EACZ,GAAI;EACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"Drawer.d.ts","names":[],"sources":["../src/components/Drawer/Drawer.tsx"],"mappings":";;;;;UAIiB,WAAA;EACf,QAAA,GAAW,SAAA;EACX,WAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,KAAA;EACA,YAAA,IAAgB,IAAA;EAChB,IAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA,EAAS,SAAA;AAAA;AAAA,cAGE,MAAA;EAAM,QAAA;EAAA,WAAA;EAAA,WAAA;EAAA,SAAA;EAAA,WAAA;EAAA,KAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA,KAAA;EAAA;AAAA,GAA+J,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Drawer.d.ts","names":[],"sources":["../src/components/Drawer/Drawer.tsx"],"mappings":";;;;;UAKiB,WAAA;EACf,QAAA,GAAW,SAAA;EACX,WAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,KAAA;EACA,YAAA,IAAgB,IAAA;EAChB,IAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA,EAAS,SAAA;AAAA;AAAA,cAGE,MAAA;EAAM,QAAA;EAAA,WAAA;EAAA,WAAA;EAAA,SAAA;EAAA,WAAA;EAAA,KAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA,KAAA;EAAA;AAAA,GAA+J,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/Drawer.js CHANGED
@@ -1,4 +1,5 @@
1
1
  'use client';
2
+ import { cn } from "./utils/twUtils.js";
2
3
  import { SpectralProvider } from "./components/SpectralProvider/SpectralProvider.js";
3
4
  import "react";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -11,19 +12,19 @@ const Drawer = ({ children, defaultOpen = false, description, direction = "right
11
12
  const hasDescription = typeof description === "string" && description.trim().length > 0;
12
13
  const { className, style } = {
13
14
  left: {
14
- className: `${baseStyles} top-0 bottom-0 left-0 shadow-[20px_0_20px_rgba(0,0,0,0.4)]`,
15
+ className: cn(baseStyles, "top-0 bottom-0 left-0 shadow-[20px_0_20px_var(--color-black-40)]"),
15
16
  style: { width: size }
16
17
  },
17
18
  right: {
18
- className: `${baseStyles} top-0 bottom-0 right-0 shadow-[-20px_0_20px_rgba(0,0,0,0.4)]`,
19
+ className: cn(baseStyles, "top-0 bottom-0 right-0 shadow-[-20px_0_20px_var(--color-black-40)]"),
19
20
  style: { width: size }
20
21
  },
21
22
  top: {
22
- className: `${baseStyles} top-0 left-0 right-0 shadow-[0_20px_20px_rgba(0,0,0,0.4)]`,
23
+ className: cn(baseStyles, "top-0 left-0 right-0 shadow-[0_20px_20px_var(--color-black-40)]"),
23
24
  style: { height: size }
24
25
  },
25
26
  bottom: {
26
- className: `${baseStyles} bottom-0 left-0 right-0 shadow-[0_-20px_20px_rgba(0,0,0,0.4)]`,
27
+ className: cn(baseStyles, "bottom-0 left-0 right-0 shadow-[0_-20px_20px_var(--color-black-40)]"),
27
28
  style: { height: size }
28
29
  }
29
30
  }[direction];
@@ -45,27 +46,30 @@ const Drawer = ({ children, defaultOpen = false, description, direction = "right
45
46
  }), /* @__PURE__ */ jsx(Drawer$1.Content, {
46
47
  asChild: true,
47
48
  "aria-label": !hasTitle && !hasDescription ? "Drawer" : void 0,
48
- className: `z-10 flex flex-col overscroll-contain bg-drawer-bg outline-none **:box-border ${className}`,
49
+ className: `z-10 flex flex-col overscroll-contain bg-drawer-bg **:box-border focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent ${className}`,
49
50
  style,
50
51
  "data-testid": "spectral-drawer-content",
51
- children: /* @__PURE__ */ jsxs("div", { children: [
52
- /* @__PURE__ */ jsx(Drawer$1.Close, {}),
53
- hasTitle && /* @__PURE__ */ jsx(Drawer$1.Title, {
54
- className: "px-3 pt-4 text-lg font-medium text-text-primary",
55
- "data-testid": "spectral-drawer-title",
56
- children: title
57
- }),
58
- hasDescription && /* @__PURE__ */ jsx(Drawer$1.Description, {
59
- className: "mb-2 px-3 text-xs! text-text-secondary! uppercase",
60
- "data-testid": "spectral-drawer-description",
61
- children: description
62
- }),
63
- /* @__PURE__ */ jsx("div", {
64
- className: "py-2 px-3 min-w-0 *:min-w-0 w-auto overflow-hidden overscroll-contain *:box-border",
65
- "data-testid": "spectral-drawer-body",
66
- children
67
- })
68
- ] })
52
+ children: /* @__PURE__ */ jsxs("div", {
53
+ className: "min-h-0 flex h-full flex-col",
54
+ children: [
55
+ /* @__PURE__ */ jsx(Drawer$1.Close, {}),
56
+ hasTitle && /* @__PURE__ */ jsx(Drawer$1.Title, {
57
+ className: "px-3 pt-4 text-lg font-medium text-text-primary",
58
+ "data-testid": "spectral-drawer-title",
59
+ children: title
60
+ }),
61
+ hasDescription && /* @__PURE__ */ jsx(Drawer$1.Description, {
62
+ className: "mb-2 px-3 text-xs! text-text-secondary! uppercase",
63
+ "data-testid": "spectral-drawer-description",
64
+ children: description
65
+ }),
66
+ /* @__PURE__ */ jsx("div", {
67
+ className: "py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 min-h-0 flex-1 overflow-x-hidden overflow-y-auto overscroll-contain *:box-border",
68
+ "data-testid": "spectral-drawer-body",
69
+ children
70
+ })
71
+ ]
72
+ })
69
73
  })] })]
70
74
  }) });
71
75
  };