@fanvue/ui 3.2.0 → 3.4.0
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/cjs/components/Accordion/AccordionTrigger.cjs +1 -1
- package/dist/cjs/components/Accordion/AccordionTrigger.cjs.map +1 -1
- package/dist/cjs/components/BottomNavigation/BottomNavigationAction.cjs +2 -2
- package/dist/cjs/components/BottomNavigation/BottomNavigationAction.cjs.map +1 -1
- package/dist/cjs/components/Button/Button.cjs +101 -25
- package/dist/cjs/components/Button/Button.cjs.map +1 -1
- package/dist/cjs/components/ChatInput/ChatInput.cjs +9 -7
- package/dist/cjs/components/ChatInput/ChatInput.cjs.map +1 -1
- package/dist/cjs/components/Checkbox/Checkbox.cjs +1 -1
- package/dist/cjs/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/cjs/components/CreatorCover/CreatorCover.cjs.map +1 -1
- package/dist/cjs/components/CyclingText/CyclingText.cjs +16 -1
- package/dist/cjs/components/CyclingText/CyclingText.cjs.map +1 -1
- package/dist/cjs/components/CyclingText/useCyclingCycle.cjs +1 -0
- package/dist/cjs/components/CyclingText/useCyclingCycle.cjs.map +1 -1
- package/dist/cjs/components/Dialog/Dialog.cjs +30 -16
- package/dist/cjs/components/Dialog/Dialog.cjs.map +1 -1
- package/dist/cjs/components/Radio/Radio.cjs +1 -1
- package/dist/cjs/components/Radio/Radio.cjs.map +1 -1
- package/dist/cjs/components/Slider/SliderThumb.cjs +1 -1
- package/dist/cjs/components/Slider/SliderThumb.cjs.map +1 -1
- package/dist/cjs/components/Tabs/TabsList.cjs +7 -0
- package/dist/cjs/components/Tabs/TabsList.cjs.map +1 -1
- package/dist/cjs/components/Tabs/TabsTrigger.cjs +1 -1
- package/dist/cjs/components/Tabs/TabsTrigger.cjs.map +1 -1
- package/dist/components/Accordion/AccordionTrigger.mjs +1 -1
- package/dist/components/Accordion/AccordionTrigger.mjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigationAction.mjs +2 -2
- package/dist/components/BottomNavigation/BottomNavigationAction.mjs.map +1 -1
- package/dist/components/Button/Button.mjs +101 -25
- package/dist/components/Button/Button.mjs.map +1 -1
- package/dist/components/ChatInput/ChatInput.mjs +9 -7
- package/dist/components/ChatInput/ChatInput.mjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.mjs +1 -1
- package/dist/components/Checkbox/Checkbox.mjs.map +1 -1
- package/dist/components/CreatorCover/CreatorCover.mjs.map +1 -1
- package/dist/components/CyclingText/CyclingText.mjs +16 -1
- package/dist/components/CyclingText/CyclingText.mjs.map +1 -1
- package/dist/components/CyclingText/useCyclingCycle.mjs +1 -0
- package/dist/components/CyclingText/useCyclingCycle.mjs.map +1 -1
- package/dist/components/Dialog/Dialog.mjs +30 -16
- package/dist/components/Dialog/Dialog.mjs.map +1 -1
- package/dist/components/Radio/Radio.mjs +1 -1
- package/dist/components/Radio/Radio.mjs.map +1 -1
- package/dist/components/Slider/SliderThumb.mjs +1 -1
- package/dist/components/Slider/SliderThumb.mjs.map +1 -1
- package/dist/components/Tabs/TabsList.mjs +7 -0
- package/dist/components/Tabs/TabsList.mjs.map +1 -1
- package/dist/components/Tabs/TabsTrigger.mjs +1 -1
- package/dist/components/Tabs/TabsTrigger.mjs.map +1 -1
- package/dist/index.d.ts +27 -4
- package/dist/styles/theme.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreatorCover.cjs","sources":["../../../../src/components/CreatorCover/CreatorCover.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Pill } from \"../Pill/Pill\";\n\n/** Slot that accepts a string (rendered as default styling) or a node for full control. */\nexport type CreatorCoverSlot = string | React.ReactNode;\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nexport interface CreatorCoverProps extends Omit<React.HTMLAttributes<HTMLElement>, \"title\"> {\n /** URL of the creator image displayed in the centre card. Also used as the blurred backdrop unless `backgroundSrc` is provided. */\n imageSrc: string;\n /** Alt text for the centre cover image. @default \"\" */\n imageAlt?: string;\n /** Override URL used for the blurred background image. @default `imageSrc` */\n backgroundSrc?: string;\n /** Creator's name, rendered as the heading. */\n name: string;\n /** Smaller subtitle below the name (e.g. \"GLOBAL POPSTAR\"). Rendered uppercase in the brand colour. */\n tagline?: string;\n /**\n * Status label rendered as a pill overlapping the bottom of the cover image (e.g. \"New Joiner\").\n * Strings render with default green pill styling; pass a node for custom markup.\n */\n tag?: CreatorCoverSlot;\n /**\n * Primary call to action displayed below the title.\n */\n action?: React.ReactNode;\n /** When `true`, fades the bottom of the component to transparent and increases bottom padding to 64px. @default false */\n fadeBottom?: boolean;\n}\n\n/**\n * A creator profile hero with a stylised blurred backdrop, central cover image,\n * status pill, name, tagline, and primary call to action.\n *\n * @example\n * ```tsx\n * <CreatorCover\n * imageSrc=\"/creator.jpg\"\n * imageAlt=\"Jane Doe\"\n * name=\"JANE DOE\"\n * tagline=\"GLOBAL POPSTAR\"\n * tag=\"New Joiner\"\n * action={<Button variant=\"
|
|
1
|
+
{"version":3,"file":"CreatorCover.cjs","sources":["../../../../src/components/CreatorCover/CreatorCover.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Pill } from \"../Pill/Pill\";\n\n/** Slot that accepts a string (rendered as default styling) or a node for full control. */\nexport type CreatorCoverSlot = string | React.ReactNode;\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nexport interface CreatorCoverProps extends Omit<React.HTMLAttributes<HTMLElement>, \"title\"> {\n /** URL of the creator image displayed in the centre card. Also used as the blurred backdrop unless `backgroundSrc` is provided. */\n imageSrc: string;\n /** Alt text for the centre cover image. @default \"\" */\n imageAlt?: string;\n /** Override URL used for the blurred background image. @default `imageSrc` */\n backgroundSrc?: string;\n /** Creator's name, rendered as the heading. */\n name: string;\n /** Smaller subtitle below the name (e.g. \"GLOBAL POPSTAR\"). Rendered uppercase in the brand colour. */\n tagline?: string;\n /**\n * Status label rendered as a pill overlapping the bottom of the cover image (e.g. \"New Joiner\").\n * Strings render with default green pill styling; pass a node for custom markup.\n */\n tag?: CreatorCoverSlot;\n /**\n * Primary call to action displayed below the title.\n */\n action?: React.ReactNode;\n /** When `true`, fades the bottom of the component to transparent and increases bottom padding to 64px. @default false */\n fadeBottom?: boolean;\n}\n\n/**\n * A creator profile hero with a stylised blurred backdrop, central cover image,\n * status pill, name, tagline, and primary call to action.\n *\n * @example\n * ```tsx\n * <CreatorCover\n * imageSrc=\"/creator.jpg\"\n * imageAlt=\"Jane Doe\"\n * name=\"JANE DOE\"\n * tagline=\"GLOBAL POPSTAR\"\n * tag=\"New Joiner\"\n * action={<Button variant=\"brand\" size=\"48\" fullWidth>Join for free for 7 days</Button>}\n * />\n * ```\n */\nexport const CreatorCover = React.forwardRef<HTMLElement, CreatorCoverProps>(\n (\n { className, imageSrc, imageAlt = \"\", backgroundSrc, name, tagline, tag, action, ...props },\n ref,\n ) => {\n const headingId = React.useId();\n\n const renderedTag = isNonEmptyString(tag) ? <Pill variant=\"brand\">{tag}</Pill> : tag;\n\n return (\n <section\n ref={ref}\n aria-labelledby={headingId}\n data-testid=\"creator-cover\"\n className={cn(\n \"relative isolate w-full overflow-hidden bg-white dark:bg-background-primary\",\n className,\n )}\n {...props}\n >\n <div className=\"absolute inset-0 -z-10\">\n <img\n src={backgroundSrc ?? imageSrc}\n alt=\"\"\n loading=\"lazy\"\n className=\"size-full scale-110 object-cover blur-3xl\"\n />\n <div className=\"absolute inset-0 bg-linear-to-b from-white/30 to-white/15 dark:from-background-primary/30 dark:to-background-primary/15\" />\n <div className=\"absolute inset-x-0 bottom-0 h-1/3 bg-linear-to-b from-transparent to-white dark:to-background-primary\" />\n </div>\n <div className={cn(\"mx-auto flex max-w-90 flex-col items-center gap-4 px-4 pt-17 pb-16\")}>\n <div className=\"relative\">\n <img\n src={imageSrc}\n alt={imageAlt}\n loading=\"lazy\"\n className=\"block h-55 w-37.5 rounded-lg object-cover\"\n />\n {renderedTag ? (\n <div className=\"absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-1/2\">\n {renderedTag}\n </div>\n ) : null}\n </div>\n <div className=\"flex flex-col items-center gap-1 pt-4 text-center\">\n <h2 id={headingId} className=\"typography-header-heading-md m-0 text-white\">\n {name}\n </h2>\n {tagline ? (\n <p className=\"typography-badge-badgecaps m-0 text-brand-primary-default uppercase\">\n {tagline}\n </p>\n ) : null}\n </div>\n {action ? <div className=\"w-full pt-2\">{action}</div> : null}\n </div>\n </section>\n );\n },\n);\n\nCreatorCover.displayName = \"CreatorCover\";\n"],"names":["React","Pill","jsxs","cn","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAOA,SAAS,iBAAiB,OAAiC;AACzD,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS;AACrD;AA0CO,MAAM,eAAeA,iBAAM;AAAA,EAChC,CACE,EAAE,WAAW,UAAU,WAAW,IAAI,eAAe,MAAM,SAAS,KAAK,QAAQ,GAAG,MAAA,GACpF,QACG;AACH,UAAM,YAAYA,iBAAM,MAAA;AAExB,UAAM,cAAc,iBAAiB,GAAG,mCAAKC,KAAAA,MAAA,EAAK,SAAQ,SAAS,UAAA,IAAA,CAAI,IAAU;AAEjF,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,mBAAiB;AAAA,QACjB,eAAY;AAAA,QACZ,WAAWC,GAAAA;AAAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAAD,2BAAAA,KAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,YAAAE,2BAAAA;AAAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAK,iBAAiB;AAAA,gBACtB,KAAI;AAAA,gBACJ,SAAQ;AAAA,gBACR,WAAU;AAAA,cAAA;AAAA,YAAA;AAAA,YAEZA,2BAAAA,IAAC,OAAA,EAAI,WAAU,0HAAA,CAA0H;AAAA,YACzIA,2BAAAA,IAAC,OAAA,EAAI,WAAU,wGAAA,CAAwG;AAAA,UAAA,GACzH;AAAA,UACAF,2BAAAA,KAAC,OAAA,EAAI,WAAWC,GAAAA,GAAG,oEAAoE,GACrF,UAAA;AAAA,YAAAD,2BAAAA,KAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,cAAAE,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,KAAK;AAAA,kBACL,KAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,WAAU;AAAA,gBAAA;AAAA,cAAA;AAAA,cAEX,cACCA,2BAAAA,IAAC,OAAA,EAAI,WAAU,+DACZ,uBACH,IACE;AAAA,YAAA,GACN;AAAA,YACAF,2BAAAA,KAAC,OAAA,EAAI,WAAU,qDACb,UAAA;AAAA,cAAAE,+BAAC,MAAA,EAAG,IAAI,WAAW,WAAU,+CAC1B,UAAA,MACH;AAAA,cACC,UACCA,2BAAAA,IAAC,KAAA,EAAE,WAAU,uEACV,mBACH,IACE;AAAA,YAAA,GACN;AAAA,YACC,SAASA,2BAAAA,IAAC,OAAA,EAAI,WAAU,eAAe,kBAAO,IAAS;AAAA,UAAA,EAAA,CAC1D;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACF;AAEA,aAAa,cAAc;;"}
|
|
@@ -39,13 +39,28 @@ const CyclingText = React__namespace.forwardRef(
|
|
|
39
39
|
className,
|
|
40
40
|
labelClassName,
|
|
41
41
|
announceChanges = false,
|
|
42
|
+
onActiveIndexChange,
|
|
42
43
|
...rest
|
|
43
44
|
}, ref) => {
|
|
44
45
|
const docVisible = usePageVisibility.usePageVisibility();
|
|
45
46
|
const reducedMotion = usePrefersReducedMotion.usePrefersReducedMotion();
|
|
46
47
|
const { sizingLabelRef, trackWidth } = useCyclingTextTrackWidth.useCyclingTextTrackWidth();
|
|
47
|
-
const {
|
|
48
|
+
const {
|
|
49
|
+
cycle,
|
|
50
|
+
currentIndex,
|
|
51
|
+
currentLabel,
|
|
52
|
+
incomingLabel,
|
|
53
|
+
sizingLabel,
|
|
54
|
+
onOutgoingTransitionEnd
|
|
55
|
+
} = useCyclingCycle.useCyclingCycle(items, sizing, intervalMs, paused, docVisible, transitionMs);
|
|
48
56
|
const itemCount = items.length;
|
|
57
|
+
const onActiveIndexChangeRef = React__namespace.useRef(onActiveIndexChange);
|
|
58
|
+
React__namespace.useEffect(() => {
|
|
59
|
+
onActiveIndexChangeRef.current = onActiveIndexChange;
|
|
60
|
+
}, [onActiveIndexChange]);
|
|
61
|
+
React__namespace.useEffect(() => {
|
|
62
|
+
onActiveIndexChangeRef.current?.(currentIndex);
|
|
63
|
+
}, [currentIndex]);
|
|
49
64
|
const outgoingMotionStyle = React__namespace.useMemo(() => {
|
|
50
65
|
const durMs = reducedMotion ? 0 : transitionMs;
|
|
51
66
|
const exiting = cycle.transitioning;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CyclingText.cjs","sources":["../../../../src/components/CyclingText/CyclingText.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCyclingCycle } from \"./useCyclingCycle\";\nimport { useCyclingTextTrackWidth } from \"./useCyclingTextTrackWidth\";\nimport { usePageVisibility } from \"./usePageVisibility\";\nimport { usePrefersReducedMotion } from \"./usePrefersReducedMotion\";\n\nconst DEFAULT_INTERVAL_MS = 2100;\nconst DEFAULT_TRANSITION_MS = 200;\n\nconst SLIDE_OFFSET_PX = 18;\n\n/** How the wrapper should be sized to accommodate variable-length items. */\nexport type CyclingTextSizing = \"longest\" | \"current\";\n\nexport interface CyclingTextProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** Strings to cycle through, in order. Cycles back to the first after the last. */\n items: readonly string[];\n /**\n * Milliseconds to wait after the previous transition finishes before starting the next one.\n * @default 2100\n */\n intervalMs?: number;\n /** Slide and cross-fade duration in milliseconds. @default 200 */\n transitionMs?: number;\n /** Direction the outgoing item slides. @default \"up\" */\n direction?: \"up\" | \"down\";\n /** When true, freezes on the current item — no further cycling until cleared. @default false */\n paused?: boolean;\n /**\n * How the wrapper sizes itself horizontally.\n * - `longest` reserves space for the longest item — no width jitter as items cycle.\n * - `current` shrinks/grows with each item, animating width between cycles.\n * @default \"longest\"\n */\n sizing?: CyclingTextSizing;\n /**\n * When `true`, updates are exposed to assistive technologies via `aria-live=\"polite\"`.\n * Leave `false` for decorative or frequently changing copy so screen readers are not interrupted on every cycle.\n * @default false\n */\n announceChanges?: boolean;\n /**\n * Class applied to each visible label span (current + incoming). Use this for\n * effects that have to sit on the text element itself, e.g. `background-clip: text`.\n */\n labelClassName?: string;\n}\n\n/**\n * Cycles through a list of strings with a slide-in/slide-out animation. Lives\n * inline so it can sit inside divs, spans, buttons, or as a fake placeholder\n * overlay.\n *\n * @example\n * ```tsx\n * <CyclingText items={[\"Thinking\", \"Reading messages\", \"Drafting reply\"]} />\n * ```\n */\nexport const CyclingText = React.forwardRef<HTMLSpanElement, CyclingTextProps>(\n (\n {\n items,\n intervalMs = DEFAULT_INTERVAL_MS,\n transitionMs = DEFAULT_TRANSITION_MS,\n direction = \"up\",\n paused = false,\n sizing = \"longest\",\n className,\n labelClassName,\n announceChanges = false,\n ...rest\n },\n ref,\n ) => {\n const docVisible = usePageVisibility();\n const reducedMotion = usePrefersReducedMotion();\n const { sizingLabelRef, trackWidth } = useCyclingTextTrackWidth();\n const { cycle, currentLabel, incomingLabel, sizingLabel, onOutgoingTransitionEnd } =\n useCyclingCycle(items, sizing, intervalMs, paused, docVisible, transitionMs);\n\n const itemCount = items.length;\n\n const outgoingMotionStyle = React.useMemo((): React.CSSProperties => {\n const durMs = reducedMotion ? 0 : transitionMs;\n const exiting = cycle.transitioning;\n const yExit = direction === \"up\" ? -SLIDE_OFFSET_PX : SLIDE_OFFSET_PX;\n return {\n opacity: exiting ? 0 : 1,\n transform: exiting ? `translate3d(0, ${yExit}px, 0)` : \"translate3d(0, 0, 0)\",\n transition:\n exiting && durMs > 0\n ? `opacity ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1)`\n : \"none\",\n };\n }, [cycle.transitioning, direction, transitionMs, reducedMotion]);\n\n const incomingMotionStyle = React.useMemo((): React.CSSProperties => {\n const durMs = reducedMotion ? 0 : transitionMs;\n const entered = cycle.incomingEntered;\n const yEnter = direction === \"up\" ? SLIDE_OFFSET_PX : -SLIDE_OFFSET_PX;\n return {\n opacity: entered ? 1 : 0,\n transform: entered ? \"translate3d(0, 0, 0)\" : `translate3d(0, ${yEnter}px, 0)`,\n transition:\n durMs > 0\n ? `opacity ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1)`\n : \"none\",\n };\n }, [cycle.incomingEntered, direction, transitionMs, reducedMotion]);\n\n if (itemCount === 0) {\n return null;\n }\n\n const wrapperStyle = {\n ...(trackWidth !== null ? { width: `${trackWidth}px` } : {}),\n // paddingTop: SLIDE_OFFSET_PX,\n } as React.CSSProperties;\n\n const showIncoming = incomingLabel !== null && cycle.transitioning;\n\n return (\n <span\n ref={ref}\n data-testid=\"cycling-text\"\n data-paused={paused ? \"true\" : undefined}\n className={cn(\n \"relative inline-flex items-center overflow-hidden align-middle leading-[inherit]\",\n \"motion-safe:transition-[width] motion-safe:duration-300 motion-safe:ease-out\",\n className,\n )}\n style={wrapperStyle}\n {...rest}\n >\n <span\n ref={sizingLabelRef}\n aria-hidden=\"true\"\n className=\"pointer-events-none invisible inline-block select-none whitespace-nowrap leading-[inherit]\"\n >\n {sizingLabel}\n </span>\n\n <span\n data-layer=\"current\"\n aria-live={announceChanges ? \"polite\" : undefined}\n aria-atomic={announceChanges ? true : undefined}\n data-state={cycle.transitioning ? \"exit\" : \"idle\"}\n onTransitionEnd={onOutgoingTransitionEnd}\n className={cn(\n \"absolute inset-0 flex items-center whitespace-nowrap leading-[inherit]\",\n labelClassName,\n )}\n style={outgoingMotionStyle}\n >\n {currentLabel}\n </span>\n\n {showIncoming ? (\n <span\n aria-hidden=\"true\"\n data-layer=\"incoming\"\n data-state={cycle.incomingEntered ? \"idle\" : \"enter\"}\n className={cn(\n \"absolute inset-0 flex items-center whitespace-nowrap leading-[inherit]\",\n labelClassName,\n )}\n style={incomingMotionStyle}\n >\n {incomingLabel}\n </span>\n ) : null}\n </span>\n );\n },\n);\n\nCyclingText.displayName = \"CyclingText\";\n"],"names":["React","usePageVisibility","usePrefersReducedMotion","useCyclingTextTrackWidth","useCyclingCycle","jsxs","cn","jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CyclingText.cjs","sources":["../../../../src/components/CyclingText/CyclingText.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCyclingCycle } from \"./useCyclingCycle\";\nimport { useCyclingTextTrackWidth } from \"./useCyclingTextTrackWidth\";\nimport { usePageVisibility } from \"./usePageVisibility\";\nimport { usePrefersReducedMotion } from \"./usePrefersReducedMotion\";\n\nconst DEFAULT_INTERVAL_MS = 2100;\nconst DEFAULT_TRANSITION_MS = 200;\n\nconst SLIDE_OFFSET_PX = 18;\n\n/** How the wrapper should be sized to accommodate variable-length items. */\nexport type CyclingTextSizing = \"longest\" | \"current\";\n\nexport interface CyclingTextProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** Strings to cycle through, in order. Cycles back to the first after the last. */\n items: readonly string[];\n /**\n * Milliseconds to wait after the previous transition finishes before starting the next one.\n * @default 2100\n */\n intervalMs?: number;\n /** Slide and cross-fade duration in milliseconds. @default 200 */\n transitionMs?: number;\n /** Direction the outgoing item slides. @default \"up\" */\n direction?: \"up\" | \"down\";\n /** When true, freezes on the current item — no further cycling until cleared. @default false */\n paused?: boolean;\n /**\n * How the wrapper sizes itself horizontally.\n * - `longest` reserves space for the longest item — no width jitter as items cycle.\n * - `current` shrinks/grows with each item, animating width between cycles.\n * @default \"longest\"\n */\n sizing?: CyclingTextSizing;\n /**\n * When `true`, updates are exposed to assistive technologies via `aria-live=\"polite\"`.\n * Leave `false` for decorative or frequently changing copy so screen readers are not interrupted on every cycle.\n * @default false\n */\n announceChanges?: boolean;\n /**\n * Class applied to each visible label span (current + incoming). Use this for\n * effects that have to sit on the text element itself, e.g. `background-clip: text`.\n */\n labelClassName?: string;\n /**\n * Called with the index of the settled, fully-visible item — once on mount and\n * again whenever it changes (after each transition completes). Lets a parent\n * stay in lockstep with what is on screen (e.g. to act on the item the user is\n * currently looking at) without running a second, drifting timer of its own.\n */\n onActiveIndexChange?: (index: number) => void;\n}\n\n/**\n * Cycles through a list of strings with a slide-in/slide-out animation. Lives\n * inline so it can sit inside divs, spans, buttons, or as a fake placeholder\n * overlay.\n *\n * @example\n * ```tsx\n * <CyclingText items={[\"Thinking\", \"Reading messages\", \"Drafting reply\"]} />\n * ```\n */\nexport const CyclingText = React.forwardRef<HTMLSpanElement, CyclingTextProps>(\n (\n {\n items,\n intervalMs = DEFAULT_INTERVAL_MS,\n transitionMs = DEFAULT_TRANSITION_MS,\n direction = \"up\",\n paused = false,\n sizing = \"longest\",\n className,\n labelClassName,\n announceChanges = false,\n onActiveIndexChange,\n ...rest\n },\n ref,\n ) => {\n const docVisible = usePageVisibility();\n const reducedMotion = usePrefersReducedMotion();\n const { sizingLabelRef, trackWidth } = useCyclingTextTrackWidth();\n const {\n cycle,\n currentIndex,\n currentLabel,\n incomingLabel,\n sizingLabel,\n onOutgoingTransitionEnd,\n } = useCyclingCycle(items, sizing, intervalMs, paused, docVisible, transitionMs);\n\n const itemCount = items.length;\n\n // Notify the parent of the settled active index without re-subscribing when\n // an inline callback identity changes each render — the latest is always\n // read from the ref.\n const onActiveIndexChangeRef = React.useRef(onActiveIndexChange);\n React.useEffect(() => {\n onActiveIndexChangeRef.current = onActiveIndexChange;\n }, [onActiveIndexChange]);\n React.useEffect(() => {\n onActiveIndexChangeRef.current?.(currentIndex);\n }, [currentIndex]);\n\n const outgoingMotionStyle = React.useMemo((): React.CSSProperties => {\n const durMs = reducedMotion ? 0 : transitionMs;\n const exiting = cycle.transitioning;\n const yExit = direction === \"up\" ? -SLIDE_OFFSET_PX : SLIDE_OFFSET_PX;\n return {\n opacity: exiting ? 0 : 1,\n transform: exiting ? `translate3d(0, ${yExit}px, 0)` : \"translate3d(0, 0, 0)\",\n transition:\n exiting && durMs > 0\n ? `opacity ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1)`\n : \"none\",\n };\n }, [cycle.transitioning, direction, transitionMs, reducedMotion]);\n\n const incomingMotionStyle = React.useMemo((): React.CSSProperties => {\n const durMs = reducedMotion ? 0 : transitionMs;\n const entered = cycle.incomingEntered;\n const yEnter = direction === \"up\" ? SLIDE_OFFSET_PX : -SLIDE_OFFSET_PX;\n return {\n opacity: entered ? 1 : 0,\n transform: entered ? \"translate3d(0, 0, 0)\" : `translate3d(0, ${yEnter}px, 0)`,\n transition:\n durMs > 0\n ? `opacity ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${durMs}ms cubic-bezier(0.4, 0, 0.2, 1)`\n : \"none\",\n };\n }, [cycle.incomingEntered, direction, transitionMs, reducedMotion]);\n\n if (itemCount === 0) {\n return null;\n }\n\n const wrapperStyle = {\n ...(trackWidth !== null ? { width: `${trackWidth}px` } : {}),\n // paddingTop: SLIDE_OFFSET_PX,\n } as React.CSSProperties;\n\n const showIncoming = incomingLabel !== null && cycle.transitioning;\n\n return (\n <span\n ref={ref}\n data-testid=\"cycling-text\"\n data-paused={paused ? \"true\" : undefined}\n className={cn(\n \"relative inline-flex items-center overflow-hidden align-middle leading-[inherit]\",\n \"motion-safe:transition-[width] motion-safe:duration-300 motion-safe:ease-out\",\n className,\n )}\n style={wrapperStyle}\n {...rest}\n >\n <span\n ref={sizingLabelRef}\n aria-hidden=\"true\"\n className=\"pointer-events-none invisible inline-block select-none whitespace-nowrap leading-[inherit]\"\n >\n {sizingLabel}\n </span>\n\n <span\n data-layer=\"current\"\n aria-live={announceChanges ? \"polite\" : undefined}\n aria-atomic={announceChanges ? true : undefined}\n data-state={cycle.transitioning ? \"exit\" : \"idle\"}\n onTransitionEnd={onOutgoingTransitionEnd}\n className={cn(\n \"absolute inset-0 flex items-center whitespace-nowrap leading-[inherit]\",\n labelClassName,\n )}\n style={outgoingMotionStyle}\n >\n {currentLabel}\n </span>\n\n {showIncoming ? (\n <span\n aria-hidden=\"true\"\n data-layer=\"incoming\"\n data-state={cycle.incomingEntered ? \"idle\" : \"enter\"}\n className={cn(\n \"absolute inset-0 flex items-center whitespace-nowrap leading-[inherit]\",\n labelClassName,\n )}\n style={incomingMotionStyle}\n >\n {incomingLabel}\n </span>\n ) : null}\n </span>\n );\n },\n);\n\nCyclingText.displayName = \"CyclingText\";\n"],"names":["React","usePageVisibility","usePrefersReducedMotion","useCyclingTextTrackWidth","useCyclingCycle","jsxs","cn","jsx"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCyclingCycle.cjs","sources":["../../../../src/components/CyclingText/useCyclingCycle.ts"],"sourcesContent":["import * as React from \"react\";\n\ntype CyclingTextSizingOption = \"longest\" | \"current\";\n\ntype CycleState = {\n currentIndex: number;\n incomingIndex: number | null;\n incomingEntered: boolean;\n transitioning: boolean;\n};\n\ntype CycleAction =\n | { type: \"tick\"; itemCount: number }\n | { type: \"incoming_entered\" }\n | { type: \"transition_complete\" }\n | { type: \"pause_clear\" }\n | { type: \"clamp_after_items_change\"; itemCount: number };\n\nconst initialCycleState: CycleState = {\n currentIndex: 0,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n};\n\nfunction cycleReducer(state: CycleState, action: CycleAction): CycleState {\n switch (action.type) {\n case \"tick\": {\n if (action.itemCount <= 1) return state;\n const next = (state.currentIndex + 1) % action.itemCount;\n return {\n ...state,\n incomingIndex: next,\n incomingEntered: false,\n transitioning: true,\n };\n }\n case \"incoming_entered\":\n return { ...state, incomingEntered: true };\n case \"transition_complete\": {\n if (!state.transitioning || state.incomingIndex === null) return state;\n return {\n currentIndex: state.incomingIndex,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n }\n case \"pause_clear\":\n return {\n ...state,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n case \"clamp_after_items_change\": {\n if (action.itemCount === 0) return state;\n const idx = state.currentIndex >= action.itemCount ? 0 : state.currentIndex;\n return {\n currentIndex: idx,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n }\n default:\n return state;\n }\n}\n\nexport function useCyclingCycle(\n items: readonly string[],\n sizing: CyclingTextSizingOption,\n intervalMs: number,\n paused: boolean,\n docVisible: boolean,\n transitionMs: number,\n) {\n const [cycle, dispatch] = React.useReducer(cycleReducer, initialCycleState);\n\n const enterOuterFrameRef = React.useRef<ReturnType<typeof requestAnimationFrame> | null>(null);\n const enterInnerFrameRef = React.useRef<ReturnType<typeof requestAnimationFrame> | null>(null);\n const fallbackTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n const cycleTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearCycleTimeout = React.useCallback(() => {\n if (cycleTimeoutRef.current !== null) {\n clearTimeout(cycleTimeoutRef.current);\n cycleTimeoutRef.current = null;\n }\n }, []);\n\n const clearAnimationArtifacts = React.useCallback(() => {\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n enterOuterFrameRef.current = null;\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n enterInnerFrameRef.current = null;\n }\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n clearCycleTimeout();\n }, [clearCycleTimeout]);\n\n const itemCount = items.length;\n\n React.useEffect(() => {\n if (itemCount === 0) return;\n dispatch({ type: \"clamp_after_items_change\", itemCount });\n }, [itemCount]);\n\n const safeCurrentIndex = itemCount === 0 ? 0 : cycle.currentIndex % itemCount;\n const safeIncomingIndex =\n cycle.incomingIndex === null || itemCount === 0 ? null : cycle.incomingIndex % itemCount;\n\n const currentLabel = itemCount === 0 ? \"\" : (items[safeCurrentIndex] ?? \"\");\n const incomingLabel = safeIncomingIndex === null ? null : (items[safeIncomingIndex] ?? \"\");\n\n const longestItem = React.useMemo(() => {\n if (itemCount === 0) return \"\";\n let longest = items[0] ?? \"\";\n for (const item of items) {\n if (item.length > longest.length) longest = item;\n }\n return longest;\n }, [items, itemCount]);\n\n const sizingLabel =\n sizing === \"longest\"\n ? longestItem\n : incomingLabel && incomingLabel.length > currentLabel.length\n ? incomingLabel\n : currentLabel;\n\n const shouldCycle = !paused && docVisible && itemCount > 1;\n\n React.useEffect(() => {\n if (!shouldCycle || itemCount <= 1) {\n clearCycleTimeout();\n return;\n }\n\n if (cycle.transitioning) {\n return;\n }\n\n cycleTimeoutRef.current = setTimeout(() => {\n cycleTimeoutRef.current = null;\n dispatch({ type: \"tick\", itemCount });\n }, intervalMs);\n\n return () => {\n clearCycleTimeout();\n };\n }, [shouldCycle, itemCount, intervalMs, cycle.transitioning, clearCycleTimeout]);\n\n React.useEffect(() => {\n if (paused) {\n clearAnimationArtifacts();\n dispatch({ type: \"pause_clear\" });\n }\n }, [paused, clearAnimationArtifacts]);\n\n React.useEffect(() => {\n return () => {\n clearAnimationArtifacts();\n };\n }, [clearAnimationArtifacts]);\n\n React.useEffect(() => {\n if (!cycle.transitioning || cycle.incomingIndex === null || cycle.incomingEntered) {\n return;\n }\n\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n }\n\n enterOuterFrameRef.current = requestAnimationFrame(() => {\n enterOuterFrameRef.current = null;\n enterInnerFrameRef.current = requestAnimationFrame(() => {\n enterInnerFrameRef.current = null;\n dispatch({ type: \"incoming_entered\" });\n });\n });\n\n return () => {\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n enterOuterFrameRef.current = null;\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n enterInnerFrameRef.current = null;\n }\n };\n }, [cycle.transitioning, cycle.incomingIndex, cycle.incomingEntered]);\n\n React.useEffect(() => {\n if (!cycle.transitioning) {\n return;\n }\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n }\n fallbackTimerRef.current = setTimeout(() => {\n dispatch({ type: \"transition_complete\" });\n fallbackTimerRef.current = null;\n }, transitionMs);\n\n return () => {\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n };\n }, [cycle.transitioning, transitionMs]);\n\n const onOutgoingTransitionEnd = React.useCallback(\n (event: React.TransitionEvent<HTMLSpanElement>) => {\n if (!cycle.transitioning) return;\n if (event.propertyName !== \"opacity\") return;\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n dispatch({ type: \"transition_complete\" });\n },\n [cycle.transitioning],\n );\n\n return {\n cycle,\n currentLabel,\n incomingLabel,\n sizingLabel,\n onOutgoingTransitionEnd,\n };\n}\n"],"names":["React"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCyclingCycle.cjs","sources":["../../../../src/components/CyclingText/useCyclingCycle.ts"],"sourcesContent":["import * as React from \"react\";\n\ntype CyclingTextSizingOption = \"longest\" | \"current\";\n\ntype CycleState = {\n currentIndex: number;\n incomingIndex: number | null;\n incomingEntered: boolean;\n transitioning: boolean;\n};\n\ntype CycleAction =\n | { type: \"tick\"; itemCount: number }\n | { type: \"incoming_entered\" }\n | { type: \"transition_complete\" }\n | { type: \"pause_clear\" }\n | { type: \"clamp_after_items_change\"; itemCount: number };\n\nconst initialCycleState: CycleState = {\n currentIndex: 0,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n};\n\nfunction cycleReducer(state: CycleState, action: CycleAction): CycleState {\n switch (action.type) {\n case \"tick\": {\n if (action.itemCount <= 1) return state;\n const next = (state.currentIndex + 1) % action.itemCount;\n return {\n ...state,\n incomingIndex: next,\n incomingEntered: false,\n transitioning: true,\n };\n }\n case \"incoming_entered\":\n return { ...state, incomingEntered: true };\n case \"transition_complete\": {\n if (!state.transitioning || state.incomingIndex === null) return state;\n return {\n currentIndex: state.incomingIndex,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n }\n case \"pause_clear\":\n return {\n ...state,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n case \"clamp_after_items_change\": {\n if (action.itemCount === 0) return state;\n const idx = state.currentIndex >= action.itemCount ? 0 : state.currentIndex;\n return {\n currentIndex: idx,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n }\n default:\n return state;\n }\n}\n\nexport function useCyclingCycle(\n items: readonly string[],\n sizing: CyclingTextSizingOption,\n intervalMs: number,\n paused: boolean,\n docVisible: boolean,\n transitionMs: number,\n) {\n const [cycle, dispatch] = React.useReducer(cycleReducer, initialCycleState);\n\n const enterOuterFrameRef = React.useRef<ReturnType<typeof requestAnimationFrame> | null>(null);\n const enterInnerFrameRef = React.useRef<ReturnType<typeof requestAnimationFrame> | null>(null);\n const fallbackTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n const cycleTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearCycleTimeout = React.useCallback(() => {\n if (cycleTimeoutRef.current !== null) {\n clearTimeout(cycleTimeoutRef.current);\n cycleTimeoutRef.current = null;\n }\n }, []);\n\n const clearAnimationArtifacts = React.useCallback(() => {\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n enterOuterFrameRef.current = null;\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n enterInnerFrameRef.current = null;\n }\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n clearCycleTimeout();\n }, [clearCycleTimeout]);\n\n const itemCount = items.length;\n\n React.useEffect(() => {\n if (itemCount === 0) return;\n dispatch({ type: \"clamp_after_items_change\", itemCount });\n }, [itemCount]);\n\n const safeCurrentIndex = itemCount === 0 ? 0 : cycle.currentIndex % itemCount;\n const safeIncomingIndex =\n cycle.incomingIndex === null || itemCount === 0 ? null : cycle.incomingIndex % itemCount;\n\n const currentLabel = itemCount === 0 ? \"\" : (items[safeCurrentIndex] ?? \"\");\n const incomingLabel = safeIncomingIndex === null ? null : (items[safeIncomingIndex] ?? \"\");\n\n const longestItem = React.useMemo(() => {\n if (itemCount === 0) return \"\";\n let longest = items[0] ?? \"\";\n for (const item of items) {\n if (item.length > longest.length) longest = item;\n }\n return longest;\n }, [items, itemCount]);\n\n const sizingLabel =\n sizing === \"longest\"\n ? longestItem\n : incomingLabel && incomingLabel.length > currentLabel.length\n ? incomingLabel\n : currentLabel;\n\n const shouldCycle = !paused && docVisible && itemCount > 1;\n\n React.useEffect(() => {\n if (!shouldCycle || itemCount <= 1) {\n clearCycleTimeout();\n return;\n }\n\n if (cycle.transitioning) {\n return;\n }\n\n cycleTimeoutRef.current = setTimeout(() => {\n cycleTimeoutRef.current = null;\n dispatch({ type: \"tick\", itemCount });\n }, intervalMs);\n\n return () => {\n clearCycleTimeout();\n };\n }, [shouldCycle, itemCount, intervalMs, cycle.transitioning, clearCycleTimeout]);\n\n React.useEffect(() => {\n if (paused) {\n clearAnimationArtifacts();\n dispatch({ type: \"pause_clear\" });\n }\n }, [paused, clearAnimationArtifacts]);\n\n React.useEffect(() => {\n return () => {\n clearAnimationArtifacts();\n };\n }, [clearAnimationArtifacts]);\n\n React.useEffect(() => {\n if (!cycle.transitioning || cycle.incomingIndex === null || cycle.incomingEntered) {\n return;\n }\n\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n }\n\n enterOuterFrameRef.current = requestAnimationFrame(() => {\n enterOuterFrameRef.current = null;\n enterInnerFrameRef.current = requestAnimationFrame(() => {\n enterInnerFrameRef.current = null;\n dispatch({ type: \"incoming_entered\" });\n });\n });\n\n return () => {\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n enterOuterFrameRef.current = null;\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n enterInnerFrameRef.current = null;\n }\n };\n }, [cycle.transitioning, cycle.incomingIndex, cycle.incomingEntered]);\n\n React.useEffect(() => {\n if (!cycle.transitioning) {\n return;\n }\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n }\n fallbackTimerRef.current = setTimeout(() => {\n dispatch({ type: \"transition_complete\" });\n fallbackTimerRef.current = null;\n }, transitionMs);\n\n return () => {\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n };\n }, [cycle.transitioning, transitionMs]);\n\n const onOutgoingTransitionEnd = React.useCallback(\n (event: React.TransitionEvent<HTMLSpanElement>) => {\n if (!cycle.transitioning) return;\n if (event.propertyName !== \"opacity\") return;\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n dispatch({ type: \"transition_complete\" });\n },\n [cycle.transitioning],\n );\n\n return {\n cycle,\n currentIndex: safeCurrentIndex,\n currentLabel,\n incomingLabel,\n sizingLabel,\n onOutgoingTransitionEnd,\n };\n}\n"],"names":["React"],"mappings":"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"}
|
|
@@ -56,13 +56,14 @@ const DialogContent = React__namespace.forwardRef(
|
|
|
56
56
|
size = "md",
|
|
57
57
|
overlay = true,
|
|
58
58
|
portal = true,
|
|
59
|
+
showMobileHandle = true,
|
|
59
60
|
style,
|
|
60
61
|
onOpenAutoFocus,
|
|
61
62
|
...props
|
|
62
63
|
}, ref) => {
|
|
63
64
|
const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
64
65
|
overlay && /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
65
|
-
/* @__PURE__ */ jsxRuntime.
|
|
66
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
66
67
|
DialogPrimitive__namespace.Content,
|
|
67
68
|
{
|
|
68
69
|
ref,
|
|
@@ -76,13 +77,13 @@ const DialogContent = React__namespace.forwardRef(
|
|
|
76
77
|
e.currentTarget.focus();
|
|
77
78
|
},
|
|
78
79
|
className: cn.cn(
|
|
79
|
-
"fixed flex flex-col overflow-hidden bg-background
|
|
80
|
-
"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-
|
|
80
|
+
"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none",
|
|
81
|
+
"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3",
|
|
81
82
|
"data-[state=open]:fade-in-0 data-[state=open]:animate-in",
|
|
82
83
|
"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out",
|
|
83
84
|
"data-[state=open]:slide-in-from-bottom-full",
|
|
84
85
|
"data-[state=closed]:slide-out-to-bottom-full",
|
|
85
|
-
"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-
|
|
86
|
+
"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-xl sm:p-6",
|
|
86
87
|
"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95",
|
|
87
88
|
"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95",
|
|
88
89
|
"duration-200",
|
|
@@ -90,7 +91,16 @@ const DialogContent = React__namespace.forwardRef(
|
|
|
90
91
|
className
|
|
91
92
|
),
|
|
92
93
|
...props,
|
|
93
|
-
children
|
|
94
|
+
children: [
|
|
95
|
+
showMobileHandle && /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
|
+
"div",
|
|
97
|
+
{
|
|
98
|
+
"aria-hidden": "true",
|
|
99
|
+
className: "mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden"
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
children
|
|
103
|
+
]
|
|
94
104
|
}
|
|
95
105
|
)
|
|
96
106
|
] });
|
|
@@ -114,22 +124,30 @@ const DialogHeader = React__namespace.forwardRef(
|
|
|
114
124
|
"div",
|
|
115
125
|
{
|
|
116
126
|
ref,
|
|
117
|
-
className: cn.cn("flex
|
|
127
|
+
className: cn.cn("flex shrink-0 items-center justify-end gap-4", className),
|
|
118
128
|
...props,
|
|
119
129
|
children: [
|
|
120
130
|
shouldShowBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
121
131
|
IconButton.IconButton,
|
|
122
132
|
{
|
|
123
|
-
variant: "
|
|
133
|
+
variant: "secondary",
|
|
124
134
|
size: "32",
|
|
125
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(ArrowLeftIcon.ArrowLeftIcon, {}),
|
|
135
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(ArrowLeftIcon.ArrowLeftIcon, { size: 16 }),
|
|
126
136
|
onClick: onBack,
|
|
127
137
|
disabled: !onBack,
|
|
128
138
|
"aria-label": backLabel
|
|
129
139
|
}
|
|
130
140
|
),
|
|
131
141
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children }),
|
|
132
|
-
showClose && /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
142
|
+
showClose && /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
143
|
+
IconButton.IconButton,
|
|
144
|
+
{
|
|
145
|
+
variant: "secondary",
|
|
146
|
+
size: "32",
|
|
147
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon.CloseIcon, { size: 16 }),
|
|
148
|
+
"aria-label": closeLabel
|
|
149
|
+
}
|
|
150
|
+
) })
|
|
133
151
|
]
|
|
134
152
|
}
|
|
135
153
|
);
|
|
@@ -140,7 +158,7 @@ const DialogTitle = React__namespace.forwardRef(({ className, ...props }, ref) =
|
|
|
140
158
|
DialogPrimitive__namespace.Title,
|
|
141
159
|
{
|
|
142
160
|
ref,
|
|
143
|
-
className: cn.cn("typography-header-heading-xs
|
|
161
|
+
className: cn.cn("typography-header-heading-xs text-content-primary", className),
|
|
144
162
|
...props
|
|
145
163
|
}
|
|
146
164
|
));
|
|
@@ -155,7 +173,7 @@ const DialogDescription = React__namespace.forwardRef(({ className, ...props },
|
|
|
155
173
|
));
|
|
156
174
|
DialogDescription.displayName = "DialogDescription";
|
|
157
175
|
const DialogBody = React__namespace.forwardRef(
|
|
158
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn.cn("flex-1 overflow-y-auto
|
|
176
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn.cn("flex-1 overflow-y-auto py-4 sm:py-6", className), ...props })
|
|
159
177
|
);
|
|
160
178
|
DialogBody.displayName = "DialogBody";
|
|
161
179
|
const DialogFooter = React__namespace.forwardRef(
|
|
@@ -163,11 +181,7 @@ const DialogFooter = React__namespace.forwardRef(
|
|
|
163
181
|
"div",
|
|
164
182
|
{
|
|
165
183
|
ref,
|
|
166
|
-
className: cn.cn(
|
|
167
|
-
"flex shrink-0 items-center gap-3 px-6 pt-3 pb-6",
|
|
168
|
-
"[&>*]:min-w-0 [&>*]:flex-1",
|
|
169
|
-
className
|
|
170
|
-
),
|
|
184
|
+
className: cn.cn("flex shrink-0 items-center gap-2", "[&>*]:min-w-0 [&>*]:flex-1", className),
|
|
171
185
|
...props
|
|
172
186
|
}
|
|
173
187
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.cjs","sources":["../../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ArrowLeftIcon } from \"../Icons/ArrowLeftIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Props for the {@link Dialog} root component. */\nexport interface DialogProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /** Controlled open state. When provided, you must also supply `onOpenChange`. */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the dialog when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a dialog. */\nexport const Dialog = DialogPrimitive.Root;\n\n/** Props for the {@link DialogTrigger} component. */\nexport type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the dialog when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the dialog on a scroll-drag-end.\n */\nexport const DialogTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DialogTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDialogTrigger.displayName = \"DialogTrigger\";\n\n/** Convenience alias for Radix `Dialog.Close`. Closes the dialog when clicked. */\nexport const DialogClose = DialogPrimitive.Close;\n\n/** Props for the {@link DialogClose} component. */\nexport type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\nexport interface DialogOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * Semi-transparent backdrop rendered behind the dialog content.\n * Rendered by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\n */\nexport const DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-background-overlay-default data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className,\n )}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport interface DialogContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * Width preset for the dialog.\n * - `\"sm\"` — 400px max-width (confirmations, simple forms)\n * - `\"md\"` — 440px max-width (default, standard dialogs)\n * - `\"lg\"` — 600px max-width (complex content, tables)\n *\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** When true, renders overlay automatically. @default true */\n overlay?: boolean;\n /**\n * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n}\n\nconst SIZE_CLASSES: Record<NonNullable<DialogContentProps[\"size\"]>, string> = {\n sm: \"sm:max-w-[400px]\",\n md: \"sm:max-w-[440px]\",\n lg: \"sm:max-w-[600px]\",\n};\n\n/**\n * The dialog panel. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius. On larger viewports it renders centered with\n * full border radius.\n *\n * @example\n * ```tsx\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Title</DialogTitle>\n * </DialogHeader>\n * <DialogBody>Content here</DialogBody>\n * <DialogFooter>\n * <DialogClose asChild>\n * <Button variant=\"secondary\">Cancel</Button>\n * </DialogClose>\n * <Button>Accept</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n */\nexport const DialogContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\n {overlay && <DialogOverlay />}\n <DialogPrimitive.Content\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n onOpenAutoFocus={(e) => {\n if (onOpenAutoFocus) {\n onOpenAutoFocus(e);\n return;\n }\n e.preventDefault();\n (e.currentTarget as HTMLElement).focus();\n }}\n className={cn(\n \"fixed flex flex-col overflow-hidden bg-background-primary shadow-lg focus:outline-none dark:bg-surface-primary\",\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-lg\",\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg\",\n \"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95\",\n \"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\n);\nDialogContent.displayName = \"DialogContent\";\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Show the close (X) button in the header. @default true */\n showClose?: boolean;\n /** Show a back arrow button on the left side. Defaults to `true` when `onBack` is provided. */\n showBack?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible label for the back button. @default \"Go back\" */\n backLabel?: string;\n /** Accessible label for the close button. @default \"Close\" */\n closeLabel?: string;\n}\n\n/**\n * Header bar for the dialog. Renders the title with an optional back arrow\n * and close button.\n *\n * @example\n * ```tsx\n * <DialogHeader>\n * <DialogTitle>Settings</DialogTitle>\n * </DialogHeader>\n *\n * <DialogHeader showBack onBack={() => setStep(0)}>\n * <DialogTitle>Step 2</DialogTitle>\n * </DialogHeader>\n * ```\n */\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n (\n {\n className,\n children,\n showClose = true,\n showBack,\n onBack,\n backLabel = \"Go back\",\n closeLabel = \"Close\",\n ...props\n },\n ref,\n ) => {\n const shouldShowBack = showBack ?? !!onBack;\n\n return (\n <div\n ref={ref}\n className={cn(\"flex h-16 shrink-0 items-center gap-2 px-6 py-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<ArrowLeftIcon />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton variant=\"tertiary\" size=\"32\" icon={<CloseIcon />} aria-label={closeLabel} />\n </DialogPrimitive.Close>\n )}\n </div>\n );\n },\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Props for the {@link DialogTitle} component. */\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\n/**\n * Accessible title for the dialog. Must be rendered inside {@link DialogHeader}\n * or directly within {@link DialogContent}.\n */\nexport const DialogTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-header-heading-xs truncate text-content-primary\", className)}\n {...props}\n />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Props for the {@link DialogDescription} component. */\nexport type DialogDescriptionProps = React.ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/** Accessible description for the dialog. Rendered as secondary text. */\nexport const DialogDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-default-16px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Scrollable content area (slot) between the header and footer.\n * Grows to fill available space and scrolls when content overflows.\n */\nexport const DialogBody = React.forwardRef<HTMLDivElement, DialogBodyProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex-1 overflow-y-auto px-6 py-4\", className)} {...props} />\n ),\n);\nDialogBody.displayName = \"DialogBody\";\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Footer bar for the dialog. Typically contains action buttons.\n * Children are laid out in a horizontal row with equal flex-basis.\n */\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex shrink-0 items-center gap-3 px-6 pt-3 pb-6\",\n \"[&>*]:min-w-0 [&>*]:flex-1\",\n className,\n )}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":["DialogPrimitive","React","jsx","useSuppressClickAfterDrag","cn","jsxs","Fragment","IconButton","ArrowLeftIcon","CloseIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dialog.cjs","sources":["../../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ArrowLeftIcon } from \"../Icons/ArrowLeftIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Props for the {@link Dialog} root component. */\nexport interface DialogProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /** Controlled open state. When provided, you must also supply `onOpenChange`. */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the dialog when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a dialog. */\nexport const Dialog = DialogPrimitive.Root;\n\n/** Props for the {@link DialogTrigger} component. */\nexport type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the dialog when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the dialog on a scroll-drag-end.\n */\nexport const DialogTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DialogTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDialogTrigger.displayName = \"DialogTrigger\";\n\n/** Convenience alias for Radix `Dialog.Close`. Closes the dialog when clicked. */\nexport const DialogClose = DialogPrimitive.Close;\n\n/** Props for the {@link DialogClose} component. */\nexport type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\nexport interface DialogOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * Semi-transparent backdrop rendered behind the dialog content.\n * Rendered by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\n */\nexport const DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-background-overlay-default data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className,\n )}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport interface DialogContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * Width preset for the dialog.\n * - `\"sm\"` — 400px max-width (confirmations, simple forms)\n * - `\"md\"` — 440px max-width (default, standard dialogs)\n * - `\"lg\"` — 600px max-width (complex content, tables)\n *\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** When true, renders overlay automatically. @default true */\n overlay?: boolean;\n /**\n * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n /** Show the v2 mobile sheet pull handle. @default true */\n showMobileHandle?: boolean;\n}\n\nconst SIZE_CLASSES: Record<NonNullable<DialogContentProps[\"size\"]>, string> = {\n sm: \"sm:max-w-[400px]\",\n md: \"sm:max-w-[440px]\",\n lg: \"sm:max-w-[600px]\",\n};\n\n/**\n * The dialog panel. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius. On larger viewports it renders centered with\n * full border radius.\n *\n * @example\n * ```tsx\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Title</DialogTitle>\n * </DialogHeader>\n * <DialogBody>Content here</DialogBody>\n * <DialogFooter>\n * <DialogClose asChild>\n * <Button variant=\"secondary\">Cancel</Button>\n * </DialogClose>\n * <Button>Accept</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n */\nexport const DialogContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n showMobileHandle = true,\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\n {overlay && <DialogOverlay />}\n <DialogPrimitive.Content\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n onOpenAutoFocus={(e) => {\n if (onOpenAutoFocus) {\n onOpenAutoFocus(e);\n return;\n }\n e.preventDefault();\n (e.currentTarget as HTMLElement).focus();\n }}\n className={cn(\n \"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none\",\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3\",\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-xl sm:p-6\",\n \"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95\",\n \"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {showMobileHandle && (\n <div\n aria-hidden=\"true\"\n className=\"mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden\"\n />\n )}\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\n);\nDialogContent.displayName = \"DialogContent\";\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Show the close (X) button in the header. @default true */\n showClose?: boolean;\n /** Show a back arrow button on the left side. Defaults to `true` when `onBack` is provided. */\n showBack?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible label for the back button. @default \"Go back\" */\n backLabel?: string;\n /** Accessible label for the close button. @default \"Close\" */\n closeLabel?: string;\n}\n\n/**\n * Header bar for the dialog. Renders the title with an optional back arrow\n * and close button.\n *\n * @example\n * ```tsx\n * <DialogHeader>\n * <DialogTitle>Settings</DialogTitle>\n * </DialogHeader>\n *\n * <DialogHeader showBack onBack={() => setStep(0)}>\n * <DialogTitle>Step 2</DialogTitle>\n * </DialogHeader>\n * ```\n */\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n (\n {\n className,\n children,\n showClose = true,\n showBack,\n onBack,\n backLabel = \"Go back\",\n closeLabel = \"Close\",\n ...props\n },\n ref,\n ) => {\n const shouldShowBack = showBack ?? !!onBack;\n\n return (\n <div\n ref={ref}\n className={cn(\"flex shrink-0 items-center justify-end gap-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<ArrowLeftIcon size={16} />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<CloseIcon size={16} />}\n aria-label={closeLabel}\n />\n </DialogPrimitive.Close>\n )}\n </div>\n );\n },\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Props for the {@link DialogTitle} component. */\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\n/**\n * Accessible title for the dialog. Must be rendered inside {@link DialogHeader}\n * or directly within {@link DialogContent}.\n */\nexport const DialogTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-header-heading-xs text-content-primary\", className)}\n {...props}\n />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Props for the {@link DialogDescription} component. */\nexport type DialogDescriptionProps = React.ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/** Accessible description for the dialog. Rendered as secondary text. */\nexport const DialogDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-default-16px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Scrollable content area (slot) between the header and footer.\n * Grows to fill available space and scrolls when content overflows.\n */\nexport const DialogBody = React.forwardRef<HTMLDivElement, DialogBodyProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex-1 overflow-y-auto py-4 sm:py-6\", className)} {...props} />\n ),\n);\nDialogBody.displayName = \"DialogBody\";\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Footer bar for the dialog. Typically contains action buttons.\n * Children are laid out in a horizontal row with equal flex-basis.\n */\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex shrink-0 items-center gap-2\", \"[&>*]:min-w-0 [&>*]:flex-1\", className)}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":["DialogPrimitive","React","jsx","useSuppressClickAfterDrag","cn","jsxs","Fragment","IconButton","ArrowLeftIcon","CloseIcon"],"mappings":"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"}
|
|
@@ -36,7 +36,7 @@ const Radio = React__namespace.forwardRef(({ className, size = "default", label,
|
|
|
36
36
|
"data-testid": "radio",
|
|
37
37
|
"aria-describedby": helperText ? helperTextId : void 0,
|
|
38
38
|
className: cn.cn(
|
|
39
|
-
"relative h-4 w-4 shrink-0 cursor-pointer appearance-none rounded-full border border-content-primary bg-transparent transition-colors hover:bg-brand-primary-muted focus-visible:
|
|
39
|
+
"relative h-4 w-4 shrink-0 cursor-pointer appearance-none rounded-full border border-content-primary bg-transparent transition-colors hover:bg-brand-primary-muted focus-visible:shadow-focus-ring focus-visible:outline-none not-disabled:active:bg-brand-primary-muted disabled:cursor-not-allowed disabled:border-neutral-alphas-600 disabled:bg-transparent data-[state=checked]:border-content-primary data-[state=checked]:bg-transparent",
|
|
40
40
|
helperText && "mt-1 self-start"
|
|
41
41
|
),
|
|
42
42
|
...props,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Radio.cjs","sources":["../../../../src/components/Radio/Radio.tsx"],"sourcesContent":["import * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface RadioProps\n extends Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, \"asChild\"> {\n /** Size variant controlling label and helper text typography. @default \"default\" */\n size?: \"default\" | \"small\";\n /** Label text displayed next to the radio button. */\n label?: string;\n /** Descriptive text displayed below the label. */\n helperText?: string;\n}\n\n/**\n * A single radio option within a {@link RadioGroup}. Includes an optional label\n * and helper text.\n *\n * @example\n * ```tsx\n * <RadioGroup value={value} onValueChange={setValue}>\n * <Radio value=\"a\" label=\"Option A\" />\n * <Radio value=\"b\" label=\"Option B\" />\n * </RadioGroup>\n * ```\n */\nexport const Radio = React.forwardRef<\n React.ComponentRef<typeof RadioGroupPrimitive.Item>,\n RadioProps\n>(({ className, size = \"default\", label, helperText, id, ...props }, ref) => {\n const generatedId = React.useId();\n const inputId = id || generatedId;\n const helperTextId = `${inputId}-helper`;\n\n return (\n <div className={cn(\"group inline-flex items-center gap-2\", className)}>\n <RadioGroupPrimitive.Item\n ref={ref}\n id={inputId}\n data-testid=\"radio\"\n aria-describedby={helperText ? helperTextId : undefined}\n className={cn(\n \"relative h-4 w-4 shrink-0 cursor-pointer appearance-none rounded-full border border-content-primary bg-transparent transition-colors hover:bg-brand-primary-muted focus-visible:
|
|
1
|
+
{"version":3,"file":"Radio.cjs","sources":["../../../../src/components/Radio/Radio.tsx"],"sourcesContent":["import * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface RadioProps\n extends Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>, \"asChild\"> {\n /** Size variant controlling label and helper text typography. @default \"default\" */\n size?: \"default\" | \"small\";\n /** Label text displayed next to the radio button. */\n label?: string;\n /** Descriptive text displayed below the label. */\n helperText?: string;\n}\n\n/**\n * A single radio option within a {@link RadioGroup}. Includes an optional label\n * and helper text.\n *\n * @example\n * ```tsx\n * <RadioGroup value={value} onValueChange={setValue}>\n * <Radio value=\"a\" label=\"Option A\" />\n * <Radio value=\"b\" label=\"Option B\" />\n * </RadioGroup>\n * ```\n */\nexport const Radio = React.forwardRef<\n React.ComponentRef<typeof RadioGroupPrimitive.Item>,\n RadioProps\n>(({ className, size = \"default\", label, helperText, id, ...props }, ref) => {\n const generatedId = React.useId();\n const inputId = id || generatedId;\n const helperTextId = `${inputId}-helper`;\n\n return (\n <div className={cn(\"group inline-flex items-center gap-2\", className)}>\n <RadioGroupPrimitive.Item\n ref={ref}\n id={inputId}\n data-testid=\"radio\"\n aria-describedby={helperText ? helperTextId : undefined}\n className={cn(\n \"relative h-4 w-4 shrink-0 cursor-pointer appearance-none rounded-full border border-content-primary bg-transparent transition-colors hover:bg-brand-primary-muted focus-visible:shadow-focus-ring focus-visible:outline-none not-disabled:active:bg-brand-primary-muted disabled:cursor-not-allowed disabled:border-neutral-alphas-600 disabled:bg-transparent data-[state=checked]:border-content-primary data-[state=checked]:bg-transparent\",\n helperText && \"mt-1 self-start\",\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"size-2 rounded-full bg-content-primary group-has-disabled:bg-neutral-alphas-600\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n {(label || helperText) && (\n <div className=\"flex flex-col gap-0.5\">\n {label && (\n <label\n htmlFor={inputId}\n className={cn(\n \"cursor-pointer select-none text-content-primary group-has-disabled:cursor-not-allowed group-has-disabled:text-content-tertiary\",\n size === \"small\"\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\",\n )}\n >\n {label}\n </label>\n )}\n {helperText && (\n <span\n id={helperTextId}\n className={cn(\n \"text-content-secondary group-has-disabled:cursor-not-allowed group-has-disabled:text-content-tertiary\",\n size === \"small\"\n ? \"typography-body-small-14px-semibold\"\n : \"typography-description-12px-regular\",\n )}\n >\n {helperText}\n </span>\n )}\n </div>\n )}\n </div>\n );\n});\n\nRadio.displayName = \"Radio\";\n"],"names":["React","cn","jsx","RadioGroupPrimitive","jsxs"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0BO,MAAM,QAAQA,iBAAM,WAGzB,CAAC,EAAE,WAAW,OAAO,WAAW,OAAO,YAAY,IAAI,GAAG,MAAA,GAAS,QAAQ;AAC3E,QAAM,cAAcA,iBAAM,MAAA;AAC1B,QAAM,UAAU,MAAM;AACtB,QAAM,eAAe,GAAG,OAAO;AAE/B,yCACG,OAAA,EAAI,WAAWC,GAAAA,GAAG,wCAAwC,SAAS,GAClE,UAAA;AAAA,IAAAC,2BAAAA;AAAAA,MAACC,+BAAoB;AAAA,MAApB;AAAA,QACC;AAAA,QACA,IAAI;AAAA,QACJ,eAAY;AAAA,QACZ,oBAAkB,aAAa,eAAe;AAAA,QAC9C,WAAWF,GAAAA;AAAAA,UACT;AAAA,UACA,cAAc;AAAA,QAAA;AAAA,QAEf,GAAG;AAAA,QAEJ,UAAAC,2BAAAA,IAACC,+BAAoB,WAApB,EAA8B,WAAU,qDACvC,UAAAD,2BAAAA,IAAC,QAAA,EAAK,WAAU,kFAAA,CAAkF,EAAA,CACpG;AAAA,MAAA;AAAA,IAAA;AAAA,KAEA,SAAS,eACTE,2BAAAA,KAAC,OAAA,EAAI,WAAU,yBACZ,UAAA;AAAA,MAAA,SACCF,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAWD,GAAAA;AAAAA,YACT;AAAA,YACA,SAAS,UACL,wCACA;AAAA,UAAA;AAAA,UAGL,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAGJ,cACCC,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,WAAWD,GAAAA;AAAAA,YACT;AAAA,YACA,SAAS,UACL,wCACA;AAAA,UAAA;AAAA,UAGL,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IACH,EAAA,CAEJ;AAAA,EAAA,GAEJ;AAEJ,CAAC;AAED,MAAM,cAAc;;"}
|
|
@@ -60,7 +60,7 @@ function SliderThumb({
|
|
|
60
60
|
"transition-shadow duration-150",
|
|
61
61
|
"hover:ring-2 hover:ring-brand-primary-default",
|
|
62
62
|
"not-data-disabled:active:ring-2 not-data-disabled:active:ring-brand-primary-default",
|
|
63
|
-
"focus-visible:
|
|
63
|
+
"focus-visible:shadow-focus-ring focus-visible:outline-none",
|
|
64
64
|
"data-disabled:cursor-not-allowed"
|
|
65
65
|
),
|
|
66
66
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliderThumb.cjs","sources":["../../../../src/components/Slider/SliderThumb.tsx"],"sourcesContent":["import * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\ninterface SliderThumbProps {\n showTooltip: boolean;\n formatTooltip?: (value: number) => string;\n index: number;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n}\n\nexport function SliderThumb({\n showTooltip,\n formatTooltip,\n index,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n}: SliderThumbProps) {\n const thumbRef = React.useCallback(\n (el: HTMLSpanElement | null) => {\n if (!el || !showTooltip) return;\n syncTooltipText(el, formatTooltip);\n },\n [showTooltip, formatTooltip],\n );\n\n return (\n <SliderPrimitive.Thumb\n ref={thumbRef}\n data-index={index}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n onPointerDown={(e) => {\n if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);\n }}\n onPointerMove={(e) => {\n if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);\n }}\n onKeyDown={(e) => {\n if (showTooltip) {\n requestAnimationFrame(() => syncTooltipText(e.currentTarget, formatTooltip));\n }\n }}\n className={cn(\n \"flex size-6 items-center justify-center rounded-full border border-border-primary bg-background-primary shadow-sm\",\n \"transition-shadow duration-150\",\n \"hover:ring-2 hover:ring-brand-primary-default\",\n \"not-data-disabled:active:ring-2 not-data-disabled:active:ring-brand-primary-default\",\n \"focus-visible:
|
|
1
|
+
{"version":3,"file":"SliderThumb.cjs","sources":["../../../../src/components/Slider/SliderThumb.tsx"],"sourcesContent":["import * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\ninterface SliderThumbProps {\n showTooltip: boolean;\n formatTooltip?: (value: number) => string;\n index: number;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n}\n\nexport function SliderThumb({\n showTooltip,\n formatTooltip,\n index,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n}: SliderThumbProps) {\n const thumbRef = React.useCallback(\n (el: HTMLSpanElement | null) => {\n if (!el || !showTooltip) return;\n syncTooltipText(el, formatTooltip);\n },\n [showTooltip, formatTooltip],\n );\n\n return (\n <SliderPrimitive.Thumb\n ref={thumbRef}\n data-index={index}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n onPointerDown={(e) => {\n if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);\n }}\n onPointerMove={(e) => {\n if (showTooltip) syncTooltipText(e.currentTarget, formatTooltip);\n }}\n onKeyDown={(e) => {\n if (showTooltip) {\n requestAnimationFrame(() => syncTooltipText(e.currentTarget, formatTooltip));\n }\n }}\n className={cn(\n \"flex size-6 items-center justify-center rounded-full border border-border-primary bg-background-primary shadow-sm\",\n \"transition-shadow duration-150\",\n \"hover:ring-2 hover:ring-brand-primary-default\",\n \"not-data-disabled:active:ring-2 not-data-disabled:active:ring-brand-primary-default\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n \"data-disabled:cursor-not-allowed\",\n )}\n >\n <span className=\"block size-3 rounded-full bg-brand-primary-default shadow-[inset_0px_1px_2px_0px_rgba(0,0,0,0.1)]\" />\n\n {showTooltip && (\n <span\n role=\"tooltip\"\n data-slider-tooltip\n className=\"typography-description-12px-semibold pointer-events-none absolute bottom-full mb-2 rounded-lg bg-surface-primary-inverted px-2 py-1 text-content-primary-inverted shadow-sm\"\n />\n )}\n </SliderPrimitive.Thumb>\n );\n}\n\nfunction syncTooltipText(thumb: HTMLElement, formatTooltip?: (value: number) => string) {\n const raw = thumb.getAttribute(\"aria-valuenow\");\n const tooltip = thumb.querySelector<HTMLSpanElement>(\"[data-slider-tooltip]\");\n if (raw == null || !tooltip) return;\n const num = Number(raw);\n tooltip.textContent = formatTooltip ? formatTooltip(num) : String(num);\n}\n"],"names":["React","jsxs","SliderPrimitive","cn","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAYO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,mBAAmB;AACrB,GAAqB;AACnB,QAAM,WAAWA,iBAAM;AAAA,IACrB,CAAC,OAA+B;AAC9B,UAAI,CAAC,MAAM,CAAC,YAAa;AACzB,sBAAgB,IAAI,aAAa;AAAA,IACnC;AAAA,IACA,CAAC,aAAa,aAAa;AAAA,EAAA;AAG7B,SACEC,2BAAAA;AAAAA,IAACC,2BAAgB;AAAA,IAAhB;AAAA,MACC,KAAK;AAAA,MACL,cAAY;AAAA,MACZ,cAAY;AAAA,MACZ,mBAAiB;AAAA,MACjB,eAAe,CAAC,MAAM;AACpB,YAAI,YAAa,iBAAgB,EAAE,eAAe,aAAa;AAAA,MACjE;AAAA,MACA,eAAe,CAAC,MAAM;AACpB,YAAI,YAAa,iBAAgB,EAAE,eAAe,aAAa;AAAA,MACjE;AAAA,MACA,WAAW,CAAC,MAAM;AAChB,YAAI,aAAa;AACf,gCAAsB,MAAM,gBAAgB,EAAE,eAAe,aAAa,CAAC;AAAA,QAC7E;AAAA,MACF;AAAA,MACA,WAAWC,GAAAA;AAAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAAC,2BAAAA,IAAC,QAAA,EAAK,WAAU,oGAAA,CAAoG;AAAA,QAEnH,eACCA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,uBAAmB;AAAA,YACnB,WAAU;AAAA,UAAA;AAAA,QAAA;AAAA,MACZ;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,gBAAgB,OAAoB,eAA2C;AACtF,QAAM,MAAM,MAAM,aAAa,eAAe;AAC9C,QAAM,UAAU,MAAM,cAA+B,uBAAuB;AAC5E,MAAI,OAAO,QAAQ,CAAC,QAAS;AAC7B,QAAM,MAAM,OAAO,GAAG;AACtB,UAAQ,cAAc,gBAAgB,cAAc,GAAG,IAAI,OAAO,GAAG;AACvE;;"}
|
|
@@ -81,7 +81,14 @@ const TabsList = React__namespace.forwardRef(({ className, children, fullWidth =
|
|
|
81
81
|
});
|
|
82
82
|
const resizeObserver = new ResizeObserver(updateIndicator);
|
|
83
83
|
resizeObserver.observe(list);
|
|
84
|
+
let cancelled = false;
|
|
85
|
+
if (document.fonts?.status !== "loaded") {
|
|
86
|
+
document.fonts?.ready.then(() => {
|
|
87
|
+
if (!cancelled) updateIndicator();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
84
90
|
return () => {
|
|
91
|
+
cancelled = true;
|
|
85
92
|
mutationObserver.disconnect();
|
|
86
93
|
resizeObserver.disconnect();
|
|
87
94
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabsList.cjs","sources":["../../../../src/components/Tabs/TabsList.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Breakpoint values for responsive props. */\ntype Breakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\";\n\nconst alignLeftClasses: Record<Breakpoint | \"always\", string> = {\n always: \"[&>[role=tab]]:flex-initial\",\n sm: \"[&>[role=tab]]:sm:flex-initial\",\n md: \"[&>[role=tab]]:md:flex-initial\",\n lg: \"[&>[role=tab]]:lg:flex-initial\",\n xl: \"[&>[role=tab]]:xl:flex-initial\",\n};\n\nfunction getLayoutClass(fullWidth: boolean, alignLeft?: boolean | Breakpoint): string {\n if (!fullWidth) return \"inline-flex\";\n\n const base = \"flex w-full [&>[role=tab]]:flex-1\";\n if (alignLeft === true) return `${base} ${alignLeftClasses.always}`;\n if (typeof alignLeft === \"string\") return `${base} ${alignLeftClasses[alignLeft]}`;\n return base;\n}\n\n/** Props for the {@link TabsList} component. */\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {\n /** When `true` (the default), the tab list spans the full width of its container and each tab grows equally. Set to `false` for inline sizing. */\n fullWidth?: boolean;\n /**\n * Controls tab alignment within a full-width container.\n * - `false` (default): tabs spread evenly\n * - `true`: tabs left-aligned, sized to content\n * - `\"md\"` (breakpoint): spread on mobile, left-aligned at breakpoint and up\n */\n alignLeft?: boolean | Breakpoint;\n};\n\n/** Container for {@link TabsTrigger} elements. Renders a sliding active-tab indicator that animates between tabs. */\nexport const TabsList = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, children, fullWidth = true, alignLeft, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null);\n const indicatorRef = React.useRef<HTMLSpanElement>(null);\n\n React.useImperativeHandle(ref, () => innerRef.current as HTMLDivElement);\n\n const updateIndicator = React.useCallback(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n const activeTab = list.querySelector<HTMLElement>('[data-state=\"active\"]');\n if (!activeTab) {\n indicator.style.opacity = \"0\";\n return;\n }\n\n const isVertical = list.dataset.orientation === \"vertical\";\n\n indicator.style.opacity = \"1\";\n\n if (isVertical) {\n indicator.style.inset = `0 0 auto auto`;\n indicator.style.width = \"4px\";\n indicator.style.height = `${activeTab.offsetHeight}px`;\n indicator.style.transform = `translateY(${activeTab.offsetTop}px)`;\n } else {\n indicator.style.inset = `auto auto 0 0`;\n indicator.style.height = \"4px\";\n indicator.style.width = `${activeTab.offsetWidth}px`;\n indicator.style.transform = `translateX(${activeTab.offsetLeft}px)`;\n }\n }, []);\n\n React.useLayoutEffect(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n indicator.style.transitionDuration = \"0s\";\n updateIndicator();\n indicator.getBoundingClientRect();\n indicator.style.transitionDuration = \"\";\n\n const mutationObserver = new MutationObserver(updateIndicator);\n mutationObserver.observe(list, {\n attributes: true,\n attributeFilter: [\"data-state\"],\n childList: true,\n subtree: true,\n });\n\n const resizeObserver = new ResizeObserver(updateIndicator);\n resizeObserver.observe(list);\n\n return () => {\n mutationObserver.disconnect();\n resizeObserver.disconnect();\n };\n }, [updateIndicator]);\n\n return (\n <TabsPrimitive.List\n ref={innerRef}\n className={cn(\n \"relative\",\n getLayoutClass(fullWidth, alignLeft),\n \"data-[orientation=horizontal]:items-center data-[orientation=horizontal]:shadow-[inset_0_-1px_0_0_var(--color-neutral-alphas-200)]\",\n \"data-[orientation=vertical]:flex-col data-[orientation=vertical]:shadow-[inset_-1px_0_0_0_var(--color-neutral-alphas-200)]\",\n className,\n )}\n {...props}\n >\n {children}\n <span\n ref={indicatorRef}\n aria-hidden\n className=\"pointer-events-none absolute rounded-full bg-brand-primary-default motion-safe:transition-[transform,width,height] motion-safe:duration-200 motion-safe:ease-in-out\"\n style={{ opacity: 0 }}\n />\n </TabsPrimitive.List>\n );\n});\n\nTabsList.displayName = \"TabsList\";\n"],"names":["React","jsxs","TabsPrimitive","cn","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAOA,MAAM,mBAA0D;AAAA,EAC9D,QAAQ;AAAA,EACR,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,SAAS,eAAe,WAAoB,WAA0C;AACpF,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,OAAO;AACb,MAAI,cAAc,KAAM,QAAO,GAAG,IAAI,IAAI,iBAAiB,MAAM;AACjE,MAAI,OAAO,cAAc,SAAU,QAAO,GAAG,IAAI,IAAI,iBAAiB,SAAS,CAAC;AAChF,SAAO;AACT;AAgBO,MAAM,WAAWA,iBAAM,WAG5B,CAAC,EAAE,WAAW,UAAU,YAAY,MAAM,WAAW,GAAG,MAAA,GAAS,QAAQ;AACzE,QAAM,WAAWA,iBAAM,OAAuB,IAAI;AAClD,QAAM,eAAeA,iBAAM,OAAwB,IAAI;AAEvDA,mBAAM,oBAAoB,KAAK,MAAM,SAAS,OAAyB;AAEvE,QAAM,kBAAkBA,iBAAM,YAAY,MAAM;AAC9C,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,UAAM,YAAY,KAAK,cAA2B,uBAAuB;AACzE,QAAI,CAAC,WAAW;AACd,gBAAU,MAAM,UAAU;AAC1B;AAAA,IACF;AAEA,UAAM,aAAa,KAAK,QAAQ,gBAAgB;AAEhD,cAAU,MAAM,UAAU;AAE1B,QAAI,YAAY;AACd,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS,GAAG,UAAU,YAAY;AAClD,gBAAU,MAAM,YAAY,cAAc,UAAU,SAAS;AAAA,IAC/D,OAAO;AACL,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS;AACzB,gBAAU,MAAM,QAAQ,GAAG,UAAU,WAAW;AAChD,gBAAU,MAAM,YAAY,cAAc,UAAU,UAAU;AAAA,IAChE;AAAA,EACF,GAAG,CAAA,CAAE;AAELA,mBAAM,gBAAgB,MAAM;AAC1B,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,cAAU,MAAM,qBAAqB;AACrC,oBAAA;AACA,cAAU,sBAAA;AACV,cAAU,MAAM,qBAAqB;AAErC,UAAM,mBAAmB,IAAI,iBAAiB,eAAe;AAC7D,qBAAiB,QAAQ,MAAM;AAAA,MAC7B,YAAY;AAAA,MACZ,iBAAiB,CAAC,YAAY;AAAA,MAC9B,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,CACV;AAED,UAAM,iBAAiB,IAAI,eAAe,eAAe;AACzD,mBAAe,QAAQ,IAAI;AAE3B,WAAO,MAAM;AACX,uBAAiB,WAAA;AACjB,qBAAe,WAAA;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAEpB,SACEC,2BAAAA;AAAAA,IAACC,yBAAc;AAAA,IAAd;AAAA,MACC,KAAK;AAAA,MACL,WAAWC,GAAAA;AAAAA,QACT;AAAA,QACA,eAAe,WAAW,SAAS;AAAA,QACnC;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA;AAAA,QACDC,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,eAAW;AAAA,YACX,WAAU;AAAA,YACV,OAAO,EAAE,SAAS,EAAA;AAAA,UAAE;AAAA,QAAA;AAAA,MACtB;AAAA,IAAA;AAAA,EAAA;AAGN,CAAC;AAED,SAAS,cAAc;;"}
|
|
1
|
+
{"version":3,"file":"TabsList.cjs","sources":["../../../../src/components/Tabs/TabsList.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Breakpoint values for responsive props. */\ntype Breakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\";\n\nconst alignLeftClasses: Record<Breakpoint | \"always\", string> = {\n always: \"[&>[role=tab]]:flex-initial\",\n sm: \"[&>[role=tab]]:sm:flex-initial\",\n md: \"[&>[role=tab]]:md:flex-initial\",\n lg: \"[&>[role=tab]]:lg:flex-initial\",\n xl: \"[&>[role=tab]]:xl:flex-initial\",\n};\n\nfunction getLayoutClass(fullWidth: boolean, alignLeft?: boolean | Breakpoint): string {\n if (!fullWidth) return \"inline-flex\";\n\n const base = \"flex w-full [&>[role=tab]]:flex-1\";\n if (alignLeft === true) return `${base} ${alignLeftClasses.always}`;\n if (typeof alignLeft === \"string\") return `${base} ${alignLeftClasses[alignLeft]}`;\n return base;\n}\n\n/** Props for the {@link TabsList} component. */\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {\n /** When `true` (the default), the tab list spans the full width of its container and each tab grows equally. Set to `false` for inline sizing. */\n fullWidth?: boolean;\n /**\n * Controls tab alignment within a full-width container.\n * - `false` (default): tabs spread evenly\n * - `true`: tabs left-aligned, sized to content\n * - `\"md\"` (breakpoint): spread on mobile, left-aligned at breakpoint and up\n */\n alignLeft?: boolean | Breakpoint;\n};\n\n/** Container for {@link TabsTrigger} elements. Renders a sliding active-tab indicator that animates between tabs. */\nexport const TabsList = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, children, fullWidth = true, alignLeft, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null);\n const indicatorRef = React.useRef<HTMLSpanElement>(null);\n\n React.useImperativeHandle(ref, () => innerRef.current as HTMLDivElement);\n\n const updateIndicator = React.useCallback(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n const activeTab = list.querySelector<HTMLElement>('[data-state=\"active\"]');\n if (!activeTab) {\n indicator.style.opacity = \"0\";\n return;\n }\n\n const isVertical = list.dataset.orientation === \"vertical\";\n\n indicator.style.opacity = \"1\";\n\n if (isVertical) {\n indicator.style.inset = `0 0 auto auto`;\n indicator.style.width = \"4px\";\n indicator.style.height = `${activeTab.offsetHeight}px`;\n indicator.style.transform = `translateY(${activeTab.offsetTop}px)`;\n } else {\n indicator.style.inset = `auto auto 0 0`;\n indicator.style.height = \"4px\";\n indicator.style.width = `${activeTab.offsetWidth}px`;\n indicator.style.transform = `translateX(${activeTab.offsetLeft}px)`;\n }\n }, []);\n\n React.useLayoutEffect(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n indicator.style.transitionDuration = \"0s\";\n updateIndicator();\n indicator.getBoundingClientRect();\n indicator.style.transitionDuration = \"\";\n\n const mutationObserver = new MutationObserver(updateIndicator);\n mutationObserver.observe(list, {\n attributes: true,\n attributeFilter: [\"data-state\"],\n childList: true,\n subtree: true,\n });\n\n const resizeObserver = new ResizeObserver(updateIndicator);\n resizeObserver.observe(list);\n\n let cancelled = false;\n if (document.fonts?.status !== \"loaded\") {\n document.fonts?.ready.then(() => {\n if (!cancelled) updateIndicator();\n });\n }\n\n return () => {\n cancelled = true;\n mutationObserver.disconnect();\n resizeObserver.disconnect();\n };\n }, [updateIndicator]);\n\n return (\n <TabsPrimitive.List\n ref={innerRef}\n className={cn(\n \"relative\",\n getLayoutClass(fullWidth, alignLeft),\n \"data-[orientation=horizontal]:items-center data-[orientation=horizontal]:shadow-[inset_0_-1px_0_0_var(--color-neutral-alphas-200)]\",\n \"data-[orientation=vertical]:flex-col data-[orientation=vertical]:shadow-[inset_-1px_0_0_0_var(--color-neutral-alphas-200)]\",\n className,\n )}\n {...props}\n >\n {children}\n <span\n ref={indicatorRef}\n aria-hidden\n className=\"pointer-events-none absolute rounded-full bg-brand-primary-default motion-safe:transition-[transform,width,height] motion-safe:duration-200 motion-safe:ease-in-out\"\n style={{ opacity: 0 }}\n />\n </TabsPrimitive.List>\n );\n});\n\nTabsList.displayName = \"TabsList\";\n"],"names":["React","jsxs","TabsPrimitive","cn","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAOA,MAAM,mBAA0D;AAAA,EAC9D,QAAQ;AAAA,EACR,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,SAAS,eAAe,WAAoB,WAA0C;AACpF,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,OAAO;AACb,MAAI,cAAc,KAAM,QAAO,GAAG,IAAI,IAAI,iBAAiB,MAAM;AACjE,MAAI,OAAO,cAAc,SAAU,QAAO,GAAG,IAAI,IAAI,iBAAiB,SAAS,CAAC;AAChF,SAAO;AACT;AAgBO,MAAM,WAAWA,iBAAM,WAG5B,CAAC,EAAE,WAAW,UAAU,YAAY,MAAM,WAAW,GAAG,MAAA,GAAS,QAAQ;AACzE,QAAM,WAAWA,iBAAM,OAAuB,IAAI;AAClD,QAAM,eAAeA,iBAAM,OAAwB,IAAI;AAEvDA,mBAAM,oBAAoB,KAAK,MAAM,SAAS,OAAyB;AAEvE,QAAM,kBAAkBA,iBAAM,YAAY,MAAM;AAC9C,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,UAAM,YAAY,KAAK,cAA2B,uBAAuB;AACzE,QAAI,CAAC,WAAW;AACd,gBAAU,MAAM,UAAU;AAC1B;AAAA,IACF;AAEA,UAAM,aAAa,KAAK,QAAQ,gBAAgB;AAEhD,cAAU,MAAM,UAAU;AAE1B,QAAI,YAAY;AACd,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS,GAAG,UAAU,YAAY;AAClD,gBAAU,MAAM,YAAY,cAAc,UAAU,SAAS;AAAA,IAC/D,OAAO;AACL,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS;AACzB,gBAAU,MAAM,QAAQ,GAAG,UAAU,WAAW;AAChD,gBAAU,MAAM,YAAY,cAAc,UAAU,UAAU;AAAA,IAChE;AAAA,EACF,GAAG,CAAA,CAAE;AAELA,mBAAM,gBAAgB,MAAM;AAC1B,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,cAAU,MAAM,qBAAqB;AACrC,oBAAA;AACA,cAAU,sBAAA;AACV,cAAU,MAAM,qBAAqB;AAErC,UAAM,mBAAmB,IAAI,iBAAiB,eAAe;AAC7D,qBAAiB,QAAQ,MAAM;AAAA,MAC7B,YAAY;AAAA,MACZ,iBAAiB,CAAC,YAAY;AAAA,MAC9B,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,CACV;AAED,UAAM,iBAAiB,IAAI,eAAe,eAAe;AACzD,mBAAe,QAAQ,IAAI;AAE3B,QAAI,YAAY;AAChB,QAAI,SAAS,OAAO,WAAW,UAAU;AACvC,eAAS,OAAO,MAAM,KAAK,MAAM;AAC/B,YAAI,CAAC,UAAW,iBAAA;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,WAAO,MAAM;AACX,kBAAY;AACZ,uBAAiB,WAAA;AACjB,qBAAe,WAAA;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAEpB,SACEC,2BAAAA;AAAAA,IAACC,yBAAc;AAAA,IAAd;AAAA,MACC,KAAK;AAAA,MACL,WAAWC,GAAAA;AAAAA,QACT;AAAA,QACA,eAAe,WAAW,SAAS;AAAA,QACnC;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA;AAAA,QACDC,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,eAAW;AAAA,YACX,WAAU;AAAA,YACV,OAAO,EAAE,SAAS,EAAA;AAAA,UAAE;AAAA,QAAA;AAAA,MACtB;AAAA,IAAA;AAAA,EAAA;AAGN,CAAC;AAED,SAAS,cAAc;;"}
|
|
@@ -41,7 +41,7 @@ const TabsTrigger = React__namespace.forwardRef(({ className, children, ...props
|
|
|
41
41
|
"data-disabled:pointer-events-none",
|
|
42
42
|
"data-disabled:data-[state=active]:text-content-tertiary",
|
|
43
43
|
"data-disabled:data-[state=inactive]:text-neutral-alphas-300",
|
|
44
|
-
"focus-visible:
|
|
44
|
+
"focus-visible:shadow-focus-ring focus-visible:outline-none",
|
|
45
45
|
className
|
|
46
46
|
),
|
|
47
47
|
...props,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabsTrigger.cjs","sources":["../../../../src/components/Tabs/TabsTrigger.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsTrigger} button component. */\nexport type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;\n\n/** An interactive tab button that activates its associated {@link TabsContent} panel when clicked. */\nexport const TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex min-w-0 items-center justify-center\",\n \"rounded-xs\",\n \"typography-body-default-16px-semibold cursor-pointer text-content-primary\",\n \"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out\",\n \"data-[orientation=horizontal]:px-4 data-[orientation=horizontal]:py-3\",\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:px-4 data-[orientation=vertical]:py-3\",\n \"data-[state=active]:hover:text-buttons-primary-muted\",\n \"data-[state=inactive]:hover:text-neutral-alphas-300\",\n \"data-[state=active]:active:text-buttons-primary-muted\",\n \"data-[state=inactive]:active:text-neutral-alphas-300\",\n \"data-disabled:pointer-events-none\",\n \"data-disabled:data-[state=active]:text-content-tertiary\",\n \"data-disabled:data-[state=inactive]:text-neutral-alphas-300\",\n \"focus-visible:
|
|
1
|
+
{"version":3,"file":"TabsTrigger.cjs","sources":["../../../../src/components/Tabs/TabsTrigger.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsTrigger} button component. */\nexport type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;\n\n/** An interactive tab button that activates its associated {@link TabsContent} panel when clicked. */\nexport const TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex min-w-0 items-center justify-center\",\n \"rounded-xs\",\n \"typography-body-default-16px-semibold cursor-pointer text-content-primary\",\n \"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out\",\n \"data-[orientation=horizontal]:px-4 data-[orientation=horizontal]:py-3\",\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:px-4 data-[orientation=vertical]:py-3\",\n \"data-[state=active]:hover:text-buttons-primary-muted\",\n \"data-[state=inactive]:hover:text-neutral-alphas-300\",\n \"data-[state=active]:active:text-buttons-primary-muted\",\n \"data-[state=inactive]:active:text-neutral-alphas-300\",\n \"data-disabled:pointer-events-none\",\n \"data-disabled:data-[state=active]:text-content-tertiary\",\n \"data-disabled:data-[state=inactive]:text-neutral-alphas-300\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n className,\n )}\n {...props}\n >\n <span className=\"min-w-0 truncate\">{children}</span>\n </TabsPrimitive.Trigger>\n));\n\nTabsTrigger.displayName = \"TabsTrigger\";\n"],"names":["React","jsx","TabsPrimitive","cn"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAQO,MAAM,cAAcA,iBAAM,WAG/B,CAAC,EAAE,WAAW,UAAU,GAAG,SAAS,QACpCC,2BAAAA;AAAAA,EAACC,yBAAc;AAAA,EAAd;AAAA,IACC;AAAA,IACA,WAAWC,GAAAA;AAAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,IAEJ,UAAAF,2BAAAA,IAAC,QAAA,EAAK,WAAU,oBAAoB,SAAA,CAAS;AAAA,EAAA;AAC/C,CACD;AAED,YAAY,cAAc;;"}
|
|
@@ -18,7 +18,7 @@ const AccordionTrigger = React.forwardRef(({ className, children, icon, ...props
|
|
|
18
18
|
"cursor-pointer",
|
|
19
19
|
"motion-safe:transition-colors motion-safe:duration-200 motion-safe:ease-in-out",
|
|
20
20
|
"hover:bg-neutral-alphas-100",
|
|
21
|
-
"focus-visible:
|
|
21
|
+
"focus-visible:shadow-focus-ring focus-visible:outline-none",
|
|
22
22
|
"data-disabled:pointer-events-none data-disabled:opacity-50",
|
|
23
23
|
className
|
|
24
24
|
),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionTrigger.mjs","sources":["../../../src/components/Accordion/AccordionTrigger.tsx"],"sourcesContent":["import * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\n\n/** Props for the {@link AccordionTrigger} button component. */\nexport type AccordionTriggerProps = React.ComponentPropsWithoutRef<\n typeof AccordionPrimitive.Trigger\n> & {\n /** Custom icon element. Defaults to `ChevronDownIcon`. Pass `null` to suppress the icon entirely. */\n icon?: React.ReactNode | null;\n};\n\n/** An interactive button that toggles the visibility of its associated {@link AccordionContent} panel. */\nexport const AccordionTrigger = React.forwardRef<\n React.ComponentRef<typeof AccordionPrimitive.Trigger>,\n AccordionTriggerProps\n>(({ className, children, icon, ...props }, ref) => {\n const showIcon = icon !== null;\n const iconElement =\n icon === undefined ? (\n <ChevronDownIcon className=\"size-4 shrink-0 text-content-secondary\" />\n ) : (\n icon\n );\n\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between gap-3\",\n \"rounded-sm px-3 py-3\",\n \"typography-body-small-14px-semibold text-content-primary\",\n \"cursor-pointer\",\n \"motion-safe:transition-colors motion-safe:duration-200 motion-safe:ease-in-out\",\n \"hover:bg-neutral-alphas-100\",\n \"focus-visible:
|
|
1
|
+
{"version":3,"file":"AccordionTrigger.mjs","sources":["../../../src/components/Accordion/AccordionTrigger.tsx"],"sourcesContent":["import * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\n\n/** Props for the {@link AccordionTrigger} button component. */\nexport type AccordionTriggerProps = React.ComponentPropsWithoutRef<\n typeof AccordionPrimitive.Trigger\n> & {\n /** Custom icon element. Defaults to `ChevronDownIcon`. Pass `null` to suppress the icon entirely. */\n icon?: React.ReactNode | null;\n};\n\n/** An interactive button that toggles the visibility of its associated {@link AccordionContent} panel. */\nexport const AccordionTrigger = React.forwardRef<\n React.ComponentRef<typeof AccordionPrimitive.Trigger>,\n AccordionTriggerProps\n>(({ className, children, icon, ...props }, ref) => {\n const showIcon = icon !== null;\n const iconElement =\n icon === undefined ? (\n <ChevronDownIcon className=\"size-4 shrink-0 text-content-secondary\" />\n ) : (\n icon\n );\n\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between gap-3\",\n \"rounded-sm px-3 py-3\",\n \"typography-body-small-14px-semibold text-content-primary\",\n \"cursor-pointer\",\n \"motion-safe:transition-colors motion-safe:duration-200 motion-safe:ease-in-out\",\n \"hover:bg-neutral-alphas-100\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n \"data-disabled:pointer-events-none data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"min-w-0 flex-1 truncate text-left\">{children}</span>\n {showIcon && (\n <span className=\"shrink-0 motion-safe:transition-transform motion-safe:duration-200 [[data-state=open]>&]:rotate-180\">\n {iconElement}\n </span>\n )}\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n );\n});\n\nAccordionTrigger.displayName = \"AccordionTrigger\";\n"],"names":[],"mappings":";;;;;;AAcO,MAAM,mBAAmB,MAAM,WAGpC,CAAC,EAAE,WAAW,UAAU,MAAM,GAAG,MAAA,GAAS,QAAQ;AAClD,QAAM,WAAW,SAAS;AAC1B,QAAM,cACJ,SAAS,6BACN,iBAAA,EAAgB,WAAU,0CAAyC,IAEpE;AAGJ,SACE,oBAAC,mBAAmB,QAAnB,EAA0B,WAAU,QACnC,UAAA;AAAA,IAAC,mBAAmB;AAAA,IAAnB;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAK,WAAU,qCAAqC,SAAA,CAAS;AAAA,QAC7D,YACC,oBAAC,QAAA,EAAK,WAAU,uGACb,UAAA,YAAA,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAGN;AAEJ,CAAC;AAED,iBAAiB,cAAc;"}
|
|
@@ -30,7 +30,7 @@ const BottomNavigationAction = React.forwardRef(({ className, value, icon, label
|
|
|
30
30
|
"relative flex min-w-0 flex-1 cursor-pointer flex-col items-center justify-center gap-1",
|
|
31
31
|
isActive ? "text-icons-primary" : "text-icons-tertiary",
|
|
32
32
|
"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out",
|
|
33
|
-
"focus-visible:
|
|
33
|
+
"focus-visible:shadow-focus-ring focus-visible:outline-none",
|
|
34
34
|
className
|
|
35
35
|
),
|
|
36
36
|
children: [
|
|
@@ -65,7 +65,7 @@ const BottomNavigationAction = React.forwardRef(({ className, value, icon, label
|
|
|
65
65
|
"relative flex min-w-0 flex-1 cursor-pointer flex-col items-center justify-center gap-0.5 overflow-hidden px-2 py-2",
|
|
66
66
|
"text-content-primary",
|
|
67
67
|
"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out",
|
|
68
|
-
"focus-visible:
|
|
68
|
+
"focus-visible:shadow-focus-ring focus-visible:outline-none",
|
|
69
69
|
className
|
|
70
70
|
),
|
|
71
71
|
onClick: handleClick,
|