@fanvue/ui 3.3.0 → 3.5.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/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/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/Pill/Pill.cjs +2 -1
- package/dist/cjs/components/Pill/Pill.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/Table/Table.cjs +25 -18
- package/dist/cjs/components/Table/Table.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/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/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/Pill/Pill.mjs +2 -1
- package/dist/components/Pill/Pill.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/Table/Table.mjs +25 -18
- package/dist/components/Table/Table.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 +25 -6
- package/dist/styles/theme.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.mjs","sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { MinusIcon } from \"../Icons/MinusIcon\";\n\n/**\n * Size variant for the checkbox.\n *\n * - `\"20\"` (default) — 20px box, body-lg label.\n * - `\"16\"` — 16px box, body-md label, used in compact contexts like data tables.\n * - `\"default\"` and `\"small\"` are legacy aliases retained for back-compat\n * (`\"default\"` → `\"20\"`, `\"small\"` → `\"20\"` with smaller label typography).\n */\nexport type CheckboxSize =\n | \"20\"\n | \"16\"\n /** @deprecated Use `\"20\"` instead. */\n | \"default\"\n /** @deprecated Use `\"20\"` (the smaller-typography variant remains via `\"small\"`). */\n | \"small\";\n\nconst BOX_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-5\",\n \"16\": \"size-4\",\n};\n\nconst INDICATOR_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-3\",\n \"16\": \"size-2.5\",\n};\n\nexport interface CheckboxProps\n extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, \"asChild\"> {\n /** Size variant. @default \"20\" */\n size?: CheckboxSize;\n /** Label text displayed next to the checkbox. */\n label?: string;\n /** Descriptive text displayed below the label. */\n helperText?: string;\n}\n\n/**\n * A checkbox input with optional label and helper text. Supports checked,\n * unchecked, and indeterminate states.\n *\n * The ref type is intentionally `HTMLInputElement` (not `HTMLButtonElement`) for\n * form-library compatibility — libraries like react-hook-form call `register()`\n * which expects an `HTMLInputElement` ref. A hidden `<input>` is synced to the\n * Radix checkbox state via `useImperativeHandle`.\n *\n * @example\n * ```tsx\n * <Checkbox label=\"Accept terms\" helperText=\"Required to continue\" />\n * ```\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ className, size = \"20\", label, helperText, disabled, name, ...props }, ref) => {\n const id = React.useId();\n const helperTextId = helperText ? `${id}-helper` : undefined;\n const hasLabel = Boolean(label || helperText);\n const boxSize: \"20\" | \"16\" = size === \"16\" ? \"16\" : \"20\";\n const useSmallLabelTypography = size === \"small\";\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n !label &&\n !props[\"aria-label\"] &&\n !props[\"aria-labelledby\"]\n ) {\n console.warn(\n \"Checkbox: No accessible name provided. Add a `label`, `aria-label`, or `aria-labelledby` prop so screen readers can announce this checkbox.\",\n );\n }\n\n // Hidden input for form library compatibility (e.g. react-hook-form register)\n const inputRef = React.useRef<HTMLInputElement>(null);\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);\n\n const handleCheckedChange = (value: boolean | \"indeterminate\") => {\n const checked = value === true;\n if (inputRef.current) {\n inputRef.current.checked = checked;\n inputRef.current.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n props.onCheckedChange?.(value);\n };\n\n const checkboxElement = (\n <span\n className={cn(\n \"relative inline-flex shrink-0\",\n BOX_SIZE_CLASS[boxSize],\n // Alignment when used with label\n label && (helperText ? \"mt-1\" : \"mt-0.5\"),\n )}\n >\n <input\n ref={inputRef}\n type=\"checkbox\"\n name={name}\n disabled={disabled}\n aria-hidden\n tabIndex={-1}\n onChange={() => {}}\n className=\"pointer-events-none absolute size-px overflow-hidden opacity-0\"\n style={{ clip: \"rect(0,0,0,0)\" }}\n />\n <CheckboxPrimitive.Root\n id={id}\n disabled={disabled}\n aria-describedby={helperTextId}\n data-testid=\"checkbox\"\n {...props}\n onCheckedChange={handleCheckedChange}\n className={cn(\n // Base styles\n \"flex items-center justify-center rounded border-2\",\n BOX_SIZE_CLASS[boxSize],\n \"transition-[border-color,background-color,color,box-shadow] duration-150\",\n // Default state\n \"border-content-primary bg-transparent text-transparent\",\n // Checked state\n \"data-[state=checked]:border-content-primary data-[state=checked]:bg-content-primary data-[state=checked]:text-content-primary-inverted\",\n // Indeterminate state\n \"data-[state=indeterminate]:border-content-primary data-[state=indeterminate]:bg-content-primary data-[state=indeterminate]:text-content-primary-inverted\",\n // Hover & active state\n \"hover:ring-2 hover:ring-brand-primary-default group-hover:ring-2 group-hover:ring-brand-primary-default\",\n \"not-disabled:active:ring-2 not-disabled:active:ring-brand-primary-default\",\n // Focus state\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-interaction-focus focus-visible:ring-offset-2 focus-visible:ring-offset-background-primary\",\n // Disabled state\n \"disabled:cursor-not-allowed disabled:border-neutral-alphas-600 disabled:ring-0 disabled:group-hover:ring-0\",\n \"disabled:data-[state=checked]:border-neutral-alphas-600 disabled:data-[state=checked]:bg-neutral-alphas-600 disabled:data-[state=checked]:text-content-tertiary\",\n !hasLabel && className,\n )}\n >\n <CheckboxPrimitive.Indicator\n forceMount\n className={cn(\n \"flex items-center justify-center text-content-primary-inverted\",\n INDICATOR_SIZE_CLASS[boxSize],\n \"data-[state=unchecked]:invisible\",\n )}\n >\n {props.checked === \"indeterminate\" ? <MinusIcon /> : <CheckIcon />}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n </span>\n );\n\n if (!hasLabel) {\n return checkboxElement;\n }\n\n return (\n <div\n className={cn(\n \"inline-flex flex-col gap-0.5\",\n disabled && \"is-disabled cursor-not-allowed\",\n className,\n )}\n >\n <div className=\"group inline-flex items-start gap-2\">\n {checkboxElement}\n {label && (\n <label\n htmlFor={id}\n className={cn(\n \"cursor-pointer select-none text-content-primary\",\n \"group-has-disabled:cursor-not-allowed group-has-disabled:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\",\n )}\n >\n {label}\n </label>\n )}\n </div>\n {helperText && (\n <span\n id={helperTextId}\n className={cn(\n \"ml-7 text-content-secondary\",\n \"in-[.is-disabled]:cursor-not-allowed in-[.is-disabled]:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-description-12px-regular\"\n : \"typography-body-small-14px-regular\",\n )}\n >\n {helperText}\n </span>\n )}\n </div>\n );\n },\n);\n\nCheckbox.displayName = \"Checkbox\";\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Checkbox.mjs","sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { MinusIcon } from \"../Icons/MinusIcon\";\n\n/**\n * Size variant for the checkbox.\n *\n * - `\"20\"` (default) — 20px box, body-lg label.\n * - `\"16\"` — 16px box, body-md label, used in compact contexts like data tables.\n * - `\"default\"` and `\"small\"` are legacy aliases retained for back-compat\n * (`\"default\"` → `\"20\"`, `\"small\"` → `\"20\"` with smaller label typography).\n */\nexport type CheckboxSize =\n | \"20\"\n | \"16\"\n /** @deprecated Use `\"20\"` instead. */\n | \"default\"\n /** @deprecated Use `\"20\"` (the smaller-typography variant remains via `\"small\"`). */\n | \"small\";\n\nconst BOX_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-5\",\n \"16\": \"size-4\",\n};\n\nconst INDICATOR_SIZE_CLASS: Record<\"20\" | \"16\", string> = {\n \"20\": \"size-3\",\n \"16\": \"size-2.5\",\n};\n\nexport interface CheckboxProps\n extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, \"asChild\"> {\n /** Size variant. @default \"20\" */\n size?: CheckboxSize;\n /** Label text displayed next to the checkbox. */\n label?: string;\n /** Descriptive text displayed below the label. */\n helperText?: string;\n}\n\n/**\n * A checkbox input with optional label and helper text. Supports checked,\n * unchecked, and indeterminate states.\n *\n * The ref type is intentionally `HTMLInputElement` (not `HTMLButtonElement`) for\n * form-library compatibility — libraries like react-hook-form call `register()`\n * which expects an `HTMLInputElement` ref. A hidden `<input>` is synced to the\n * Radix checkbox state via `useImperativeHandle`.\n *\n * @example\n * ```tsx\n * <Checkbox label=\"Accept terms\" helperText=\"Required to continue\" />\n * ```\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ className, size = \"20\", label, helperText, disabled, name, ...props }, ref) => {\n const id = React.useId();\n const helperTextId = helperText ? `${id}-helper` : undefined;\n const hasLabel = Boolean(label || helperText);\n const boxSize: \"20\" | \"16\" = size === \"16\" ? \"16\" : \"20\";\n const useSmallLabelTypography = size === \"small\";\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n !label &&\n !props[\"aria-label\"] &&\n !props[\"aria-labelledby\"]\n ) {\n console.warn(\n \"Checkbox: No accessible name provided. Add a `label`, `aria-label`, or `aria-labelledby` prop so screen readers can announce this checkbox.\",\n );\n }\n\n // Hidden input for form library compatibility (e.g. react-hook-form register)\n const inputRef = React.useRef<HTMLInputElement>(null);\n React.useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);\n\n const handleCheckedChange = (value: boolean | \"indeterminate\") => {\n const checked = value === true;\n if (inputRef.current) {\n inputRef.current.checked = checked;\n inputRef.current.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n props.onCheckedChange?.(value);\n };\n\n const checkboxElement = (\n <span\n className={cn(\n \"relative inline-flex shrink-0\",\n BOX_SIZE_CLASS[boxSize],\n // Alignment when used with label\n label && (helperText ? \"mt-1\" : \"mt-0.5\"),\n )}\n >\n <input\n ref={inputRef}\n type=\"checkbox\"\n name={name}\n disabled={disabled}\n aria-hidden\n tabIndex={-1}\n onChange={() => {}}\n className=\"pointer-events-none absolute size-px overflow-hidden opacity-0\"\n style={{ clip: \"rect(0,0,0,0)\" }}\n />\n <CheckboxPrimitive.Root\n id={id}\n disabled={disabled}\n aria-describedby={helperTextId}\n data-testid=\"checkbox\"\n {...props}\n onCheckedChange={handleCheckedChange}\n className={cn(\n // Base styles\n \"flex items-center justify-center rounded border-2\",\n BOX_SIZE_CLASS[boxSize],\n \"transition-[border-color,background-color,color,box-shadow] duration-150\",\n // Default state\n \"border-content-primary bg-transparent text-transparent\",\n // Checked state\n \"data-[state=checked]:border-content-primary data-[state=checked]:bg-content-primary data-[state=checked]:text-content-primary-inverted\",\n // Indeterminate state\n \"data-[state=indeterminate]:border-content-primary data-[state=indeterminate]:bg-content-primary data-[state=indeterminate]:text-content-primary-inverted\",\n // Hover & active state\n \"hover:ring-2 hover:ring-brand-primary-default group-hover:ring-2 group-hover:ring-brand-primary-default\",\n \"not-disabled:active:ring-2 not-disabled:active:ring-brand-primary-default\",\n // Focus state\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled state\n \"disabled:cursor-not-allowed disabled:border-neutral-alphas-600 disabled:ring-0 disabled:group-hover:ring-0\",\n \"disabled:data-[state=checked]:border-neutral-alphas-600 disabled:data-[state=checked]:bg-neutral-alphas-600 disabled:data-[state=checked]:text-content-tertiary\",\n !hasLabel && className,\n )}\n >\n <CheckboxPrimitive.Indicator\n forceMount\n className={cn(\n \"flex items-center justify-center text-content-primary-inverted\",\n INDICATOR_SIZE_CLASS[boxSize],\n \"data-[state=unchecked]:invisible\",\n )}\n >\n {props.checked === \"indeterminate\" ? <MinusIcon /> : <CheckIcon />}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n </span>\n );\n\n if (!hasLabel) {\n return checkboxElement;\n }\n\n return (\n <div\n className={cn(\n \"inline-flex flex-col gap-0.5\",\n disabled && \"is-disabled cursor-not-allowed\",\n className,\n )}\n >\n <div className=\"group inline-flex items-start gap-2\">\n {checkboxElement}\n {label && (\n <label\n htmlFor={id}\n className={cn(\n \"cursor-pointer select-none text-content-primary\",\n \"group-has-disabled:cursor-not-allowed group-has-disabled:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\",\n )}\n >\n {label}\n </label>\n )}\n </div>\n {helperText && (\n <span\n id={helperTextId}\n className={cn(\n \"ml-7 text-content-secondary\",\n \"in-[.is-disabled]:cursor-not-allowed in-[.is-disabled]:text-content-tertiary\",\n useSmallLabelTypography\n ? \"typography-description-12px-regular\"\n : \"typography-body-small-14px-regular\",\n )}\n >\n {helperText}\n </span>\n )}\n </div>\n );\n },\n);\n\nCheckbox.displayName = \"Checkbox\";\n"],"names":[],"mappings":";;;;;;;AAsBA,MAAM,iBAA8C;AAAA,EAClD,MAAM;AAAA,EACN,MAAM;AACR;AAEA,MAAM,uBAAoD;AAAA,EACxD,MAAM;AAAA,EACN,MAAM;AACR;AA0BO,MAAM,WAAW,MAAM;AAAA,EAC5B,CAAC,EAAE,WAAW,OAAO,MAAM,OAAO,YAAY,UAAU,MAAM,GAAG,MAAA,GAAS,QAAQ;AAChF,UAAM,KAAK,MAAM,MAAA;AACjB,UAAM,eAAe,aAAa,GAAG,EAAE,YAAY;AACnD,UAAM,WAAW,QAAQ,SAAS,UAAU;AAC5C,UAAM,UAAuB,SAAS,OAAO,OAAO;AACpD,UAAM,0BAA0B,SAAS;AAEzC,QACE,QAAQ,IAAI,aAAa,gBACzB,CAAC,SACD,CAAC,MAAM,YAAY,KACnB,CAAC,MAAM,iBAAiB,GACxB;AACA,cAAQ;AAAA,QACN;AAAA,MAAA;AAAA,IAEJ;AAGA,UAAM,WAAW,MAAM,OAAyB,IAAI;AACpD,UAAM,oBAAoB,KAAK,MAAM,SAAS,OAA2B;AAEzE,UAAM,sBAAsB,CAAC,UAAqC;AAChE,YAAM,UAAU,UAAU;AAC1B,UAAI,SAAS,SAAS;AACpB,iBAAS,QAAQ,UAAU;AAC3B,iBAAS,QAAQ,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAA,CAAM,CAAC;AAAA,MACvE;AACA,YAAM,kBAAkB,KAAK;AAAA,IAC/B;AAEA,UAAM,kBACJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,eAAe,OAAO;AAAA;AAAA,UAEtB,UAAU,aAAa,SAAS;AAAA,QAAA;AAAA,QAGlC,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL;AAAA,cACA;AAAA,cACA,eAAW;AAAA,cACX,UAAU;AAAA,cACV,UAAU,MAAM;AAAA,cAAC;AAAA,cACjB,WAAU;AAAA,cACV,OAAO,EAAE,MAAM,gBAAA;AAAA,YAAgB;AAAA,UAAA;AAAA,UAEjC;AAAA,YAAC,kBAAkB;AAAA,YAAlB;AAAA,cACC;AAAA,cACA;AAAA,cACA,oBAAkB;AAAA,cAClB,eAAY;AAAA,cACX,GAAG;AAAA,cACJ,iBAAiB;AAAA,cACjB,WAAW;AAAA;AAAA,gBAET;AAAA,gBACA,eAAe,OAAO;AAAA,gBACtB;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA,gBACA;AAAA;AAAA,gBAEA;AAAA;AAAA,gBAEA;AAAA,gBACA;AAAA,gBACA,CAAC,YAAY;AAAA,cAAA;AAAA,cAGf,UAAA;AAAA,gBAAC,kBAAkB;AAAA,gBAAlB;AAAA,kBACC,YAAU;AAAA,kBACV,WAAW;AAAA,oBACT;AAAA,oBACA,qBAAqB,OAAO;AAAA,oBAC5B;AAAA,kBAAA;AAAA,kBAGD,gBAAM,YAAY,sCAAmB,WAAA,EAAU,wBAAM,WAAA,CAAA,CAAU;AAAA,gBAAA;AAAA,cAAA;AAAA,YAClE;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAAA;AAIJ,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,UACZ;AAAA,QAAA;AAAA,QAGF,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,uCACZ,UAAA;AAAA,YAAA;AAAA,YACA,SACC;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAW;AAAA,kBACT;AAAA,kBACA;AAAA,kBACA,0BACI,wCACA;AAAA,gBAAA;AAAA,gBAGL,UAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACH,GAEJ;AAAA,UACC,cACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,IAAI;AAAA,cACJ,WAAW;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA,0BACI,wCACA;AAAA,cAAA;AAAA,cAGL,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,SAAS,cAAc;"}
|
|
@@ -20,13 +20,28 @@ const CyclingText = React.forwardRef(
|
|
|
20
20
|
className,
|
|
21
21
|
labelClassName,
|
|
22
22
|
announceChanges = false,
|
|
23
|
+
onActiveIndexChange,
|
|
23
24
|
...rest
|
|
24
25
|
}, ref) => {
|
|
25
26
|
const docVisible = usePageVisibility();
|
|
26
27
|
const reducedMotion = usePrefersReducedMotion();
|
|
27
28
|
const { sizingLabelRef, trackWidth } = useCyclingTextTrackWidth();
|
|
28
|
-
const {
|
|
29
|
+
const {
|
|
30
|
+
cycle,
|
|
31
|
+
currentIndex,
|
|
32
|
+
currentLabel,
|
|
33
|
+
incomingLabel,
|
|
34
|
+
sizingLabel,
|
|
35
|
+
onOutgoingTransitionEnd
|
|
36
|
+
} = useCyclingCycle(items, sizing, intervalMs, paused, docVisible, transitionMs);
|
|
29
37
|
const itemCount = items.length;
|
|
38
|
+
const onActiveIndexChangeRef = React.useRef(onActiveIndexChange);
|
|
39
|
+
React.useEffect(() => {
|
|
40
|
+
onActiveIndexChangeRef.current = onActiveIndexChange;
|
|
41
|
+
}, [onActiveIndexChange]);
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
onActiveIndexChangeRef.current?.(currentIndex);
|
|
44
|
+
}, [currentIndex]);
|
|
30
45
|
const outgoingMotionStyle = React.useMemo(() => {
|
|
31
46
|
const durMs = reducedMotion ? 0 : transitionMs;
|
|
32
47
|
const exiting = cycle.transitioning;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CyclingText.mjs","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 {
|
|
1
|
+
{"version":3,"file":"CyclingText.mjs","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":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCyclingCycle.mjs","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":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCyclingCycle.mjs","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":[],"mappings":";;AAkBA,MAAM,oBAAgC;AAAA,EACpC,cAAc;AAAA,EACd,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAEA,SAAS,aAAa,OAAmB,QAAiC;AACxE,UAAQ,OAAO,MAAA;AAAA,IACb,KAAK,QAAQ;AACX,UAAI,OAAO,aAAa,EAAG,QAAO;AAClC,YAAM,QAAQ,MAAM,eAAe,KAAK,OAAO;AAC/C,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe;AAAA,QACf,iBAAiB;AAAA,QACjB,eAAe;AAAA,MAAA;AAAA,IAEnB;AAAA,IACA,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,iBAAiB,KAAA;AAAA,IACtC,KAAK,uBAAuB;AAC1B,UAAI,CAAC,MAAM,iBAAiB,MAAM,kBAAkB,KAAM,QAAO;AACjE,aAAO;AAAA,QACL,cAAc,MAAM;AAAA,QACpB,eAAe;AAAA,QACf,iBAAiB;AAAA,QACjB,eAAe;AAAA,MAAA;AAAA,IAEnB;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe;AAAA,QACf,iBAAiB;AAAA,QACjB,eAAe;AAAA,MAAA;AAAA,IAEnB,KAAK,4BAA4B;AAC/B,UAAI,OAAO,cAAc,EAAG,QAAO;AACnC,YAAM,MAAM,MAAM,gBAAgB,OAAO,YAAY,IAAI,MAAM;AAC/D,aAAO;AAAA,QACL,cAAc;AAAA,QACd,eAAe;AAAA,QACf,iBAAiB;AAAA,QACjB,eAAe;AAAA,MAAA;AAAA,IAEnB;AAAA,IACA;AACE,aAAO;AAAA,EAAA;AAEb;AAEO,SAAS,gBACd,OACA,QACA,YACA,QACA,YACA,cACA;AACA,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,WAAW,cAAc,iBAAiB;AAE1E,QAAM,qBAAqB,MAAM,OAAwD,IAAI;AAC7F,QAAM,qBAAqB,MAAM,OAAwD,IAAI;AAC7F,QAAM,mBAAmB,MAAM,OAA6C,IAAI;AAChF,QAAM,kBAAkB,MAAM,OAA6C,IAAI;AAE/E,QAAM,oBAAoB,MAAM,YAAY,MAAM;AAChD,QAAI,gBAAgB,YAAY,MAAM;AACpC,mBAAa,gBAAgB,OAAO;AACpC,sBAAgB,UAAU;AAAA,IAC5B;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,QAAM,0BAA0B,MAAM,YAAY,MAAM;AACtD,QAAI,mBAAmB,YAAY,MAAM;AACvC,2BAAqB,mBAAmB,OAAO;AAC/C,yBAAmB,UAAU;AAAA,IAC/B;AACA,QAAI,mBAAmB,YAAY,MAAM;AACvC,2BAAqB,mBAAmB,OAAO;AAC/C,yBAAmB,UAAU;AAAA,IAC/B;AACA,QAAI,iBAAiB,YAAY,MAAM;AACrC,mBAAa,iBAAiB,OAAO;AACrC,uBAAiB,UAAU;AAAA,IAC7B;AACA,sBAAA;AAAA,EACF,GAAG,CAAC,iBAAiB,CAAC;AAEtB,QAAM,YAAY,MAAM;AAExB,QAAM,UAAU,MAAM;AACpB,QAAI,cAAc,EAAG;AACrB,aAAS,EAAE,MAAM,4BAA4B,UAAA,CAAW;AAAA,EAC1D,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,mBAAmB,cAAc,IAAI,IAAI,MAAM,eAAe;AACpE,QAAM,oBACJ,MAAM,kBAAkB,QAAQ,cAAc,IAAI,OAAO,MAAM,gBAAgB;AAEjF,QAAM,eAAe,cAAc,IAAI,KAAM,MAAM,gBAAgB,KAAK;AACxE,QAAM,gBAAgB,sBAAsB,OAAO,OAAQ,MAAM,iBAAiB,KAAK;AAEvF,QAAM,cAAc,MAAM,QAAQ,MAAM;AACtC,QAAI,cAAc,EAAG,QAAO;AAC5B,QAAI,UAAU,MAAM,CAAC,KAAK;AAC1B,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,SAAS,QAAQ,OAAQ,WAAU;AAAA,IAC9C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,SAAS,CAAC;AAErB,QAAM,cACJ,WAAW,YACP,cACA,iBAAiB,cAAc,SAAS,aAAa,SACnD,gBACA;AAER,QAAM,cAAc,CAAC,UAAU,cAAc,YAAY;AAEzD,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,eAAe,aAAa,GAAG;AAClC,wBAAA;AACA;AAAA,IACF;AAEA,QAAI,MAAM,eAAe;AACvB;AAAA,IACF;AAEA,oBAAgB,UAAU,WAAW,MAAM;AACzC,sBAAgB,UAAU;AAC1B,eAAS,EAAE,MAAM,QAAQ,UAAA,CAAW;AAAA,IACtC,GAAG,UAAU;AAEb,WAAO,MAAM;AACX,wBAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,aAAa,WAAW,YAAY,MAAM,eAAe,iBAAiB,CAAC;AAE/E,QAAM,UAAU,MAAM;AACpB,QAAI,QAAQ;AACV,8BAAA;AACA,eAAS,EAAE,MAAM,eAAe;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,QAAQ,uBAAuB,CAAC;AAEpC,QAAM,UAAU,MAAM;AACpB,WAAO,MAAM;AACX,8BAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,uBAAuB,CAAC;AAE5B,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,MAAM,iBAAiB,MAAM,kBAAkB,QAAQ,MAAM,iBAAiB;AACjF;AAAA,IACF;AAEA,QAAI,mBAAmB,YAAY,MAAM;AACvC,2BAAqB,mBAAmB,OAAO;AAAA,IACjD;AACA,QAAI,mBAAmB,YAAY,MAAM;AACvC,2BAAqB,mBAAmB,OAAO;AAAA,IACjD;AAEA,uBAAmB,UAAU,sBAAsB,MAAM;AACvD,yBAAmB,UAAU;AAC7B,yBAAmB,UAAU,sBAAsB,MAAM;AACvD,2BAAmB,UAAU;AAC7B,iBAAS,EAAE,MAAM,oBAAoB;AAAA,MACvC,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM;AACX,UAAI,mBAAmB,YAAY,MAAM;AACvC,6BAAqB,mBAAmB,OAAO;AAC/C,2BAAmB,UAAU;AAAA,MAC/B;AACA,UAAI,mBAAmB,YAAY,MAAM;AACvC,6BAAqB,mBAAmB,OAAO;AAC/C,2BAAmB,UAAU;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,eAAe,MAAM,eAAe,MAAM,eAAe,CAAC;AAEpE,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,MAAM,eAAe;AACxB;AAAA,IACF;AACA,QAAI,iBAAiB,YAAY,MAAM;AACrC,mBAAa,iBAAiB,OAAO;AAAA,IACvC;AACA,qBAAiB,UAAU,WAAW,MAAM;AAC1C,eAAS,EAAE,MAAM,uBAAuB;AACxC,uBAAiB,UAAU;AAAA,IAC7B,GAAG,YAAY;AAEf,WAAO,MAAM;AACX,UAAI,iBAAiB,YAAY,MAAM;AACrC,qBAAa,iBAAiB,OAAO;AACrC,yBAAiB,UAAU;AAAA,MAC7B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,eAAe,YAAY,CAAC;AAEtC,QAAM,0BAA0B,MAAM;AAAA,IACpC,CAAC,UAAkD;AACjD,UAAI,CAAC,MAAM,cAAe;AAC1B,UAAI,MAAM,iBAAiB,UAAW;AACtC,UAAI,iBAAiB,YAAY,MAAM;AACrC,qBAAa,iBAAiB,OAAO;AACrC,yBAAiB,UAAU;AAAA,MAC7B;AACA,eAAS,EAAE,MAAM,uBAAuB;AAAA,IAC1C;AAAA,IACA,CAAC,MAAM,aAAa;AAAA,EAAA;AAGtB,SAAO;AAAA,IACL;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
|
@@ -14,7 +14,8 @@ const pillVariants = {
|
|
|
14
14
|
brand: "bg-brand-primary-default text-content-always-black",
|
|
15
15
|
brandLight: "bg-brand-primary-muted text-content-primary",
|
|
16
16
|
beta: "bg-brand-secondary-default text-content-always-black",
|
|
17
|
-
error: "bg-error-content text-error-surface"
|
|
17
|
+
error: "bg-error-content text-error-surface",
|
|
18
|
+
red: "bg-error-surface text-error-content"
|
|
18
19
|
}
|
|
19
20
|
};
|
|
20
21
|
const Pill = React.forwardRef(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pill.mjs","sources":["../../../src/components/Pill/Pill.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst pillVariants = {\n variant: {\n green: \"bg-success-surface text-success-content\",\n grey: \"bg-neutral-alphas-50 text-content-secondary\",\n blue: \"bg-info-surface text-info-content\",\n gold: \"bg-warning-surface text-warning-content\",\n pinkLight: \"bg-brand-secondary-muted text-content-primary\",\n base: \"bg-surface-primary-inverted text-content-primary-inverted\",\n brand: \"bg-brand-primary-default text-content-always-black\",\n brandLight: \"bg-brand-primary-muted text-content-primary\",\n beta: \"bg-brand-secondary-default text-content-always-black\",\n error: \"bg-error-content text-error-surface\",\n },\n} as const;\n\n/** Colour variant of the pill. */\nexport type PillVariant =\n | \"green\"\n | \"grey\"\n | \"blue\"\n | \"gold\"\n | \"pinkLight\"\n | \"base\"\n | \"brand\"\n | \"brandLight\"\n | \"beta\"\n | \"error\";\n\nexport interface PillProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Colour variant of the pill. @default \"green\" */\n variant?: PillVariant;\n /** Icon element displayed before the label. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed after the label. */\n rightIcon?: React.ReactNode;\n /** Merge props onto a child element instead of rendering a `<span>`. @default false */\n asChild?: boolean;\n}\n\n/**\n * A small rounded label for categorisation, status, or tagging.\n *\n * @example\n * ```tsx\n * <Pill variant=\"brand\">New</Pill>\n * ```\n */\nexport const Pill = React.forwardRef<HTMLSpanElement, PillProps>(\n (\n {\n className,\n variant = \"green\",\n leftIcon,\n rightIcon,\n asChild = false,\n onClick,\n children,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"pill\"\n className={cn(\n // Base styles\n \"inline-flex min-w-0 items-center justify-center gap-2 rounded-full px-3 py-1\",\n // Typography\n \"typography-description-12px-semibold\",\n // Variant styles\n pillVariants.variant[variant],\n // Interactive\n onClick && \"cursor-pointer\",\n // Manual CSS overrides\n className,\n )}\n onClick={onClick}\n {...props}\n >\n {leftIcon && (\n <span className=\"flex [&>svg]:size-3\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n {asChild ? (\n <Slottable>{children}</Slottable>\n ) : (\n <span className=\"min-w-0 truncate\">{children}</span>\n )}\n {rightIcon && (\n <span className=\"flex [&>svg]:size-3\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nPill.displayName = \"Pill\";\n"],"names":[],"mappings":";;;;;AAIA,MAAM,eAAe;AAAA,EACnB,SAAS;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,EAAA;
|
|
1
|
+
{"version":3,"file":"Pill.mjs","sources":["../../../src/components/Pill/Pill.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst pillVariants = {\n variant: {\n green: \"bg-success-surface text-success-content\",\n grey: \"bg-neutral-alphas-50 text-content-secondary\",\n blue: \"bg-info-surface text-info-content\",\n gold: \"bg-warning-surface text-warning-content\",\n pinkLight: \"bg-brand-secondary-muted text-content-primary\",\n base: \"bg-surface-primary-inverted text-content-primary-inverted\",\n brand: \"bg-brand-primary-default text-content-always-black\",\n brandLight: \"bg-brand-primary-muted text-content-primary\",\n beta: \"bg-brand-secondary-default text-content-always-black\",\n error: \"bg-error-content text-error-surface\",\n red: \"bg-error-surface text-error-content\",\n },\n} as const;\n\n/** Colour variant of the pill. */\nexport type PillVariant =\n | \"green\"\n | \"grey\"\n | \"blue\"\n | \"gold\"\n | \"pinkLight\"\n | \"base\"\n | \"brand\"\n | \"brandLight\"\n | \"beta\"\n | \"error\"\n | \"red\";\n\nexport interface PillProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Colour variant of the pill. @default \"green\" */\n variant?: PillVariant;\n /** Icon element displayed before the label. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed after the label. */\n rightIcon?: React.ReactNode;\n /** Merge props onto a child element instead of rendering a `<span>`. @default false */\n asChild?: boolean;\n}\n\n/**\n * A small rounded label for categorisation, status, or tagging.\n *\n * @example\n * ```tsx\n * <Pill variant=\"brand\">New</Pill>\n * ```\n */\nexport const Pill = React.forwardRef<HTMLSpanElement, PillProps>(\n (\n {\n className,\n variant = \"green\",\n leftIcon,\n rightIcon,\n asChild = false,\n onClick,\n children,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"pill\"\n className={cn(\n // Base styles\n \"inline-flex min-w-0 items-center justify-center gap-2 rounded-full px-3 py-1\",\n // Typography\n \"typography-description-12px-semibold\",\n // Variant styles\n pillVariants.variant[variant],\n // Interactive\n onClick && \"cursor-pointer\",\n // Manual CSS overrides\n className,\n )}\n onClick={onClick}\n {...props}\n >\n {leftIcon && (\n <span className=\"flex [&>svg]:size-3\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n {asChild ? (\n <Slottable>{children}</Slottable>\n ) : (\n <span className=\"min-w-0 truncate\">{children}</span>\n )}\n {rightIcon && (\n <span className=\"flex [&>svg]:size-3\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nPill.displayName = \"Pill\";\n"],"names":[],"mappings":";;;;;AAIA,MAAM,eAAe;AAAA,EACnB,SAAS;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,EAAA;AAET;AAmCO,MAAM,OAAO,MAAM;AAAA,EACxB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,OAAO,UAAU,OAAO;AAE9B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAW;AAAA;AAAA,UAET;AAAA;AAAA,UAEA;AAAA;AAAA,UAEA,aAAa,QAAQ,OAAO;AAAA;AAAA,UAE5B,WAAW;AAAA;AAAA,UAEX;AAAA,QAAA;AAAA,QAEF;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,gCACE,QAAA,EAAK,WAAU,uBAAsB,eAAY,QAC/C,UAAA,UACH;AAAA,UAED,8BACE,WAAA,EAAW,SAAA,CAAS,IAErB,oBAAC,QAAA,EAAK,WAAU,oBAAoB,SAAA,CAAS;AAAA,UAE9C,aACC,oBAAC,QAAA,EAAK,WAAU,uBAAsB,eAAY,QAC/C,UAAA,UAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;"}
|
|
@@ -16,7 +16,7 @@ const Radio = React.forwardRef(({ className, size = "default", label, helperText
|
|
|
16
16
|
"data-testid": "radio",
|
|
17
17
|
"aria-describedby": helperText ? helperTextId : void 0,
|
|
18
18
|
className: cn(
|
|
19
|
-
"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:
|
|
19
|
+
"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",
|
|
20
20
|
helperText && "mt-1 self-start"
|
|
21
21
|
),
|
|
22
22
|
...props,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Radio.mjs","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.mjs","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":[],"mappings":";;;;;AA0BO,MAAM,QAAQ,MAAM,WAGzB,CAAC,EAAE,WAAW,OAAO,WAAW,OAAO,YAAY,IAAI,GAAG,MAAA,GAAS,QAAQ;AAC3E,QAAM,cAAc,MAAM,MAAA;AAC1B,QAAM,UAAU,MAAM;AACtB,QAAM,eAAe,GAAG,OAAO;AAE/B,8BACG,OAAA,EAAI,WAAW,GAAG,wCAAwC,SAAS,GAClE,UAAA;AAAA,IAAA;AAAA,MAAC,oBAAoB;AAAA,MAApB;AAAA,QACC;AAAA,QACA,IAAI;AAAA,QACJ,eAAY;AAAA,QACZ,oBAAkB,aAAa,eAAe;AAAA,QAC9C,WAAW;AAAA,UACT;AAAA,UACA,cAAc;AAAA,QAAA;AAAA,QAEf,GAAG;AAAA,QAEJ,UAAA,oBAAC,oBAAoB,WAApB,EAA8B,WAAU,qDACvC,UAAA,oBAAC,QAAA,EAAK,WAAU,kFAAA,CAAkF,EAAA,CACpG;AAAA,MAAA;AAAA,IAAA;AAAA,KAEA,SAAS,eACT,qBAAC,OAAA,EAAI,WAAU,yBACZ,UAAA;AAAA,MAAA,SACC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAW;AAAA,YACT;AAAA,YACA,SAAS,UACL,wCACA;AAAA,UAAA;AAAA,UAGL,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAGJ,cACC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,WAAW;AAAA,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;"}
|
|
@@ -40,7 +40,7 @@ function SliderThumb({
|
|
|
40
40
|
"transition-shadow duration-150",
|
|
41
41
|
"hover:ring-2 hover:ring-brand-primary-default",
|
|
42
42
|
"not-data-disabled:active:ring-2 not-data-disabled:active:ring-brand-primary-default",
|
|
43
|
-
"focus-visible:
|
|
43
|
+
"focus-visible:shadow-focus-ring focus-visible:outline-none",
|
|
44
44
|
"data-disabled:cursor-not-allowed"
|
|
45
45
|
),
|
|
46
46
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliderThumb.mjs","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.mjs","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":[],"mappings":";;;;;AAYO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,mBAAmB;AACrB,GAAqB;AACnB,QAAM,WAAW,MAAM;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,SACE;AAAA,IAAC,gBAAgB;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,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAK,WAAU,oGAAA,CAAoG;AAAA,QAEnH,eACC;AAAA,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;"}
|
|
@@ -39,14 +39,23 @@ const TableToolbar = React.forwardRef(
|
|
|
39
39
|
);
|
|
40
40
|
TableToolbar.displayName = "TableToolbar";
|
|
41
41
|
const TableScrollArea = React.forwardRef(
|
|
42
|
-
({ className, children, roundTop: _roundTop, ...props }, ref) => {
|
|
42
|
+
({ className, children, roundTop: _roundTop, showScrollbar = false, ...props }, ref) => {
|
|
43
43
|
return /* @__PURE__ */ jsx(
|
|
44
44
|
"div",
|
|
45
45
|
{
|
|
46
46
|
ref,
|
|
47
47
|
className: cn("relative w-full min-w-0 overflow-hidden", className),
|
|
48
48
|
...props,
|
|
49
|
-
children: /* @__PURE__ */ jsx(
|
|
49
|
+
children: /* @__PURE__ */ jsx(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
className: cn(
|
|
53
|
+
"overflow-x-auto",
|
|
54
|
+
showScrollbar && "pb-3 [scrollbar-color:var(--color-border-strong)_transparent] [scrollbar-width:thin]"
|
|
55
|
+
),
|
|
56
|
+
children
|
|
57
|
+
}
|
|
58
|
+
)
|
|
50
59
|
}
|
|
51
60
|
);
|
|
52
61
|
}
|
|
@@ -100,13 +109,15 @@ const HEAD_INTENT_CLASSES = {
|
|
|
100
109
|
};
|
|
101
110
|
const TableHead = React.forwardRef(
|
|
102
111
|
({ className, intent = "default", scope = "col", ...props }, ref) => {
|
|
112
|
+
const size = useTableSize();
|
|
103
113
|
return /* @__PURE__ */ jsx(
|
|
104
114
|
"th",
|
|
105
115
|
{
|
|
106
116
|
ref,
|
|
107
117
|
scope,
|
|
108
118
|
className: cn(
|
|
109
|
-
"
|
|
119
|
+
size === "condensed" ? "typography-body-small-14px-semibold" : "typography-body-default-16px-semibold",
|
|
120
|
+
"box-border h-12 min-h-12 border-b border-border-primary px-4 py-3 align-middle text-content-tertiary",
|
|
110
121
|
HEAD_INTENT_CLASSES[intent],
|
|
111
122
|
className
|
|
112
123
|
),
|
|
@@ -119,6 +130,7 @@ TableHead.displayName = "TableHead";
|
|
|
119
130
|
const CELL_MIN_HEIGHT = {
|
|
120
131
|
md: "h-16 min-h-16",
|
|
121
132
|
default: "h-16 min-h-16",
|
|
133
|
+
condensed: "h-12 min-h-12 py-1",
|
|
122
134
|
lg: "h-20 min-h-20"
|
|
123
135
|
};
|
|
124
136
|
const CELL_VARIANT_CLASSES = {
|
|
@@ -136,7 +148,7 @@ const CELL_INTENT_CLASSES = {
|
|
|
136
148
|
const TableCell = React.forwardRef(
|
|
137
149
|
({ className, cellVariant = "default", intent = "default", ...props }, ref) => {
|
|
138
150
|
const size = useTableSize();
|
|
139
|
-
const typo = intent === "sideLabel" ? "typography-
|
|
151
|
+
const typo = intent === "sideLabel" ? "typography-body-small-14px-semibold" : "typography-body-small-14px-regular";
|
|
140
152
|
return /* @__PURE__ */ jsx(
|
|
141
153
|
"td",
|
|
142
154
|
{
|
|
@@ -170,19 +182,23 @@ function TableCellContent({
|
|
|
170
182
|
}) {
|
|
171
183
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-0.5", className), children: [
|
|
172
184
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
173
|
-
/* @__PURE__ */ jsx("span", { className: "typography-
|
|
185
|
+
/* @__PURE__ */ jsx("span", { className: "typography-body-small-14px-semibold text-content-primary", children: primary }),
|
|
174
186
|
primaryAdornment
|
|
175
187
|
] }),
|
|
176
188
|
(secondary != null || secondaryAdornment != null) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
177
|
-
secondary != null && /* @__PURE__ */ jsx("span", { className: "typography-
|
|
189
|
+
secondary != null && /* @__PURE__ */ jsx("span", { className: "typography-body-small-14px-regular text-content-secondary", children: secondary }),
|
|
178
190
|
secondaryAdornment
|
|
179
191
|
] })
|
|
180
192
|
] });
|
|
181
193
|
}
|
|
182
194
|
TableCellContent.displayName = "TableCellContent";
|
|
183
195
|
const TableMediaThumbnail = React.forwardRef(
|
|
184
|
-
({ className, src, alt = "", blurred, align = "start", ...props }, ref) => {
|
|
185
|
-
const frame =
|
|
196
|
+
({ className, src, alt = "", blurred, align = "start", size = "48", ...props }, ref) => {
|
|
197
|
+
const frame = cn(
|
|
198
|
+
"overflow-hidden bg-neutral-alphas-200",
|
|
199
|
+
size === "48" && "size-12 rounded-sm",
|
|
200
|
+
size === "32" && "size-8 rounded-xs"
|
|
201
|
+
);
|
|
186
202
|
return /* @__PURE__ */ jsx(
|
|
187
203
|
"div",
|
|
188
204
|
{
|
|
@@ -262,16 +278,7 @@ const TableSortLabel = React.forwardRef(
|
|
|
262
278
|
className: cn("inline-flex items-center gap-1 text-content-primary", className),
|
|
263
279
|
...props,
|
|
264
280
|
children: [
|
|
265
|
-
/* @__PURE__ */ jsx(
|
|
266
|
-
"span",
|
|
267
|
-
{
|
|
268
|
-
className: cn(
|
|
269
|
-
"typography-description-12px-semibold",
|
|
270
|
-
direction != null && "border-b border-content-primary pb-px"
|
|
271
|
-
),
|
|
272
|
-
children
|
|
273
|
-
}
|
|
274
|
-
),
|
|
281
|
+
/* @__PURE__ */ jsx("span", { className: cn(direction != null && "border-b border-content-primary pb-px"), children }),
|
|
275
282
|
direction != null && /* @__PURE__ */ jsx(Icon, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
276
283
|
]
|
|
277
284
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.mjs","sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { ArrowDownIcon } from \"../Icons/ArrowDownIcon\";\nimport { ArrowUpIcon } from \"../Icons/ArrowUpIcon\";\nimport { Select, SelectContent, SelectItem } from \"../Select/Select\";\n\n/**\n * Row density for body cells.\n *\n * - `\"md\"` (default) → 64px Figma `V2 Table Cell` Small.\n * - `\"lg\"` → 80px Figma `V2 Table Cell` Large.\n *\n * `\"default\"` is the v2 numeric-token equivalent of `\"md\"` and is preferred\n * for new code.\n */\nexport type TableSize = \"md\" | \"lg\" | \"default\";\n\nexport interface TableCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Row density applied to {@link TableCell} descendants. @default \"md\" */\n size?: TableSize;\n}\n\nconst TableSizeContext = React.createContext<TableSize>(\"md\");\n\nfunction useTableSize(): TableSize {\n return React.useContext(TableSizeContext);\n}\n\n/**\n * Surface wrapper for data tables: rounded 24px container with a strong\n * outer border, inner spacing, and size context for {@link TableCell}\n * descendants. Compose with {@link TableScrollArea}, {@link Table},\n * {@link TableHeader}, {@link TableBody}, {@link TableRow},\n * {@link TableHead}, and {@link TableCell}.\n *\n * @example\n * ```tsx\n * <TableCard>\n * <TableScrollArea>\n * <Table>\n * <TableHeader>\n * <TableRow>\n * <TableHead>Name</TableHead>\n * </TableRow>\n * </TableHeader>\n * <TableBody>\n * <TableRow>\n * <TableCell>Jane Doe</TableCell>\n * </TableRow>\n * </TableBody>\n * </Table>\n * </TableScrollArea>\n * </TableCard>\n * ```\n */\nexport const TableCard = React.forwardRef<HTMLDivElement, TableCardProps>(\n ({ className, size = \"md\", ...props }, ref) => {\n return (\n <TableSizeContext.Provider value={size}>\n <div\n ref={ref}\n className={cn(\n \"isolate flex flex-col gap-2 overflow-hidden rounded-3xl border border-border-strong px-3 py-1\",\n className,\n )}\n {...props}\n />\n </TableSizeContext.Provider>\n );\n },\n);\nTableCard.displayName = \"TableCard\";\n\nexport interface TableToolbarProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Optional toolbar row above the table (e.g. bulk selection actions).\n */\nexport const TableToolbar = React.forwardRef<HTMLDivElement, TableToolbarProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"flex flex-wrap items-center gap-4 px-4 py-3\", className)}\n {...props}\n />\n );\n },\n);\nTableToolbar.displayName = \"TableToolbar\";\n\nexport interface TableScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * No longer needed in v2 — {@link TableCard} handles corner rounding via\n * its own `overflow-hidden rounded-3xl`. Accepted for back-compat.\n *\n * @deprecated v2 ignores this prop; safe to remove.\n */\n roundTop?: boolean;\n}\n\n/**\n * Horizontal scroll container for wide tables. The inner scrollport keeps\n * `border-collapse` styles intact when the table wraps.\n */\nexport const TableScrollArea = React.forwardRef<HTMLDivElement, TableScrollAreaProps>(\n ({ className, children, roundTop: _roundTop, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"relative w-full min-w-0 overflow-hidden\", className)}\n {...props}\n >\n <div className=\"overflow-x-auto\">{children}</div>\n </div>\n );\n },\n);\nTableScrollArea.displayName = \"TableScrollArea\";\n\nexport interface TableProps extends React.TableHTMLAttributes<HTMLTableElement> {}\n\n/**\n * Semantic `<table>` element. Place inside {@link TableScrollArea}.\n */\nexport const Table = React.forwardRef<HTMLTableElement, TableProps>(\n ({ className, ...props }, ref) => {\n return (\n <table\n ref={ref}\n className={cn(\n \"w-full caption-bottom border-separate border-spacing-0 text-left\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nTable.displayName = \"Table\";\n\nexport interface TableHeaderProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableHeader = React.forwardRef<HTMLTableSectionElement, TableHeaderProps>(\n ({ className, ...props }, ref) => {\n return <thead ref={ref} className={cn(className)} {...props} />;\n },\n);\nTableHeader.displayName = \"TableHeader\";\n\nexport interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\n/**\n * `<tbody>` wrapper. Removes the bottom border on cells in the final row to\n * match the Figma `V2 Table Final Row` treatment.\n */\nexport const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(\n ({ className, ...props }, ref) => {\n return (\n <tbody ref={ref} className={cn(\"[&_tr:last-child_td]:border-b-0\", className)} {...props} />\n );\n },\n);\nTableBody.displayName = \"TableBody\";\n\nexport interface TableFooterProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableFooter = React.forwardRef<HTMLTableSectionElement, TableFooterProps>(\n ({ className, ...props }, ref) => {\n return <tfoot ref={ref} className={cn(className)} {...props} />;\n },\n);\nTableFooter.displayName = \"TableFooter\";\n\nexport interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {}\n\nexport const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(\n ({ className, ...props }, ref) => {\n return <tr ref={ref} className={cn(className)} {...props} />;\n },\n);\nTableRow.displayName = \"TableRow\";\n\n/** Column layout preset for {@link TableHead}. */\nexport type TableHeadIntent = \"default\" | \"checkbox\" | \"sort\" | \"leading\";\n\nconst HEAD_INTENT_CLASSES: Record<TableHeadIntent, string> = {\n default: \"text-left\",\n checkbox: \"w-12 min-w-12 max-w-12 text-center\",\n sort: \"text-right\",\n leading: \"min-w-0 w-2/5 text-left\",\n};\n\nexport interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {\n /** Layout preset for common column types. @default \"default\" */\n intent?: TableHeadIntent;\n}\n\n/**\n * Header cell. v2: transparent background, 48px min height, tertiary text,\n * `border-border-primary` bottom rule.\n */\nexport const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(\n ({ className, intent = \"default\", scope = \"col\", ...props }, ref) => {\n return (\n <th\n ref={ref}\n scope={scope}\n className={cn(\n \"typography-description-12px-semibold box-border min-h-12 border-b border-border-primary px-4 py-3 align-middle text-content-tertiary\",\n HEAD_INTENT_CLASSES[intent],\n className,\n )}\n {...props}\n />\n );\n },\n);\nTableHead.displayName = \"TableHead\";\n\nconst CELL_MIN_HEIGHT: Record<TableSize, string> = {\n md: \"h-16 min-h-16\",\n default: \"h-16 min-h-16\",\n lg: \"h-20 min-h-20\",\n};\n\n/** Bottom border and padding preset for body cells (Figma table cell component). */\nexport type TableCellVariant = \"default\" | \"chip\" | \"pillProgress\";\n\nconst CELL_VARIANT_CLASSES: Record<TableCellVariant, string> = {\n default: \"border-b border-border-primary px-4 py-3\",\n chip: \"border-b border-border-primary px-4 py-3\",\n pillProgress: \"border-b border-border-primary px-4 py-3\",\n};\n\n/** Layout / typography preset for {@link TableCell} (orthogonal to {@link TableCellVariant}). */\nexport type TableCellIntent = \"default\" | \"checkbox\" | \"stacked\" | \"multiline\" | \"sideLabel\";\n\nconst CELL_INTENT_CLASSES: Record<TableCellIntent, string> = {\n default: \"\",\n checkbox: \"w-12 min-w-12 max-w-12 text-center\",\n stacked: \"align-top\",\n multiline: \"max-w-[240px]\",\n sideLabel: \"\",\n};\n\nexport interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElement> {\n /** Padding preset for the cell. v2 uses identical padding across variants; values are kept for back-compat. @default \"default\" */\n cellVariant?: TableCellVariant;\n /** Alignment and typography preset for common cell types. @default \"default\" */\n intent?: TableCellIntent;\n}\n\n/**\n * Body cell. v2: `h-16` (or `h-20` when the parent {@link TableCard} uses\n * `size=\"lg\"`), `px-4 py-3` padding, body-sm typography, and a single\n * `border-border-primary` rule that is zeroed by {@link TableBody} for the\n * final row.\n */\nexport const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(\n ({ className, cellVariant = \"default\", intent = \"default\", ...props }, ref) => {\n const size = useTableSize();\n const typo =\n intent === \"sideLabel\"\n ? \"typography-description-12px-semibold\"\n : \"typography-description-12px-regular\";\n return (\n <td\n ref={ref}\n className={cn(\n typo,\n \"align-middle text-content-primary\",\n CELL_VARIANT_CLASSES[cellVariant],\n CELL_MIN_HEIGHT[size],\n CELL_INTENT_CLASSES[intent],\n className,\n )}\n {...props}\n />\n );\n },\n);\nTableCell.displayName = \"TableCell\";\n\nexport interface TableCellGroupProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Horizontal group for icons, chips, and metadata inside a {@link TableCell}\n * (Figma `gap-[4px]`).\n */\nexport const TableCellGroup = React.forwardRef<HTMLDivElement, TableCellGroupProps>(\n ({ className, ...props }, ref) => {\n return <div ref={ref} className={cn(\"flex items-center gap-1\", className)} {...props} />;\n },\n);\nTableCellGroup.displayName = \"TableCellGroup\";\n\nexport interface TableCellContentProps {\n /** Primary line (semibold body-sm). */\n primary: React.ReactNode;\n /** Optional secondary line (regular body-sm, secondary color). */\n secondary?: React.ReactNode;\n /** Inline node rendered next to the primary line (icon, chip). */\n primaryAdornment?: React.ReactNode;\n /** Inline node rendered next to the secondary line. */\n secondaryAdornment?: React.ReactNode;\n /** Class for the outer wrapper. */\n className?: string;\n}\n\n/**\n * Two-line content slot matching Figma `V2 Table Content` — primary line\n * (semibold) over an optional secondary line (regular, muted) with a 2px\n * gap. Use inside {@link TableCell} for the common stacked-text pattern.\n */\nexport function TableCellContent({\n primary,\n secondary,\n primaryAdornment,\n secondaryAdornment,\n className,\n}: TableCellContentProps) {\n return (\n <div className={cn(\"flex flex-col gap-0.5\", className)}>\n <div className=\"flex items-center gap-1\">\n <span className=\"typography-description-12px-semibold text-content-primary\">{primary}</span>\n {primaryAdornment}\n </div>\n {(secondary != null || secondaryAdornment != null) && (\n <div className=\"flex items-center gap-1\">\n {secondary != null && (\n <span className=\"typography-description-12px-regular text-content-secondary\">\n {secondary}\n </span>\n )}\n {secondaryAdornment}\n </div>\n )}\n </div>\n );\n}\nTableCellContent.displayName = \"TableCellContent\";\n\nexport interface TableMediaThumbnailProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Image URL. */\n src: string;\n /** Alt text for the image. @default \"\" */\n alt?: string;\n /** Applies the table's blurred-media treatment. @default false */\n blurred?: boolean;\n /** `center` uses the fixed media column width from the lg spec. @default \"start\" */\n align?: \"start\" | \"center\";\n}\n\n/**\n * Square 48px thumbnail used inside {@link TableCell} for media columns\n * (Figma `V2 Media Thumbnail Item`).\n */\nexport const TableMediaThumbnail = React.forwardRef<HTMLDivElement, TableMediaThumbnailProps>(\n ({ className, src, alt = \"\", blurred, align = \"start\", ...props }, ref) => {\n const frame = \"size-12 overflow-hidden rounded-sm bg-neutral-alphas-200\";\n return (\n <div\n ref={ref}\n className={cn(\n align === \"center\" && \"flex w-16 shrink-0 justify-center\",\n align === \"start\" && \"inline-flex shrink-0\",\n )}\n >\n <div className={cn(frame, blurred && \"blur-[2px]\", className)} {...props}>\n <img alt={alt} className=\"size-full object-cover\" src={src} />\n </div>\n </div>\n );\n },\n);\nTableMediaThumbnail.displayName = \"TableMediaThumbnail\";\n\nexport interface TableStatusDotProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Small status indicator dot for table cells (Figma status column).\n */\nexport const TableStatusDot = React.forwardRef<HTMLDivElement, TableStatusDotProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"size-2 shrink-0 rounded-full bg-info-content\", className)}\n {...props}\n />\n );\n },\n);\nTableStatusDot.displayName = \"TableStatusDot\";\n\nexport interface TableProgressTrackProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Fill width from 0–100. @default 0 */\n value?: number;\n}\n\n/**\n * Thin progress track used with badges in table cells (Figma pill + progress).\n * Renders with `role=\"progressbar\"` and a default `aria-label` of `\"Progress\"`.\n */\nexport const TableProgressTrack = React.forwardRef<HTMLDivElement, TableProgressTrackProps>(\n ({ className, value = 0, \"aria-label\": ariaLabel = \"Progress\", ...props }, ref) => {\n const width = Math.min(100, Math.max(0, value));\n const rounded = Math.round(width);\n return (\n <div\n ref={ref}\n role=\"progressbar\"\n aria-valuenow={rounded}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n className={cn(\n \"relative h-1 w-full overflow-hidden rounded-full bg-neutral-alphas-200\",\n className,\n )}\n {...props}\n >\n <div\n className=\"absolute top-0 left-0 h-1 rounded-full bg-buttons-primary-default\"\n style={{ width: `${width}%` }}\n aria-hidden\n />\n </div>\n );\n },\n);\nTableProgressTrack.displayName = \"TableProgressTrack\";\n\nexport interface TablePillProgressLayoutProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Vertical layout for pill label + {@link TableProgressTrack} in a cell.\n */\nexport const TablePillProgressLayout = React.forwardRef<\n HTMLDivElement,\n TablePillProgressLayoutProps\n>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"flex min-w-[120px] flex-col items-start gap-2\", className)}\n {...props}\n />\n );\n});\nTablePillProgressLayout.displayName = \"TablePillProgressLayout\";\n\n/** Current sort direction of a {@link TableSortLabel}. `null` means unsorted. */\nexport type TableSortDirection = \"asc\" | \"desc\" | null;\n\nexport interface TableSortLabelProps extends React.HTMLAttributes<HTMLSpanElement> {\n children: React.ReactNode;\n /**\n * Visual indicator of the column's sort state. When set to `\"asc\"` or\n * `\"desc\"`, a 1px underline accent appears beneath the label and a small\n * directional arrow is shown next to it. @default null\n */\n direction?: TableSortDirection;\n}\n\n/**\n * Sortable column label. v2 expresses the sort state with a 1px underline\n * beneath the label plus a directional arrow when sorted.\n */\nexport const TableSortLabel = React.forwardRef<HTMLSpanElement, TableSortLabelProps>(\n ({ className, children, direction = null, ...props }, ref) => {\n const Icon = direction === \"desc\" ? ArrowDownIcon : ArrowUpIcon;\n return (\n <span\n ref={ref}\n className={cn(\"inline-flex items-center gap-1 text-content-primary\", className)}\n {...props}\n >\n <span\n className={cn(\n \"typography-description-12px-semibold\",\n direction != null && \"border-b border-content-primary pb-px\",\n )}\n >\n {children}\n </span>\n {direction != null && <Icon className=\"size-4 shrink-0\" aria-hidden />}\n </span>\n );\n },\n);\nTableSortLabel.displayName = \"TableSortLabel\";\n\nexport interface TableStackedTextProps {\n /** Primary line (semibold body). */\n title: React.ReactNode;\n /** Secondary line (caption, muted). */\n subtitle: React.ReactNode;\n}\n\n/**\n * Two-line primary + secondary text block for \"cell + info\" patterns.\n *\n * @deprecated Prefer {@link TableCellContent} which supports adornments and\n * matches the Figma `V2 Table Content` slot.\n */\nexport function TableStackedText({ title, subtitle }: TableStackedTextProps) {\n return <TableCellContent primary={title} secondary={subtitle} />;\n}\n\nTableStackedText.displayName = \"TableStackedText\";\n\nexport interface TableLineClampProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Number of lines before ellipsis. @default 2 */\n lines?: 1 | 2 | 3;\n}\n\n/**\n * Clamps child text to a fixed number of lines inside a {@link TableCell}.\n */\nexport const TableLineClamp = React.forwardRef<HTMLDivElement, TableLineClampProps>(\n ({ className, lines = 2, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\n lines === 1 && \"line-clamp-1\",\n lines === 2 && \"line-clamp-2\",\n lines === 3 && \"line-clamp-3\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nTableLineClamp.displayName = \"TableLineClamp\";\n\nexport interface TableRowsPerPageSelectProps {\n /** Passed to the trigger for forms and labels. */\n id?: string;\n /** Accessible name for the trigger when no visible label. @default \"Rows per page\" */\n \"aria-label\"?: string;\n}\n\n/**\n * Rows-per-page {@link Select} styled for {@link TablePagination}. v2 uses a\n * subtle pill trigger with the table's secondary-surface background.\n */\nexport function TableRowsPerPageSelect(props: TableRowsPerPageSelectProps) {\n const { id, \"aria-label\": ariaLabel = \"Rows per page\" } = props;\n return (\n <Select\n defaultValue=\"10\"\n size=\"32\"\n aria-label={ariaLabel}\n className=\"w-[154px] [&_button]:rounded-sm [&_button]:border-transparent [&_button]:bg-inputs-inputs-primary\"\n id={id}\n >\n <SelectContent>\n <SelectItem value=\"10\">10 rows per page</SelectItem>\n <SelectItem value=\"25\">25 rows per page</SelectItem>\n <SelectItem value=\"50\">50 rows per page</SelectItem>\n </SelectContent>\n </Select>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Table.mjs","sources":["../../../src/components/Table/Table.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { ArrowDownIcon } from \"../Icons/ArrowDownIcon\";\nimport { ArrowUpIcon } from \"../Icons/ArrowUpIcon\";\nimport { Select, SelectContent, SelectItem } from \"../Select/Select\";\n\n/**\n * Row density for body cells.\n *\n * - `\"md\"` (default) → 64px Figma `V2 Table Cell` Default.\n * - `\"condensed\"` → 48px Figma `V2 Table Cell` Condensed.\n * - `\"lg\"` → 80px rows; no longer in Figma, kept for back-compat.\n *\n * `\"default\"` is the v2 numeric-token equivalent of `\"md\"` and is preferred\n * for new code.\n */\nexport type TableSize = \"md\" | \"lg\" | \"condensed\" | \"default\";\n\nexport interface TableCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Row density applied to {@link TableCell} descendants. @default \"md\" */\n size?: TableSize;\n}\n\nconst TableSizeContext = React.createContext<TableSize>(\"md\");\n\nfunction useTableSize(): TableSize {\n return React.useContext(TableSizeContext);\n}\n\n/**\n * Surface wrapper for data tables: rounded 24px container with a strong\n * outer border, inner spacing, and size context for {@link TableCell}\n * descendants. Compose with {@link TableScrollArea}, {@link Table},\n * {@link TableHeader}, {@link TableBody}, {@link TableRow},\n * {@link TableHead}, and {@link TableCell}.\n *\n * @example\n * ```tsx\n * <TableCard>\n * <TableScrollArea>\n * <Table>\n * <TableHeader>\n * <TableRow>\n * <TableHead>Name</TableHead>\n * </TableRow>\n * </TableHeader>\n * <TableBody>\n * <TableRow>\n * <TableCell>Jane Doe</TableCell>\n * </TableRow>\n * </TableBody>\n * </Table>\n * </TableScrollArea>\n * </TableCard>\n * ```\n */\nexport const TableCard = React.forwardRef<HTMLDivElement, TableCardProps>(\n ({ className, size = \"md\", ...props }, ref) => {\n return (\n <TableSizeContext.Provider value={size}>\n <div\n ref={ref}\n className={cn(\n \"isolate flex flex-col gap-2 overflow-hidden rounded-3xl border border-border-strong px-3 py-1\",\n className,\n )}\n {...props}\n />\n </TableSizeContext.Provider>\n );\n },\n);\nTableCard.displayName = \"TableCard\";\n\nexport interface TableToolbarProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Optional toolbar row above the table (e.g. bulk selection actions).\n */\nexport const TableToolbar = React.forwardRef<HTMLDivElement, TableToolbarProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"flex flex-wrap items-center gap-4 px-4 py-3\", className)}\n {...props}\n />\n );\n },\n);\nTableToolbar.displayName = \"TableToolbar\";\n\nexport interface TableScrollAreaProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * No longer needed in v2 — {@link TableCard} handles corner rounding via\n * its own `overflow-hidden rounded-3xl`. Accepted for back-compat.\n *\n * @deprecated v2 ignores this prop; safe to remove.\n */\n roundTop?: boolean;\n /**\n * Shows a slim horizontal scrollbar beneath the table when the content\n * overflows (Figma `V2 Scroll Bar`). @default false\n */\n showScrollbar?: boolean;\n}\n\n/**\n * Horizontal scroll container for wide tables. The inner scrollport keeps\n * `border-collapse` styles intact when the table wraps.\n */\nexport const TableScrollArea = React.forwardRef<HTMLDivElement, TableScrollAreaProps>(\n ({ className, children, roundTop: _roundTop, showScrollbar = false, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"relative w-full min-w-0 overflow-hidden\", className)}\n {...props}\n >\n <div\n className={cn(\n \"overflow-x-auto\",\n showScrollbar &&\n \"pb-3 [scrollbar-color:var(--color-border-strong)_transparent] [scrollbar-width:thin]\",\n )}\n >\n {children}\n </div>\n </div>\n );\n },\n);\nTableScrollArea.displayName = \"TableScrollArea\";\n\nexport interface TableProps extends React.TableHTMLAttributes<HTMLTableElement> {}\n\n/**\n * Semantic `<table>` element. Place inside {@link TableScrollArea}.\n */\nexport const Table = React.forwardRef<HTMLTableElement, TableProps>(\n ({ className, ...props }, ref) => {\n return (\n <table\n ref={ref}\n className={cn(\n \"w-full caption-bottom border-separate border-spacing-0 text-left\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nTable.displayName = \"Table\";\n\nexport interface TableHeaderProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableHeader = React.forwardRef<HTMLTableSectionElement, TableHeaderProps>(\n ({ className, ...props }, ref) => {\n return <thead ref={ref} className={cn(className)} {...props} />;\n },\n);\nTableHeader.displayName = \"TableHeader\";\n\nexport interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\n/**\n * `<tbody>` wrapper. Removes the bottom border on cells in the final row to\n * match the Figma `V2 Table Final Row` treatment.\n */\nexport const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(\n ({ className, ...props }, ref) => {\n return (\n <tbody ref={ref} className={cn(\"[&_tr:last-child_td]:border-b-0\", className)} {...props} />\n );\n },\n);\nTableBody.displayName = \"TableBody\";\n\nexport interface TableFooterProps extends React.HTMLAttributes<HTMLTableSectionElement> {}\n\nexport const TableFooter = React.forwardRef<HTMLTableSectionElement, TableFooterProps>(\n ({ className, ...props }, ref) => {\n return <tfoot ref={ref} className={cn(className)} {...props} />;\n },\n);\nTableFooter.displayName = \"TableFooter\";\n\nexport interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {}\n\nexport const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(\n ({ className, ...props }, ref) => {\n return <tr ref={ref} className={cn(className)} {...props} />;\n },\n);\nTableRow.displayName = \"TableRow\";\n\n/** Column layout preset for {@link TableHead}. */\nexport type TableHeadIntent = \"default\" | \"checkbox\" | \"sort\" | \"leading\";\n\nconst HEAD_INTENT_CLASSES: Record<TableHeadIntent, string> = {\n default: \"text-left\",\n checkbox: \"w-12 min-w-12 max-w-12 text-center\",\n sort: \"text-right\",\n leading: \"min-w-0 w-2/5 text-left\",\n};\n\nexport interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {\n /** Layout preset for common column types. @default \"default\" */\n intent?: TableHeadIntent;\n}\n\n/**\n * Header cell. v2: transparent background, 48px min height, tertiary text,\n * `border-border-primary` bottom rule. Uses 16px semibold type, or 14px when\n * the parent {@link TableCard} is `size=\"condensed\"`.\n */\nexport const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(\n ({ className, intent = \"default\", scope = \"col\", ...props }, ref) => {\n const size = useTableSize();\n return (\n <th\n ref={ref}\n scope={scope}\n className={cn(\n size === \"condensed\"\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\",\n \"box-border h-12 min-h-12 border-b border-border-primary px-4 py-3 align-middle text-content-tertiary\",\n HEAD_INTENT_CLASSES[intent],\n className,\n )}\n {...props}\n />\n );\n },\n);\nTableHead.displayName = \"TableHead\";\n\nconst CELL_MIN_HEIGHT: Record<TableSize, string> = {\n md: \"h-16 min-h-16\",\n default: \"h-16 min-h-16\",\n condensed: \"h-12 min-h-12 py-1\",\n lg: \"h-20 min-h-20\",\n};\n\n/** Bottom border and padding preset for body cells (Figma table cell component). */\nexport type TableCellVariant = \"default\" | \"chip\" | \"pillProgress\";\n\nconst CELL_VARIANT_CLASSES: Record<TableCellVariant, string> = {\n default: \"border-b border-border-primary px-4 py-3\",\n chip: \"border-b border-border-primary px-4 py-3\",\n pillProgress: \"border-b border-border-primary px-4 py-3\",\n};\n\n/** Layout / typography preset for {@link TableCell} (orthogonal to {@link TableCellVariant}). */\nexport type TableCellIntent = \"default\" | \"checkbox\" | \"stacked\" | \"multiline\" | \"sideLabel\";\n\nconst CELL_INTENT_CLASSES: Record<TableCellIntent, string> = {\n default: \"\",\n checkbox: \"w-12 min-w-12 max-w-12 text-center\",\n stacked: \"align-top\",\n multiline: \"max-w-[240px]\",\n sideLabel: \"\",\n};\n\nexport interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElement> {\n /** Padding preset for the cell. v2 uses identical padding across variants; values are kept for back-compat. @default \"default\" */\n cellVariant?: TableCellVariant;\n /** Alignment and typography preset for common cell types. @default \"default\" */\n intent?: TableCellIntent;\n}\n\n/**\n * Body cell. v2: `h-16` (or `h-20` when the parent {@link TableCard} uses\n * `size=\"lg\"`), `px-4 py-3` padding, body-sm typography, and a single\n * `border-border-primary` rule that is zeroed by {@link TableBody} for the\n * final row.\n */\nexport const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(\n ({ className, cellVariant = \"default\", intent = \"default\", ...props }, ref) => {\n const size = useTableSize();\n const typo =\n intent === \"sideLabel\"\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-small-14px-regular\";\n return (\n <td\n ref={ref}\n className={cn(\n typo,\n \"align-middle text-content-primary\",\n CELL_VARIANT_CLASSES[cellVariant],\n CELL_MIN_HEIGHT[size],\n CELL_INTENT_CLASSES[intent],\n className,\n )}\n {...props}\n />\n );\n },\n);\nTableCell.displayName = \"TableCell\";\n\nexport interface TableCellGroupProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Horizontal group for icons, chips, and metadata inside a {@link TableCell}\n * (Figma `gap-[4px]`).\n */\nexport const TableCellGroup = React.forwardRef<HTMLDivElement, TableCellGroupProps>(\n ({ className, ...props }, ref) => {\n return <div ref={ref} className={cn(\"flex items-center gap-1\", className)} {...props} />;\n },\n);\nTableCellGroup.displayName = \"TableCellGroup\";\n\nexport interface TableCellContentProps {\n /** Primary line (semibold body-sm). */\n primary: React.ReactNode;\n /** Optional secondary line (regular body-sm, secondary color). */\n secondary?: React.ReactNode;\n /** Inline node rendered next to the primary line (icon, chip). */\n primaryAdornment?: React.ReactNode;\n /** Inline node rendered next to the secondary line. */\n secondaryAdornment?: React.ReactNode;\n /** Class for the outer wrapper. */\n className?: string;\n}\n\n/**\n * Two-line content slot matching Figma `V2 Table Content` — primary line\n * (semibold) over an optional secondary line (regular, muted) with a 2px\n * gap. Use inside {@link TableCell} for the common stacked-text pattern.\n */\nexport function TableCellContent({\n primary,\n secondary,\n primaryAdornment,\n secondaryAdornment,\n className,\n}: TableCellContentProps) {\n return (\n <div className={cn(\"flex flex-col gap-0.5\", className)}>\n <div className=\"flex items-center gap-1\">\n <span className=\"typography-body-small-14px-semibold text-content-primary\">{primary}</span>\n {primaryAdornment}\n </div>\n {(secondary != null || secondaryAdornment != null) && (\n <div className=\"flex items-center gap-1\">\n {secondary != null && (\n <span className=\"typography-body-small-14px-regular text-content-secondary\">\n {secondary}\n </span>\n )}\n {secondaryAdornment}\n </div>\n )}\n </div>\n );\n}\nTableCellContent.displayName = \"TableCellContent\";\n\n/** Pixel size of the square {@link TableMediaThumbnail}. */\nexport type TableMediaThumbnailSize = \"48\" | \"32\";\n\nexport interface TableMediaThumbnailProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Image URL. */\n src: string;\n /** Alt text for the image. @default \"\" */\n alt?: string;\n /** Applies the table's blurred-media treatment. @default false */\n blurred?: boolean;\n /** `center` uses the fixed media column width from the lg spec. @default \"start\" */\n align?: \"start\" | \"center\";\n /** Pixel size of the square thumbnail; `\"32\"` matches the current Figma `V2 Media Thumbnail Item`. @default \"48\" */\n size?: TableMediaThumbnailSize;\n}\n\n/**\n * Square thumbnail used inside {@link TableCell} for media columns\n * (Figma `V2 Media Thumbnail Item`).\n */\nexport const TableMediaThumbnail = React.forwardRef<HTMLDivElement, TableMediaThumbnailProps>(\n ({ className, src, alt = \"\", blurred, align = \"start\", size = \"48\", ...props }, ref) => {\n const frame = cn(\n \"overflow-hidden bg-neutral-alphas-200\",\n size === \"48\" && \"size-12 rounded-sm\",\n size === \"32\" && \"size-8 rounded-xs\",\n );\n return (\n <div\n ref={ref}\n className={cn(\n align === \"center\" && \"flex w-16 shrink-0 justify-center\",\n align === \"start\" && \"inline-flex shrink-0\",\n )}\n >\n <div className={cn(frame, blurred && \"blur-[2px]\", className)} {...props}>\n <img alt={alt} className=\"size-full object-cover\" src={src} />\n </div>\n </div>\n );\n },\n);\nTableMediaThumbnail.displayName = \"TableMediaThumbnail\";\n\nexport interface TableStatusDotProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Small status indicator dot for table cells (Figma status column).\n */\nexport const TableStatusDot = React.forwardRef<HTMLDivElement, TableStatusDotProps>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"size-2 shrink-0 rounded-full bg-info-content\", className)}\n {...props}\n />\n );\n },\n);\nTableStatusDot.displayName = \"TableStatusDot\";\n\nexport interface TableProgressTrackProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Fill width from 0–100. @default 0 */\n value?: number;\n}\n\n/**\n * Thin progress track used with badges in table cells (Figma pill + progress).\n * Renders with `role=\"progressbar\"` and a default `aria-label` of `\"Progress\"`.\n */\nexport const TableProgressTrack = React.forwardRef<HTMLDivElement, TableProgressTrackProps>(\n ({ className, value = 0, \"aria-label\": ariaLabel = \"Progress\", ...props }, ref) => {\n const width = Math.min(100, Math.max(0, value));\n const rounded = Math.round(width);\n return (\n <div\n ref={ref}\n role=\"progressbar\"\n aria-valuenow={rounded}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n className={cn(\n \"relative h-1 w-full overflow-hidden rounded-full bg-neutral-alphas-200\",\n className,\n )}\n {...props}\n >\n <div\n className=\"absolute top-0 left-0 h-1 rounded-full bg-buttons-primary-default\"\n style={{ width: `${width}%` }}\n aria-hidden\n />\n </div>\n );\n },\n);\nTableProgressTrack.displayName = \"TableProgressTrack\";\n\nexport interface TablePillProgressLayoutProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Vertical layout for pill label + {@link TableProgressTrack} in a cell.\n */\nexport const TablePillProgressLayout = React.forwardRef<\n HTMLDivElement,\n TablePillProgressLayoutProps\n>(({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"flex min-w-[120px] flex-col items-start gap-2\", className)}\n {...props}\n />\n );\n});\nTablePillProgressLayout.displayName = \"TablePillProgressLayout\";\n\n/** Current sort direction of a {@link TableSortLabel}. `null` means unsorted. */\nexport type TableSortDirection = \"asc\" | \"desc\" | null;\n\nexport interface TableSortLabelProps extends React.HTMLAttributes<HTMLSpanElement> {\n children: React.ReactNode;\n /**\n * Visual indicator of the column's sort state. When set to `\"asc\"` or\n * `\"desc\"`, a 1px underline accent appears beneath the label and a small\n * directional arrow is shown next to it. @default null\n */\n direction?: TableSortDirection;\n}\n\n/**\n * Sortable column label. v2 expresses the sort state with a 1px underline\n * beneath the label plus a directional arrow when sorted.\n */\nexport const TableSortLabel = React.forwardRef<HTMLSpanElement, TableSortLabelProps>(\n ({ className, children, direction = null, ...props }, ref) => {\n const Icon = direction === \"desc\" ? ArrowDownIcon : ArrowUpIcon;\n return (\n <span\n ref={ref}\n className={cn(\"inline-flex items-center gap-1 text-content-primary\", className)}\n {...props}\n >\n <span className={cn(direction != null && \"border-b border-content-primary pb-px\")}>\n {children}\n </span>\n {direction != null && <Icon className=\"size-4 shrink-0\" aria-hidden />}\n </span>\n );\n },\n);\nTableSortLabel.displayName = \"TableSortLabel\";\n\nexport interface TableStackedTextProps {\n /** Primary line (semibold body). */\n title: React.ReactNode;\n /** Secondary line (caption, muted). */\n subtitle: React.ReactNode;\n}\n\n/**\n * Two-line primary + secondary text block for \"cell + info\" patterns.\n *\n * @deprecated Prefer {@link TableCellContent} which supports adornments and\n * matches the Figma `V2 Table Content` slot.\n */\nexport function TableStackedText({ title, subtitle }: TableStackedTextProps) {\n return <TableCellContent primary={title} secondary={subtitle} />;\n}\n\nTableStackedText.displayName = \"TableStackedText\";\n\nexport interface TableLineClampProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Number of lines before ellipsis. @default 2 */\n lines?: 1 | 2 | 3;\n}\n\n/**\n * Clamps child text to a fixed number of lines inside a {@link TableCell}.\n */\nexport const TableLineClamp = React.forwardRef<HTMLDivElement, TableLineClampProps>(\n ({ className, lines = 2, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\n lines === 1 && \"line-clamp-1\",\n lines === 2 && \"line-clamp-2\",\n lines === 3 && \"line-clamp-3\",\n className,\n )}\n {...props}\n />\n );\n },\n);\nTableLineClamp.displayName = \"TableLineClamp\";\n\nexport interface TableRowsPerPageSelectProps {\n /** Passed to the trigger for forms and labels. */\n id?: string;\n /** Accessible name for the trigger when no visible label. @default \"Rows per page\" */\n \"aria-label\"?: string;\n}\n\n/**\n * Rows-per-page {@link Select} styled for {@link TablePagination}. v2 uses a\n * subtle pill trigger with the table's secondary-surface background.\n */\nexport function TableRowsPerPageSelect(props: TableRowsPerPageSelectProps) {\n const { id, \"aria-label\": ariaLabel = \"Rows per page\" } = props;\n return (\n <Select\n defaultValue=\"10\"\n size=\"32\"\n aria-label={ariaLabel}\n className=\"w-[154px] [&_button]:rounded-sm [&_button]:border-transparent [&_button]:bg-inputs-inputs-primary\"\n id={id}\n >\n <SelectContent>\n <SelectItem value=\"10\">10 rows per page</SelectItem>\n <SelectItem value=\"25\">25 rows per page</SelectItem>\n <SelectItem value=\"50\">50 rows per page</SelectItem>\n </SelectContent>\n </Select>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -61,7 +61,14 @@ const TabsList = React.forwardRef(({ className, children, fullWidth = true, alig
|
|
|
61
61
|
});
|
|
62
62
|
const resizeObserver = new ResizeObserver(updateIndicator);
|
|
63
63
|
resizeObserver.observe(list);
|
|
64
|
+
let cancelled = false;
|
|
65
|
+
if (document.fonts?.status !== "loaded") {
|
|
66
|
+
document.fonts?.ready.then(() => {
|
|
67
|
+
if (!cancelled) updateIndicator();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
64
70
|
return () => {
|
|
71
|
+
cancelled = true;
|
|
65
72
|
mutationObserver.disconnect();
|
|
66
73
|
resizeObserver.disconnect();
|
|
67
74
|
};
|