@spear-ai/spectral 1.20.0 → 1.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Accordion.js +0 -4
- package/dist/Accordion.js.map +1 -1
- package/dist/Alert/AlertBase.d.ts +0 -1
- package/dist/Alert/AlertBase.d.ts.map +1 -1
- package/dist/Alert/AlertBase.js +14 -17
- package/dist/Alert/AlertBase.js.map +1 -1
- package/dist/Alert.js +16 -4
- package/dist/Alert.js.map +1 -1
- package/dist/AlertDialog.js +3 -3
- package/dist/AlertDialog.js.map +1 -1
- package/dist/Avatar.js +1 -9
- package/dist/Avatar.js.map +1 -1
- package/dist/Badge.js +0 -1
- package/dist/Badge.js.map +1 -1
- package/dist/Button.js +0 -3
- package/dist/Button.js.map +1 -1
- package/dist/ButtonGroup.js +0 -4
- package/dist/ButtonGroup.js.map +1 -1
- package/dist/ButtonIcon.js +0 -1
- package/dist/ButtonIcon.js.map +1 -1
- package/dist/ButtonIconSlideout.js +0 -3
- package/dist/ButtonIconSlideout.js.map +1 -1
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Checkbox.js +5 -8
- package/dist/Checkbox.js.map +1 -1
- package/dist/Combobox.d.ts +1 -0
- package/dist/Combobox.d.ts.map +1 -1
- package/dist/Combobox.js +0 -4
- package/dist/Combobox.js.map +1 -1
- package/dist/ControlGroup/ControlGroupSelect.js +0 -5
- package/dist/ControlGroup/ControlGroupSelect.js.map +1 -1
- package/dist/DataCard/Card.js +0 -6
- package/dist/DataCard/Card.js.map +1 -1
- package/dist/DataCard.js +1 -7
- package/dist/DataCard.js.map +1 -1
- package/dist/DateTimePicker/Calendar.js +0 -1
- package/dist/DateTimePicker/Calendar.js.map +1 -1
- package/dist/DateTimePicker/DateTimeInput.js +0 -1
- package/dist/DateTimePicker/DateTimeInput.js.map +1 -1
- package/dist/DateTimePicker/TimePeriodSelect.js +0 -4
- package/dist/DateTimePicker/TimePeriodSelect.js.map +1 -1
- package/dist/DateTimePicker/TimePicker.js +0 -3
- package/dist/DateTimePicker/TimePicker.js.map +1 -1
- package/dist/DateTimePicker.js +0 -4
- package/dist/DateTimePicker.js.map +1 -1
- package/dist/Dialog.js +0 -16
- package/dist/Dialog.js.map +1 -1
- package/dist/DirectionalColorWheel/DirectionalColorWheelDisclosure.js +0 -2
- package/dist/DirectionalColorWheel/DirectionalColorWheelDisclosure.js.map +1 -1
- package/dist/DirectionalColorWheel/DirectionalColorWheelGlyph.js +0 -1
- package/dist/DirectionalColorWheel/DirectionalColorWheelGlyph.js.map +1 -1
- package/dist/DirectionalColorWheel.js +9 -21
- package/dist/DirectionalColorWheel.js.map +1 -1
- package/dist/Drawer.js +6 -29
- package/dist/Drawer.js.map +1 -1
- package/dist/DropdownMenu.js +1 -9
- package/dist/DropdownMenu.js.map +1 -1
- package/dist/FormFieldMessage.js +0 -1
- package/dist/FormFieldMessage.js.map +1 -1
- package/dist/HoverCard.js +0 -3
- package/dist/HoverCard.js.map +1 -1
- package/dist/Input.js +0 -10
- package/dist/Input.js.map +1 -1
- package/dist/InputOTP.js +0 -4
- package/dist/InputOTP.js.map +1 -1
- package/dist/InputSearch.js +3 -15
- package/dist/InputSearch.js.map +1 -1
- package/dist/Kbd.js +0 -2
- package/dist/Kbd.js.map +1 -1
- package/dist/Meter.d.ts +23 -0
- package/dist/Meter.d.ts.map +1 -0
- package/dist/Meter.js +45 -0
- package/dist/Meter.js.map +1 -0
- package/dist/MultiSelect/MultiSelectBase.js +1 -16
- package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
- package/dist/Popover.js +0 -3
- package/dist/Popover.js.map +1 -1
- package/dist/RadialMenu.js +1 -7
- package/dist/RadialMenu.js.map +1 -1
- package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
- package/dist/RadioButtonGroup/RadioButtonGroupBase.js +1 -4
- package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
- package/dist/RadioButtonGroup.js +1 -1
- package/dist/RadioButtonGroup.js.map +1 -1
- package/dist/RadioGroup.js +0 -6
- package/dist/RadioGroup.js.map +1 -1
- package/dist/Select.js +11 -40
- package/dist/Select.js.map +1 -1
- package/dist/Slider.js +2 -11
- package/dist/Slider.js.map +1 -1
- package/dist/Switch.js +0 -6
- package/dist/Switch.js.map +1 -1
- package/dist/Tabs/TabsBase.js +0 -5
- package/dist/Tabs/TabsBase.js.map +1 -1
- package/dist/Textarea.js +0 -4
- package/dist/Textarea.js.map +1 -1
- package/dist/Toast.js +1 -3
- package/dist/Toast.js.map +1 -1
- package/dist/Toggle.js +0 -1
- package/dist/Toggle.js.map +1 -1
- package/dist/ToggleGroup/ToggleGroupItem.js +0 -1
- package/dist/ToggleGroup/ToggleGroupItem.js.map +1 -1
- package/dist/ToggleGroup.js +0 -1
- package/dist/ToggleGroup.js.map +1 -1
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip.js +4 -5
- package/dist/Tooltip.js.map +1 -1
- package/dist/Tray.js +1 -9
- package/dist/Tray.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/styles/horizon/base.css +31 -16
- package/dist/styles/horizon/colors.css +37 -21
- package/dist/styles/horizon/theme.css +15 -7
- package/dist/styles/horizon/utilities.css +19 -45
- package/dist/styles/spectral.css +1 -1
- package/package.json +4 -1
package/dist/Accordion.js
CHANGED
|
@@ -37,7 +37,6 @@ const AccordionRoot = ({ className, ref, variant = "default", ...props }) => {
|
|
|
37
37
|
"data-scroll-options": JSON.stringify(accordionContext),
|
|
38
38
|
"data-scroll-padding": scrollPadding,
|
|
39
39
|
"data-slot": "accordion",
|
|
40
|
-
"data-testid": "spectral-accordion",
|
|
41
40
|
...props.type === "single" ? { collapsible: true } : {},
|
|
42
41
|
children: Children.map(children, (child) => {
|
|
43
42
|
if (isValidElement(child)) return cloneElement(child, { variant });
|
|
@@ -52,7 +51,6 @@ const AccordionItem = ({ className, ref, ...props }) => {
|
|
|
52
51
|
return /* @__PURE__ */ jsx(AccordionPrimitive.Item, {
|
|
53
52
|
className: cn("w-full", itemStyles[variant], className),
|
|
54
53
|
"data-slot": "accordion-item",
|
|
55
|
-
"data-testid": "spectral-accordion-item",
|
|
56
54
|
ref,
|
|
57
55
|
...props
|
|
58
56
|
});
|
|
@@ -71,7 +69,6 @@ const AccordionTrigger = ({ ref, className, title, subtitle, ...props }) => {
|
|
|
71
69
|
children: /* @__PURE__ */ jsxs(AccordionPrimitive.Trigger, {
|
|
72
70
|
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
71
|
"data-slot": "accordion-trigger",
|
|
74
|
-
"data-testid": "spectral-accordion-trigger",
|
|
75
72
|
onClick: handleAccordionOpen,
|
|
76
73
|
ref: useMergedRef,
|
|
77
74
|
...props,
|
|
@@ -92,7 +89,6 @@ AccordionTrigger.displayName = "AccordionTrigger";
|
|
|
92
89
|
const AccordionContent = ({ ref, className, children, ...props }) => /* @__PURE__ */ jsx(AccordionPrimitive.Content, {
|
|
93
90
|
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),
|
|
94
91
|
"data-slot": "accordion-content",
|
|
95
|
-
"data-testid": "spectral-accordion-content",
|
|
96
92
|
ref,
|
|
97
93
|
...props,
|
|
98
94
|
children: /* @__PURE__ */ jsx("div", {
|
package/dist/Accordion.js.map
CHANGED
|
@@ -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 {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useRef,\n type ComponentPropsWithoutRef,\n type ComponentRef,\n type ReactNode,\n type Ref,\n} 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 <AccordionPrimitive.Item className={cn('w-full', itemStyles[variant], className)} data-slot='accordion-item' data-testid='spectral-accordion-item' ref={ref} {...props} />\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='flex w-full flex-col gap-0.5 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 className='px-1 pb-4 pt-0' data-slot='accordion-content-inner'>\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":";;;;;;;;;AA0DA,MAAM,gBAAgB;CACpB,SAAS;CACT,WAAW;CACX,WAAW;
|
|
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 {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useRef,\n type ComponentPropsWithoutRef,\n type ComponentRef,\n type ReactNode,\n type Ref,\n} 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 <AccordionPrimitive.Item className={cn('w-full', itemStyles[variant], className)} data-slot='accordion-item' data-testid='spectral-accordion-item' ref={ref} {...props} />\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='flex w-full flex-col gap-0.5 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 className='px-1 pb-4 pt-0' data-slot='accordion-content-inner'>\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":";;;;;;;;;AA0DA,MAAM,gBAAgB;CACpB,SAAS;CACT,WAAW;CACX,WAAW;CACb;AAEA,MAAM,aAAa;CACjB,SAAS;CACT,WAAW;CACX,WAAW;CACb;AAEA,MAAM,mBAAmB,cAA0D,EAAE,SAAS,WAAW,CAAA;AAEzG,MAAM,iBAAiB,EACrB,WACA,KACA,UAAU,WACV,GAAG,YAGC;CACJ,MAAM,EAAE,aAAa,SAAS,gBAAgB,KAAK,UAAU,GAAG,SAAS;CAEzE,MAAM,mBAAkC;EACtC;EACA;EACF;CAEA,MAAM,YAAY;EAChB,GAAG;EACH;EACF;AAEA,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;GAEV,GAAK,MAAM,SAAS,WAAW,EAAE,aAAa,MAAM,GAAG,EAAE;aAExD,SAAS,IAAI,WAAW,UAAqB;AAC5C,QAAI,eAAe,MAAM,CACvB,QAAO,aAAa,OAAO,EAAE,SAAS,CAA+B;AAEvE,WAAO;KACP;GACqB;EACA;;AAG/B,cAAc,cAAc;AAE5B,MAAa,iBAAiB,EAC5B,WACA,KACA,GAAG,YAGC;CACJ,MAAM,EAAE,UAAU,cAAc,WAAW,iBAAgB;AAE3D,QAAO,oBAAC,mBAAmB,MAApB;EAAyB,WAAW,GAAG,UAAU,WAAW,UAAU,UAAU;EAAE,aAAU;EAA4D;EAAK,GAAI;EAAQ;;AAElL,cAAc,cAAc;AAE5B,MAAa,oBAAoB,EAC/B,KACA,WACA,OACA,UACA,GAAG,YAKC;CACJ,MAAM,aAAa,OAA0B,KAAI;CACjD,MAAM,sBAAsB,uBAAuB,WAAU;CAE7D,MAAM,eAAe,aAClB,YAA+B;AAC9B,MAAI,OAAO,QAAQ,WACjB,KAAI,QAAO;WACF,IACT,KAAI,UAAU;AAEhB,aAAW,UAAU;IAEvB,CAAC,IAAI,CACP;AAEA,QACE,oBAAC,mBAAmB,QAApB;EAA2B,WAAU;YACnC,qBAAC,mBAAmB,SAApB;GACE,WAAW,GAAG,uHAAuH,mEAAmE,UAAU;GAClN,aAAU;GAEV,SAAS;GACT,KAAK;GACL,GAAI;aANN,CAQE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eAA2C;KAAW,GACpE,YAAY,oBAAC,OAAD;KAAK,WAAU;eAA2C;KAAe,EACnF;OACL,oBAAC,iBAAD,EAAiB,WAAU,8CAA8C,EAC/C;;EACH;;AAG/B,iBAAiB,cAAc;AAE/B,MAAa,oBAAoB,EAC/B,KACA,WACA,UACA,GAAG,YAIH,oBAAC,mBAAmB,SAApB;CACE,WAAW,GAAG,0IAA0I,UAAU;CAClK,aAAU;CAEL;CACL,GAAI;WAEJ,oBAAC,OAAD;EAAK,WAAU;EAAiB,aAAU;EACvC;EACE;CACqB;AAE9B,iBAAiB,cAAc;AAE/B,MAAa,YAA2B,OAAO,OAAO,eAAe;CACnE,SAAS;CACT,MAAM;CACN,SAAS;CACV,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlertBase.d.ts","names":[],"sources":["../../src/components/Alert/AlertBase.tsx"],"mappings":";;;;;;;;cAMM,aAAA,GAAa,KAAA;;
|
|
1
|
+
{"version":3,"file":"AlertBase.d.ts","names":[],"sources":["../../src/components/Alert/AlertBase.tsx"],"mappings":";;;;;;;;cAMM,aAAA,GAAa,KAAA;;IAiBlB,iCAAA,CAAA,SAAA;AAAA,KAUI,YAAA;AAAA;EAGH,GAAA;EACA,SAAA;EACA,OAAA;EAAA,GACG;AAAA,GACF,cAAA,CAAe,cAAA,IAChB,YAAA,QAAoB,aAAA;EAClB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EAKD,SAAA;EACA,GAAA;EAAA,GACG;AAAA,GACF,cAAA,CAAe,cAAA;EAChB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EAKC,SAAA;EACA,GAAA;EACA,OAAA;EAAA,GACG;AAAA,GACF,cAAA,CAAe,cAAA;EAChB,GAAA,GAAM,GAAA,CAAI,cAAA;EACV,OAAA,EAAS,YAAA;AAAA,IACV,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EAKC,SAAA;EACA,GAAA;EAAA,GACG;AAAA,GACF,cAAA,CAAe,cAAA;EAChB,GAAA,GAAM,GAAA,CAAI,cAAA;EACV,OAAA,EAAS,YAAA;AAAA,IACV,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EAKC,SAAA;EACA,GAAA;EACA,OAAA;EAAA,GACG;AAAA,GACF,cAAA,CAAe,aAAA;EAChB,GAAA,GAAM,GAAA,CAAI,aAAA;EACV,OAAA,EAAS,YAAA;AAAA,IACV,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;UAeS,gBAAA;EACR,QAAA,EAAU,SAAA;EACV,SAAA,GAAY,OAAA,GAAU,gBAAA;AAAA;AAAA,cAGX,WAAA;EAAW,QAAA;EAAA;AAAA,GAA6B,gBAAA,KAAgB,OAAA,CAAA,WAAA"}
|
package/dist/Alert/AlertBase.js
CHANGED
|
@@ -7,7 +7,8 @@ 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-opacity duration-200
|
|
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
|
|
11
|
+
ease-out motion-safe:duration-200 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-full shadow-elevation-2`, {
|
|
11
12
|
variants: { variant: {
|
|
12
13
|
default: "border-alert-border bg-alert-bg",
|
|
13
14
|
success: "border-alert-success-border bg-alert-success-bg",
|
|
@@ -17,52 +18,48 @@ const alertVariants = cva(`top-2 max-w-md rounded-md px-4 py-3 text-sm gap-y-1 t
|
|
|
17
18
|
} },
|
|
18
19
|
defaultVariants: { variant: "default" }
|
|
19
20
|
});
|
|
20
|
-
const
|
|
21
|
-
success: "text-alert-success-text
|
|
22
|
-
warning: "text-alert-warning-text
|
|
23
|
-
danger: "text-alert-danger-text
|
|
24
|
-
info: "text-alert-info-text
|
|
25
|
-
default: "text-alert-text
|
|
21
|
+
const titleTextColors = {
|
|
22
|
+
success: "text-alert-success-text",
|
|
23
|
+
warning: "text-alert-warning-text",
|
|
24
|
+
danger: "text-alert-danger-text",
|
|
25
|
+
info: "text-alert-info-text",
|
|
26
|
+
default: "text-alert-text"
|
|
26
27
|
};
|
|
27
28
|
const AlertBase = ({ ref, className, variant, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
28
29
|
className: cn(alertVariants({ variant }), className),
|
|
29
30
|
"data-slot": "alert",
|
|
30
|
-
"data-testid": "spectral-alert",
|
|
31
31
|
ref,
|
|
32
32
|
role: "alert",
|
|
33
33
|
...props
|
|
34
34
|
});
|
|
35
35
|
AlertBase.displayName = "AlertBase";
|
|
36
36
|
const AlertHeader = ({ className, ref, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
37
|
-
className: cn("gap-2
|
|
37
|
+
className: cn("gap-2 flex items-center [&>svg]:shrink-0", className),
|
|
38
38
|
"data-slot": "alert-header",
|
|
39
39
|
ref,
|
|
40
40
|
...props
|
|
41
41
|
});
|
|
42
42
|
AlertHeader.displayName = "AlertHeader";
|
|
43
43
|
const AlertTitle = ({ className, ref, variant, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
44
|
-
className: cn(
|
|
44
|
+
className: cn(titleTextColors[variant], "font-medium text-lg tracking-tight line-clamp-1 flex-1", className),
|
|
45
45
|
"data-slot": "alert-title",
|
|
46
|
-
"data-testid": "spectral-alert-title",
|
|
47
46
|
ref,
|
|
48
47
|
...props
|
|
49
48
|
});
|
|
50
49
|
AlertTitle.displayName = "AlertTitle";
|
|
51
|
-
const AlertDescription = ({ className, ref,
|
|
52
|
-
className: cn(
|
|
50
|
+
const AlertDescription = ({ className, ref, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
51
|
+
className: cn("gap-1 text-text-primary text-sm [&_p]:leading-relaxed grid justify-items-start", className),
|
|
53
52
|
"data-slot": "alert-description",
|
|
54
|
-
"data-testid": "spectral-alert-description",
|
|
55
53
|
ref,
|
|
56
54
|
...props
|
|
57
55
|
});
|
|
58
56
|
AlertDescription.displayName = "AlertDescription";
|
|
59
57
|
const AlertCloseButton = ({ className, ref, variant, ...props }) => /* @__PURE__ */ jsx(CloseIcon, {
|
|
60
58
|
"aria-label": "Close alert",
|
|
61
|
-
className: cn(
|
|
59
|
+
className: cn(titleTextColors[variant], "rounded shrink-0 cursor-pointer outline-transparent focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-text-secondary", className),
|
|
62
60
|
"data-slot": "close-icon",
|
|
63
|
-
"data-testid": "spectral-alert-close-button",
|
|
64
61
|
ref,
|
|
65
|
-
size:
|
|
62
|
+
size: 18,
|
|
66
63
|
tabIndex: 0,
|
|
67
64
|
...props
|
|
68
65
|
});
|
|
@@ -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-opacity duration-200
|
|
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\n ease-out motion-safe:duration-200 motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-top-full shadow-elevation-2`,\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 titleTextColors = {\n success: 'text-alert-success-text',\n warning: 'text-alert-warning-text',\n danger: 'text-alert-danger-text',\n info: 'text-alert-info-text',\n default: '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 }) => <div className={cn(alertVariants({ variant }), className)} data-slot='alert' data-testid='spectral-alert' ref={ref} role='alert' {...props} />\n\nAlertBase.displayName = 'AlertBase'\n\nexport const AlertHeader = ({\n className,\n ref,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n}) => <div className={cn('gap-2 flex items-center [&>svg]:shrink-0', className)} data-slot='alert-header' ref={ref} {...props} />\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}) => <div className={cn(titleTextColors[variant], 'font-medium text-lg tracking-tight line-clamp-1 flex-1', className)} data-slot='alert-title' data-testid='spectral-alert-title' ref={ref} {...props} />\n\nAlertTitle.displayName = 'AlertTitle'\n\nexport const AlertDescription = ({\n className,\n ref,\n ...props\n}: HTMLAttributes<HTMLDivElement> & {\n ref?: Ref<HTMLDivElement>\n variant: AlertVariant\n}) => <div className={cn('gap-1 text-text-primary text-sm [&_p]:leading-relaxed grid justify-items-start', className)} data-slot='alert-description' data-testid='spectral-alert-description' ref={ref} {...props} />\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(titleTextColors[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={18}\n tabIndex={0}\n {...props}\n />\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;uIAEA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,SAAS;EACT,SAAS;EACT,QAAQ;EACR,MAAM;EACP,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CACH;AAEA,MAAM,kBAAkB;CACtB,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;CACN,SAAS;CACX;AAIA,MAAa,aAAa,EACxB,KACA,WACA,SACA,GAAG,YAIG,oBAAC,OAAD;CAAK,WAAW,GAAG,cAAc,EAAE,SAAS,CAAC,EAAE,UAAU;CAAE,aAAU;CAA0C;CAAK,MAAK;CAAQ,GAAI;CAAQ;AAErJ,UAAU,cAAc;AAExB,MAAa,eAAe,EAC1B,WACA,KACA,GAAG,YAGC,oBAAC,OAAD;CAAK,WAAW,GAAG,4CAA4C,UAAU;CAAE,aAAU;CAAoB;CAAK,GAAI;CAAQ;AAEhI,YAAY,cAAc;AAE1B,MAAa,cAAc,EACzB,WACA,KACA,SACA,GAAG,YAIC,oBAAC,OAAD;CAAK,WAAW,GAAG,gBAAgB,UAAU,0DAA0D,UAAU;CAAE,aAAU;CAAsD;CAAK,GAAI;CAAQ;AAE1M,WAAW,cAAc;AAEzB,MAAa,oBAAoB,EAC/B,WACA,KACA,GAAG,YAIC,oBAAC,OAAD;CAAK,WAAW,GAAG,kFAAkF,UAAU;CAAE,aAAU;CAAkE;CAAK,GAAI;CAAQ;AAEpN,iBAAiB,cAAc;AAE/B,MAAa,oBAAoB,EAC/B,WACA,KACA,SACA,GAAG,YAKH,oBAAC,WAAD;CACE,cAAW;CACX,WAAW,GAAG,gBAAgB,UAAU,mJAAmJ,UAAU;CACrM,aAAU;CAEL;CACL,MAAM;CACN,UAAU;CACV,GAAI;CACL;AAGH,iBAAiB,cAAc;AAO/B,MAAa,eAAe,EAAE,UAAU,gBAAkC;CACxE,MAAM,CAAC,SAAS,cAAc,SAAS,MAAK;AAE5C,iBAAgB;AACd,aAAW,KAAI;AACf,eAAa,WAAW,MAAK;IAC5B,EAAE,CAAA;AAEL,KAAI,CAAC,QAAS,QAAO;AAErB,QAAO,aAAa,UAAU,aAAa,SAAS,KAAI"}
|
package/dist/Alert.js
CHANGED
|
@@ -12,10 +12,22 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
12
12
|
const Alert = ({ className, description, icon, id, onClose, title, variant = "default" }) => {
|
|
13
13
|
const wrapperRef = useRef(null);
|
|
14
14
|
const displayIcon = icon ?? {
|
|
15
|
-
info: /* @__PURE__ */ jsx(InfoIcon, {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
info: /* @__PURE__ */ jsx(InfoIcon, {
|
|
16
|
+
className: "text-alert-info-text",
|
|
17
|
+
size: 24
|
|
18
|
+
}),
|
|
19
|
+
success: /* @__PURE__ */ jsx(CheckSquareIcon, {
|
|
20
|
+
className: "text-alert-success-text",
|
|
21
|
+
size: 24
|
|
22
|
+
}),
|
|
23
|
+
warning: /* @__PURE__ */ jsx(WarningIcon, {
|
|
24
|
+
className: "text-alert-warning-text",
|
|
25
|
+
size: 24
|
|
26
|
+
}),
|
|
27
|
+
danger: /* @__PURE__ */ jsx(CloseCircleIcon, {
|
|
28
|
+
className: "text-alert-danger-text",
|
|
29
|
+
size: 24
|
|
30
|
+
}),
|
|
19
31
|
default: null
|
|
20
32
|
}[variant];
|
|
21
33
|
const closeAlert = useCallback(() => {
|
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 }, 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 aria-live={ariaLive} className={cn('alert-wrapper transition-opacity duration-200 ease-out', className)} data-slot='alert' data-variant={variant} id={id} ref={wrapperRef} variant={variant}>\n <AlertHeader>\n {displayIcon}\n <AlertTitle variant={variant}>{title}</AlertTitle>\n <AlertCloseButton onClick={handleClose} variant={variant} />\n </AlertHeader>\n {description && (\n <AlertDescription className={displayIcon ? 'ml-8' : undefined} variant={variant}>\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,
|
|
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' size={24} />,\n success: <CheckSquareIcon className='text-alert-success-text' size={24} />,\n warning: <WarningIcon className='text-alert-warning-text' size={24} />,\n danger: <CloseCircleIcon className='text-alert-danger-text' size={24} />,\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 aria-live={ariaLive} className={cn('alert-wrapper transition-opacity duration-200 ease-out', className)} data-slot='alert' data-variant={variant} id={id} ref={wrapperRef} variant={variant}>\n <AlertHeader>\n {displayIcon}\n <AlertTitle variant={variant}>{title}</AlertTitle>\n <AlertCloseButton onClick={handleClose} variant={variant} />\n </AlertHeader>\n {description && (\n <AlertDescription className={displayIcon ? 'ml-8' : undefined} variant={variant}>\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;GAAU,WAAU;GAAuB,MAAM;GAAM;EAC7D,SAAS,oBAAC,iBAAD;GAAiB,WAAU;GAA0B,MAAM;GAAM;EAC1E,SAAS,oBAAC,aAAD;GAAa,WAAU;GAA0B,MAAM;GAAM;EACtE,QAAQ,oBAAC,iBAAD;GAAiB,WAAU;GAAyB,MAAM;GAAM;EACxE,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;EAAW,aAJE,YAAY,aAAa,YAAY,WAAW,cAAc;EAI3C,WAAW,GAAG,0DAA0D,UAAU;EAAE,aAAU;EAAQ,gBAAc;EAAa;EAAI,KAAK;EAAqB;YAA/L,CACE,qBAAC,aAAD;GACG;GACD,oBAAC,YAAD;IAAqB;cAAU;IAAmB;GAClD,oBAAC,kBAAD;IAAkB,SAAS;IAAsB;IAAW;GAChD,KACb,eACC,oBAAC,kBAAD;GAAkB,WAAW,cAAc,SAAS;GAAoB;aACrE;GACgB,EAEX;KACA"}
|
package/dist/AlertDialog.js
CHANGED
|
@@ -25,14 +25,14 @@ const AlertDialogTrigger = (props) => {
|
|
|
25
25
|
};
|
|
26
26
|
const AlertDialogBackdrop = ({ className, ...props }) => {
|
|
27
27
|
return /* @__PURE__ */ jsx(AlertDialog$1.Backdrop, {
|
|
28
|
-
className: cn("inset-0 bg-black/50 backdrop-blur-sm fixed z-
|
|
28
|
+
className: cn("inset-0 bg-black/50 backdrop-blur-sm fixed z-[60] 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),
|
|
29
29
|
"data-slot": "alert-dialog-backdrop",
|
|
30
30
|
...props
|
|
31
31
|
});
|
|
32
32
|
};
|
|
33
33
|
const AlertDialogViewport = ({ className, ...props }) => {
|
|
34
34
|
return /* @__PURE__ */ jsx(AlertDialog$1.Viewport, {
|
|
35
|
-
className: cn("fixed inset-0 z-
|
|
35
|
+
className: cn("fixed inset-0 z-[60] grid grid-rows-[1fr_auto_3fr] justify-items-center p-4", className),
|
|
36
36
|
"data-slot": "alert-dialog-viewport",
|
|
37
37
|
...props
|
|
38
38
|
});
|
|
@@ -63,7 +63,7 @@ const AlertDialogHeader = ({ className, children, icon, iconColor, variant = "de
|
|
|
63
63
|
className: builtInIconColorClass[variant],
|
|
64
64
|
size: 24
|
|
65
65
|
}) : /* @__PURE__ */ jsx(WarningIcon, {
|
|
66
|
-
className: builtInIconColorClass[variant],
|
|
66
|
+
className: cn(builtInIconColorClass[variant], "-translate-y-px"),
|
|
67
67
|
size: 24
|
|
68
68
|
});
|
|
69
69
|
const customIconStyle = variant === "custom" ? {
|
package/dist/AlertDialog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlertDialog.js","names":["AlertDialogPrimitive"],"sources":["../src/components/AlertDialog/AlertDialog.tsx"],"sourcesContent":["import { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog'\nimport { CheckCircleIcon } from '@components/Icons/CheckCircleIcon'\nimport { WarningIcon } from '@components/Icons/WarningIcon'\nimport { cn } from '@utils/twUtils'\nimport { Children, type ComponentProps, type CSSProperties, type ReactElement, type ReactNode } from 'react'\n\nexport interface AlertDialogProps<Payload = unknown> extends AlertDialogPrimitive.Root.Props<Payload> {\n open?: AlertDialogPrimitive.Root.Props<Payload>['open']\n onOpenChange?: AlertDialogPrimitive.Root.Props<Payload>['onOpenChange']\n handle?: AlertDialogPrimitive.Root.Props<Payload>['handle']\n onOpenChangeComplete?: AlertDialogPrimitive.Root.Props<Payload>['onOpenChangeComplete']\n triggerId?: AlertDialogPrimitive.Root.Props<Payload>['triggerId']\n}\n\nexport interface AlertDialogTriggerProps extends AlertDialogPrimitive.Trigger.Props {\n}\n\nexport interface AlertDialogPopupProps extends AlertDialogPrimitive.Popup.Props {\n portalProps?: AlertDialogPrimitive.Portal.Props\n}\n\nexport type AlertDialogVariant = 'default' | 'warning' | 'success' | 'custom'\n\ninterface AlertDialogRootComponent {\n <Payload = unknown>(props: AlertDialogPrimitive.Root.Props<Payload>): ReactElement\n createHandle: typeof AlertDialogPrimitive.createHandle\n displayName?: string\n}\n\nconst AlertDialogRoot = <Payload = unknown,>(\n props: AlertDialogPrimitive.Root.Props<Payload>,\n): ReactElement => {\n return <AlertDialogPrimitive.Root {...props} />\n}\n\nexport const AlertDialog = Object.assign(AlertDialogRoot, {\n createHandle: AlertDialogPrimitive.createHandle,\n}) as AlertDialogRootComponent\nAlertDialog.displayName = 'AlertDialog'\n\nexport const AlertDialogCreateHandle: typeof AlertDialogPrimitive.createHandle =\n AlertDialog.createHandle\n\nexport const AlertDialogPortal = (\n props: AlertDialogPrimitive.Portal.Props,\n): ReactElement => {\n return <AlertDialogPrimitive.Portal {...props} />\n}\nAlertDialogPortal.displayName = 'AlertDialogPortal'\n\nexport const AlertDialogTrigger = (\n props: AlertDialogTriggerProps,\n): ReactElement => {\n return (\n <AlertDialogPrimitive.Trigger data-slot='alert-dialog-trigger' {...props} />\n )\n}\n\nexport const AlertDialogBackdrop = ({\n className,\n ...props\n}: AlertDialogPrimitive.Backdrop.Props): ReactElement => {\n return (\n <AlertDialogPrimitive.Backdrop\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-
|
|
1
|
+
{"version":3,"file":"AlertDialog.js","names":["AlertDialogPrimitive"],"sources":["../src/components/AlertDialog/AlertDialog.tsx"],"sourcesContent":["import { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog'\nimport { CheckCircleIcon } from '@components/Icons/CheckCircleIcon'\nimport { WarningIcon } from '@components/Icons/WarningIcon'\nimport { cn } from '@utils/twUtils'\nimport { Children, type ComponentProps, type CSSProperties, type ReactElement, type ReactNode } from 'react'\n\nexport interface AlertDialogProps<Payload = unknown> extends AlertDialogPrimitive.Root.Props<Payload> {\n open?: AlertDialogPrimitive.Root.Props<Payload>['open']\n onOpenChange?: AlertDialogPrimitive.Root.Props<Payload>['onOpenChange']\n handle?: AlertDialogPrimitive.Root.Props<Payload>['handle']\n onOpenChangeComplete?: AlertDialogPrimitive.Root.Props<Payload>['onOpenChangeComplete']\n triggerId?: AlertDialogPrimitive.Root.Props<Payload>['triggerId']\n}\n\nexport interface AlertDialogTriggerProps extends AlertDialogPrimitive.Trigger.Props {\n}\n\nexport interface AlertDialogPopupProps extends AlertDialogPrimitive.Popup.Props {\n portalProps?: AlertDialogPrimitive.Portal.Props\n}\n\nexport type AlertDialogVariant = 'default' | 'warning' | 'success' | 'custom'\n\ninterface AlertDialogRootComponent {\n <Payload = unknown>(props: AlertDialogPrimitive.Root.Props<Payload>): ReactElement\n createHandle: typeof AlertDialogPrimitive.createHandle\n displayName?: string\n}\n\nconst AlertDialogRoot = <Payload = unknown,>(\n props: AlertDialogPrimitive.Root.Props<Payload>,\n): ReactElement => {\n return <AlertDialogPrimitive.Root {...props} />\n}\n\nexport const AlertDialog = Object.assign(AlertDialogRoot, {\n createHandle: AlertDialogPrimitive.createHandle,\n}) as AlertDialogRootComponent\nAlertDialog.displayName = 'AlertDialog'\n\nexport const AlertDialogCreateHandle: typeof AlertDialogPrimitive.createHandle =\n AlertDialog.createHandle\n\nexport const AlertDialogPortal = (\n props: AlertDialogPrimitive.Portal.Props,\n): ReactElement => {\n return <AlertDialogPrimitive.Portal {...props} />\n}\nAlertDialogPortal.displayName = 'AlertDialogPortal'\n\nexport const AlertDialogTrigger = (\n props: AlertDialogTriggerProps,\n): ReactElement => {\n return (\n <AlertDialogPrimitive.Trigger data-slot='alert-dialog-trigger' {...props} />\n )\n}\n\nexport const AlertDialogBackdrop = ({\n className,\n ...props\n}: AlertDialogPrimitive.Backdrop.Props): ReactElement => {\n return (\n <AlertDialogPrimitive.Backdrop\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-[60] motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:animate-out',\n 'motion-safe:data-[state=closed]:fade-out-0', className)}\n data-slot='alert-dialog-backdrop'\n {...props}\n />\n )\n}\n\nexport const AlertDialogViewport = ({\n className,\n ...props\n}: AlertDialogPrimitive.Viewport.Props): ReactElement => {\n return (\n <AlertDialogPrimitive.Viewport\n className={cn('fixed inset-0 z-[60] grid grid-rows-[1fr_auto_3fr] justify-items-center p-4', className)}\n data-slot='alert-dialog-viewport'\n {...props}\n />\n )\n}\n\nexport const AlertDialogPopup = ({\n className,\n portalProps,\n ...props\n}: AlertDialogPopupProps): ReactElement => {\n return (\n <AlertDialogPortal {...portalProps}>\n <AlertDialogBackdrop />\n <AlertDialogViewport>\n <AlertDialogPrimitive.Popup\n className={cn(\n 'relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg origin-center flex-col rounded-xl border border-black/40 bg-level-zero text-text-primary',\n 'shadow-elevation-3 transition-[scale,opacity,translate] duration-200 ease-in-out before:pointer-events-none before:absolute before:inset-0',\n 'before:rounded-[calc(var(--radius-2xl)-1px)] data-[ending-style]:opacity-0 data-[starting-style]:opacity-0',\n className,\n )}\n data-slot='alert-dialog-popup'\n {...props}\n />\n </AlertDialogViewport>\n </AlertDialogPortal>\n )\n}\n\nexport const AlertDialogHeader = ({\n className,\n children,\n icon,\n iconColor,\n variant = 'default',\n ...props\n}: ComponentProps<'div'> & {\n icon?: ReactNode\n iconColor?: string\n variant?: AlertDialogVariant\n}): ReactElement => {\n const customIconColor = iconColor ?? 'var(--color-danger-400)'\n const builtInIconClasses = {\n default: 'bg-danger-400/20 text-danger-400',\n warning: 'bg-warning-400/20 text-warning-400',\n success: 'bg-success-400/20 text-success-400',\n } as const\n const builtInIconColorClass = {\n default: 'text-danger-400',\n warning: 'text-warning-400',\n success: 'text-success-400',\n } as const\n\n const headerIcon = variant === 'custom'\n ? (icon ?? <WarningIcon size={24} />)\n : variant === 'success'\n ? <CheckCircleIcon className={builtInIconColorClass[variant]} size={24} />\n : <WarningIcon className={cn(builtInIconColorClass[variant], '-translate-y-px')} size={24} />\n\n const customIconStyle: CSSProperties | undefined = variant === 'custom'\n ? {\n color: customIconColor,\n backgroundColor: `oklch(from ${customIconColor} l c h / 0.2)`,\n }\n : undefined\n const [titleChild, ...descriptionChildren] = Children.toArray(children)\n\n return (\n <div\n className={cn(\n 'flex flex-col gap-2 p-6',\n className,\n )}\n data-slot='alert-dialog-header'\n {...props}\n >\n <div className='flex items-center gap-3'>\n <div\n aria-hidden='true'\n className={cn(\n 'rounded-full flex items-center justify-center size-10 shrink-0 [&>svg]:size-6!',\n variant !== 'custom' && builtInIconClasses[variant],\n )}\n data-slot='alert-dialog-header-icon'\n style={customIconStyle}\n >\n {headerIcon}\n </div>\n {titleChild}\n </div>\n {descriptionChildren.length > 0 && descriptionChildren}\n </div>\n )\n}\n\nexport const AlertDialogFooter = ({\n className,\n children,\n ...props\n}: ComponentProps<'div'>): ReactElement => {\n return (\n <div\n className={cn('flex gap-2 px-6 pb-6 pt-2 flex-row justify-end rounded-b-[calc(var(--radius-2xl)-1px)]', className)}\n data-slot='alert-dialog-footer'\n {...props}\n >\n {children}\n </div>\n )\n}\n\nexport const AlertDialogTitle = ({\n className,\n ...props\n}: AlertDialogPrimitive.Title.Props): ReactElement => {\n return (\n <AlertDialogPrimitive.Title\n className={cn(\n 'font-heading font-medium text-xl leading-tight',\n className,\n )}\n data-slot='alert-dialog-title'\n {...props}\n />\n )\n}\n\nexport const AlertDialogDescription = ({\n className,\n ...props\n}: AlertDialogPrimitive.Description.Props): ReactElement => {\n return (\n <AlertDialogPrimitive.Description\n className={cn('text-text-secondary! text-sm mt-1', className)}\n data-slot='alert-dialog-description'\n {...props}\n />\n )\n}\n\nexport const AlertDialogClose = (\n props: AlertDialogPrimitive.Close.Props,\n): ReactElement => {\n return (\n <AlertDialogPrimitive.Close data-slot='alert-dialog-close' {...props} />\n )\n}\n"],"mappings":";;;;;;;;;AA6BA,MAAM,mBACJ,UACiB;AACjB,QAAO,oBAACA,cAAqB,MAAtB,EAA2B,GAAI,OAAS;;AAGjD,MAAa,cAAc,OAAO,OAAO,iBAAiB,EACxD,cAAcA,cAAqB,cACpC,CAAC;AACF,YAAY,cAAc;AAE1B,MAAa,0BACX,YAAY;AAEd,MAAa,qBACX,UACiB;AACjB,QAAO,oBAACA,cAAqB,QAAtB,EAA6B,GAAI,OAAS;;AAEnD,kBAAkB,cAAc;AAEhC,MAAa,sBACX,UACiB;AACjB,QACE,oBAACA,cAAqB,SAAtB;EAA8B,aAAU;EAAuB,GAAI;EAAS;;AAIhF,MAAa,uBAAuB,EAClC,WACA,GAAG,YACoD;AACvD,QACE,oBAACA,cAAqB,UAAtB;EACE,WAAW,GAAG,kLACd,8CAA8C,UAAU;EACxD,aAAU;EACV,GAAI;EACJ;;AAIN,MAAa,uBAAuB,EAClC,WACA,GAAG,YACoD;AACvD,QACE,oBAACA,cAAqB,UAAtB;EACE,WAAW,GAAG,+EAA+E,UAAU;EACvG,aAAU;EACV,GAAI;EACJ;;AAIN,MAAa,oBAAoB,EAC/B,WACA,aACA,GAAG,YACsC;AACzC,QACE,qBAAC,mBAAD;EAAmB,GAAI;YAAvB,CACE,oBAAC,qBAAD,EAAuB,GACvB,oBAAC,qBAAD,YACE,oBAACA,cAAqB,OAAtB;GACE,WAAW,GACT,iKACA,8IACA,8GACA,UACD;GACD,aAAU;GACV,GAAI;GACJ,GACkB,EACJ;;;AAIxB,MAAa,qBAAqB,EAChC,WACA,UACA,MACA,WACA,UAAU,WACV,GAAG,YAKe;CAClB,MAAM,kBAAkB,aAAa;CACrC,MAAM,qBAAqB;EACzB,SAAS;EACT,SAAS;EACT,SAAS;EACV;CACD,MAAM,wBAAwB;EAC5B,SAAS;EACT,SAAS;EACT,SAAS;EACV;CAED,MAAM,aAAa,YAAY,WAC1B,QAAQ,oBAAC,aAAD,EAAa,MAAM,IAAM,IAClC,YAAY,YACV,oBAAC,iBAAD;EAAiB,WAAW,sBAAsB;EAAU,MAAM;EAAM,IACxE,oBAAC,aAAD;EAAa,WAAW,GAAG,sBAAsB,UAAU,kBAAkB;EAAE,MAAM;EAAM;CAEjG,MAAM,kBAA6C,YAAY,WAC3D;EACA,OAAO;EACP,iBAAiB,cAAc,gBAAgB;EAChD,GACC;CACJ,MAAM,CAAC,YAAY,GAAG,uBAAuB,SAAS,QAAQ,SAAS;AAEvE,QACE,qBAAC,OAAD;EACE,WAAW,GACT,2BACA,UACD;EACD,aAAU;EACV,GAAI;YANN,CAQE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IACE,eAAY;IACZ,WAAW,GACT,kFACA,YAAY,YAAY,mBAAmB,SAC5C;IACD,aAAU;IACV,OAAO;cAEN;IACG,GACL,WACG;MACL,oBAAoB,SAAS,KAAK,oBAC/B;;;AAIV,MAAa,qBAAqB,EAChC,WACA,UACA,GAAG,YACsC;AACzC,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,0FAA0F,UAAU;EAClH,aAAU;EACV,GAAI;EAEH;EACG;;AAIV,MAAa,oBAAoB,EAC/B,WACA,GAAG,YACiD;AACpD,QACE,oBAACA,cAAqB,OAAtB;EACE,WAAW,GACT,kDACA,UACD;EACD,aAAU;EACV,GAAI;EACJ;;AAIN,MAAa,0BAA0B,EACrC,WACA,GAAG,YACuD;AAC1D,QACE,oBAACA,cAAqB,aAAtB;EACE,WAAW,GAAG,qCAAqC,UAAU;EAC7D,aAAU;EACV,GAAI;EACJ;;AAIN,MAAa,oBACX,UACiB;AACjB,QACE,oBAACA,cAAqB,OAAtB;EAA4B,aAAU;EAAqB,GAAI;EAAS"}
|
package/dist/Avatar.js
CHANGED
|
@@ -51,7 +51,6 @@ const Avatar = ({ alt, className, fallback, icon, imageSource, size = "md", user
|
|
|
51
51
|
if (userFullName) return /* @__PURE__ */ jsx("span", {
|
|
52
52
|
"aria-label": userFullName + " avatar",
|
|
53
53
|
className: cn("font-bold tracking-tighter flex size-full items-center justify-center text-inherit font-stretch-condensed", textSizeClasses[size]),
|
|
54
|
-
"data-testid": "spectral-avatar-initials",
|
|
55
54
|
children: getInitials(userFullName)
|
|
56
55
|
});
|
|
57
56
|
if (icon) {
|
|
@@ -75,7 +74,6 @@ const Avatar = ({ alt, className, fallback, icon, imageSource, size = "md", user
|
|
|
75
74
|
alt: alt ?? "Avatar",
|
|
76
75
|
"aria-label": alt ?? "Avatar",
|
|
77
76
|
className: "inset-0 absolute size-full rounded-full object-cover",
|
|
78
|
-
"data-testid": "spectral-avatar-image",
|
|
79
77
|
height: imageDimensions[size],
|
|
80
78
|
role: "img",
|
|
81
79
|
src: imageSource,
|
|
@@ -83,24 +81,18 @@ const Avatar = ({ alt, className, fallback, icon, imageSource, size = "md", user
|
|
|
83
81
|
});
|
|
84
82
|
if (imageSource && imageStatus === "error" && fallback) return /* @__PURE__ */ jsx("span", {
|
|
85
83
|
className: "text-inherit flex size-full items-center justify-center",
|
|
86
|
-
"data-testid": "spectral-avatar-img-error-fallback",
|
|
87
84
|
children: fallback
|
|
88
85
|
});
|
|
89
86
|
if (fallback) return /* @__PURE__ */ jsx("span", {
|
|
90
87
|
className: cn("text-inherit flex size-full items-center justify-center", textSizeClasses[size]),
|
|
91
|
-
"data-testid": "spectral-avatar-fallback",
|
|
92
88
|
children: fallback
|
|
93
89
|
});
|
|
94
|
-
if (imageSource && imageStatus === "loading") return /* @__PURE__ */ jsx("span", {
|
|
95
|
-
className: "motion-safe:animate-pulse flex size-full items-center justify-center",
|
|
96
|
-
"data-testid": "spectral-avatar-loading"
|
|
97
|
-
});
|
|
90
|
+
if (imageSource && imageStatus === "loading") return /* @__PURE__ */ jsx("span", { className: "motion-safe:animate-pulse flex size-full items-center justify-center" });
|
|
98
91
|
return /* @__PURE__ */ jsx(UserIcon, { className: "text-inherit" });
|
|
99
92
|
};
|
|
100
93
|
return /* @__PURE__ */ jsx("div", {
|
|
101
94
|
className: cn("text-text-primary relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-level-two", sizeClasses[size], className),
|
|
102
95
|
"data-slot": "avatar",
|
|
103
|
-
"data-testid": "spectral-avatar",
|
|
104
96
|
children: renderContent()
|
|
105
97
|
});
|
|
106
98
|
};
|
package/dist/Avatar.js.map
CHANGED
|
@@ -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: '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-inherit 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='text-inherit flex size-full items-center justify-center'>\n {isValidElement(icon)\n ? (() => {\n const baseIconProps = {\n className: cn('shrink-0 text-inherit', (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 className='text-inherit flex size-full items-center justify-center' data-testid='spectral-avatar-img-error-fallback'>\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 className={cn('text-inherit flex size-full items-center justify-center', textSizeClasses[size as keyof typeof textSizeClasses])} data-testid='spectral-avatar-fallback'>\n {fallback}\n </span>\n )\n }\n\n // Show empty/skeleton state while image is loading\n if (imageSource && imageStatus === 'loading') {\n return <span className='motion-safe:animate-pulse flex size-full items-center justify-center' data-testid='spectral-avatar-loading' />\n }\n\n // Last resort: (only when no imageSource and no fallback)\n return <UserIcon className='text-inherit' />\n }\n\n return (\n <div className={cn('text-text-primary relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-level-two', sizeClasses[size as keyof typeof sizeClasses], className)} data-slot='avatar' data-testid='spectral-avatar'>\n {renderContent()}\n </div>\n )\n}\n"],"mappings":";;;;;;;AAgBA,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;
|
|
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-inherit 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='text-inherit flex size-full items-center justify-center'>\n {isValidElement(icon)\n ? (() => {\n const baseIconProps = {\n className: cn('shrink-0 text-inherit', (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 className='text-inherit flex size-full items-center justify-center' data-testid='spectral-avatar-img-error-fallback'>\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 className={cn('text-inherit flex size-full items-center justify-center', textSizeClasses[size as keyof typeof textSizeClasses])} data-testid='spectral-avatar-fallback'>\n {fallback}\n </span>\n )\n }\n\n // Show empty/skeleton state while image is loading\n if (imageSource && imageStatus === 'loading') {\n return <span className='motion-safe:animate-pulse flex size-full items-center justify-center' data-testid='spectral-avatar-loading' />\n }\n\n // Last resort: (only when no imageSource and no fallback)\n return <UserIcon className='text-inherit' />\n }\n\n return (\n <div className={cn('text-text-primary relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-level-two', sizeClasses[size as keyof typeof sizeClasses], className)} data-slot='avatar' data-testid='spectral-avatar'>\n {renderContent()}\n </div>\n )\n}\n"],"mappings":";;;;;;;AAgBA,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,kBAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,kBAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,YAAY;CAChB,IAAI;CACJ,IAAI;CACJ,IAAI;CACN;AAEA,MAAM,eAAe,SAAyB;CAC5C,MAAM,UAAU,KAAK,MAAK;AAC1B,KAAI,CAAC,QAAS,QAAO;CAErB,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC,OAAO,QAAO;AAEjD,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,KAAI,MAAM,WAAW,EAAG,QAAO,MAAM,GAAG,OAAO,EAAE,CAAC,aAAY;AAE9D,SAAQ,MAAM,GAAG,OAAO,EAAE,GAAG,MAAM,MAAM,SAAS,GAAG,OAAO,EAAE,EAAE,aAAY;;AAG9E,MAAa,UAAU,EAAE,KAAK,WAAW,UAAU,MAAM,aAAa,OAAO,MAAM,mBAAgC;CACjH,MAAM,CAAC,aAAa,kBAAkB,SAAyC,UAAS;AAExF,iBAAgB;AACd,MAAI,CAAC,YAAa;AAElB,iBAAe,UAAS;EAExB,MAAM,MAAM,IAAI,OAAM;AACtB,MAAI,MAAM;AAEV,MAAI,eAAe,eAAe,SAAQ;AAC1C,MAAI,gBAAgB,eAAe,QAAO;AAE1C,eAAa;AACX,OAAI,SAAS;AACb,OAAI,UAAU;;IAEf,CAAC,YAAY,CAAA;CAEhB,MAAM,sBAAsB;AAC1B,MAAI,aACF,QACE,oBAAC,QAAD;GAEE,cAAY,eAAe;GAC3B,WAAW,GAAG,6GAA6G,gBAAgB,MAAsC;aAGhL,YAAY,aAAa;GACtB;AAIV,MAAI,MAAM;GACR,MAAM,WAAW,UAAU;AAE3B,UACE,oBAAC,QAAD;IAAM,WAAU;cACb,eAAe,KAAI,UACT;KACL,MAAM,gBAAgB;MACpB,WAAW,GAAG,yBAA0B,KAAK,MAAiC,UAAU;MACxF,eAAe;MACjB;AAMA,SAHsB,KAAK,KACW,aAAa,SAAS,OAAO,IAAI,MAOrE,QAAO,aAAa,MAAM;MAHxB,GAAG;MACH,MAAM;MAEmC,CAAA;AAG7C,YAAO,aAAa,MAAM,cAAa;QACtC,GACH;IACA;;AAIV,MAAI,eAAe,gBAAgB,SACjC,QACE,oBAAC,OAAD;GACE,KAAK,OAAO;GACZ,cAAY,OAAO;GACnB,WAAU;GAEV,QAAQ,gBAAgB;GACxB,MAAK;GACL,KAAK;GACL,OAAO,gBAAgB;GACxB;AAIL,MAAI,eAAe,gBAAgB,WAAW,SAC5C,QACE,oBAAC,QAAD;GAAM,WAAU;aACb;GACG;AAKV,MAAI,SACF,QACE,oBAAC,QAAD;GAAM,WAAW,GAAG,2DAA2D,gBAAgB,MAAsC;aAClI;GACG;AAKV,MAAI,eAAe,gBAAgB,UACjC,QAAO,oBAAC,QAAD,EAAM,WAAU,wEAA8G;AAIvI,SAAO,oBAAC,UAAD,EAAU,WAAU,gBAAgB;;AAG7C,QACE,oBAAC,OAAD;EAAK,WAAW,GAAG,yHAAyH,YAAY,OAAmC,UAAU;EAAE,aAAU;YAC9M,eAAe;EACb"}
|
package/dist/Badge.js
CHANGED
|
@@ -19,7 +19,6 @@ const Badge = ({ asChild = false, className, variant, ...props }) => {
|
|
|
19
19
|
return /* @__PURE__ */ jsx(asChild ? Slot : "span", {
|
|
20
20
|
className: cn(badgeVariants({ variant }), className),
|
|
21
21
|
"data-slot": "badge",
|
|
22
|
-
"data-testid": "spectral-badge",
|
|
23
22
|
...props
|
|
24
23
|
});
|
|
25
24
|
};
|
package/dist/Badge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.js","names":[],"sources":["../src/components/Badge/Badge.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 type BadgeProps = ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }\n\nconst badgeVariants = cva(\n `rounded-sm px-2 py-0.5 text-xs font-medium [&>svg]:size-3 gap-1 inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-[background-color,color,box-shadow] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent aria-invalid:border-danger-200 aria-invalid:outline-danger-200/20 [&>svg]:pointer-events-none`,\n {\n variants: {\n variant: {\n default: 'bg-badge-primary-bg text-text-primary group-active:[background-color:var(--color-toggle-border--active)] group-aria-pressed:[background-color:var(--color-toggle-border--active)] group-data-[state=on]:[background-color:var(--color-toggle-border--active)] [a&]:hover:bg-badge-primary-bg--hover',\n secondary: '[a&]:hover:bg-badge-secondary-bg--hover bg-badge-secondary-bg text-badge-secondary-text',\n destructive: 'bg-badge-destructive-bg text-text-primary focus-visible:outline-badge-destructive-border [a&]:hover:bg-danger-400',\n outline: '[a&]:hover:text-accent-foreground border border-badge-outline-border text-text-primary [a&]:hover:bg-accent',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n)\n\nexport const Badge = ({ asChild = false, className, variant, ...props }: BadgeProps) => {\n const Comp = asChild ? Slot : 'span'\n\n return <Comp className={cn(badgeVariants({ variant }), className)} data-slot='badge' data-testid='spectral-badge' {...props} />\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,gBAAgB,IACpB,6XACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,WAAW;EACX,aAAa;EACb,SAAS;EACV,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,
|
|
1
|
+
{"version":3,"file":"Badge.js","names":[],"sources":["../src/components/Badge/Badge.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 type BadgeProps = ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }\n\nconst badgeVariants = cva(\n `rounded-sm px-2 py-0.5 text-xs font-medium [&>svg]:size-3 gap-1 inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-[background-color,color,box-shadow] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent aria-invalid:border-danger-200 aria-invalid:outline-danger-200/20 [&>svg]:pointer-events-none`,\n {\n variants: {\n variant: {\n default: 'bg-badge-primary-bg text-text-primary group-active:[background-color:var(--color-toggle-border--active)] group-aria-pressed:[background-color:var(--color-toggle-border--active)] group-data-[state=on]:[background-color:var(--color-toggle-border--active)] [a&]:hover:bg-badge-primary-bg--hover',\n secondary: '[a&]:hover:bg-badge-secondary-bg--hover bg-badge-secondary-bg text-badge-secondary-text',\n destructive: 'bg-badge-destructive-bg text-text-primary focus-visible:outline-badge-destructive-border [a&]:hover:bg-danger-400',\n outline: '[a&]:hover:text-accent-foreground border border-badge-outline-border text-text-primary [a&]:hover:bg-accent',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n)\n\nexport const Badge = ({ asChild = false, className, variant, ...props }: BadgeProps) => {\n const Comp = asChild ? Slot : 'span'\n\n return <Comp className={cn(badgeVariants({ variant }), className)} data-slot='badge' data-testid='spectral-badge' {...props} />\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,gBAAgB,IACpB,6XACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,WAAW;EACX,aAAa;EACb,SAAS;EACV,EACF;CACD,iBAAiB,EACf,SAAS,WACV;CACF,CACH;AAEA,MAAa,SAAS,EAAE,UAAU,OAAO,WAAW,SAAS,GAAG,YAAwB;AAGtF,QAAO,oBAFM,UAAU,OAAO,QAEvB;EAAM,WAAW,GAAG,cAAc,EAAE,SAAS,CAAC,EAAE,UAAU;EAAE,aAAU;EAAqC,GAAI;EAAQ"}
|
package/dist/Button.js
CHANGED
|
@@ -70,7 +70,6 @@ const Button = ({ asChild = false, children, className, dataTestId, disabled, en
|
|
|
70
70
|
className: cn(classes, canUseAsChild && "no-underline! before:content-none after:content-none", canUseAsChild && disabled && "pointer-events-none opacity-50"),
|
|
71
71
|
"data-as-child": canUseAsChild ? "true" : void 0,
|
|
72
72
|
"data-state": state,
|
|
73
|
-
"data-testid": dataTestId ?? `spectral-button-${variant}`,
|
|
74
73
|
"data-variant": variant,
|
|
75
74
|
disabled: canUseAsChild ? void 0 : disabled,
|
|
76
75
|
id,
|
|
@@ -84,7 +83,6 @@ const Button = ({ asChild = false, children, className, dataTestId, disabled, en
|
|
|
84
83
|
startIcon && /* @__PURE__ */ jsx("span", {
|
|
85
84
|
className: cn("flex", variant !== "unstyled" && "pr-1"),
|
|
86
85
|
"aria-hidden": true,
|
|
87
|
-
"data-testid": "spectral-button-start-icon",
|
|
88
86
|
children: startIcon
|
|
89
87
|
}),
|
|
90
88
|
state === "loading" && /* @__PURE__ */ jsx(LoaderIcon, { className: "ml-2 size-5!" }),
|
|
@@ -92,7 +90,6 @@ const Button = ({ asChild = false, children, className, dataTestId, disabled, en
|
|
|
92
90
|
endIcon && state !== "loading" && /* @__PURE__ */ jsx("span", {
|
|
93
91
|
className: cn("flex", variant !== "unstyled" && "pl-2"),
|
|
94
92
|
"aria-hidden": true,
|
|
95
|
-
"data-testid": "spectral-button-end-icon",
|
|
96
93
|
children: endIcon
|
|
97
94
|
})
|
|
98
95
|
] })
|
package/dist/Button.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","names":[],"sources":["../src/components/Button/Button.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { Slot, type AsChildProp } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { Children, isValidElement, type ButtonHTMLAttributes, type MouseEvent, type ReactNode, type Ref } from 'react'\n\nconst buttonVariants = cva(\n `gap-2 rounded-md font-semibold [&_svg]:size-4 relative flex cursor-pointer items-center justify-center border font-sans! whitespace-nowrap transition-[background-color,border-color,color,transform] duration-200 ease-out motion-reduce:transition-none disabled:active:scale-100 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0`,\n {\n variants: {\n variant: {\n primary: `border-button-primary-border bg-button-primary-bg text-button-primary-text hover:border-button-primary-border--hover hover:bg-button-primary-bg--hover hover:text-button-primary-text--hover active:scale-[0.97] focus-visible:outline-button-primary-border disabled:border-button-primary-border--disabled disabled:bg-button-primary-bg--disabled disabled:text-button-primary-text--disabled`,\n secondary: `border-button-secondary-border bg-button-secondary-bg text-button-secondary-text hover:bg-button-secondary-bg--hover hover:border-button-secondary-border--hover hover:text-button-secondary-text--hover active:scale-[0.97] focus-visible:outline-button-secondary-border disabled:border-button-secondary-border--disabled disabled:text-button-secondary-text--disabled`,\n outline: `border-button-secondary-border bg-button-secondary-bg text-button-secondary-text hover:bg-button-secondary-bg--hover hover:border-button-secondary-border--hover hover:text-button-secondary-text--hover active:scale-[0.97] focus-visible:outline-button-secondary-border disabled:border-button-secondary-border--disabled disabled:text-button-secondary-text--disabled`,\n ghost: 'border-none bg-button-ghost-bg text-button-ghost-text hover:bg-button-ghost-bg--hover hover:text-button-ghost-text--hover active:scale-[0.97] focus-visible:outline-button-outline-border disabled:text-button-ghost-text--disabled',\n unstyled: 'font-inherit! font-normal gap-0 p-0! inline-flex w-auto! justify-start rounded-none! border-none! bg-transparent text-inherit shadow-none! hover:cursor-pointer hover:bg-transparent active:scale-100 focus-visible:outline-button-outline-border disabled:opacity-50',\n destructive: 'border-button-destructive-border bg-button-destructive-bg text-button-destructive-text hover:bg-button-destructive-bg--hover active:scale-[0.97] disabled:border-button-destructive-border--disabled disabled:bg-button-destructive-bg--disabled disabled:text-button-destructive-text--disabled focus-visible:outline-button-destructive-border',\n },\n size: {\n small: 'py-1.5 px-3 text-sm! w-fit',\n default: 'py-2 px-4 text-sm! w-fit',\n fullWidth: 'py-2 px-4 text-sm! w-full',\n },\n state: {\n default: '',\n error: 'bg-button-danger text-text-primary transition focus-visible:outline-danger-400',\n loading: 'pointer-events-none cursor-wait',\n },\n },\n defaultVariants: {\n variant: 'primary',\n state: 'default',\n size: 'default',\n },\n },\n)\n\nexport interface ButtonProps extends AsChildProp, Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'>, VariantProps<typeof buttonVariants> {\n dataTestId?: string\n disabled?: boolean\n endIcon?: ReactNode\n label?: string\n onClick?: (event: MouseEvent<HTMLElement>) => void\n size?: 'small' | 'default' | 'fullWidth'\n startIcon?: ReactNode\n state?: 'default' | 'error' | 'loading'\n type?: 'button' | 'submit' | 'reset'\n variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'unstyled'\n}\n\nexport const Button = ({\n asChild = false,\n children,\n className,\n dataTestId,\n disabled,\n endIcon,\n id,\n label,\n onClick,\n ref,\n size,\n startIcon,\n state,\n type = 'button',\n variant = 'primary',\n ...props\n}: ButtonProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const stateStyles = {\n error: {\n primary: 'border-button-destructive-border bg-button-destructive-bg text-button-destructive-text hover:bg-button-destructive-bg--hover hover:text-button-destructive-text--hover focus-visible:outline-button-destructive-border',\n secondary: 'bg-transparent border-button-destructive-border text-button-destructive-text hover:border-button-destructive-border--hover hover:text-button-destructive-text--hover hover:bg-button-destructive-bg--hover focus-visible:outline-button-destructive-border',\n outline: 'bg-transparent border-button-destructive-border text-button-destructive-text hover:border-button-destructive-border--hover hover:text-button-destructive-text--hover hover:bg-button-destructive-bg--hover focus-visible:outline-button-destructive-border',\n ghost: 'bg-transparent text-button-destructive-text hover:text-button-destructive-text--hover hover:bg-button-destructive-bg--hover',\n unstyled: 'bg-transparent text-button-destructive-text',\n },\n loading: {\n primary: 'bg-button-primary-bg--loading border-button-primary-border--loading text-button-primary-text--loading pointer-events-none',\n secondary: 'bg-button-secondary-bg--loading border-button-secondary-border--loading text-button-secondary-text--loading pointer-events-none',\n outline: 'bg-button-secondary-bg--loading border-button-secondary-border--loading text-button-secondary-text--loading pointer-events-none',\n destructive: 'bg-button-destructive-bg--loading border-button-destructive-border--loading text-button-destructive-text--loading pointer-events-none',\n ghost: 'bg-transparent text-button-ghost-text--loading pointer-events-none',\n unstyled: 'bg-transparent opacity-50 pointer-events-none',\n },\n }\n\n const classes = cn(buttonVariants({ variant, state, size }), state === 'error' && stateStyles.error[variant as keyof typeof stateStyles.error], state === 'loading' && stateStyles.loading[variant as keyof typeof stateStyles.loading], className)\n\n const canUseAsChild = asChild && isValidElement(children) && Children.count(children) === 1\n const content = canUseAsChild ? undefined : (children ?? label)\n\n if (!canUseAsChild && !content) {\n throw new Error('Button requires either `label` or `children`')\n }\n\n const handleDisabledClickCapture = (event: MouseEvent<HTMLElement>) => {\n if (!disabled) return\n event.preventDefault()\n event.stopPropagation()\n }\n\n const Comp = canUseAsChild ? Slot : 'button'\n\n return (\n <Comp\n aria-disabled={disabled}\n className={cn(classes, canUseAsChild && 'no-underline! before:content-none after:content-none', canUseAsChild && disabled && 'pointer-events-none opacity-50')}\n data-as-child={canUseAsChild ? 'true' : undefined}\n data-state={state}\n data-testid={dataTestId ?? `spectral-button-${variant}`}\n data-variant={variant}\n disabled={canUseAsChild ? undefined : disabled}\n id={id}\n onClick={onClick}\n onClickCapture={canUseAsChild ? handleDisabledClickCapture : undefined}\n ref={ref}\n tabIndex={canUseAsChild && disabled ? -1 : undefined}\n type={canUseAsChild ? undefined : type}\n {...props}\n >\n {canUseAsChild ? (\n children\n ) : (\n <>\n {startIcon && (\n <span className={cn('flex', variant !== 'unstyled' && 'pr-1')} aria-hidden data-testid='spectral-button-start-icon'>\n {startIcon}\n </span>\n )}\n {state === 'loading' && <LoaderIcon className='ml-2 size-5!' />}\n {content}\n {endIcon && state !== 'loading' && (\n <span className={cn('flex', variant !== 'unstyled' && 'pl-2')} aria-hidden data-testid='spectral-button-end-icon'>\n {endIcon}\n </span>\n )}\n </>\n )}\n </Comp>\n )\n}\nButton.displayName = 'Button'\n"],"mappings":";;;;;;;;;AAMA,MAAM,iBAAiB,IACrB,2aACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,WAAW;GACX,SAAS;GACT,OAAO;GACP,UAAU;GACV,aAAa;GACd;EACD,MAAM;GACJ,OAAO;GACP,SAAS;GACT,WAAW;GACZ;EACD,OAAO;GACL,SAAS;GACT,OAAO;GACP,SAAS;GACV;EACF;CACD,iBAAiB;EACf,SAAS;EACT,OAAO;EACP,MAAM;EACP;CACF,
|
|
1
|
+
{"version":3,"file":"Button.js","names":[],"sources":["../src/components/Button/Button.tsx"],"sourcesContent":["import { LoaderIcon } from '@components/Icons'\nimport { Slot, type AsChildProp } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { Children, isValidElement, type ButtonHTMLAttributes, type MouseEvent, type ReactNode, type Ref } from 'react'\n\nconst buttonVariants = cva(\n `gap-2 rounded-md font-semibold [&_svg]:size-4 relative flex cursor-pointer items-center justify-center border font-sans! whitespace-nowrap transition-[background-color,border-color,color,transform] duration-200 ease-out motion-reduce:transition-none disabled:active:scale-100 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0`,\n {\n variants: {\n variant: {\n primary: `border-button-primary-border bg-button-primary-bg text-button-primary-text hover:border-button-primary-border--hover hover:bg-button-primary-bg--hover hover:text-button-primary-text--hover active:scale-[0.97] focus-visible:outline-button-primary-border disabled:border-button-primary-border--disabled disabled:bg-button-primary-bg--disabled disabled:text-button-primary-text--disabled`,\n secondary: `border-button-secondary-border bg-button-secondary-bg text-button-secondary-text hover:bg-button-secondary-bg--hover hover:border-button-secondary-border--hover hover:text-button-secondary-text--hover active:scale-[0.97] focus-visible:outline-button-secondary-border disabled:border-button-secondary-border--disabled disabled:text-button-secondary-text--disabled`,\n outline: `border-button-secondary-border bg-button-secondary-bg text-button-secondary-text hover:bg-button-secondary-bg--hover hover:border-button-secondary-border--hover hover:text-button-secondary-text--hover active:scale-[0.97] focus-visible:outline-button-secondary-border disabled:border-button-secondary-border--disabled disabled:text-button-secondary-text--disabled`,\n ghost: 'border-none bg-button-ghost-bg text-button-ghost-text hover:bg-button-ghost-bg--hover hover:text-button-ghost-text--hover active:scale-[0.97] focus-visible:outline-button-outline-border disabled:text-button-ghost-text--disabled',\n unstyled: 'font-inherit! font-normal gap-0 p-0! inline-flex w-auto! justify-start rounded-none! border-none! bg-transparent text-inherit shadow-none! hover:cursor-pointer hover:bg-transparent active:scale-100 focus-visible:outline-button-outline-border disabled:opacity-50',\n destructive: 'border-button-destructive-border bg-button-destructive-bg text-button-destructive-text hover:bg-button-destructive-bg--hover active:scale-[0.97] disabled:border-button-destructive-border--disabled disabled:bg-button-destructive-bg--disabled disabled:text-button-destructive-text--disabled focus-visible:outline-button-destructive-border',\n },\n size: {\n small: 'py-1.5 px-3 text-sm! w-fit',\n default: 'py-2 px-4 text-sm! w-fit',\n fullWidth: 'py-2 px-4 text-sm! w-full',\n },\n state: {\n default: '',\n error: 'bg-button-danger text-text-primary transition focus-visible:outline-danger-400',\n loading: 'pointer-events-none cursor-wait',\n },\n },\n defaultVariants: {\n variant: 'primary',\n state: 'default',\n size: 'default',\n },\n },\n)\n\nexport interface ButtonProps extends AsChildProp, Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'>, VariantProps<typeof buttonVariants> {\n dataTestId?: string\n disabled?: boolean\n endIcon?: ReactNode\n label?: string\n onClick?: (event: MouseEvent<HTMLElement>) => void\n size?: 'small' | 'default' | 'fullWidth'\n startIcon?: ReactNode\n state?: 'default' | 'error' | 'loading'\n type?: 'button' | 'submit' | 'reset'\n variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'unstyled'\n}\n\nexport const Button = ({\n asChild = false,\n children,\n className,\n dataTestId,\n disabled,\n endIcon,\n id,\n label,\n onClick,\n ref,\n size,\n startIcon,\n state,\n type = 'button',\n variant = 'primary',\n ...props\n}: ButtonProps & {\n ref?: Ref<HTMLButtonElement>\n}) => {\n const stateStyles = {\n error: {\n primary: 'border-button-destructive-border bg-button-destructive-bg text-button-destructive-text hover:bg-button-destructive-bg--hover hover:text-button-destructive-text--hover focus-visible:outline-button-destructive-border',\n secondary: 'bg-transparent border-button-destructive-border text-button-destructive-text hover:border-button-destructive-border--hover hover:text-button-destructive-text--hover hover:bg-button-destructive-bg--hover focus-visible:outline-button-destructive-border',\n outline: 'bg-transparent border-button-destructive-border text-button-destructive-text hover:border-button-destructive-border--hover hover:text-button-destructive-text--hover hover:bg-button-destructive-bg--hover focus-visible:outline-button-destructive-border',\n ghost: 'bg-transparent text-button-destructive-text hover:text-button-destructive-text--hover hover:bg-button-destructive-bg--hover',\n unstyled: 'bg-transparent text-button-destructive-text',\n },\n loading: {\n primary: 'bg-button-primary-bg--loading border-button-primary-border--loading text-button-primary-text--loading pointer-events-none',\n secondary: 'bg-button-secondary-bg--loading border-button-secondary-border--loading text-button-secondary-text--loading pointer-events-none',\n outline: 'bg-button-secondary-bg--loading border-button-secondary-border--loading text-button-secondary-text--loading pointer-events-none',\n destructive: 'bg-button-destructive-bg--loading border-button-destructive-border--loading text-button-destructive-text--loading pointer-events-none',\n ghost: 'bg-transparent text-button-ghost-text--loading pointer-events-none',\n unstyled: 'bg-transparent opacity-50 pointer-events-none',\n },\n }\n\n const classes = cn(buttonVariants({ variant, state, size }), state === 'error' && stateStyles.error[variant as keyof typeof stateStyles.error], state === 'loading' && stateStyles.loading[variant as keyof typeof stateStyles.loading], className)\n\n const canUseAsChild = asChild && isValidElement(children) && Children.count(children) === 1\n const content = canUseAsChild ? undefined : (children ?? label)\n\n if (!canUseAsChild && !content) {\n throw new Error('Button requires either `label` or `children`')\n }\n\n const handleDisabledClickCapture = (event: MouseEvent<HTMLElement>) => {\n if (!disabled) return\n event.preventDefault()\n event.stopPropagation()\n }\n\n const Comp = canUseAsChild ? Slot : 'button'\n\n return (\n <Comp\n aria-disabled={disabled}\n className={cn(classes, canUseAsChild && 'no-underline! before:content-none after:content-none', canUseAsChild && disabled && 'pointer-events-none opacity-50')}\n data-as-child={canUseAsChild ? 'true' : undefined}\n data-state={state}\n data-testid={dataTestId ?? `spectral-button-${variant}`}\n data-variant={variant}\n disabled={canUseAsChild ? undefined : disabled}\n id={id}\n onClick={onClick}\n onClickCapture={canUseAsChild ? handleDisabledClickCapture : undefined}\n ref={ref}\n tabIndex={canUseAsChild && disabled ? -1 : undefined}\n type={canUseAsChild ? undefined : type}\n {...props}\n >\n {canUseAsChild ? (\n children\n ) : (\n <>\n {startIcon && (\n <span className={cn('flex', variant !== 'unstyled' && 'pr-1')} aria-hidden data-testid='spectral-button-start-icon'>\n {startIcon}\n </span>\n )}\n {state === 'loading' && <LoaderIcon className='ml-2 size-5!' />}\n {content}\n {endIcon && state !== 'loading' && (\n <span className={cn('flex', variant !== 'unstyled' && 'pl-2')} aria-hidden data-testid='spectral-button-end-icon'>\n {endIcon}\n </span>\n )}\n </>\n )}\n </Comp>\n )\n}\nButton.displayName = 'Button'\n"],"mappings":";;;;;;;;;AAMA,MAAM,iBAAiB,IACrB,2aACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,WAAW;GACX,SAAS;GACT,OAAO;GACP,UAAU;GACV,aAAa;GACd;EACD,MAAM;GACJ,OAAO;GACP,SAAS;GACT,WAAW;GACZ;EACD,OAAO;GACL,SAAS;GACT,OAAO;GACP,SAAS;GACV;EACF;CACD,iBAAiB;EACf,SAAS;EACT,OAAO;EACP,MAAM;EACP;CACF,CACH;AAeA,MAAa,UAAU,EACrB,UAAU,OACV,UACA,WACA,YACA,UACA,SACA,IACA,OACA,SACA,KACA,MACA,WACA,OACA,OAAO,UACP,UAAU,WACV,GAAG,YAGC;CACJ,MAAM,cAAc;EAClB,OAAO;GACL,SAAS;GACT,WAAW;GACX,SAAS;GACT,OAAO;GACP,UAAU;GACX;EACD,SAAS;GACP,SAAS;GACT,WAAW;GACX,SAAS;GACT,aAAa;GACb,OAAO;GACP,UAAU;GACX;EACH;CAEA,MAAM,UAAU,GAAG,eAAe;EAAE;EAAS;EAAO;EAAM,CAAC,EAAE,UAAU,WAAW,YAAY,MAAM,UAA4C,UAAU,aAAa,YAAY,QAAQ,UAA8C,UAAS;CAElP,MAAM,gBAAgB,WAAW,eAAe,SAAS,IAAI,SAAS,MAAM,SAAS,KAAK;CAC1F,MAAM,UAAU,gBAAgB,SAAa,YAAY;AAEzD,KAAI,CAAC,iBAAiB,CAAC,QACrB,OAAM,IAAI,MAAM,+CAA8C;CAGhE,MAAM,8BAA8B,UAAmC;AACrE,MAAI,CAAC,SAAU;AACf,QAAM,gBAAe;AACrB,QAAM,iBAAgB;;AAKxB,QACE,oBAHW,gBAAgB,OAAO,UAGlC;EACE,iBAAe;EACf,WAAW,GAAG,SAAS,iBAAiB,wDAAwD,iBAAiB,YAAY,iCAAiC;EAC9J,iBAAe,gBAAgB,SAAS;EACxC,cAAY;EAEZ,gBAAc;EACd,UAAU,gBAAgB,SAAY;EAClC;EACK;EACT,gBAAgB,gBAAgB,6BAA6B;EACxD;EACL,UAAU,iBAAiB,WAAW,KAAK;EAC3C,MAAM,gBAAgB,SAAY;EAClC,GAAI;YAEH,gBACC,WAEA;GACG,aACC,oBAAC,QAAD;IAAM,WAAW,GAAG,QAAQ,YAAY,cAAc,OAAO;IAAE;cAC5D;IACG;GAEP,UAAU,aAAa,oBAAC,YAAD,EAAY,WAAU,gBAAiB;GAC9D;GACA,WAAW,UAAU,aACpB,oBAAC,QAAD;IAAM,WAAW,GAAG,QAAQ,YAAY,cAAc,OAAO;IAAE;cAC5D;IACG;GAER;EAEA;;AAGV,OAAO,cAAc"}
|
package/dist/ButtonGroup.js
CHANGED
|
@@ -21,7 +21,6 @@ const ButtonGroup = ({ children, className, orientation = "horizontal", size = "
|
|
|
21
21
|
className: cn(buttonGroupVariants({ orientation }), className),
|
|
22
22
|
"data-orientation": orientation,
|
|
23
23
|
"data-slot": "button-group",
|
|
24
|
-
"data-testid": "spectral-button-group",
|
|
25
24
|
"data-variant": variant,
|
|
26
25
|
role: "group",
|
|
27
26
|
...props,
|
|
@@ -40,7 +39,6 @@ const ButtonGroupItem = ({ asChild, children, className, size, variant, ...props
|
|
|
40
39
|
asChild,
|
|
41
40
|
className: cn(className),
|
|
42
41
|
"data-slot": "button-group-item",
|
|
43
|
-
"data-testid": "spectral-button-group-item",
|
|
44
42
|
"data-variant": variant,
|
|
45
43
|
size,
|
|
46
44
|
variant,
|
|
@@ -53,7 +51,6 @@ const ButtonGroupText = ({ asChild = false, className, ...props }) => {
|
|
|
53
51
|
return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
|
|
54
52
|
className: cn(`bg-muted gap-2 rounded-md px-4 text-sm font-medium shadow-xs [&_svg:not([class*='size-'])]:size-4 flex items-center border [&_svg]:pointer-events-none`, className),
|
|
55
53
|
"data-slot": "button-group-text",
|
|
56
|
-
"data-testid": "spectral-button-group-text",
|
|
57
54
|
...props
|
|
58
55
|
});
|
|
59
56
|
};
|
|
@@ -61,7 +58,6 @@ const ButtonGroupSeparator = ({ className, orientation = "vertical", ...props })
|
|
|
61
58
|
return /* @__PURE__ */ jsx(Separator, {
|
|
62
59
|
className: cn("m-0! relative self-stretch bg-input-primitive-border data-[orientation=vertical]:h-auto", className),
|
|
63
60
|
"data-slot": "button-group-separator",
|
|
64
|
-
"data-testid": "spectral-button-group-separator",
|
|
65
61
|
orientation,
|
|
66
62
|
...props
|
|
67
63
|
});
|
package/dist/ButtonGroup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ButtonGroup.js","names":[],"sources":["../src/components/ButtonGroup/ButtonGroup.tsx"],"sourcesContent":["import { Separator } from '@components/Separator/Separator'\nimport { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { Children, cloneElement, isValidElement, type ComponentProps, type ReactElement } from 'react'\nimport { ButtonGroupButton } from './ButtonGroupButton'\n\ninterface ButtonGroupChildProps {\n size?: 'md' | 'sm' | 'lg' | 'icon-md' | 'icon-sm' | 'icon-lg'\n variant?: 'default' | 'outline' | 'divided'\n}\n\nexport type ButtonGroupProps = ComponentProps<typeof ButtonGroup> & VariantProps<typeof buttonGroupVariants>\n\nexport const buttonGroupVariants = cva(\n `has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2 flex w-fit items-stretch [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 data-[variant='divided']:[&>[data-slot=button-group-item]]:border-y-0 data-[variant='divided']:[&>[data-slot=button-group-item]:first-of-type]:border-l-0 data-[variant='divided']:[&>[data-slot=button-group-item]:last-of-type]:border-r-0 data-[orientation='vertical']:data-[variant='divided']:[&>[data-slot=button-group-item]]:border-x-0 data-[orientation='vertical']:data-[variant='divided']:[&>[data-slot=button-group-item]:first-of-type]:border-t-0 data-[orientation='vertical']:data-[variant='divided']:[&>[data-slot=button-group-item]:last-of-type]:border-b-0`,\n {\n variants: {\n orientation: {\n horizontal: '[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',\n vertical: 'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n },\n },\n)\n\nexport const ButtonGroup = ({\n children,\n className,\n orientation = 'horizontal',\n size = 'md',\n variant = 'default',\n ...props\n}: ComponentProps<'div'> &\n VariantProps<typeof buttonGroupVariants> & {\n size?: 'md' | 'sm' | 'lg' | 'icon-md' | 'icon-sm' | 'icon-lg'\n variant?: 'default' | 'outline' | 'divided'\n }) => {\n return (\n <div aria-label={props['aria-label']} className={cn(buttonGroupVariants({ orientation }), className)} data-orientation={orientation} data-slot='button-group' data-testid='spectral-button-group' data-variant={variant} role='group' {...props}>\n {Children.map(children, (child) => {\n if (isValidElement<ButtonGroupChildProps>(child) && (child.type === ButtonGroupItem || child.type === ButtonGroupButton)) {\n return cloneElement(child as ReactElement<ButtonGroupChildProps>, {\n variant: child.props.variant ?? variant,\n size: child.props.size ?? size,\n })\n }\n return child\n })}\n </div>\n )\n}\nButtonGroup.displayName = 'ButtonGroup'\n\nexport const ButtonGroupItem = ({\n asChild,\n children,\n className,\n size,\n variant,\n ...props\n}: ComponentProps<'button'> & {\n asChild?: boolean\n size?: 'sm' | 'md' | 'lg' | 'icon-sm' | 'icon-md' | 'icon-lg'\n variant?: 'default' | 'outline' | 'divided'\n}) => {\n return (\n <ButtonGroupButton asChild={asChild} className={cn(className)} data-slot='button-group-item' data-testid='spectral-button-group-item' data-variant={variant} size={size} variant={variant} {...props}>\n {children}\n </ButtonGroupButton>\n )\n}\nButtonGroupItem.displayName = 'ButtonGroupItem'\n\nexport const ButtonGroupText = ({\n asChild = false,\n className,\n ...props\n}: ComponentProps<'div'> & {\n asChild?: boolean\n}) => {\n const Comp = asChild ? Slot : 'div'\n return <Comp className={cn(`bg-muted gap-2 rounded-md px-4 text-sm font-medium shadow-xs [&_svg:not([class*='size-'])]:size-4 flex items-center border [&_svg]:pointer-events-none`, className)} data-slot='button-group-text' data-testid='spectral-button-group-text' {...props} />\n}\n\nexport const ButtonGroupSeparator = ({\n className,\n orientation = 'vertical',\n ...props\n}: ComponentProps<typeof Separator> & {\n orientation?: 'vertical' | 'horizontal'\n}) => {\n return <Separator className={cn('m-0! relative self-stretch bg-input-primitive-border data-[orientation=vertical]:h-auto', className)} data-slot='button-group-separator' data-testid='spectral-button-group-separator' orientation={orientation} {...props} />\n}\nButtonGroupSeparator.displayName = 'ButtonGroupSeparator'\n"],"mappings":";;;;;;;;;;AAcA,MAAa,sBAAsB,IACjC,w1BACA;CACE,UAAU,EACR,aAAa;EACX,YAAY;EACZ,UAAU;EACX,EACF;CACD,iBAAiB,EACf,aAAa,cACd;CACF,
|
|
1
|
+
{"version":3,"file":"ButtonGroup.js","names":[],"sources":["../src/components/ButtonGroup/ButtonGroup.tsx"],"sourcesContent":["import { Separator } from '@components/Separator/Separator'\nimport { Slot } from '@primitives/slot'\nimport { cn } from '@utils/twUtils'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { Children, cloneElement, isValidElement, type ComponentProps, type ReactElement } from 'react'\nimport { ButtonGroupButton } from './ButtonGroupButton'\n\ninterface ButtonGroupChildProps {\n size?: 'md' | 'sm' | 'lg' | 'icon-md' | 'icon-sm' | 'icon-lg'\n variant?: 'default' | 'outline' | 'divided'\n}\n\nexport type ButtonGroupProps = ComponentProps<typeof ButtonGroup> & VariantProps<typeof buttonGroupVariants>\n\nexport const buttonGroupVariants = cva(\n `has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2 flex w-fit items-stretch [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 data-[variant='divided']:[&>[data-slot=button-group-item]]:border-y-0 data-[variant='divided']:[&>[data-slot=button-group-item]:first-of-type]:border-l-0 data-[variant='divided']:[&>[data-slot=button-group-item]:last-of-type]:border-r-0 data-[orientation='vertical']:data-[variant='divided']:[&>[data-slot=button-group-item]]:border-x-0 data-[orientation='vertical']:data-[variant='divided']:[&>[data-slot=button-group-item]:first-of-type]:border-t-0 data-[orientation='vertical']:data-[variant='divided']:[&>[data-slot=button-group-item]:last-of-type]:border-b-0`,\n {\n variants: {\n orientation: {\n horizontal: '[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',\n vertical: 'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n },\n },\n)\n\nexport const ButtonGroup = ({\n children,\n className,\n orientation = 'horizontal',\n size = 'md',\n variant = 'default',\n ...props\n}: ComponentProps<'div'> &\n VariantProps<typeof buttonGroupVariants> & {\n size?: 'md' | 'sm' | 'lg' | 'icon-md' | 'icon-sm' | 'icon-lg'\n variant?: 'default' | 'outline' | 'divided'\n }) => {\n return (\n <div aria-label={props['aria-label']} className={cn(buttonGroupVariants({ orientation }), className)} data-orientation={orientation} data-slot='button-group' data-testid='spectral-button-group' data-variant={variant} role='group' {...props}>\n {Children.map(children, (child) => {\n if (isValidElement<ButtonGroupChildProps>(child) && (child.type === ButtonGroupItem || child.type === ButtonGroupButton)) {\n return cloneElement(child as ReactElement<ButtonGroupChildProps>, {\n variant: child.props.variant ?? variant,\n size: child.props.size ?? size,\n })\n }\n return child\n })}\n </div>\n )\n}\nButtonGroup.displayName = 'ButtonGroup'\n\nexport const ButtonGroupItem = ({\n asChild,\n children,\n className,\n size,\n variant,\n ...props\n}: ComponentProps<'button'> & {\n asChild?: boolean\n size?: 'sm' | 'md' | 'lg' | 'icon-sm' | 'icon-md' | 'icon-lg'\n variant?: 'default' | 'outline' | 'divided'\n}) => {\n return (\n <ButtonGroupButton asChild={asChild} className={cn(className)} data-slot='button-group-item' data-testid='spectral-button-group-item' data-variant={variant} size={size} variant={variant} {...props}>\n {children}\n </ButtonGroupButton>\n )\n}\nButtonGroupItem.displayName = 'ButtonGroupItem'\n\nexport const ButtonGroupText = ({\n asChild = false,\n className,\n ...props\n}: ComponentProps<'div'> & {\n asChild?: boolean\n}) => {\n const Comp = asChild ? Slot : 'div'\n return <Comp className={cn(`bg-muted gap-2 rounded-md px-4 text-sm font-medium shadow-xs [&_svg:not([class*='size-'])]:size-4 flex items-center border [&_svg]:pointer-events-none`, className)} data-slot='button-group-text' data-testid='spectral-button-group-text' {...props} />\n}\n\nexport const ButtonGroupSeparator = ({\n className,\n orientation = 'vertical',\n ...props\n}: ComponentProps<typeof Separator> & {\n orientation?: 'vertical' | 'horizontal'\n}) => {\n return <Separator className={cn('m-0! relative self-stretch bg-input-primitive-border data-[orientation=vertical]:h-auto', className)} data-slot='button-group-separator' data-testid='spectral-button-group-separator' orientation={orientation} {...props} />\n}\nButtonGroupSeparator.displayName = 'ButtonGroupSeparator'\n"],"mappings":";;;;;;;;;;AAcA,MAAa,sBAAsB,IACjC,w1BACA;CACE,UAAU,EACR,aAAa;EACX,YAAY;EACZ,UAAU;EACX,EACF;CACD,iBAAiB,EACf,aAAa,cACd;CACF,CACH;AAEA,MAAa,eAAe,EAC1B,UACA,WACA,cAAc,cACd,OAAO,MACP,UAAU,WACV,GAAG,YAKG;AACN,QACE,oBAAC,OAAD;EAAK,cAAY,MAAM;EAAe,WAAW,GAAG,oBAAoB,EAAE,aAAa,CAAC,EAAE,UAAU;EAAE,oBAAkB;EAAa,aAAU;EAAmD,gBAAc;EAAS,MAAK;EAAQ,GAAI;YACvO,SAAS,IAAI,WAAW,UAAU;AACjC,OAAI,eAAsC,MAAM,KAAK,MAAM,SAAS,mBAAmB,MAAM,SAAS,mBACpG,QAAO,aAAa,OAA8C;IAChE,SAAS,MAAM,MAAM,WAAW;IAChC,MAAM,MAAM,MAAM,QAAQ;IAC3B,CAAA;AAEH,UAAO;IACP;EACC;;AAGT,YAAY,cAAc;AAE1B,MAAa,mBAAmB,EAC9B,SACA,UACA,WACA,MACA,SACA,GAAG,YAKC;AACJ,QACE,oBAAC,mBAAD;EAA4B;EAAS,WAAW,GAAG,UAAU;EAAE,aAAU;EAA6D,gBAAc;EAAe;EAAe;EAAS,GAAI;EAC5L;EACgB;;AAGvB,gBAAgB,cAAc;AAE9B,MAAa,mBAAmB,EAC9B,UAAU,OACV,WACA,GAAG,YAGC;AAEJ,QAAO,oBADM,UAAU,OAAO,OACvB;EAAM,WAAW,GAAG,0JAA0J,UAAU;EAAE,aAAU;EAA6D,GAAI;EAAQ;;AAGtR,MAAa,wBAAwB,EACnC,WACA,cAAc,YACd,GAAG,YAGC;AACJ,QAAO,oBAAC,WAAD;EAAW,WAAW,GAAG,2FAA2F,UAAU;EAAE,aAAU;EAAoF;EAAa,GAAI;EAAQ;;AAEhQ,qBAAqB,cAAc"}
|
package/dist/ButtonIcon.js
CHANGED
|
@@ -54,7 +54,6 @@ const ButtonIcon = ({ className, disabled, icon, isLoading = false, label, onCli
|
|
|
54
54
|
return /* @__PURE__ */ jsx("button", {
|
|
55
55
|
"aria-label": effectiveLabel,
|
|
56
56
|
className: cn(buttonStyles, shape === "circle" ? "rounded-full" : "rounded-lg", sizeConfig[size].button, isLoading && "cursor-wait", disabled && "cursor-not-allowed opacity-50", className),
|
|
57
|
-
"data-testid": "spectral-button-icon",
|
|
58
57
|
disabled: disabled ?? isLoading,
|
|
59
58
|
onClick: handleClick,
|
|
60
59
|
ref,
|