@fanvue/ui 1.8.0 → 1.10.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/Chip/Chip.cjs +1 -1
- package/dist/cjs/components/Chip/Chip.cjs.map +1 -1
- package/dist/cjs/components/Count/Count.cjs +14 -2
- package/dist/cjs/components/Count/Count.cjs.map +1 -1
- package/dist/cjs/components/IconButton/IconButton.cjs +15 -1
- package/dist/cjs/components/IconButton/IconButton.cjs.map +1 -1
- package/dist/cjs/components/Tabs/TabsList.cjs +3 -2
- package/dist/cjs/components/Tabs/TabsList.cjs.map +1 -1
- package/dist/components/Chip/Chip.mjs +1 -1
- package/dist/components/Chip/Chip.mjs.map +1 -1
- package/dist/components/Count/Count.mjs +14 -2
- package/dist/components/Count/Count.mjs.map +1 -1
- package/dist/components/IconButton/IconButton.mjs +15 -1
- package/dist/components/IconButton/IconButton.mjs.map +1 -1
- package/dist/components/Tabs/TabsList.mjs +3 -2
- package/dist/components/Tabs/TabsList.mjs.map +1 -1
- package/dist/index.d.ts +13 -2
- package/package.json +3 -2
|
@@ -47,7 +47,7 @@ const Chip = React__namespace.forwardRef(
|
|
|
47
47
|
ref,
|
|
48
48
|
"data-testid": "chip",
|
|
49
49
|
className: cn.cn(
|
|
50
|
-
"typography-caption-semibold relative inline-flex items-center gap-2 px-3 motion-safe:transition-colors motion-safe:duration-150",
|
|
50
|
+
"typography-caption-semibold relative inline-flex items-center justify-center gap-2 whitespace-nowrap px-3 motion-safe:transition-colors motion-safe:duration-150",
|
|
51
51
|
// Shape
|
|
52
52
|
variant === "square" ? "rounded-lg" : "rounded-full",
|
|
53
53
|
// Size
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chip.cjs","sources":["../../../../src/components/Chip/Chip.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Visual variant of the chip. */\nexport type ChipVariant = \"rounded\" | \"square\" | \"dark\";\n/** Height of the chip in pixels. */\nexport type ChipSize = \"32\" | \"40\";\n\nexport interface ChipProps extends React.HTMLAttributes<HTMLElement> {\n /** Visual variant of the chip. @default \"rounded\" */\n variant?: ChipVariant;\n /** Height of the chip in pixels. @default \"32\" */\n size?: ChipSize;\n /** Whether the chip is in a selected (pressed) state. @default false */\n selected?: boolean;\n /** Whether the chip is disabled. @default false */\n disabled?: boolean;\n /** Whether to show a coloured status dot at the leading edge. @default false */\n leftDot?: boolean;\n /** Icon element displayed before the label. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed after the label. */\n rightIcon?: React.ReactNode;\n /** Notification badge content (e.g. `\"99+\"`). Passed as a string for i18n support. */\n notificationLabel?: string;\n /** Click handler — when provided, the chip renders as a `<button>` for accessibility. */\n onClick?: React.MouseEventHandler<HTMLElement>;\n /** Merge props onto a child element instead of rendering a wrapper. @default false */\n asChild?: boolean;\n}\n\n/**\n * A compact element for filters, tags, or toggleable actions. When an `onClick`\n * handler is provided, the chip renders as an interactive `<button>` with\n * `aria-pressed` support.\n *\n * @example\n * ```tsx\n * <Chip selected onClick={toggle}>Music</Chip>\n * ```\n */\nexport const Chip = React.forwardRef<HTMLButtonElement, ChipProps>(\n (\n {\n className,\n variant = \"rounded\",\n size = \"32\",\n selected = false,\n disabled = false,\n leftDot = false,\n leftIcon,\n rightIcon,\n notificationLabel,\n onClick,\n asChild = false,\n children,\n ...props\n },\n ref,\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Variant-heavy UI component\n ) => {\n const isInteractive = !!onClick && !asChild;\n const Comp = asChild ? Slot : isInteractive ? \"button\" : \"span\";\n const isDark = variant === \"dark\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"chip\"\n className={cn(\n \"typography-caption-semibold relative inline-flex items-center gap-2 px-3 motion-safe:transition-colors motion-safe:duration-150\",\n // Shape\n variant === \"square\" ? \"rounded-lg\" : \"rounded-full\",\n // Size\n size === \"32\" && \"h-8 py-1\",\n size === \"40\" && \"h-10 py-2.5\",\n // Variant colors\n isDark && \"bg-background-800 text-body-white-solid-constant\",\n !isDark && selected && \"bg-brand-green-50 text-neutral-400\",\n !isDark && !selected && \"bg-neutral-100 text-neutral-400\",\n // Hover\n isInteractive &&\n !disabled &&\n !isDark &&\n selected &&\n \"hover:bg-brand-green-500 hover:text-body-black-solid-constant active:bg-brand-green-500 active:text-body-black-solid-constant\",\n isInteractive &&\n !disabled &&\n !isDark &&\n !selected &&\n \"hover:bg-hover-400 active:bg-hover-400\",\n // Focus\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled\n disabled && isDark && \"pointer-events-none opacity-50\",\n disabled && !isDark && \"pointer-events-none text-neutral-300\",\n className,\n )}\n {...(isInteractive && {\n type: \"button\" as const,\n disabled,\n \"aria-pressed\": selected,\n onClick,\n })}\n {...(!isInteractive && disabled && { \"aria-disabled\": true })}\n {...(selected && { \"data-selected\": \"\" })}\n {...props}\n >\n {leftDot && <span className=\"size-2 shrink-0 rounded-full bg-current\" aria-hidden=\"true\" />}\n {leftIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n <Slottable>{children}</Slottable>\n {rightIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n {notificationLabel && (\n <span className=\"typography-caption-semibold absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-body-100 px-1 text-body-300\">\n {notificationLabel}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nChip.displayName = \"Chip\";\n"],"names":["React","Slot","jsxs","cn","jsx","Slottable"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0CO,MAAM,OAAOA,iBAAM;AAAA,EACxB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QAEG;AACH,UAAM,gBAAgB,CAAC,CAAC,WAAW,CAAC;AACpC,UAAM,OAAO,UAAUC,UAAAA,OAAO,gBAAgB,WAAW;AACzD,UAAM,SAAS,YAAY;AAE3B,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAWC,GAAAA;AAAAA,UACT;AAAA;AAAA,UAEA,YAAY,WAAW,eAAe;AAAA;AAAA,UAEtC,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA;AAAA,UAEjB,UAAU;AAAA,UACV,CAAC,UAAU,YAAY;AAAA,UACvB,CAAC,UAAU,CAAC,YAAY;AAAA;AAAA,UAExB,iBACE,CAAC,YACD,CAAC,UACD,YACA;AAAA,UACF,iBACE,CAAC,YACD,CAAC,UACD,CAAC,YACD;AAAA;AAAA,UAEF;AAAA;AAAA,UAEA,YAAY,UAAU;AAAA,UACtB,YAAY,CAAC,UAAU;AAAA,UACvB;AAAA,QAAA;AAAA,QAED,GAAI,iBAAiB;AAAA,UACpB,MAAM;AAAA,UACN;AAAA,UACA,gBAAgB;AAAA,UAChB;AAAA,QAAA;AAAA,QAED,GAAI,CAAC,iBAAiB,YAAY,EAAE,iBAAiB,KAAA;AAAA,QACrD,GAAI,YAAY,EAAE,iBAAiB,GAAA;AAAA,QACnC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,WAAWC,2BAAAA,IAAC,QAAA,EAAK,WAAU,2CAA0C,eAAY,QAAO;AAAA,UACxF,YACCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,UACH;AAAA,UAEFA,+BAACC,UAAAA,aAAW,UAAS;AAAA,UACpB,aACCD,2BAAAA,IAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,WACH;AAAA,UAED,qBACCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,iJACb,UAAA,kBAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;;"}
|
|
1
|
+
{"version":3,"file":"Chip.cjs","sources":["../../../../src/components/Chip/Chip.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Visual variant of the chip. */\nexport type ChipVariant = \"rounded\" | \"square\" | \"dark\";\n/** Height of the chip in pixels. */\nexport type ChipSize = \"32\" | \"40\";\n\nexport interface ChipProps extends React.HTMLAttributes<HTMLElement> {\n /** Visual variant of the chip. @default \"rounded\" */\n variant?: ChipVariant;\n /** Height of the chip in pixels. @default \"32\" */\n size?: ChipSize;\n /** Whether the chip is in a selected (pressed) state. @default false */\n selected?: boolean;\n /** Whether the chip is disabled. @default false */\n disabled?: boolean;\n /** Whether to show a coloured status dot at the leading edge. @default false */\n leftDot?: boolean;\n /** Icon element displayed before the label. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed after the label. */\n rightIcon?: React.ReactNode;\n /** Notification badge content (e.g. `\"99+\"`). Passed as a string for i18n support. */\n notificationLabel?: string;\n /** Click handler — when provided, the chip renders as a `<button>` for accessibility. */\n onClick?: React.MouseEventHandler<HTMLElement>;\n /** Merge props onto a child element instead of rendering a wrapper. @default false */\n asChild?: boolean;\n}\n\n/**\n * A compact element for filters, tags, or toggleable actions. When an `onClick`\n * handler is provided, the chip renders as an interactive `<button>` with\n * `aria-pressed` support.\n *\n * @example\n * ```tsx\n * <Chip selected onClick={toggle}>Music</Chip>\n * ```\n */\nexport const Chip = React.forwardRef<HTMLButtonElement, ChipProps>(\n (\n {\n className,\n variant = \"rounded\",\n size = \"32\",\n selected = false,\n disabled = false,\n leftDot = false,\n leftIcon,\n rightIcon,\n notificationLabel,\n onClick,\n asChild = false,\n children,\n ...props\n },\n ref,\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Variant-heavy UI component\n ) => {\n const isInteractive = !!onClick && !asChild;\n const Comp = asChild ? Slot : isInteractive ? \"button\" : \"span\";\n const isDark = variant === \"dark\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"chip\"\n className={cn(\n \"typography-caption-semibold relative inline-flex items-center justify-center gap-2 whitespace-nowrap px-3 motion-safe:transition-colors motion-safe:duration-150\",\n // Shape\n variant === \"square\" ? \"rounded-lg\" : \"rounded-full\",\n // Size\n size === \"32\" && \"h-8 py-1\",\n size === \"40\" && \"h-10 py-2.5\",\n // Variant colors\n isDark && \"bg-background-800 text-body-white-solid-constant\",\n !isDark && selected && \"bg-brand-green-50 text-neutral-400\",\n !isDark && !selected && \"bg-neutral-100 text-neutral-400\",\n // Hover\n isInteractive &&\n !disabled &&\n !isDark &&\n selected &&\n \"hover:bg-brand-green-500 hover:text-body-black-solid-constant active:bg-brand-green-500 active:text-body-black-solid-constant\",\n isInteractive &&\n !disabled &&\n !isDark &&\n !selected &&\n \"hover:bg-hover-400 active:bg-hover-400\",\n // Focus\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled\n disabled && isDark && \"pointer-events-none opacity-50\",\n disabled && !isDark && \"pointer-events-none text-neutral-300\",\n className,\n )}\n {...(isInteractive && {\n type: \"button\" as const,\n disabled,\n \"aria-pressed\": selected,\n onClick,\n })}\n {...(!isInteractive && disabled && { \"aria-disabled\": true })}\n {...(selected && { \"data-selected\": \"\" })}\n {...props}\n >\n {leftDot && <span className=\"size-2 shrink-0 rounded-full bg-current\" aria-hidden=\"true\" />}\n {leftIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n <Slottable>{children}</Slottable>\n {rightIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n {notificationLabel && (\n <span className=\"typography-caption-semibold absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-body-100 px-1 text-body-300\">\n {notificationLabel}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nChip.displayName = \"Chip\";\n"],"names":["React","Slot","jsxs","cn","jsx","Slottable"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0CO,MAAM,OAAOA,iBAAM;AAAA,EACxB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QAEG;AACH,UAAM,gBAAgB,CAAC,CAAC,WAAW,CAAC;AACpC,UAAM,OAAO,UAAUC,UAAAA,OAAO,gBAAgB,WAAW;AACzD,UAAM,SAAS,YAAY;AAE3B,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAWC,GAAAA;AAAAA,UACT;AAAA;AAAA,UAEA,YAAY,WAAW,eAAe;AAAA;AAAA,UAEtC,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA;AAAA,UAEjB,UAAU;AAAA,UACV,CAAC,UAAU,YAAY;AAAA,UACvB,CAAC,UAAU,CAAC,YAAY;AAAA;AAAA,UAExB,iBACE,CAAC,YACD,CAAC,UACD,YACA;AAAA,UACF,iBACE,CAAC,YACD,CAAC,UACD,CAAC,YACD;AAAA;AAAA,UAEF;AAAA;AAAA,UAEA,YAAY,UAAU;AAAA,UACtB,YAAY,CAAC,UAAU;AAAA,UACvB;AAAA,QAAA;AAAA,QAED,GAAI,iBAAiB;AAAA,UACpB,MAAM;AAAA,UACN;AAAA,UACA,gBAAgB;AAAA,UAChB;AAAA,QAAA;AAAA,QAED,GAAI,CAAC,iBAAiB,YAAY,EAAE,iBAAiB,KAAA;AAAA,QACrD,GAAI,YAAY,EAAE,iBAAiB,GAAA;AAAA,QACnC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,WAAWC,2BAAAA,IAAC,QAAA,EAAK,WAAU,2CAA0C,eAAY,QAAO;AAAA,UACxF,YACCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,UACH;AAAA,UAEFA,+BAACC,UAAAA,aAAW,UAAS;AAAA,UACpB,aACCD,2BAAAA,IAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,WACH;AAAA,UAED,qBACCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,iJACb,UAAA,kBAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;;"}
|
|
@@ -26,7 +26,16 @@ function getDisplayValue(value, max) {
|
|
|
26
26
|
return value > max ? `${max}+` : value.toString();
|
|
27
27
|
}
|
|
28
28
|
const Count = React__namespace.forwardRef(
|
|
29
|
-
({
|
|
29
|
+
({
|
|
30
|
+
className,
|
|
31
|
+
variant = "default",
|
|
32
|
+
value = 0,
|
|
33
|
+
max = 99,
|
|
34
|
+
size = "32",
|
|
35
|
+
asChild = false,
|
|
36
|
+
children,
|
|
37
|
+
...props
|
|
38
|
+
}, ref) => {
|
|
30
39
|
if (value === 0 && !children) {
|
|
31
40
|
return null;
|
|
32
41
|
}
|
|
@@ -36,7 +45,10 @@ const Count = React__namespace.forwardRef(
|
|
|
36
45
|
{
|
|
37
46
|
ref,
|
|
38
47
|
className: cn.cn(
|
|
39
|
-
"typography-caption-semibold inline-flex
|
|
48
|
+
"typography-caption-semibold inline-flex shrink-0 items-center justify-center rounded-full tabular-nums leading-none",
|
|
49
|
+
size === "16" && "h-3 min-w-3 px-0.5 text-[8px]",
|
|
50
|
+
size === "24" && "h-4 min-w-4 px-1 text-[10px]",
|
|
51
|
+
size === "32" && "h-5 min-w-5 px-1.5 text-[12px]",
|
|
40
52
|
variant === "default" && "bg-error-500 text-body-white-solid-constant",
|
|
41
53
|
variant === "brand" && "bg-brand-green-500 text-body-black-solid-constant",
|
|
42
54
|
variant === "pink" && "bg-brand-pink-500 text-body-black-solid-constant",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Count.cjs","sources":["../../../../src/components/Count/Count.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Colour variant for the count badge. */\nexport type CountVariant = \"default\" | \"brand\" | \"pink\" | \"info\" | \"success\" | \"warning\";\n\nfunction getDisplayValue(value: number, max: number): string {\n return value > max ? `${max}+` : value.toString();\n}\n\nexport interface CountProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Colour variant of the count badge. @default \"default\" */\n variant?: CountVariant;\n /** Numeric value to display. Renders nothing when `0` and no `children` are provided. @default 0 */\n value?: number;\n /** Maximum value before showing overflow (e.g. `\"99+\"`). @default 99 */\n max?: number;\n /** Merge props onto a child element instead of rendering a `<span>`. @default false */\n asChild?: boolean;\n}\n\n/**\n * A numeric badge typically used for notification counts. Automatically\n * truncates values above `max` (e.g. `\"99+\"`). Renders nothing when the\n * value is `0` and no children are provided.\n *\n * @example\n * ```tsx\n * <Count value={5} variant=\"brand\" />\n * ```\n */\nexport const Count = React.forwardRef<HTMLSpanElement, CountProps>(\n (\n {
|
|
1
|
+
{"version":3,"file":"Count.cjs","sources":["../../../../src/components/Count/Count.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Colour variant for the count badge. */\nexport type CountVariant = \"default\" | \"brand\" | \"pink\" | \"info\" | \"success\" | \"warning\";\n\n/** Size of the count badge, aligned with button and icon-button sizes. */\nexport type CountSize = \"16\" | \"24\" | \"32\";\n\nfunction getDisplayValue(value: number, max: number): string {\n return value > max ? `${max}+` : value.toString();\n}\n\nexport interface CountProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Colour variant of the count badge. @default \"default\" */\n variant?: CountVariant;\n /** Numeric value to display. Renders nothing when `0` and no `children` are provided. @default 0 */\n value?: number;\n /** Maximum value before showing overflow (e.g. `\"99+\"`). @default 99 */\n max?: number;\n /** Size of the count badge. @default \"32\" */\n size?: CountSize;\n /** Merge props onto a child element instead of rendering a `<span>`. @default false */\n asChild?: boolean;\n}\n\n/**\n * A numeric badge typically used for notification counts. Automatically\n * truncates values above `max` (e.g. `\"99+\"`). Renders nothing when the\n * value is `0` and no children are provided.\n *\n * @example\n * ```tsx\n * <Count value={5} variant=\"brand\" />\n * ```\n */\nexport const Count = React.forwardRef<HTMLSpanElement, CountProps>(\n (\n {\n className,\n variant = \"default\",\n value = 0,\n max = 99,\n size = \"32\",\n asChild = false,\n children,\n ...props\n },\n ref,\n ) => {\n if (value === 0 && !children) {\n return null;\n }\n\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n className={cn(\n \"typography-caption-semibold inline-flex shrink-0 items-center justify-center rounded-full tabular-nums leading-none\",\n size === \"16\" && \"h-3 min-w-3 px-0.5 text-[8px]\",\n size === \"24\" && \"h-4 min-w-4 px-1 text-[10px]\",\n size === \"32\" && \"h-5 min-w-5 px-1.5 text-[12px]\",\n variant === \"default\" && \"bg-error-500 text-body-white-solid-constant\",\n variant === \"brand\" && \"bg-brand-green-500 text-body-black-solid-constant\",\n variant === \"pink\" && \"bg-brand-pink-500 text-body-black-solid-constant\",\n variant === \"info\" && \"bg-info-500 text-body-white-solid-constant\",\n variant === \"success\" && \"bg-success-500 text-body-white-solid-constant\",\n variant === \"warning\" && \"bg-warning-500 text-body-black-solid-constant\",\n className,\n )}\n {...props}\n >\n {children ?? getDisplayValue(value, max)}\n </Comp>\n );\n },\n);\n\nCount.displayName = \"Count\";\n"],"names":["React","Slot","jsx","cn"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAUA,SAAS,gBAAgB,OAAe,KAAqB;AAC3D,SAAO,QAAQ,MAAM,GAAG,GAAG,MAAM,MAAM,SAAA;AACzC;AAyBO,MAAM,QAAQA,iBAAM;AAAA,EACzB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,QAAI,UAAU,KAAK,CAAC,UAAU;AAC5B,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,UAAUC,UAAAA,OAAO;AAE9B,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAWC,GAAAA;AAAAA,UACT;AAAA,UACA,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA,UACjB,YAAY,aAAa;AAAA,UACzB,YAAY,WAAW;AAAA,UACvB,YAAY,UAAU;AAAA,UACtB,YAAY,UAAU;AAAA,UACtB,YAAY,aAAa;AAAA,UACzB,YAAY,aAAa;AAAA,UACzB;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEH,UAAA,YAAY,gBAAgB,OAAO,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAG7C;AACF;AAEA,MAAM,cAAc;;"}
|
|
@@ -48,6 +48,13 @@ const sizeVariants = {
|
|
|
48
48
|
52: "p-2",
|
|
49
49
|
72: "p-4"
|
|
50
50
|
};
|
|
51
|
+
const countSizeMap = {
|
|
52
|
+
24: "16",
|
|
53
|
+
32: "24",
|
|
54
|
+
40: "32",
|
|
55
|
+
52: "32",
|
|
56
|
+
72: "32"
|
|
57
|
+
};
|
|
51
58
|
const IconButton = React__namespace.forwardRef(
|
|
52
59
|
({ className, variant = "primary", size = "40", icon, counterValue, disabled = false, ...props }, ref) => {
|
|
53
60
|
if (process.env.NODE_ENV !== "production") {
|
|
@@ -85,7 +92,14 @@ const IconButton = React__namespace.forwardRef(
|
|
|
85
92
|
children: icon
|
|
86
93
|
}
|
|
87
94
|
),
|
|
88
|
-
counterValue !== void 0 &&
|
|
95
|
+
counterValue !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
|
+
Count.Count,
|
|
97
|
+
{
|
|
98
|
+
value: counterValue,
|
|
99
|
+
size: countSizeMap[size],
|
|
100
|
+
className: "absolute -top-0.5 -right-0.5"
|
|
101
|
+
}
|
|
102
|
+
)
|
|
89
103
|
]
|
|
90
104
|
}
|
|
91
105
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.cjs","sources":["../../../../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Count } from \"../Count/Count\";\n\nconst iconButtonVariants = {\n primary:\n \"bg-neutral-400 text-body-300 hover:bg-hover-100 not-disabled:active:bg-hover-100 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n secondary:\n \"bg-neutral-100 text-neutral-400 hover:bg-neutral-200 not-disabled:active:bg-neutral-200 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiary:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n brand:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n contrast:\n \"bg-transparent text-body-white-solid-constant hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n messaging:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n navTray:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiaryDestructive:\n \"bg-transparent text-error-500 hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n stop: \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n microphone:\n \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n};\n\nconst iconSizeVariants = {\n 24: \"[&>svg]:size-4\",\n 32: \"[&>svg]:size-5\",\n 40: \"[&>svg]:size-6\",\n 52: \"[&>svg]:size-7\",\n 72: \"[&>svg]:size-8\",\n} as const;\n\nconst sizeVariants = {\n 24: \"p-1\",\n 32: \"p-1.5\",\n 40: \"p-[10px]\",\n 52: \"p-2\",\n 72: \"p-4\",\n} as const;\n\n/** Visual style variant of the icon button. */\nexport type IconButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"tertiary\"\n | \"brand\"\n | \"contrast\"\n | \"messaging\"\n | \"navTray\"\n | \"tertiaryDestructive\"\n | \"stop\"\n | \"microphone\";\n\n/** Icon button size in pixels. */\nexport type IconButtonSize = \"24\" | \"32\" | \"40\" | \"52\" | \"72\";\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant of the icon button. @default \"primary\" */\n variant?: IconButtonVariant;\n /** Size of the button in pixels. @default \"40\" */\n size?: IconButtonSize;\n /** Icon element to render inside the button. */\n icon: React.ReactNode;\n /** When provided, displays a {@link Count} badge at the top-right corner (tertiary & navTray variants only). */\n counterValue?: number;\n}\n\n/**\n * A circular button containing only an icon. Use when an action can be\n * represented by an icon alone (e.g. close, send, mic). Pair with an\n * `aria-label` for accessibility.\n *\n * @example\n * ```tsx\n * <IconButton icon={<CloseIcon />} aria-label=\"Close\" variant=\"tertiary\" />\n * ```\n */\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n (\n { className, variant = \"primary\", size = \"40\", icon, counterValue, disabled = false, ...props },\n ref,\n ) => {\n if (process.env.NODE_ENV !== \"production\") {\n if (!props[\"aria-label\"] && !props[\"aria-labelledby\"] && !props.title) {\n console.warn(\n \"IconButton: No accessible name provided. Add an `aria-label`, `aria-labelledby`, or `title` prop so screen readers can announce this button.\",\n );\n }\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-testid=\"icon-button\"\n disabled={disabled}\n className={cn(\n // Base styles\n \"relative inline-flex shrink-0 items-center justify-center focus-visible:outline-none\",\n \"cursor-pointer rounded-full transition-all duration-150 ease-in-out disabled:cursor-default\",\n // Size variants\n sizeVariants[size],\n // Variant styles\n iconButtonVariants[variant],\n // Manual CSS overrides\n className,\n )}\n {...props}\n >\n <span\n className={cn(\"flex shrink-0 items-center justify-center\", iconSizeVariants[size])}\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n\n {counterValue !== undefined && (
|
|
1
|
+
{"version":3,"file":"IconButton.cjs","sources":["../../../../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Count, type CountSize } from \"../Count/Count\";\n\nconst iconButtonVariants = {\n primary:\n \"bg-neutral-400 text-body-300 hover:bg-hover-100 not-disabled:active:bg-hover-100 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n secondary:\n \"bg-neutral-100 text-neutral-400 hover:bg-neutral-200 not-disabled:active:bg-neutral-200 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiary:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n brand:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n contrast:\n \"bg-transparent text-body-white-solid-constant hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n messaging:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n navTray:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiaryDestructive:\n \"bg-transparent text-error-500 hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n stop: \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n microphone:\n \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n};\n\nconst iconSizeVariants = {\n 24: \"[&>svg]:size-4\",\n 32: \"[&>svg]:size-5\",\n 40: \"[&>svg]:size-6\",\n 52: \"[&>svg]:size-7\",\n 72: \"[&>svg]:size-8\",\n} as const;\n\nconst sizeVariants = {\n 24: \"p-1\",\n 32: \"p-1.5\",\n 40: \"p-[10px]\",\n 52: \"p-2\",\n 72: \"p-4\",\n} as const;\n\nconst countSizeMap: Record<string, CountSize> = {\n 24: \"16\",\n 32: \"24\",\n 40: \"32\",\n 52: \"32\",\n 72: \"32\",\n};\n\n/** Visual style variant of the icon button. */\nexport type IconButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"tertiary\"\n | \"brand\"\n | \"contrast\"\n | \"messaging\"\n | \"navTray\"\n | \"tertiaryDestructive\"\n | \"stop\"\n | \"microphone\";\n\n/** Icon button size in pixels. */\nexport type IconButtonSize = \"24\" | \"32\" | \"40\" | \"52\" | \"72\";\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant of the icon button. @default \"primary\" */\n variant?: IconButtonVariant;\n /** Size of the button in pixels. @default \"40\" */\n size?: IconButtonSize;\n /** Icon element to render inside the button. */\n icon: React.ReactNode;\n /** When provided, displays a {@link Count} badge at the top-right corner (tertiary & navTray variants only). */\n counterValue?: number;\n}\n\n/**\n * A circular button containing only an icon. Use when an action can be\n * represented by an icon alone (e.g. close, send, mic). Pair with an\n * `aria-label` for accessibility.\n *\n * @example\n * ```tsx\n * <IconButton icon={<CloseIcon />} aria-label=\"Close\" variant=\"tertiary\" />\n * ```\n */\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n (\n { className, variant = \"primary\", size = \"40\", icon, counterValue, disabled = false, ...props },\n ref,\n ) => {\n if (process.env.NODE_ENV !== \"production\") {\n if (!props[\"aria-label\"] && !props[\"aria-labelledby\"] && !props.title) {\n console.warn(\n \"IconButton: No accessible name provided. Add an `aria-label`, `aria-labelledby`, or `title` prop so screen readers can announce this button.\",\n );\n }\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-testid=\"icon-button\"\n disabled={disabled}\n className={cn(\n // Base styles\n \"relative inline-flex shrink-0 items-center justify-center focus-visible:outline-none\",\n \"cursor-pointer rounded-full transition-all duration-150 ease-in-out disabled:cursor-default\",\n // Size variants\n sizeVariants[size],\n // Variant styles\n iconButtonVariants[variant],\n // Manual CSS overrides\n className,\n )}\n {...props}\n >\n <span\n className={cn(\"flex shrink-0 items-center justify-center\", iconSizeVariants[size])}\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n\n {counterValue !== undefined && (\n <Count\n value={counterValue}\n size={countSizeMap[size]}\n className=\"absolute -top-0.5 -right-0.5\"\n />\n )}\n </button>\n );\n },\n);\n\nIconButton.displayName = \"IconButton\";\n"],"names":["React","jsxs","cn","jsx","Count"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,qBAAqB;AAAA,EACzB,SACE;AAAA,EACF,WACE;AAAA,EACF,UACE;AAAA,EACF,OACE;AAAA,EACF,UACE;AAAA,EACF,WACE;AAAA,EACF,SACE;AAAA,EACF,qBACE;AAAA,EACF,MAAM;AAAA,EACN,YACE;AACJ;AAEA,MAAM,mBAAmB;AAAA,EACvB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAAe;AAAA,EACnB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAA0C;AAAA,EAC9C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAuCO,MAAM,aAAaA,iBAAM;AAAA,EAC9B,CACE,EAAE,WAAW,UAAU,WAAW,OAAO,MAAM,MAAM,cAAc,WAAW,OAAO,GAAG,MAAA,GACxF,QACG;AACH,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,UAAI,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,MAAM,OAAO;AACrE,gBAAQ;AAAA,UACN;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAEA,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,eAAY;AAAA,QACZ;AAAA,QACA,WAAWC,GAAAA;AAAAA;AAAAA,UAET;AAAA,UACA;AAAA;AAAA,UAEA,aAAa,IAAI;AAAA;AAAA,UAEjB,mBAAmB,OAAO;AAAA;AAAA,UAE1B;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAAC,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWD,GAAAA,GAAG,6CAA6C,iBAAiB,IAAI,CAAC;AAAA,cACjF,eAAY;AAAA,cAEX,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGF,iBAAiB,UAChBC,2BAAAA;AAAAA,YAACC,MAAAA;AAAAA,YAAA;AAAA,cACC,OAAO;AAAA,cACP,MAAM,aAAa,IAAI;AAAA,cACvB,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACZ;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,WAAW,cAAc;;"}
|
|
@@ -23,7 +23,7 @@ function _interopNamespaceDefault(e) {
|
|
|
23
23
|
}
|
|
24
24
|
const TabsPrimitive__namespace = /* @__PURE__ */ _interopNamespaceDefault(TabsPrimitive);
|
|
25
25
|
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
26
|
-
const TabsList = React__namespace.forwardRef(({ className, children, ...props }, ref) => {
|
|
26
|
+
const TabsList = React__namespace.forwardRef(({ className, children, fullWidth = true, ...props }, ref) => {
|
|
27
27
|
const innerRef = React__namespace.useRef(null);
|
|
28
28
|
const indicatorRef = React__namespace.useRef(null);
|
|
29
29
|
React__namespace.useImperativeHandle(ref, () => innerRef.current);
|
|
@@ -77,7 +77,8 @@ const TabsList = React__namespace.forwardRef(({ className, children, ...props },
|
|
|
77
77
|
{
|
|
78
78
|
ref: innerRef,
|
|
79
79
|
className: cn.cn(
|
|
80
|
-
"relative
|
|
80
|
+
"relative",
|
|
81
|
+
fullWidth ? "flex w-full [&>[role=tab]]:flex-1" : "inline-flex",
|
|
81
82
|
"data-[orientation=horizontal]:items-center data-[orientation=horizontal]:shadow-[inset_0_-1px_0_0_var(--color-neutral-200)]",
|
|
82
83
|
"data-[orientation=vertical]:flex-col data-[orientation=vertical]:shadow-[inset_-1px_0_0_0_var(--color-neutral-200)]",
|
|
83
84
|
className
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabsList.cjs","sources":["../../../../src/components/Tabs/TabsList.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsList} component. */\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List
|
|
1
|
+
{"version":3,"file":"TabsList.cjs","sources":["../../../../src/components/Tabs/TabsList.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsList} component. */\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {\n /** When `true` (the default), the tab list spans the full width of its container and each tab grows equally. Set to `false` for inline sizing. */\n fullWidth?: boolean;\n};\n\n/** Container for {@link TabsTrigger} elements. Renders a sliding active-tab indicator that animates between tabs. */\nexport const TabsList = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, children, fullWidth = true, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null);\n const indicatorRef = React.useRef<HTMLSpanElement>(null);\n\n React.useImperativeHandle(ref, () => innerRef.current as HTMLDivElement);\n\n const updateIndicator = React.useCallback(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n const activeTab = list.querySelector<HTMLElement>('[data-state=\"active\"]');\n if (!activeTab) {\n indicator.style.opacity = \"0\";\n return;\n }\n\n const isVertical = list.dataset.orientation === \"vertical\";\n\n indicator.style.opacity = \"1\";\n\n if (isVertical) {\n indicator.style.inset = `0 0 auto auto`;\n indicator.style.width = \"4px\";\n indicator.style.height = `${activeTab.offsetHeight}px`;\n indicator.style.transform = `translateY(${activeTab.offsetTop}px)`;\n } else {\n indicator.style.inset = `auto auto 0 0`;\n indicator.style.height = \"4px\";\n indicator.style.width = `${activeTab.offsetWidth}px`;\n indicator.style.transform = `translateX(${activeTab.offsetLeft}px)`;\n }\n }, []);\n\n React.useLayoutEffect(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n indicator.style.transitionDuration = \"0s\";\n updateIndicator();\n indicator.getBoundingClientRect();\n indicator.style.transitionDuration = \"\";\n\n const mutationObserver = new MutationObserver(updateIndicator);\n mutationObserver.observe(list, {\n attributes: true,\n attributeFilter: [\"data-state\"],\n childList: true,\n subtree: true,\n });\n\n const resizeObserver = new ResizeObserver(updateIndicator);\n resizeObserver.observe(list);\n\n return () => {\n mutationObserver.disconnect();\n resizeObserver.disconnect();\n };\n }, [updateIndicator]);\n\n return (\n <TabsPrimitive.List\n ref={innerRef}\n className={cn(\n \"relative\",\n fullWidth ? \"flex w-full [&>[role=tab]]:flex-1\" : \"inline-flex\",\n \"data-[orientation=horizontal]:items-center data-[orientation=horizontal]:shadow-[inset_0_-1px_0_0_var(--color-neutral-200)]\",\n \"data-[orientation=vertical]:flex-col data-[orientation=vertical]:shadow-[inset_-1px_0_0_0_var(--color-neutral-200)]\",\n className,\n )}\n {...props}\n >\n {children}\n <span\n ref={indicatorRef}\n aria-hidden\n className=\"pointer-events-none absolute rounded-full bg-brand-green-500 motion-safe:transition-[transform,width,height] motion-safe:duration-200 motion-safe:ease-in-out\"\n style={{ opacity: 0 }}\n />\n </TabsPrimitive.List>\n );\n});\n\nTabsList.displayName = \"TabsList\";\n"],"names":["React","jsxs","TabsPrimitive","cn","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAWO,MAAM,WAAWA,iBAAM,WAG5B,CAAC,EAAE,WAAW,UAAU,YAAY,MAAM,GAAG,MAAA,GAAS,QAAQ;AAC9D,QAAM,WAAWA,iBAAM,OAAuB,IAAI;AAClD,QAAM,eAAeA,iBAAM,OAAwB,IAAI;AAEvDA,mBAAM,oBAAoB,KAAK,MAAM,SAAS,OAAyB;AAEvE,QAAM,kBAAkBA,iBAAM,YAAY,MAAM;AAC9C,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,UAAM,YAAY,KAAK,cAA2B,uBAAuB;AACzE,QAAI,CAAC,WAAW;AACd,gBAAU,MAAM,UAAU;AAC1B;AAAA,IACF;AAEA,UAAM,aAAa,KAAK,QAAQ,gBAAgB;AAEhD,cAAU,MAAM,UAAU;AAE1B,QAAI,YAAY;AACd,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS,GAAG,UAAU,YAAY;AAClD,gBAAU,MAAM,YAAY,cAAc,UAAU,SAAS;AAAA,IAC/D,OAAO;AACL,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS;AACzB,gBAAU,MAAM,QAAQ,GAAG,UAAU,WAAW;AAChD,gBAAU,MAAM,YAAY,cAAc,UAAU,UAAU;AAAA,IAChE;AAAA,EACF,GAAG,CAAA,CAAE;AAELA,mBAAM,gBAAgB,MAAM;AAC1B,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,cAAU,MAAM,qBAAqB;AACrC,oBAAA;AACA,cAAU,sBAAA;AACV,cAAU,MAAM,qBAAqB;AAErC,UAAM,mBAAmB,IAAI,iBAAiB,eAAe;AAC7D,qBAAiB,QAAQ,MAAM;AAAA,MAC7B,YAAY;AAAA,MACZ,iBAAiB,CAAC,YAAY;AAAA,MAC9B,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,CACV;AAED,UAAM,iBAAiB,IAAI,eAAe,eAAe;AACzD,mBAAe,QAAQ,IAAI;AAE3B,WAAO,MAAM;AACX,uBAAiB,WAAA;AACjB,qBAAe,WAAA;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAEpB,SACEC,2BAAAA;AAAAA,IAACC,yBAAc;AAAA,IAAd;AAAA,MACC,KAAK;AAAA,MACL,WAAWC,GAAAA;AAAAA,QACT;AAAA,QACA,YAAY,sCAAsC;AAAA,QAClD;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA;AAAA,QACDC,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,eAAW;AAAA,YACX,WAAU;AAAA,YACV,OAAO,EAAE,SAAS,EAAA;AAAA,UAAE;AAAA,QAAA;AAAA,MACtB;AAAA,IAAA;AAAA,EAAA;AAGN,CAAC;AAED,SAAS,cAAc;;"}
|
|
@@ -28,7 +28,7 @@ const Chip = React.forwardRef(
|
|
|
28
28
|
ref,
|
|
29
29
|
"data-testid": "chip",
|
|
30
30
|
className: cn(
|
|
31
|
-
"typography-caption-semibold relative inline-flex items-center gap-2 px-3 motion-safe:transition-colors motion-safe:duration-150",
|
|
31
|
+
"typography-caption-semibold relative inline-flex items-center justify-center gap-2 whitespace-nowrap px-3 motion-safe:transition-colors motion-safe:duration-150",
|
|
32
32
|
// Shape
|
|
33
33
|
variant === "square" ? "rounded-lg" : "rounded-full",
|
|
34
34
|
// Size
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chip.mjs","sources":["../../../src/components/Chip/Chip.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Visual variant of the chip. */\nexport type ChipVariant = \"rounded\" | \"square\" | \"dark\";\n/** Height of the chip in pixels. */\nexport type ChipSize = \"32\" | \"40\";\n\nexport interface ChipProps extends React.HTMLAttributes<HTMLElement> {\n /** Visual variant of the chip. @default \"rounded\" */\n variant?: ChipVariant;\n /** Height of the chip in pixels. @default \"32\" */\n size?: ChipSize;\n /** Whether the chip is in a selected (pressed) state. @default false */\n selected?: boolean;\n /** Whether the chip is disabled. @default false */\n disabled?: boolean;\n /** Whether to show a coloured status dot at the leading edge. @default false */\n leftDot?: boolean;\n /** Icon element displayed before the label. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed after the label. */\n rightIcon?: React.ReactNode;\n /** Notification badge content (e.g. `\"99+\"`). Passed as a string for i18n support. */\n notificationLabel?: string;\n /** Click handler — when provided, the chip renders as a `<button>` for accessibility. */\n onClick?: React.MouseEventHandler<HTMLElement>;\n /** Merge props onto a child element instead of rendering a wrapper. @default false */\n asChild?: boolean;\n}\n\n/**\n * A compact element for filters, tags, or toggleable actions. When an `onClick`\n * handler is provided, the chip renders as an interactive `<button>` with\n * `aria-pressed` support.\n *\n * @example\n * ```tsx\n * <Chip selected onClick={toggle}>Music</Chip>\n * ```\n */\nexport const Chip = React.forwardRef<HTMLButtonElement, ChipProps>(\n (\n {\n className,\n variant = \"rounded\",\n size = \"32\",\n selected = false,\n disabled = false,\n leftDot = false,\n leftIcon,\n rightIcon,\n notificationLabel,\n onClick,\n asChild = false,\n children,\n ...props\n },\n ref,\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Variant-heavy UI component\n ) => {\n const isInteractive = !!onClick && !asChild;\n const Comp = asChild ? Slot : isInteractive ? \"button\" : \"span\";\n const isDark = variant === \"dark\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"chip\"\n className={cn(\n \"typography-caption-semibold relative inline-flex items-center gap-2 px-3 motion-safe:transition-colors motion-safe:duration-150\",\n // Shape\n variant === \"square\" ? \"rounded-lg\" : \"rounded-full\",\n // Size\n size === \"32\" && \"h-8 py-1\",\n size === \"40\" && \"h-10 py-2.5\",\n // Variant colors\n isDark && \"bg-background-800 text-body-white-solid-constant\",\n !isDark && selected && \"bg-brand-green-50 text-neutral-400\",\n !isDark && !selected && \"bg-neutral-100 text-neutral-400\",\n // Hover\n isInteractive &&\n !disabled &&\n !isDark &&\n selected &&\n \"hover:bg-brand-green-500 hover:text-body-black-solid-constant active:bg-brand-green-500 active:text-body-black-solid-constant\",\n isInteractive &&\n !disabled &&\n !isDark &&\n !selected &&\n \"hover:bg-hover-400 active:bg-hover-400\",\n // Focus\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled\n disabled && isDark && \"pointer-events-none opacity-50\",\n disabled && !isDark && \"pointer-events-none text-neutral-300\",\n className,\n )}\n {...(isInteractive && {\n type: \"button\" as const,\n disabled,\n \"aria-pressed\": selected,\n onClick,\n })}\n {...(!isInteractive && disabled && { \"aria-disabled\": true })}\n {...(selected && { \"data-selected\": \"\" })}\n {...props}\n >\n {leftDot && <span className=\"size-2 shrink-0 rounded-full bg-current\" aria-hidden=\"true\" />}\n {leftIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n <Slottable>{children}</Slottable>\n {rightIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n {notificationLabel && (\n <span className=\"typography-caption-semibold absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-body-100 px-1 text-body-300\">\n {notificationLabel}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nChip.displayName = \"Chip\";\n"],"names":[],"mappings":";;;;;AA0CO,MAAM,OAAO,MAAM;AAAA,EACxB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QAEG;AACH,UAAM,gBAAgB,CAAC,CAAC,WAAW,CAAC;AACpC,UAAM,OAAO,UAAU,OAAO,gBAAgB,WAAW;AACzD,UAAM,SAAS,YAAY;AAE3B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA;AAAA,UAEA,YAAY,WAAW,eAAe;AAAA;AAAA,UAEtC,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA;AAAA,UAEjB,UAAU;AAAA,UACV,CAAC,UAAU,YAAY;AAAA,UACvB,CAAC,UAAU,CAAC,YAAY;AAAA;AAAA,UAExB,iBACE,CAAC,YACD,CAAC,UACD,YACA;AAAA,UACF,iBACE,CAAC,YACD,CAAC,UACD,CAAC,YACD;AAAA;AAAA,UAEF;AAAA;AAAA,UAEA,YAAY,UAAU;AAAA,UACtB,YAAY,CAAC,UAAU;AAAA,UACvB;AAAA,QAAA;AAAA,QAED,GAAI,iBAAiB;AAAA,UACpB,MAAM;AAAA,UACN;AAAA,UACA,gBAAgB;AAAA,UAChB;AAAA,QAAA;AAAA,QAED,GAAI,CAAC,iBAAiB,YAAY,EAAE,iBAAiB,KAAA;AAAA,QACrD,GAAI,YAAY,EAAE,iBAAiB,GAAA;AAAA,QACnC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,WAAW,oBAAC,QAAA,EAAK,WAAU,2CAA0C,eAAY,QAAO;AAAA,UACxF,YACC,oBAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,UACH;AAAA,UAEF,oBAAC,aAAW,UAAS;AAAA,UACpB,aACC,oBAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,WACH;AAAA,UAED,qBACC,oBAAC,QAAA,EAAK,WAAU,iJACb,UAAA,kBAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;"}
|
|
1
|
+
{"version":3,"file":"Chip.mjs","sources":["../../../src/components/Chip/Chip.tsx"],"sourcesContent":["import { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Visual variant of the chip. */\nexport type ChipVariant = \"rounded\" | \"square\" | \"dark\";\n/** Height of the chip in pixels. */\nexport type ChipSize = \"32\" | \"40\";\n\nexport interface ChipProps extends React.HTMLAttributes<HTMLElement> {\n /** Visual variant of the chip. @default \"rounded\" */\n variant?: ChipVariant;\n /** Height of the chip in pixels. @default \"32\" */\n size?: ChipSize;\n /** Whether the chip is in a selected (pressed) state. @default false */\n selected?: boolean;\n /** Whether the chip is disabled. @default false */\n disabled?: boolean;\n /** Whether to show a coloured status dot at the leading edge. @default false */\n leftDot?: boolean;\n /** Icon element displayed before the label. */\n leftIcon?: React.ReactNode;\n /** Icon element displayed after the label. */\n rightIcon?: React.ReactNode;\n /** Notification badge content (e.g. `\"99+\"`). Passed as a string for i18n support. */\n notificationLabel?: string;\n /** Click handler — when provided, the chip renders as a `<button>` for accessibility. */\n onClick?: React.MouseEventHandler<HTMLElement>;\n /** Merge props onto a child element instead of rendering a wrapper. @default false */\n asChild?: boolean;\n}\n\n/**\n * A compact element for filters, tags, or toggleable actions. When an `onClick`\n * handler is provided, the chip renders as an interactive `<button>` with\n * `aria-pressed` support.\n *\n * @example\n * ```tsx\n * <Chip selected onClick={toggle}>Music</Chip>\n * ```\n */\nexport const Chip = React.forwardRef<HTMLButtonElement, ChipProps>(\n (\n {\n className,\n variant = \"rounded\",\n size = \"32\",\n selected = false,\n disabled = false,\n leftDot = false,\n leftIcon,\n rightIcon,\n notificationLabel,\n onClick,\n asChild = false,\n children,\n ...props\n },\n ref,\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Variant-heavy UI component\n ) => {\n const isInteractive = !!onClick && !asChild;\n const Comp = asChild ? Slot : isInteractive ? \"button\" : \"span\";\n const isDark = variant === \"dark\";\n\n return (\n <Comp\n ref={ref}\n data-testid=\"chip\"\n className={cn(\n \"typography-caption-semibold relative inline-flex items-center justify-center gap-2 whitespace-nowrap px-3 motion-safe:transition-colors motion-safe:duration-150\",\n // Shape\n variant === \"square\" ? \"rounded-lg\" : \"rounded-full\",\n // Size\n size === \"32\" && \"h-8 py-1\",\n size === \"40\" && \"h-10 py-2.5\",\n // Variant colors\n isDark && \"bg-background-800 text-body-white-solid-constant\",\n !isDark && selected && \"bg-brand-green-50 text-neutral-400\",\n !isDark && !selected && \"bg-neutral-100 text-neutral-400\",\n // Hover\n isInteractive &&\n !disabled &&\n !isDark &&\n selected &&\n \"hover:bg-brand-green-500 hover:text-body-black-solid-constant active:bg-brand-green-500 active:text-body-black-solid-constant\",\n isInteractive &&\n !disabled &&\n !isDark &&\n !selected &&\n \"hover:bg-hover-400 active:bg-hover-400\",\n // Focus\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n // Disabled\n disabled && isDark && \"pointer-events-none opacity-50\",\n disabled && !isDark && \"pointer-events-none text-neutral-300\",\n className,\n )}\n {...(isInteractive && {\n type: \"button\" as const,\n disabled,\n \"aria-pressed\": selected,\n onClick,\n })}\n {...(!isInteractive && disabled && { \"aria-disabled\": true })}\n {...(selected && { \"data-selected\": \"\" })}\n {...props}\n >\n {leftDot && <span className=\"size-2 shrink-0 rounded-full bg-current\" aria-hidden=\"true\" />}\n {leftIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n <Slottable>{children}</Slottable>\n {rightIcon && (\n <span className=\"flex size-5 shrink-0 items-center justify-center\" aria-hidden=\"true\">\n {rightIcon}\n </span>\n )}\n {notificationLabel && (\n <span className=\"typography-caption-semibold absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-body-100 px-1 text-body-300\">\n {notificationLabel}\n </span>\n )}\n </Comp>\n );\n },\n);\n\nChip.displayName = \"Chip\";\n"],"names":[],"mappings":";;;;;AA0CO,MAAM,OAAO,MAAM;AAAA,EACxB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QAEG;AACH,UAAM,gBAAgB,CAAC,CAAC,WAAW,CAAC;AACpC,UAAM,OAAO,UAAU,OAAO,gBAAgB,WAAW;AACzD,UAAM,SAAS,YAAY;AAE3B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA;AAAA,UAEA,YAAY,WAAW,eAAe;AAAA;AAAA,UAEtC,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA;AAAA,UAEjB,UAAU;AAAA,UACV,CAAC,UAAU,YAAY;AAAA,UACvB,CAAC,UAAU,CAAC,YAAY;AAAA;AAAA,UAExB,iBACE,CAAC,YACD,CAAC,UACD,YACA;AAAA,UACF,iBACE,CAAC,YACD,CAAC,UACD,CAAC,YACD;AAAA;AAAA,UAEF;AAAA;AAAA,UAEA,YAAY,UAAU;AAAA,UACtB,YAAY,CAAC,UAAU;AAAA,UACvB;AAAA,QAAA;AAAA,QAED,GAAI,iBAAiB;AAAA,UACpB,MAAM;AAAA,UACN;AAAA,UACA,gBAAgB;AAAA,UAChB;AAAA,QAAA;AAAA,QAED,GAAI,CAAC,iBAAiB,YAAY,EAAE,iBAAiB,KAAA;AAAA,QACrD,GAAI,YAAY,EAAE,iBAAiB,GAAA;AAAA,QACnC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,WAAW,oBAAC,QAAA,EAAK,WAAU,2CAA0C,eAAY,QAAO;AAAA,UACxF,YACC,oBAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,UACH;AAAA,UAEF,oBAAC,aAAW,UAAS;AAAA,UACpB,aACC,oBAAC,QAAA,EAAK,WAAU,oDAAmD,eAAY,QAC5E,UAAA,WACH;AAAA,UAED,qBACC,oBAAC,QAAA,EAAK,WAAU,iJACb,UAAA,kBAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;"}
|
|
@@ -7,7 +7,16 @@ function getDisplayValue(value, max) {
|
|
|
7
7
|
return value > max ? `${max}+` : value.toString();
|
|
8
8
|
}
|
|
9
9
|
const Count = React.forwardRef(
|
|
10
|
-
({
|
|
10
|
+
({
|
|
11
|
+
className,
|
|
12
|
+
variant = "default",
|
|
13
|
+
value = 0,
|
|
14
|
+
max = 99,
|
|
15
|
+
size = "32",
|
|
16
|
+
asChild = false,
|
|
17
|
+
children,
|
|
18
|
+
...props
|
|
19
|
+
}, ref) => {
|
|
11
20
|
if (value === 0 && !children) {
|
|
12
21
|
return null;
|
|
13
22
|
}
|
|
@@ -17,7 +26,10 @@ const Count = React.forwardRef(
|
|
|
17
26
|
{
|
|
18
27
|
ref,
|
|
19
28
|
className: cn(
|
|
20
|
-
"typography-caption-semibold inline-flex
|
|
29
|
+
"typography-caption-semibold inline-flex shrink-0 items-center justify-center rounded-full tabular-nums leading-none",
|
|
30
|
+
size === "16" && "h-3 min-w-3 px-0.5 text-[8px]",
|
|
31
|
+
size === "24" && "h-4 min-w-4 px-1 text-[10px]",
|
|
32
|
+
size === "32" && "h-5 min-w-5 px-1.5 text-[12px]",
|
|
21
33
|
variant === "default" && "bg-error-500 text-body-white-solid-constant",
|
|
22
34
|
variant === "brand" && "bg-brand-green-500 text-body-black-solid-constant",
|
|
23
35
|
variant === "pink" && "bg-brand-pink-500 text-body-black-solid-constant",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Count.mjs","sources":["../../../src/components/Count/Count.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Colour variant for the count badge. */\nexport type CountVariant = \"default\" | \"brand\" | \"pink\" | \"info\" | \"success\" | \"warning\";\n\nfunction getDisplayValue(value: number, max: number): string {\n return value > max ? `${max}+` : value.toString();\n}\n\nexport interface CountProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Colour variant of the count badge. @default \"default\" */\n variant?: CountVariant;\n /** Numeric value to display. Renders nothing when `0` and no `children` are provided. @default 0 */\n value?: number;\n /** Maximum value before showing overflow (e.g. `\"99+\"`). @default 99 */\n max?: number;\n /** Merge props onto a child element instead of rendering a `<span>`. @default false */\n asChild?: boolean;\n}\n\n/**\n * A numeric badge typically used for notification counts. Automatically\n * truncates values above `max` (e.g. `\"99+\"`). Renders nothing when the\n * value is `0` and no children are provided.\n *\n * @example\n * ```tsx\n * <Count value={5} variant=\"brand\" />\n * ```\n */\nexport const Count = React.forwardRef<HTMLSpanElement, CountProps>(\n (\n {
|
|
1
|
+
{"version":3,"file":"Count.mjs","sources":["../../../src/components/Count/Count.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Colour variant for the count badge. */\nexport type CountVariant = \"default\" | \"brand\" | \"pink\" | \"info\" | \"success\" | \"warning\";\n\n/** Size of the count badge, aligned with button and icon-button sizes. */\nexport type CountSize = \"16\" | \"24\" | \"32\";\n\nfunction getDisplayValue(value: number, max: number): string {\n return value > max ? `${max}+` : value.toString();\n}\n\nexport interface CountProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Colour variant of the count badge. @default \"default\" */\n variant?: CountVariant;\n /** Numeric value to display. Renders nothing when `0` and no `children` are provided. @default 0 */\n value?: number;\n /** Maximum value before showing overflow (e.g. `\"99+\"`). @default 99 */\n max?: number;\n /** Size of the count badge. @default \"32\" */\n size?: CountSize;\n /** Merge props onto a child element instead of rendering a `<span>`. @default false */\n asChild?: boolean;\n}\n\n/**\n * A numeric badge typically used for notification counts. Automatically\n * truncates values above `max` (e.g. `\"99+\"`). Renders nothing when the\n * value is `0` and no children are provided.\n *\n * @example\n * ```tsx\n * <Count value={5} variant=\"brand\" />\n * ```\n */\nexport const Count = React.forwardRef<HTMLSpanElement, CountProps>(\n (\n {\n className,\n variant = \"default\",\n value = 0,\n max = 99,\n size = \"32\",\n asChild = false,\n children,\n ...props\n },\n ref,\n ) => {\n if (value === 0 && !children) {\n return null;\n }\n\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n ref={ref}\n className={cn(\n \"typography-caption-semibold inline-flex shrink-0 items-center justify-center rounded-full tabular-nums leading-none\",\n size === \"16\" && \"h-3 min-w-3 px-0.5 text-[8px]\",\n size === \"24\" && \"h-4 min-w-4 px-1 text-[10px]\",\n size === \"32\" && \"h-5 min-w-5 px-1.5 text-[12px]\",\n variant === \"default\" && \"bg-error-500 text-body-white-solid-constant\",\n variant === \"brand\" && \"bg-brand-green-500 text-body-black-solid-constant\",\n variant === \"pink\" && \"bg-brand-pink-500 text-body-black-solid-constant\",\n variant === \"info\" && \"bg-info-500 text-body-white-solid-constant\",\n variant === \"success\" && \"bg-success-500 text-body-white-solid-constant\",\n variant === \"warning\" && \"bg-warning-500 text-body-black-solid-constant\",\n className,\n )}\n {...props}\n >\n {children ?? getDisplayValue(value, max)}\n </Comp>\n );\n },\n);\n\nCount.displayName = \"Count\";\n"],"names":[],"mappings":";;;;;AAUA,SAAS,gBAAgB,OAAe,KAAqB;AAC3D,SAAO,QAAQ,MAAM,GAAG,GAAG,MAAM,MAAM,SAAA;AACzC;AAyBO,MAAM,QAAQ,MAAM;AAAA,EACzB,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,IACP,UAAU;AAAA,IACV;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,QAAI,UAAU,KAAK,CAAC,UAAU;AAC5B,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,UAAU,OAAO;AAE9B,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA,UACjB,YAAY,aAAa;AAAA,UACzB,YAAY,WAAW;AAAA,UACvB,YAAY,UAAU;AAAA,UACtB,YAAY,UAAU;AAAA,UACtB,YAAY,aAAa;AAAA,UACzB,YAAY,aAAa;AAAA,UACzB;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEH,UAAA,YAAY,gBAAgB,OAAO,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EAG7C;AACF;AAEA,MAAM,cAAc;"}
|
|
@@ -29,6 +29,13 @@ const sizeVariants = {
|
|
|
29
29
|
52: "p-2",
|
|
30
30
|
72: "p-4"
|
|
31
31
|
};
|
|
32
|
+
const countSizeMap = {
|
|
33
|
+
24: "16",
|
|
34
|
+
32: "24",
|
|
35
|
+
40: "32",
|
|
36
|
+
52: "32",
|
|
37
|
+
72: "32"
|
|
38
|
+
};
|
|
32
39
|
const IconButton = React.forwardRef(
|
|
33
40
|
({ className, variant = "primary", size = "40", icon, counterValue, disabled = false, ...props }, ref) => {
|
|
34
41
|
if (process.env.NODE_ENV !== "production") {
|
|
@@ -66,7 +73,14 @@ const IconButton = React.forwardRef(
|
|
|
66
73
|
children: icon
|
|
67
74
|
}
|
|
68
75
|
),
|
|
69
|
-
counterValue !== void 0 &&
|
|
76
|
+
counterValue !== void 0 && /* @__PURE__ */ jsx(
|
|
77
|
+
Count,
|
|
78
|
+
{
|
|
79
|
+
value: counterValue,
|
|
80
|
+
size: countSizeMap[size],
|
|
81
|
+
className: "absolute -top-0.5 -right-0.5"
|
|
82
|
+
}
|
|
83
|
+
)
|
|
70
84
|
]
|
|
71
85
|
}
|
|
72
86
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.mjs","sources":["../../../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Count } from \"../Count/Count\";\n\nconst iconButtonVariants = {\n primary:\n \"bg-neutral-400 text-body-300 hover:bg-hover-100 not-disabled:active:bg-hover-100 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n secondary:\n \"bg-neutral-100 text-neutral-400 hover:bg-neutral-200 not-disabled:active:bg-neutral-200 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiary:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n brand:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n contrast:\n \"bg-transparent text-body-white-solid-constant hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n messaging:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n navTray:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiaryDestructive:\n \"bg-transparent text-error-500 hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n stop: \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n microphone:\n \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n};\n\nconst iconSizeVariants = {\n 24: \"[&>svg]:size-4\",\n 32: \"[&>svg]:size-5\",\n 40: \"[&>svg]:size-6\",\n 52: \"[&>svg]:size-7\",\n 72: \"[&>svg]:size-8\",\n} as const;\n\nconst sizeVariants = {\n 24: \"p-1\",\n 32: \"p-1.5\",\n 40: \"p-[10px]\",\n 52: \"p-2\",\n 72: \"p-4\",\n} as const;\n\n/** Visual style variant of the icon button. */\nexport type IconButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"tertiary\"\n | \"brand\"\n | \"contrast\"\n | \"messaging\"\n | \"navTray\"\n | \"tertiaryDestructive\"\n | \"stop\"\n | \"microphone\";\n\n/** Icon button size in pixels. */\nexport type IconButtonSize = \"24\" | \"32\" | \"40\" | \"52\" | \"72\";\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant of the icon button. @default \"primary\" */\n variant?: IconButtonVariant;\n /** Size of the button in pixels. @default \"40\" */\n size?: IconButtonSize;\n /** Icon element to render inside the button. */\n icon: React.ReactNode;\n /** When provided, displays a {@link Count} badge at the top-right corner (tertiary & navTray variants only). */\n counterValue?: number;\n}\n\n/**\n * A circular button containing only an icon. Use when an action can be\n * represented by an icon alone (e.g. close, send, mic). Pair with an\n * `aria-label` for accessibility.\n *\n * @example\n * ```tsx\n * <IconButton icon={<CloseIcon />} aria-label=\"Close\" variant=\"tertiary\" />\n * ```\n */\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n (\n { className, variant = \"primary\", size = \"40\", icon, counterValue, disabled = false, ...props },\n ref,\n ) => {\n if (process.env.NODE_ENV !== \"production\") {\n if (!props[\"aria-label\"] && !props[\"aria-labelledby\"] && !props.title) {\n console.warn(\n \"IconButton: No accessible name provided. Add an `aria-label`, `aria-labelledby`, or `title` prop so screen readers can announce this button.\",\n );\n }\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-testid=\"icon-button\"\n disabled={disabled}\n className={cn(\n // Base styles\n \"relative inline-flex shrink-0 items-center justify-center focus-visible:outline-none\",\n \"cursor-pointer rounded-full transition-all duration-150 ease-in-out disabled:cursor-default\",\n // Size variants\n sizeVariants[size],\n // Variant styles\n iconButtonVariants[variant],\n // Manual CSS overrides\n className,\n )}\n {...props}\n >\n <span\n className={cn(\"flex shrink-0 items-center justify-center\", iconSizeVariants[size])}\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n\n {counterValue !== undefined && (
|
|
1
|
+
{"version":3,"file":"IconButton.mjs","sources":["../../../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Count, type CountSize } from \"../Count/Count\";\n\nconst iconButtonVariants = {\n primary:\n \"bg-neutral-400 text-body-300 hover:bg-hover-100 not-disabled:active:bg-hover-100 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n secondary:\n \"bg-neutral-100 text-neutral-400 hover:bg-neutral-200 not-disabled:active:bg-neutral-200 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiary:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n brand:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n contrast:\n \"bg-transparent text-body-white-solid-constant hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n messaging:\n \"bg-body-black-solid-constant text-brand-green-500 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n navTray:\n \"bg-transparent text-neutral-400 hover:bg-hover-300 not-disabled:active:bg-brand-green-50 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n tertiaryDestructive:\n \"bg-transparent text-error-500 hover:bg-hover-300 not-disabled:active:bg-hover-300 disabled:opacity-50 focus-visible:shadow-focus-ring\",\n stop: \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n microphone:\n \"bg-neutral-400 text-body-300 hover:bg-brand-green-500 hover:text-body-black-solid-constant not-disabled:active:bg-brand-green-500 not-disabled:active:text-body-black-solid-constant disabled:opacity-50 focus-visible:shadow-focus-ring\",\n};\n\nconst iconSizeVariants = {\n 24: \"[&>svg]:size-4\",\n 32: \"[&>svg]:size-5\",\n 40: \"[&>svg]:size-6\",\n 52: \"[&>svg]:size-7\",\n 72: \"[&>svg]:size-8\",\n} as const;\n\nconst sizeVariants = {\n 24: \"p-1\",\n 32: \"p-1.5\",\n 40: \"p-[10px]\",\n 52: \"p-2\",\n 72: \"p-4\",\n} as const;\n\nconst countSizeMap: Record<string, CountSize> = {\n 24: \"16\",\n 32: \"24\",\n 40: \"32\",\n 52: \"32\",\n 72: \"32\",\n};\n\n/** Visual style variant of the icon button. */\nexport type IconButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"tertiary\"\n | \"brand\"\n | \"contrast\"\n | \"messaging\"\n | \"navTray\"\n | \"tertiaryDestructive\"\n | \"stop\"\n | \"microphone\";\n\n/** Icon button size in pixels. */\nexport type IconButtonSize = \"24\" | \"32\" | \"40\" | \"52\" | \"72\";\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant of the icon button. @default \"primary\" */\n variant?: IconButtonVariant;\n /** Size of the button in pixels. @default \"40\" */\n size?: IconButtonSize;\n /** Icon element to render inside the button. */\n icon: React.ReactNode;\n /** When provided, displays a {@link Count} badge at the top-right corner (tertiary & navTray variants only). */\n counterValue?: number;\n}\n\n/**\n * A circular button containing only an icon. Use when an action can be\n * represented by an icon alone (e.g. close, send, mic). Pair with an\n * `aria-label` for accessibility.\n *\n * @example\n * ```tsx\n * <IconButton icon={<CloseIcon />} aria-label=\"Close\" variant=\"tertiary\" />\n * ```\n */\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n (\n { className, variant = \"primary\", size = \"40\", icon, counterValue, disabled = false, ...props },\n ref,\n ) => {\n if (process.env.NODE_ENV !== \"production\") {\n if (!props[\"aria-label\"] && !props[\"aria-labelledby\"] && !props.title) {\n console.warn(\n \"IconButton: No accessible name provided. Add an `aria-label`, `aria-labelledby`, or `title` prop so screen readers can announce this button.\",\n );\n }\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-testid=\"icon-button\"\n disabled={disabled}\n className={cn(\n // Base styles\n \"relative inline-flex shrink-0 items-center justify-center focus-visible:outline-none\",\n \"cursor-pointer rounded-full transition-all duration-150 ease-in-out disabled:cursor-default\",\n // Size variants\n sizeVariants[size],\n // Variant styles\n iconButtonVariants[variant],\n // Manual CSS overrides\n className,\n )}\n {...props}\n >\n <span\n className={cn(\"flex shrink-0 items-center justify-center\", iconSizeVariants[size])}\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n\n {counterValue !== undefined && (\n <Count\n value={counterValue}\n size={countSizeMap[size]}\n className=\"absolute -top-0.5 -right-0.5\"\n />\n )}\n </button>\n );\n },\n);\n\nIconButton.displayName = \"IconButton\";\n"],"names":[],"mappings":";;;;;AAIA,MAAM,qBAAqB;AAAA,EACzB,SACE;AAAA,EACF,WACE;AAAA,EACF,UACE;AAAA,EACF,OACE;AAAA,EACF,UACE;AAAA,EACF,WACE;AAAA,EACF,SACE;AAAA,EACF,qBACE;AAAA,EACF,MAAM;AAAA,EACN,YACE;AACJ;AAEA,MAAM,mBAAmB;AAAA,EACvB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAAe;AAAA,EACnB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,MAAM,eAA0C;AAAA,EAC9C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAuCO,MAAM,aAAa,MAAM;AAAA,EAC9B,CACE,EAAE,WAAW,UAAU,WAAW,OAAO,MAAM,MAAM,cAAc,WAAW,OAAO,GAAG,MAAA,GACxF,QACG;AACH,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,UAAI,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,MAAM,OAAO;AACrE,gBAAQ;AAAA,UACN;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,eAAY;AAAA,QACZ;AAAA,QACA,WAAW;AAAA;AAAA,UAET;AAAA,UACA;AAAA;AAAA,UAEA,aAAa,IAAI;AAAA;AAAA,UAEjB,mBAAmB,OAAO;AAAA;AAAA,UAE1B;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW,GAAG,6CAA6C,iBAAiB,IAAI,CAAC;AAAA,cACjF,eAAY;AAAA,cAEX,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGF,iBAAiB,UAChB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,cACP,MAAM,aAAa,IAAI;AAAA,cACvB,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACZ;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,WAAW,cAAc;"}
|
|
@@ -3,7 +3,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { cn } from "../../utils/cn.mjs";
|
|
6
|
-
const TabsList = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
6
|
+
const TabsList = React.forwardRef(({ className, children, fullWidth = true, ...props }, ref) => {
|
|
7
7
|
const innerRef = React.useRef(null);
|
|
8
8
|
const indicatorRef = React.useRef(null);
|
|
9
9
|
React.useImperativeHandle(ref, () => innerRef.current);
|
|
@@ -57,7 +57,8 @@ const TabsList = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
|
57
57
|
{
|
|
58
58
|
ref: innerRef,
|
|
59
59
|
className: cn(
|
|
60
|
-
"relative
|
|
60
|
+
"relative",
|
|
61
|
+
fullWidth ? "flex w-full [&>[role=tab]]:flex-1" : "inline-flex",
|
|
61
62
|
"data-[orientation=horizontal]:items-center data-[orientation=horizontal]:shadow-[inset_0_-1px_0_0_var(--color-neutral-200)]",
|
|
62
63
|
"data-[orientation=vertical]:flex-col data-[orientation=vertical]:shadow-[inset_-1px_0_0_0_var(--color-neutral-200)]",
|
|
63
64
|
className
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabsList.mjs","sources":["../../../src/components/Tabs/TabsList.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsList} component. */\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List
|
|
1
|
+
{"version":3,"file":"TabsList.mjs","sources":["../../../src/components/Tabs/TabsList.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsList} component. */\nexport type TabsListProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {\n /** When `true` (the default), the tab list spans the full width of its container and each tab grows equally. Set to `false` for inline sizing. */\n fullWidth?: boolean;\n};\n\n/** Container for {@link TabsTrigger} elements. Renders a sliding active-tab indicator that animates between tabs. */\nexport const TabsList = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, children, fullWidth = true, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null);\n const indicatorRef = React.useRef<HTMLSpanElement>(null);\n\n React.useImperativeHandle(ref, () => innerRef.current as HTMLDivElement);\n\n const updateIndicator = React.useCallback(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n const activeTab = list.querySelector<HTMLElement>('[data-state=\"active\"]');\n if (!activeTab) {\n indicator.style.opacity = \"0\";\n return;\n }\n\n const isVertical = list.dataset.orientation === \"vertical\";\n\n indicator.style.opacity = \"1\";\n\n if (isVertical) {\n indicator.style.inset = `0 0 auto auto`;\n indicator.style.width = \"4px\";\n indicator.style.height = `${activeTab.offsetHeight}px`;\n indicator.style.transform = `translateY(${activeTab.offsetTop}px)`;\n } else {\n indicator.style.inset = `auto auto 0 0`;\n indicator.style.height = \"4px\";\n indicator.style.width = `${activeTab.offsetWidth}px`;\n indicator.style.transform = `translateX(${activeTab.offsetLeft}px)`;\n }\n }, []);\n\n React.useLayoutEffect(() => {\n const list = innerRef.current;\n const indicator = indicatorRef.current;\n if (!list || !indicator) return;\n\n indicator.style.transitionDuration = \"0s\";\n updateIndicator();\n indicator.getBoundingClientRect();\n indicator.style.transitionDuration = \"\";\n\n const mutationObserver = new MutationObserver(updateIndicator);\n mutationObserver.observe(list, {\n attributes: true,\n attributeFilter: [\"data-state\"],\n childList: true,\n subtree: true,\n });\n\n const resizeObserver = new ResizeObserver(updateIndicator);\n resizeObserver.observe(list);\n\n return () => {\n mutationObserver.disconnect();\n resizeObserver.disconnect();\n };\n }, [updateIndicator]);\n\n return (\n <TabsPrimitive.List\n ref={innerRef}\n className={cn(\n \"relative\",\n fullWidth ? \"flex w-full [&>[role=tab]]:flex-1\" : \"inline-flex\",\n \"data-[orientation=horizontal]:items-center data-[orientation=horizontal]:shadow-[inset_0_-1px_0_0_var(--color-neutral-200)]\",\n \"data-[orientation=vertical]:flex-col data-[orientation=vertical]:shadow-[inset_-1px_0_0_0_var(--color-neutral-200)]\",\n className,\n )}\n {...props}\n >\n {children}\n <span\n ref={indicatorRef}\n aria-hidden\n className=\"pointer-events-none absolute rounded-full bg-brand-green-500 motion-safe:transition-[transform,width,height] motion-safe:duration-200 motion-safe:ease-in-out\"\n style={{ opacity: 0 }}\n />\n </TabsPrimitive.List>\n );\n});\n\nTabsList.displayName = \"TabsList\";\n"],"names":[],"mappings":";;;;;AAWO,MAAM,WAAW,MAAM,WAG5B,CAAC,EAAE,WAAW,UAAU,YAAY,MAAM,GAAG,MAAA,GAAS,QAAQ;AAC9D,QAAM,WAAW,MAAM,OAAuB,IAAI;AAClD,QAAM,eAAe,MAAM,OAAwB,IAAI;AAEvD,QAAM,oBAAoB,KAAK,MAAM,SAAS,OAAyB;AAEvE,QAAM,kBAAkB,MAAM,YAAY,MAAM;AAC9C,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,UAAM,YAAY,KAAK,cAA2B,uBAAuB;AACzE,QAAI,CAAC,WAAW;AACd,gBAAU,MAAM,UAAU;AAC1B;AAAA,IACF;AAEA,UAAM,aAAa,KAAK,QAAQ,gBAAgB;AAEhD,cAAU,MAAM,UAAU;AAE1B,QAAI,YAAY;AACd,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS,GAAG,UAAU,YAAY;AAClD,gBAAU,MAAM,YAAY,cAAc,UAAU,SAAS;AAAA,IAC/D,OAAO;AACL,gBAAU,MAAM,QAAQ;AACxB,gBAAU,MAAM,SAAS;AACzB,gBAAU,MAAM,QAAQ,GAAG,UAAU,WAAW;AAChD,gBAAU,MAAM,YAAY,cAAc,UAAU,UAAU;AAAA,IAChE;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,QAAM,gBAAgB,MAAM;AAC1B,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,QAAQ,CAAC,UAAW;AAEzB,cAAU,MAAM,qBAAqB;AACrC,oBAAA;AACA,cAAU,sBAAA;AACV,cAAU,MAAM,qBAAqB;AAErC,UAAM,mBAAmB,IAAI,iBAAiB,eAAe;AAC7D,qBAAiB,QAAQ,MAAM;AAAA,MAC7B,YAAY;AAAA,MACZ,iBAAiB,CAAC,YAAY;AAAA,MAC9B,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,CACV;AAED,UAAM,iBAAiB,IAAI,eAAe,eAAe;AACzD,mBAAe,QAAQ,IAAI;AAE3B,WAAO,MAAM;AACX,uBAAiB,WAAA;AACjB,qBAAe,WAAA;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAEpB,SACE;AAAA,IAAC,cAAc;AAAA,IAAd;AAAA,MACC,KAAK;AAAA,MACL,WAAW;AAAA,QACT;AAAA,QACA,YAAY,sCAAsC;AAAA,QAClD;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA;AAAA,QACD;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK;AAAA,YACL,eAAW;AAAA,YACX,WAAU;AAAA,YACV,OAAO,EAAE,SAAS,EAAA;AAAA,UAAE;AAAA,QAAA;AAAA,MACtB;AAAA,IAAA;AAAA,EAAA;AAGN,CAAC;AAED,SAAS,cAAc;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -378,10 +378,15 @@ export declare interface CountProps extends React_2.HTMLAttributes<HTMLSpanEleme
|
|
|
378
378
|
value?: number;
|
|
379
379
|
/** Maximum value before showing overflow (e.g. `"99+"`). @default 99 */
|
|
380
380
|
max?: number;
|
|
381
|
+
/** Size of the count badge. @default "32" */
|
|
382
|
+
size?: CountSize;
|
|
381
383
|
/** Merge props onto a child element instead of rendering a `<span>`. @default false */
|
|
382
384
|
asChild?: boolean;
|
|
383
385
|
}
|
|
384
386
|
|
|
387
|
+
/** Size of the count badge, aligned with button and icon-button sizes. */
|
|
388
|
+
export declare type CountSize = "16" | "24" | "32";
|
|
389
|
+
|
|
385
390
|
/** Colour variant for the count badge. */
|
|
386
391
|
export declare type CountVariant = "default" | "brand" | "pink" | "info" | "success" | "warning";
|
|
387
392
|
|
|
@@ -1085,10 +1090,16 @@ export declare const TabsContent: React_2.ForwardRefExoticComponent<Omit<TabsPri
|
|
|
1085
1090
|
export declare type TabsContentProps = React_2.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>;
|
|
1086
1091
|
|
|
1087
1092
|
/** Container for {@link TabsTrigger} elements. Renders a sliding active-tab indicator that animates between tabs. */
|
|
1088
|
-
export declare const TabsList: React_2.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & React_2.RefAttributes<HTMLDivElement>, "ref"> &
|
|
1093
|
+
export declare const TabsList: React_2.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & React_2.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
1094
|
+
/** When `true` (the default), the tab list spans the full width of its container and each tab grows equally. Set to `false` for inline sizing. */
|
|
1095
|
+
fullWidth?: boolean;
|
|
1096
|
+
} & React_2.RefAttributes<HTMLDivElement>>;
|
|
1089
1097
|
|
|
1090
1098
|
/** Props for the {@link TabsList} component. */
|
|
1091
|
-
export declare type TabsListProps = React_2.ComponentPropsWithoutRef<typeof TabsPrimitive.List
|
|
1099
|
+
export declare type TabsListProps = React_2.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {
|
|
1100
|
+
/** When `true` (the default), the tab list spans the full width of its container and each tab grows equally. Set to `false` for inline sizing. */
|
|
1101
|
+
fullWidth?: boolean;
|
|
1102
|
+
};
|
|
1092
1103
|
|
|
1093
1104
|
/** Props for the {@link Tabs} root component. Extends Radix `Tabs.Root` props. */
|
|
1094
1105
|
export declare type TabsProps = React_2.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanvue/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "React component library built with Tailwind CSS for Fanvue ecosystem",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org",
|
|
@@ -137,7 +137,8 @@
|
|
|
137
137
|
"overrides": {
|
|
138
138
|
"@isaacs/brace-expansion": ">=5.0.1",
|
|
139
139
|
"qs": ">=6.14.2",
|
|
140
|
-
"minimatch": ">=10.2.1"
|
|
140
|
+
"minimatch": ">=10.2.1",
|
|
141
|
+
"rollup": ">=4.59.0"
|
|
141
142
|
}
|
|
142
143
|
},
|
|
143
144
|
"size-limit": [
|