@fanvue/ui 1.15.0 → 1.16.1
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/Badge/Badge.cjs +2 -2
- package/dist/cjs/components/Badge/Badge.cjs.map +1 -1
- package/dist/cjs/components/Breadcrumb/Breadcrumb.cjs +96 -0
- package/dist/cjs/components/Breadcrumb/Breadcrumb.cjs.map +1 -0
- package/dist/cjs/components/Button/Button.cjs +5 -2
- package/dist/cjs/components/Button/Button.cjs.map +1 -1
- package/dist/cjs/components/Card/Card.cjs +105 -0
- package/dist/cjs/components/Card/Card.cjs.map +1 -0
- package/dist/cjs/components/Chip/Chip.cjs +2 -2
- package/dist/cjs/components/Chip/Chip.cjs.map +1 -1
- package/dist/cjs/components/Pill/Pill.cjs +2 -2
- package/dist/cjs/components/Pill/Pill.cjs.map +1 -1
- package/dist/cjs/components/Select/Select.cjs +1 -0
- package/dist/cjs/components/Select/Select.cjs.map +1 -1
- package/dist/cjs/components/Skeleton/Skeleton.cjs +7 -3
- package/dist/cjs/components/Skeleton/Skeleton.cjs.map +1 -1
- package/dist/cjs/components/SwitchToggle/SwitchToggle.cjs +2 -2
- package/dist/cjs/components/SwitchToggle/SwitchToggle.cjs.map +1 -1
- package/dist/cjs/components/Tabs/TabsTrigger.cjs +4 -3
- package/dist/cjs/components/Tabs/TabsTrigger.cjs.map +1 -1
- package/dist/cjs/components/Tooltip/Tooltip.cjs +2 -1
- package/dist/cjs/components/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/cjs/index.cjs +14 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/components/Badge/Badge.mjs +2 -2
- package/dist/components/Badge/Badge.mjs.map +1 -1
- package/dist/components/Breadcrumb/Breadcrumb.mjs +79 -0
- package/dist/components/Breadcrumb/Breadcrumb.mjs.map +1 -0
- package/dist/components/Button/Button.mjs +5 -2
- package/dist/components/Button/Button.mjs.map +1 -1
- package/dist/components/Card/Card.mjs +88 -0
- package/dist/components/Card/Card.mjs.map +1 -0
- package/dist/components/Chip/Chip.mjs +2 -2
- package/dist/components/Chip/Chip.mjs.map +1 -1
- package/dist/components/Pill/Pill.mjs +2 -2
- package/dist/components/Pill/Pill.mjs.map +1 -1
- package/dist/components/Select/Select.mjs +1 -0
- package/dist/components/Select/Select.mjs.map +1 -1
- package/dist/components/Skeleton/Skeleton.mjs +7 -3
- package/dist/components/Skeleton/Skeleton.mjs.map +1 -1
- package/dist/components/SwitchToggle/SwitchToggle.mjs +2 -2
- package/dist/components/SwitchToggle/SwitchToggle.mjs.map +1 -1
- package/dist/components/Tabs/TabsTrigger.mjs +4 -3
- package/dist/components/Tabs/TabsTrigger.mjs.map +1 -1
- package/dist/components/Tooltip/Tooltip.mjs +2 -1
- package/dist/components/Tooltip/Tooltip.mjs.map +1 -1
- package/dist/index.d.ts +137 -0
- package/dist/index.mjs +14 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -36,7 +36,7 @@ const Pill = React.forwardRef(
|
|
|
36
36
|
"data-testid": "pill",
|
|
37
37
|
className: cn(
|
|
38
38
|
// Base styles
|
|
39
|
-
"inline-flex items-center justify-center gap-2 rounded-full px-3 py-1",
|
|
39
|
+
"inline-flex min-w-0 items-center justify-center gap-2 rounded-full px-3 py-1",
|
|
40
40
|
// Typography
|
|
41
41
|
"typography-semibold-body-sm",
|
|
42
42
|
// Variant styles
|
|
@@ -50,7 +50,7 @@ const Pill = React.forwardRef(
|
|
|
50
50
|
...props,
|
|
51
51
|
children: [
|
|
52
52
|
leftIcon && /* @__PURE__ */ jsx("span", { className: "flex", "aria-hidden": "true", children: leftIcon }),
|
|
53
|
-
/* @__PURE__ */ jsx(Slottable, { children }),
|
|
53
|
+
asChild ? /* @__PURE__ */ jsx(Slottable, { children }) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children }),
|
|
54
54
|
rightIcon && /* @__PURE__ */ jsx("span", { className: "flex", "aria-hidden": "true", children: rightIcon })
|
|
55
55
|
]
|
|
56
56
|
}
|
|
@@ -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-background text-success-default\",\n grey: \"bg-neutral-100 text-foreground-secondary\",\n blue: \"bg-info-background text-info-default\",\n gold: \"bg-warning-background text-warning-default\",\n pinkLight: \"bg-brand-secondary-muted text-foreground-default\",\n base: \"bg-neutral-solid text-foreground-inverse\",\n brand: \"bg-brand-accent-default text-foreground-onaccent\",\n brandLight: \"bg-brand-accent-muted text-foreground-onaccent\",\n beta: \"bg-brand-secondary-default text-foreground-onaccent\",\n error: \"bg-error-default text-error-background\",\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 items-center justify-center gap-2 rounded-full px-3 py-1\",\n // Typography\n \"typography-semibold-body-sm\",\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\" aria-hidden=\"true\">\n {leftIcon}\n </span>\n )}\n <Slottable>{children}</Slottable>\n {rightIcon && (\n <span className=\"flex\" 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;AAEX;AAkCO,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,QAAO,eAAY,QAChC,UAAA,UACH;AAAA,
|
|
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-background text-success-default\",\n grey: \"bg-neutral-100 text-foreground-secondary\",\n blue: \"bg-info-background text-info-default\",\n gold: \"bg-warning-background text-warning-default\",\n pinkLight: \"bg-brand-secondary-muted text-foreground-default\",\n base: \"bg-neutral-solid text-foreground-inverse\",\n brand: \"bg-brand-accent-default text-foreground-onaccent\",\n brandLight: \"bg-brand-accent-muted text-foreground-onaccent\",\n beta: \"bg-brand-secondary-default text-foreground-onaccent\",\n error: \"bg-error-default text-error-background\",\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-semibold-body-sm\",\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\" 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\" 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;AAEX;AAkCO,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,QAAO,eAAY,QAChC,UAAA,UACH;AAAA,UAED,8BACE,WAAA,EAAW,SAAA,CAAS,IAErB,oBAAC,QAAA,EAAK,WAAU,oBAAoB,SAAA,CAAS;AAAA,UAE9C,aACC,oBAAC,QAAA,EAAK,WAAU,QAAO,eAAY,QAChC,UAAA,UAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,KAAK,cAAc;"}
|
|
@@ -127,6 +127,7 @@ const SelectContent = React.forwardRef(({ className, children, position = "poppe
|
|
|
127
127
|
ref,
|
|
128
128
|
position,
|
|
129
129
|
sideOffset,
|
|
130
|
+
collisionPadding: 8,
|
|
130
131
|
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
131
132
|
className: cn(
|
|
132
133
|
"relative min-w-(--radix-select-trigger-width) overflow-hidden rounded-xl border border-neutral-200 bg-surface-page text-foreground-default shadow-[0_4px_16px_rgba(0,0,0,0.10)]",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.mjs","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\n\n/** Select field height in pixels. */\nexport type SelectSize = \"48\" | \"40\" | \"32\";\n\ntype SelectContextValue = {\n size: SelectSize;\n error: boolean;\n disabled?: boolean;\n};\n\nconst SelectContext = React.createContext<SelectContextValue>({\n size: \"48\",\n error: false,\n});\n\nconst TRIGGER_HEIGHT: Record<SelectSize, string> = {\n \"48\": \"h-12\",\n \"40\": \"h-10\",\n \"32\": \"h-8\",\n};\n\nconst TRIGGER_PADDING_X: Record<SelectSize, string> = {\n \"48\": \"px-4\",\n \"40\": \"px-4\",\n \"32\": \"px-3\",\n};\n\nconst TRIGGER_GAP: Record<SelectSize, string> = {\n \"48\": \"gap-3\",\n \"40\": \"gap-3\",\n \"32\": \"gap-2\",\n};\n\nconst TRIGGER_TYPOGRAPHY: Record<SelectSize, string> = {\n \"48\": \"typography-regular-body-lg\",\n \"40\": \"typography-regular-body-lg\",\n \"32\": \"typography-regular-body-md\",\n};\n\nexport interface SelectProps extends Omit<SelectPrimitive.SelectProps, \"dir\"> {\n /** Label text displayed above the trigger. Also used as the accessible name. */\n label?: string;\n /** Accessible name applied directly to the trigger button when no visible `label` is provided. */\n \"aria-label\"?: string;\n /** ID of an external element that labels the trigger button. */\n \"aria-labelledby\"?: string;\n /** Helper text displayed below the trigger. Replaced by `errorMessage` when `error` is `true`. */\n helperText?: string;\n /** Height of the select field in pixels. @default \"48\" */\n size?: SelectSize;\n /** Whether the field is in an error state. @default false */\n error?: boolean;\n /** Error message displayed below the trigger. Shown instead of `helperText` when `error` is `true`. */\n errorMessage?: string;\n /** Placeholder shown when no value is selected. */\n placeholder?: string;\n /** Icon element displayed at the left side of the trigger. */\n leftIcon?: React.ReactNode;\n /** Whether the field stretches to fill its container width. @default false */\n fullWidth?: boolean;\n /** Wraps the `className` of the outermost container div. */\n className?: string;\n /** HTML `id` applied to the trigger button. Auto-generated if omitted. */\n id?: string;\n}\n\n/**\n * A select field with optional label, helper/error text, and an icon slot,\n * built on Radix UI Select for full accessibility and keyboard navigation.\n *\n * Pair with {@link SelectContent} and {@link SelectItem} to provide options.\n *\n * @example\n * ```tsx\n * <Select label=\"Country\" placeholder=\"Select a country\">\n * <SelectContent>\n * <SelectItem value=\"us\">United States</SelectItem>\n * <SelectItem value=\"uk\">United Kingdom</SelectItem>\n * </SelectContent>\n * </Select>\n * ```\n */\nexport const Select = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Trigger>,\n SelectProps\n>(\n (\n {\n label,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n placeholder,\n leftIcon,\n fullWidth = false,\n className,\n id,\n disabled,\n children,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const triggerId = id ?? generatedId;\n const helperTextId = `${triggerId}-helper`;\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n return (\n <SelectContext.Provider value={{ size, error, disabled }}>\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={triggerId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <SelectPrimitive.Root disabled={disabled} {...props}>\n <SelectPrimitive.Trigger\n ref={ref}\n id={triggerId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n aria-describedby={bottomText ? helperTextId : undefined}\n aria-invalid={error || undefined}\n className={cn(\n \"flex w-full cursor-pointer items-center justify-between rounded-xl border bg-neutral-100 outline-none motion-safe:transition-colors\",\n TRIGGER_HEIGHT[size],\n TRIGGER_PADDING_X[size],\n TRIGGER_GAP[size],\n TRIGGER_TYPOGRAPHY[size],\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled &&\n !error &&\n \"hover:border-neutral-400 data-[state=open]:border-neutral-400\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <div className=\"flex min-w-0 items-center gap-2\">\n {leftIcon && (\n <span\n className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\"\n data-testid=\"left-icon\"\n >\n {leftIcon}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate text-left text-foreground-default [&>[data-placeholder]]:text-foreground-secondary [&>[data-placeholder]]:opacity-40\">\n <SelectPrimitive.Value placeholder={placeholder} />\n </span>\n </div>\n\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n\n {children}\n </SelectPrimitive.Root>\n\n {bottomText && (\n <p\n id={helperTextId}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {bottomText}\n </p>\n )}\n </div>\n </SelectContext.Provider>\n );\n },\n);\n\nSelect.displayName = \"Select\";\n\nexport interface SelectContentProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> {}\n\n/**\n * The dropdown panel rendered inside a portal. Place {@link SelectItem} elements\n * (and optionally {@link SelectGroup} / {@link SelectLabel}) as children.\n */\nexport const SelectContent = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Content>,\n SelectContentProps\n>(({ className, children, position = \"popper\", sideOffset = 4, style, ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n sideOffset={sideOffset}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"relative min-w-(--radix-select-trigger-width) overflow-hidden rounded-xl border border-neutral-200 bg-surface-page text-foreground-default shadow-[0_4px_16px_rgba(0,0,0,0.10)]\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.Viewport className=\"max-h-[var(--radix-select-content-available-height)] overflow-y-auto p-1\">\n {children}\n </SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\n\nSelectContent.displayName = \"SelectContent\";\n\nexport interface SelectItemProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> {}\n\n/**\n * An individual option inside {@link SelectContent}.\n */\nexport const SelectItem = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Item>,\n SelectItemProps\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"typography-regular-body-lg relative flex w-full cursor-pointer select-none items-center gap-2 rounded-lg py-2 pr-2 pl-3 text-foreground-default outline-none\",\n \"focus:bg-neutral-100 data-disabled:pointer-events-none data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator className=\"ml-auto flex size-4 shrink-0 items-center justify-center\">\n <CheckIcon className=\"size-4 text-foreground-default\" />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n));\n\nSelectItem.displayName = \"SelectItem\";\n\n/** Props for {@link SelectGroup}. */\nexport type SelectGroupProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group>;\n\n/**\n * Groups related {@link SelectItem} elements under a {@link SelectLabel}.\n */\nexport const SelectGroup = SelectPrimitive.Group;\nSelectGroup.displayName = \"SelectGroup\";\n\nexport interface SelectLabelProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> {}\n\n/**\n * A non-interactive label shown above a {@link SelectGroup}.\n */\nexport const SelectLabel = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Label>,\n SelectLabelProps\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\"typography-semibold-body-sm px-3 py-1.5 text-foreground-secondary\", className)}\n {...props}\n />\n));\n\nSelectLabel.displayName = \"SelectLabel\";\n\nexport interface SelectSeparatorProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> {}\n\n/** A horizontal rule that visually separates groups in {@link SelectContent}. */\nexport const SelectSeparator = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Separator>,\n SelectSeparatorProps\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-neutral-200\", className)}\n {...props}\n />\n));\n\nSelectSeparator.displayName = \"SelectSeparator\";\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Select.mjs","sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { CheckIcon } from \"../Icons/CheckIcon\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\n\n/** Select field height in pixels. */\nexport type SelectSize = \"48\" | \"40\" | \"32\";\n\ntype SelectContextValue = {\n size: SelectSize;\n error: boolean;\n disabled?: boolean;\n};\n\nconst SelectContext = React.createContext<SelectContextValue>({\n size: \"48\",\n error: false,\n});\n\nconst TRIGGER_HEIGHT: Record<SelectSize, string> = {\n \"48\": \"h-12\",\n \"40\": \"h-10\",\n \"32\": \"h-8\",\n};\n\nconst TRIGGER_PADDING_X: Record<SelectSize, string> = {\n \"48\": \"px-4\",\n \"40\": \"px-4\",\n \"32\": \"px-3\",\n};\n\nconst TRIGGER_GAP: Record<SelectSize, string> = {\n \"48\": \"gap-3\",\n \"40\": \"gap-3\",\n \"32\": \"gap-2\",\n};\n\nconst TRIGGER_TYPOGRAPHY: Record<SelectSize, string> = {\n \"48\": \"typography-regular-body-lg\",\n \"40\": \"typography-regular-body-lg\",\n \"32\": \"typography-regular-body-md\",\n};\n\nexport interface SelectProps extends Omit<SelectPrimitive.SelectProps, \"dir\"> {\n /** Label text displayed above the trigger. Also used as the accessible name. */\n label?: string;\n /** Accessible name applied directly to the trigger button when no visible `label` is provided. */\n \"aria-label\"?: string;\n /** ID of an external element that labels the trigger button. */\n \"aria-labelledby\"?: string;\n /** Helper text displayed below the trigger. Replaced by `errorMessage` when `error` is `true`. */\n helperText?: string;\n /** Height of the select field in pixels. @default \"48\" */\n size?: SelectSize;\n /** Whether the field is in an error state. @default false */\n error?: boolean;\n /** Error message displayed below the trigger. Shown instead of `helperText` when `error` is `true`. */\n errorMessage?: string;\n /** Placeholder shown when no value is selected. */\n placeholder?: string;\n /** Icon element displayed at the left side of the trigger. */\n leftIcon?: React.ReactNode;\n /** Whether the field stretches to fill its container width. @default false */\n fullWidth?: boolean;\n /** Wraps the `className` of the outermost container div. */\n className?: string;\n /** HTML `id` applied to the trigger button. Auto-generated if omitted. */\n id?: string;\n}\n\n/**\n * A select field with optional label, helper/error text, and an icon slot,\n * built on Radix UI Select for full accessibility and keyboard navigation.\n *\n * Pair with {@link SelectContent} and {@link SelectItem} to provide options.\n *\n * @example\n * ```tsx\n * <Select label=\"Country\" placeholder=\"Select a country\">\n * <SelectContent>\n * <SelectItem value=\"us\">United States</SelectItem>\n * <SelectItem value=\"uk\">United Kingdom</SelectItem>\n * </SelectContent>\n * </Select>\n * ```\n */\nexport const Select = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Trigger>,\n SelectProps\n>(\n (\n {\n label,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n placeholder,\n leftIcon,\n fullWidth = false,\n className,\n id,\n disabled,\n children,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const triggerId = id ?? generatedId;\n const helperTextId = `${triggerId}-helper`;\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n return (\n <SelectContext.Provider value={{ size, error, disabled }}>\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={triggerId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <SelectPrimitive.Root disabled={disabled} {...props}>\n <SelectPrimitive.Trigger\n ref={ref}\n id={triggerId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n aria-describedby={bottomText ? helperTextId : undefined}\n aria-invalid={error || undefined}\n className={cn(\n \"flex w-full cursor-pointer items-center justify-between rounded-xl border bg-neutral-100 outline-none motion-safe:transition-colors\",\n TRIGGER_HEIGHT[size],\n TRIGGER_PADDING_X[size],\n TRIGGER_GAP[size],\n TRIGGER_TYPOGRAPHY[size],\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled &&\n !error &&\n \"hover:border-neutral-400 data-[state=open]:border-neutral-400\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n <div className=\"flex min-w-0 items-center gap-2\">\n {leftIcon && (\n <span\n className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\"\n data-testid=\"left-icon\"\n >\n {leftIcon}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate text-left text-foreground-default [&>[data-placeholder]]:text-foreground-secondary [&>[data-placeholder]]:opacity-40\">\n <SelectPrimitive.Value placeholder={placeholder} />\n </span>\n </div>\n\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n\n {children}\n </SelectPrimitive.Root>\n\n {bottomText && (\n <p\n id={helperTextId}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {bottomText}\n </p>\n )}\n </div>\n </SelectContext.Provider>\n );\n },\n);\n\nSelect.displayName = \"Select\";\n\nexport interface SelectContentProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> {}\n\n/**\n * The dropdown panel rendered inside a portal. Place {@link SelectItem} elements\n * (and optionally {@link SelectGroup} / {@link SelectLabel}) as children.\n */\nexport const SelectContent = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Content>,\n SelectContentProps\n>(({ className, children, position = \"popper\", sideOffset = 4, style, ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"relative min-w-(--radix-select-trigger-width) overflow-hidden rounded-xl border border-neutral-200 bg-surface-page text-foreground-default shadow-[0_4px_16px_rgba(0,0,0,0.10)]\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.Viewport className=\"max-h-[var(--radix-select-content-available-height)] overflow-y-auto p-1\">\n {children}\n </SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\n\nSelectContent.displayName = \"SelectContent\";\n\nexport interface SelectItemProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> {}\n\n/**\n * An individual option inside {@link SelectContent}.\n */\nexport const SelectItem = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Item>,\n SelectItemProps\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"typography-regular-body-lg relative flex w-full cursor-pointer select-none items-center gap-2 rounded-lg py-2 pr-2 pl-3 text-foreground-default outline-none\",\n \"focus:bg-neutral-100 data-disabled:pointer-events-none data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator className=\"ml-auto flex size-4 shrink-0 items-center justify-center\">\n <CheckIcon className=\"size-4 text-foreground-default\" />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n));\n\nSelectItem.displayName = \"SelectItem\";\n\n/** Props for {@link SelectGroup}. */\nexport type SelectGroupProps = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group>;\n\n/**\n * Groups related {@link SelectItem} elements under a {@link SelectLabel}.\n */\nexport const SelectGroup = SelectPrimitive.Group;\nSelectGroup.displayName = \"SelectGroup\";\n\nexport interface SelectLabelProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> {}\n\n/**\n * A non-interactive label shown above a {@link SelectGroup}.\n */\nexport const SelectLabel = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Label>,\n SelectLabelProps\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\"typography-semibold-body-sm px-3 py-1.5 text-foreground-secondary\", className)}\n {...props}\n />\n));\n\nSelectLabel.displayName = \"SelectLabel\";\n\nexport interface SelectSeparatorProps\n extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> {}\n\n/** A horizontal rule that visually separates groups in {@link SelectContent}. */\nexport const SelectSeparator = React.forwardRef<\n React.ComponentRef<typeof SelectPrimitive.Separator>,\n SelectSeparatorProps\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-neutral-200\", className)}\n {...props}\n />\n));\n\nSelectSeparator.displayName = \"SelectSeparator\";\n"],"names":[],"mappings":"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"}
|
|
@@ -13,8 +13,12 @@ const Skeleton = React.forwardRef(
|
|
|
13
13
|
const hasChildren = React.Children.count(children) > 0;
|
|
14
14
|
const sizeStyle = {
|
|
15
15
|
...style,
|
|
16
|
-
...width !== void 0 && {
|
|
17
|
-
|
|
16
|
+
...width !== void 0 && {
|
|
17
|
+
width: typeof width === "number" ? `${width}px` : width
|
|
18
|
+
},
|
|
19
|
+
...height !== void 0 && {
|
|
20
|
+
height: typeof height === "number" ? `${height}px` : height
|
|
21
|
+
}
|
|
18
22
|
};
|
|
19
23
|
return /* @__PURE__ */ jsx(
|
|
20
24
|
"span",
|
|
@@ -22,7 +26,7 @@ const Skeleton = React.forwardRef(
|
|
|
22
26
|
ref,
|
|
23
27
|
"aria-hidden": "true",
|
|
24
28
|
className: cn(
|
|
25
|
-
"block bg-
|
|
29
|
+
"block bg-[color-mix(in_srgb,var(--color-foreground-default)_11%,var(--color-surface-page))]",
|
|
26
30
|
VARIANT_CLASSES[variant],
|
|
27
31
|
variant === "text" && !height && !hasChildren && "h-[1em]",
|
|
28
32
|
animation === "pulse" && "animate-pulse",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Skeleton.mjs","sources":["../../../src/components/Skeleton/Skeleton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Shape variant of the skeleton placeholder. */\nexport type SkeletonVariant = \"text\" | \"circular\" | \"rectangular\" | \"rounded\";\n\n/** Animation style of the skeleton. `false` disables animation. */\nexport type SkeletonAnimation = \"pulse\" | \"wave\" | false;\n\nexport interface SkeletonProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Shape variant of the skeleton.\n *\n * - `text` – a single line of text with slight vertical margin and rounded ends\n * - `circular` – a circle (width and height should match)\n * - `rectangular` – a sharp-cornered rectangle\n * - `rounded` – a rectangle with rounded corners\n *\n * @default \"text\"\n */\n variant?: SkeletonVariant;\n /** Animation style. Set to `false` to disable animation. @default \"pulse\" */\n animation?: SkeletonAnimation;\n /** Width of the skeleton. Accepts a CSS value (number is treated as `px`). */\n width?: number | string;\n /** Height of the skeleton. Accepts a CSS value (number is treated as `px`). */\n height?: number | string;\n}\n\nconst VARIANT_CLASSES: Record<SkeletonVariant, string> = {\n text: \"rounded my-0.5\",\n circular: \"rounded-full\",\n rectangular: \"\",\n rounded: \"rounded-lg\",\n};\n\n/**\n * A placeholder preview of content before data is loaded, reducing perceived\n * load time. Mirrors common MUI Skeleton props for easy migration.\n *\n * When used as a loading state, wrap the skeleton region with `aria-busy=\"true\"`\n * and provide an accessible label so screen readers can convey the loading state.\n *\n * @example\n * ```tsx\n * <Skeleton variant=\"text\" width={200} />\n * <Skeleton variant=\"circular\" width={40} height={40} />\n * <Skeleton variant=\"rectangular\" width=\"100%\" height={120} />\n * ```\n */\nexport const Skeleton = React.forwardRef<HTMLSpanElement, SkeletonProps>(\n (\n { className, variant = \"text\", animation = \"pulse\", width, height, style, children, ...props },\n ref,\n ) => {\n const hasChildren = React.Children.count(children) > 0;\n const sizeStyle: React.CSSProperties = {\n ...style,\n ...(width !== undefined && {
|
|
1
|
+
{"version":3,"file":"Skeleton.mjs","sources":["../../../src/components/Skeleton/Skeleton.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Shape variant of the skeleton placeholder. */\nexport type SkeletonVariant = \"text\" | \"circular\" | \"rectangular\" | \"rounded\";\n\n/** Animation style of the skeleton. `false` disables animation. */\nexport type SkeletonAnimation = \"pulse\" | \"wave\" | false;\n\nexport interface SkeletonProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Shape variant of the skeleton.\n *\n * - `text` – a single line of text with slight vertical margin and rounded ends\n * - `circular` – a circle (width and height should match)\n * - `rectangular` – a sharp-cornered rectangle\n * - `rounded` – a rectangle with rounded corners\n *\n * @default \"text\"\n */\n variant?: SkeletonVariant;\n /** Animation style. Set to `false` to disable animation. @default \"pulse\" */\n animation?: SkeletonAnimation;\n /** Width of the skeleton. Accepts a CSS value (number is treated as `px`). */\n width?: number | string;\n /** Height of the skeleton. Accepts a CSS value (number is treated as `px`). */\n height?: number | string;\n}\n\nconst VARIANT_CLASSES: Record<SkeletonVariant, string> = {\n text: \"rounded my-0.5\",\n circular: \"rounded-full\",\n rectangular: \"\",\n rounded: \"rounded-lg\",\n};\n\n/**\n * A placeholder preview of content before data is loaded, reducing perceived\n * load time. Mirrors common MUI Skeleton props for easy migration.\n *\n * When used as a loading state, wrap the skeleton region with `aria-busy=\"true\"`\n * and provide an accessible label so screen readers can convey the loading state.\n *\n * @example\n * ```tsx\n * <Skeleton variant=\"text\" width={200} />\n * <Skeleton variant=\"circular\" width={40} height={40} />\n * <Skeleton variant=\"rectangular\" width=\"100%\" height={120} />\n * ```\n */\nexport const Skeleton = React.forwardRef<HTMLSpanElement, SkeletonProps>(\n (\n { className, variant = \"text\", animation = \"pulse\", width, height, style, children, ...props },\n ref,\n ) => {\n const hasChildren = React.Children.count(children) > 0;\n const sizeStyle: React.CSSProperties = {\n ...style,\n ...(width !== undefined && {\n width: typeof width === \"number\" ? `${width}px` : width,\n }),\n ...(height !== undefined && {\n height: typeof height === \"number\" ? `${height}px` : height,\n }),\n };\n\n return (\n <span\n ref={ref}\n aria-hidden=\"true\"\n className={cn(\n \"block bg-[color-mix(in_srgb,var(--color-foreground-default)_11%,var(--color-surface-page))]\",\n VARIANT_CLASSES[variant],\n variant === \"text\" && !height && !hasChildren && \"h-[1em]\",\n animation === \"pulse\" && \"animate-pulse\",\n animation === \"wave\" && \"fv-skeleton-wave\",\n hasChildren && \"relative overflow-hidden [&>*]:invisible\",\n className,\n )}\n style={sizeStyle}\n {...props}\n >\n {children}\n </span>\n );\n },\n);\n\nSkeleton.displayName = \"Skeleton\";\n"],"names":[],"mappings":";;;;AA4BA,MAAM,kBAAmD;AAAA,EACvD,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS;AACX;AAgBO,MAAM,WAAW,MAAM;AAAA,EAC5B,CACE,EAAE,WAAW,UAAU,QAAQ,YAAY,SAAS,OAAO,QAAQ,OAAO,UAAU,GAAG,MAAA,GACvF,QACG;AACH,UAAM,cAAc,MAAM,SAAS,MAAM,QAAQ,IAAI;AACrD,UAAM,YAAiC;AAAA,MACrC,GAAG;AAAA,MACH,GAAI,UAAU,UAAa;AAAA,QACzB,OAAO,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AAAA,MAAA;AAAA,MAEpD,GAAI,WAAW,UAAa;AAAA,QAC1B,QAAQ,OAAO,WAAW,WAAW,GAAG,MAAM,OAAO;AAAA,MAAA;AAAA,IACvD;AAGF,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA,UACA,gBAAgB,OAAO;AAAA,UACvB,YAAY,UAAU,CAAC,UAAU,CAAC,eAAe;AAAA,UACjD,cAAc,WAAW;AAAA,UACzB,cAAc,UAAU;AAAA,UACxB,eAAe;AAAA,UACf;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,QACN,GAAG;AAAA,QAEH;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,SAAS,cAAc;"}
|
|
@@ -86,13 +86,13 @@ const SwitchToggle = React.forwardRef(
|
|
|
86
86
|
onClick: () => handleSelect(option.value),
|
|
87
87
|
onKeyDown: (e) => handleKeyDown(e, index),
|
|
88
88
|
className: cn(
|
|
89
|
-
"relative z-10 inline-flex
|
|
89
|
+
"relative z-10 inline-flex min-w-0 cursor-pointer items-center justify-center rounded-full border border-transparent text-foreground-default",
|
|
90
90
|
"focus-visible:shadow-focus-ring focus-visible:outline-none",
|
|
91
91
|
"active:rounded-full active:bg-brand-accent-muted",
|
|
92
92
|
disabled && "pointer-events-none",
|
|
93
93
|
sizeClass
|
|
94
94
|
),
|
|
95
|
-
children: option.label
|
|
95
|
+
children: /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: option.label })
|
|
96
96
|
},
|
|
97
97
|
option.value
|
|
98
98
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SwitchToggle.mjs","sources":["../../../src/components/SwitchToggle/SwitchToggle.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Height of the switch toggle in pixels. */\nexport type SwitchToggleSize = \"24\" | \"32\" | \"40\";\n\n/** Describes one side of the binary toggle. */\nexport interface SwitchToggleOption {\n /** Display label for the option. */\n label: string;\n /** Value identifier returned via `onChange`. */\n value: string;\n}\n\nexport interface SwitchToggleProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n /** Height of the toggle in pixels. @default \"24\" */\n size?: SwitchToggleSize;\n /** The two options to toggle between (exactly two required). */\n options: [SwitchToggleOption, SwitchToggleOption];\n /** Currently selected value (controlled). */\n value?: string;\n /** Initially selected value (uncontrolled). */\n defaultValue?: string;\n /** Callback fired when the selected value changes. */\n onChange?: (value: string) => void;\n /** Whether the toggle is disabled. @default false */\n disabled?: boolean;\n}\n\nfunction warnMissingAccessibleName(ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"SwitchToggle: no accessible name provided. Pass an `aria-label` or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n/**\n * A binary segmented toggle rendered as a `radiogroup`. The active option is\n * highlighted with a sliding pill indicator. Supports both controlled and\n * uncontrolled usage.\n *\n * @example\n * ```tsx\n * <SwitchToggle\n * options={[\n * { label: \"Monthly\", value: \"monthly\" },\n * { label: \"Yearly\", value: \"yearly\" },\n * ]}\n * value={billing}\n * onChange={setBilling}\n * />\n * ```\n */\nexport const SwitchToggle = React.forwardRef<HTMLDivElement, SwitchToggleProps>(\n (\n {\n className,\n size = \"24\",\n options,\n value: controlledValue,\n defaultValue,\n onChange,\n disabled = false,\n ...props\n },\n ref,\n ) => {\n warnMissingAccessibleName(props[\"aria-label\"], props[\"aria-labelledby\"]);\n\n // Tracks selection for uncontrolled usage; ignored when `value` prop is provided\n const [internalValue, setInternalValue] = React.useState(defaultValue ?? options[0].value);\n const isControlled = controlledValue !== undefined;\n const currentValue = isControlled ? controlledValue : internalValue;\n const anySelected = options.some((o) => o.value === currentValue);\n const isSecondSelected = currentValue === options[1].value;\n const buttonRefs = React.useRef<(HTMLButtonElement | null)[]>([]);\n\n const sizeClass =\n size === \"24\"\n ? \"px-2 py-1 typography-semibold-body-sm\"\n : size === \"32\"\n ? \"px-3 py-1.75 typography-semibold-body-md\"\n : \"h-10 px-4 py-2.25 typography-semibold-body-lg\";\n\n const handleSelect = (optionValue: string) => {\n if (disabled || optionValue === currentValue) return;\n if (!isControlled) {\n setInternalValue(optionValue);\n }\n onChange?.(optionValue);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent, index: number) => {\n const nextIndex =\n e.key === \"ArrowRight\" || e.key === \"ArrowDown\"\n ? (index + 1) % options.length\n : e.key === \"ArrowLeft\" || e.key === \"ArrowUp\"\n ? (index - 1 + options.length) % options.length\n : null;\n if (nextIndex === null) return;\n e.preventDefault();\n const nextOption = options[nextIndex] as (typeof options)[number];\n handleSelect(nextOption.value);\n buttonRefs.current[nextIndex]?.focus();\n };\n\n return (\n <div\n ref={ref}\n role=\"radiogroup\"\n className={cn(\n \"relative inline-grid grid-cols-2 rounded-full border border-neutral-200 p-1\",\n disabled && \"cursor-not-allowed opacity-50\",\n className,\n )}\n {...props}\n >\n <span\n aria-hidden=\"true\"\n className={cn(\n \"absolute inset-y-1 left-1 w-[calc(50%-4px)] rounded-full border border-brand-accent-default bg-brand-accent-muted\",\n \"motion-safe:transition-transform motion-safe:duration-200 motion-safe:ease-in-out\",\n isSecondSelected && \"translate-x-full\",\n )}\n />\n {options.map((option, index) => {\n const isSelected = currentValue === option.value;\n return (\n // biome-ignore lint/a11y/useSemanticElements: native radio inputs only allow Tab-focus on the checked item; buttons with roving tabindex give full keyboard navigation\n <button\n key={option.value}\n ref={(el) => {\n buttonRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n tabIndex={isSelected || (!anySelected && index === 0) ? 0 : -1}\n disabled={disabled}\n onClick={() => handleSelect(option.value)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n className={cn(\n \"relative z-10 inline-flex
|
|
1
|
+
{"version":3,"file":"SwitchToggle.mjs","sources":["../../../src/components/SwitchToggle/SwitchToggle.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Height of the switch toggle in pixels. */\nexport type SwitchToggleSize = \"24\" | \"32\" | \"40\";\n\n/** Describes one side of the binary toggle. */\nexport interface SwitchToggleOption {\n /** Display label for the option. */\n label: string;\n /** Value identifier returned via `onChange`. */\n value: string;\n}\n\nexport interface SwitchToggleProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n /** Height of the toggle in pixels. @default \"24\" */\n size?: SwitchToggleSize;\n /** The two options to toggle between (exactly two required). */\n options: [SwitchToggleOption, SwitchToggleOption];\n /** Currently selected value (controlled). */\n value?: string;\n /** Initially selected value (uncontrolled). */\n defaultValue?: string;\n /** Callback fired when the selected value changes. */\n onChange?: (value: string) => void;\n /** Whether the toggle is disabled. @default false */\n disabled?: boolean;\n}\n\nfunction warnMissingAccessibleName(ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"SwitchToggle: no accessible name provided. Pass an `aria-label` or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n/**\n * A binary segmented toggle rendered as a `radiogroup`. The active option is\n * highlighted with a sliding pill indicator. Supports both controlled and\n * uncontrolled usage.\n *\n * @example\n * ```tsx\n * <SwitchToggle\n * options={[\n * { label: \"Monthly\", value: \"monthly\" },\n * { label: \"Yearly\", value: \"yearly\" },\n * ]}\n * value={billing}\n * onChange={setBilling}\n * />\n * ```\n */\nexport const SwitchToggle = React.forwardRef<HTMLDivElement, SwitchToggleProps>(\n (\n {\n className,\n size = \"24\",\n options,\n value: controlledValue,\n defaultValue,\n onChange,\n disabled = false,\n ...props\n },\n ref,\n ) => {\n warnMissingAccessibleName(props[\"aria-label\"], props[\"aria-labelledby\"]);\n\n // Tracks selection for uncontrolled usage; ignored when `value` prop is provided\n const [internalValue, setInternalValue] = React.useState(defaultValue ?? options[0].value);\n const isControlled = controlledValue !== undefined;\n const currentValue = isControlled ? controlledValue : internalValue;\n const anySelected = options.some((o) => o.value === currentValue);\n const isSecondSelected = currentValue === options[1].value;\n const buttonRefs = React.useRef<(HTMLButtonElement | null)[]>([]);\n\n const sizeClass =\n size === \"24\"\n ? \"px-2 py-1 typography-semibold-body-sm\"\n : size === \"32\"\n ? \"px-3 py-1.75 typography-semibold-body-md\"\n : \"h-10 px-4 py-2.25 typography-semibold-body-lg\";\n\n const handleSelect = (optionValue: string) => {\n if (disabled || optionValue === currentValue) return;\n if (!isControlled) {\n setInternalValue(optionValue);\n }\n onChange?.(optionValue);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent, index: number) => {\n const nextIndex =\n e.key === \"ArrowRight\" || e.key === \"ArrowDown\"\n ? (index + 1) % options.length\n : e.key === \"ArrowLeft\" || e.key === \"ArrowUp\"\n ? (index - 1 + options.length) % options.length\n : null;\n if (nextIndex === null) return;\n e.preventDefault();\n const nextOption = options[nextIndex] as (typeof options)[number];\n handleSelect(nextOption.value);\n buttonRefs.current[nextIndex]?.focus();\n };\n\n return (\n <div\n ref={ref}\n role=\"radiogroup\"\n className={cn(\n \"relative inline-grid grid-cols-2 rounded-full border border-neutral-200 p-1\",\n disabled && \"cursor-not-allowed opacity-50\",\n className,\n )}\n {...props}\n >\n <span\n aria-hidden=\"true\"\n className={cn(\n \"absolute inset-y-1 left-1 w-[calc(50%-4px)] rounded-full border border-brand-accent-default bg-brand-accent-muted\",\n \"motion-safe:transition-transform motion-safe:duration-200 motion-safe:ease-in-out\",\n isSecondSelected && \"translate-x-full\",\n )}\n />\n {options.map((option, index) => {\n const isSelected = currentValue === option.value;\n return (\n // biome-ignore lint/a11y/useSemanticElements: native radio inputs only allow Tab-focus on the checked item; buttons with roving tabindex give full keyboard navigation\n <button\n key={option.value}\n ref={(el) => {\n buttonRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n tabIndex={isSelected || (!anySelected && index === 0) ? 0 : -1}\n disabled={disabled}\n onClick={() => handleSelect(option.value)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n className={cn(\n \"relative z-10 inline-flex min-w-0 cursor-pointer items-center justify-center rounded-full border border-transparent text-foreground-default\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n \"active:rounded-full active:bg-brand-accent-muted\",\n disabled && \"pointer-events-none\",\n sizeClass,\n )}\n >\n <span className=\"min-w-0 truncate\">{option.label}</span>\n </button>\n );\n })}\n </div>\n );\n },\n);\n\nSwitchToggle.displayName = \"SwitchToggle\";\n"],"names":[],"mappings":";;;;AA6BA,SAAS,0BAA0B,WAAoB,gBAAyB;AAC9E,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,CAAC,aAAa,CAAC,gBAAgB;AACjC,cAAQ;AAAA,QACN;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAmBO,MAAM,eAAe,MAAM;AAAA,EAChC,CACE;AAAA,IACE;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,GAAG;AAAA,EAAA,GAEL,QACG;AACH,8BAA0B,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC;AAGvE,UAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAS,gBAAgB,QAAQ,CAAC,EAAE,KAAK;AACzF,UAAM,eAAe,oBAAoB;AACzC,UAAM,eAAe,eAAe,kBAAkB;AACtD,UAAM,cAAc,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,YAAY;AAChE,UAAM,mBAAmB,iBAAiB,QAAQ,CAAC,EAAE;AACrD,UAAM,aAAa,MAAM,OAAqC,EAAE;AAEhE,UAAM,YACJ,SAAS,OACL,0CACA,SAAS,OACP,6CACA;AAER,UAAM,eAAe,CAAC,gBAAwB;AAC5C,UAAI,YAAY,gBAAgB,aAAc;AAC9C,UAAI,CAAC,cAAc;AACjB,yBAAiB,WAAW;AAAA,MAC9B;AACA,iBAAW,WAAW;AAAA,IACxB;AAEA,UAAM,gBAAgB,CAAC,GAAwB,UAAkB;AAC/D,YAAM,YACJ,EAAE,QAAQ,gBAAgB,EAAE,QAAQ,eAC/B,QAAQ,KAAK,QAAQ,SACtB,EAAE,QAAQ,eAAe,EAAE,QAAQ,aAChC,QAAQ,IAAI,QAAQ,UAAU,QAAQ,SACvC;AACR,UAAI,cAAc,KAAM;AACxB,QAAE,eAAA;AACF,YAAM,aAAa,QAAQ,SAAS;AACpC,mBAAa,WAAW,KAAK;AAC7B,iBAAW,QAAQ,SAAS,GAAG,MAAA;AAAA,IACjC;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,UACZ;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,eAAY;AAAA,cACZ,WAAW;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA,oBAAoB;AAAA,cAAA;AAAA,YACtB;AAAA,UAAA;AAAA,UAED,QAAQ,IAAI,CAAC,QAAQ,UAAU;AAC9B,kBAAM,aAAa,iBAAiB,OAAO;AAC3C;AAAA;AAAA,cAEE;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,KAAK,CAAC,OAAO;AACX,+BAAW,QAAQ,KAAK,IAAI;AAAA,kBAC9B;AAAA,kBACA,MAAK;AAAA,kBACL,MAAK;AAAA,kBACL,gBAAc;AAAA,kBACd,UAAU,cAAe,CAAC,eAAe,UAAU,IAAK,IAAI;AAAA,kBAC5D;AAAA,kBACA,SAAS,MAAM,aAAa,OAAO,KAAK;AAAA,kBACxC,WAAW,CAAC,MAAM,cAAc,GAAG,KAAK;AAAA,kBACxC,WAAW;AAAA,oBACT;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA,YAAY;AAAA,oBACZ;AAAA,kBAAA;AAAA,kBAGF,UAAA,oBAAC,QAAA,EAAK,WAAU,oBAAoB,iBAAO,MAAA,CAAM;AAAA,gBAAA;AAAA,gBAnB5C,OAAO;AAAA,cAAA;AAAA;AAAA,UAsBlB,CAAC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;AAEA,aAAa,cAAc;"}
|
|
@@ -3,12 +3,12 @@ import { 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 TabsTrigger = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
6
|
+
const TabsTrigger = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
7
7
|
TabsPrimitive.Trigger,
|
|
8
8
|
{
|
|
9
9
|
ref,
|
|
10
10
|
className: cn(
|
|
11
|
-
"inline-flex items-center justify-center",
|
|
11
|
+
"inline-flex min-w-0 items-center justify-center",
|
|
12
12
|
"rounded-xs",
|
|
13
13
|
"typography-semibold-body-lg cursor-pointer text-foreground-default",
|
|
14
14
|
"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out",
|
|
@@ -24,7 +24,8 @@ const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
24
24
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-page",
|
|
25
25
|
className
|
|
26
26
|
),
|
|
27
|
-
...props
|
|
27
|
+
...props,
|
|
28
|
+
children: /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children })
|
|
28
29
|
}
|
|
29
30
|
));
|
|
30
31
|
TabsTrigger.displayName = "TabsTrigger";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabsTrigger.mjs","sources":["../../../src/components/Tabs/TabsTrigger.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsTrigger} button component. */\nexport type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;\n\n/** An interactive tab button that activates its associated {@link TabsContent} panel when clicked. */\nexport const TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex items-center justify-center\",\n \"rounded-xs\",\n \"typography-semibold-body-lg cursor-pointer text-foreground-default\",\n \"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out\",\n \"data-[orientation=horizontal]:px-4 data-[orientation=horizontal]:py-3\",\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:px-4 data-[orientation=vertical]:py-3\",\n \"data-[state=active]:hover:text-neutral-350\",\n \"data-[state=inactive]:hover:text-neutral-300\",\n \"data-[state=active]:active:text-neutral-350\",\n \"data-[state=inactive]:active:text-neutral-300\",\n \"data-disabled:pointer-events-none\",\n \"data-disabled:data-[state=active]:text-neutral-250\",\n \"data-disabled:data-[state=inactive]:text-neutral-300\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-page\",\n className,\n )}\n {...props}\n
|
|
1
|
+
{"version":3,"file":"TabsTrigger.mjs","sources":["../../../src/components/Tabs/TabsTrigger.tsx"],"sourcesContent":["import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TabsTrigger} button component. */\nexport type TabsTriggerProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;\n\n/** An interactive tab button that activates its associated {@link TabsContent} panel when clicked. */\nexport const TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, children, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex min-w-0 items-center justify-center\",\n \"rounded-xs\",\n \"typography-semibold-body-lg cursor-pointer text-foreground-default\",\n \"motion-safe:transition-colors motion-safe:duration-150 motion-safe:ease-in-out\",\n \"data-[orientation=horizontal]:px-4 data-[orientation=horizontal]:py-3\",\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:px-4 data-[orientation=vertical]:py-3\",\n \"data-[state=active]:hover:text-neutral-350\",\n \"data-[state=inactive]:hover:text-neutral-300\",\n \"data-[state=active]:active:text-neutral-350\",\n \"data-[state=inactive]:active:text-neutral-300\",\n \"data-disabled:pointer-events-none\",\n \"data-disabled:data-[state=active]:text-neutral-250\",\n \"data-disabled:data-[state=inactive]:text-neutral-300\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-page\",\n className,\n )}\n {...props}\n >\n <span className=\"min-w-0 truncate\">{children}</span>\n </TabsPrimitive.Trigger>\n));\n\nTabsTrigger.displayName = \"TabsTrigger\";\n"],"names":[],"mappings":";;;;;AAQO,MAAM,cAAc,MAAM,WAG/B,CAAC,EAAE,WAAW,UAAU,GAAG,SAAS,QACpC;AAAA,EAAC,cAAc;AAAA,EAAd;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAED,GAAG;AAAA,IAEJ,UAAA,oBAAC,QAAA,EAAK,WAAU,oBAAoB,SAAA,CAAS;AAAA,EAAA;AAC/C,CACD;AAED,YAAY,cAAc;"}
|
|
@@ -56,9 +56,10 @@ const TooltipContent = React.forwardRef(
|
|
|
56
56
|
{
|
|
57
57
|
ref,
|
|
58
58
|
sideOffset,
|
|
59
|
+
collisionPadding: 8,
|
|
59
60
|
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
60
61
|
className: cn(
|
|
61
|
-
"typography-regular-body-md max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]",
|
|
62
|
+
"typography-regular-body-md max-h-[var(--radix-tooltip-content-available-height)] max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]",
|
|
62
63
|
isInfobox && "border border-neutral-200",
|
|
63
64
|
className
|
|
64
65
|
),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.mjs","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\n\n/** Props for the {@link TooltipProvider}. Wraps Radix `Tooltip.Provider`. */\nexport type TooltipProviderProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>;\n\n/** Provides tooltip delay and skip-delay context. Wrap your app or a subtree. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\n/** Props for the {@link Tooltip} root component. */\nexport interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {\n /**\n * Controlled open state. When provided, the component is in controlled mode\n * and you must also supply `onOpenChange` to update the value.\n */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the tooltip when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a single tooltip. */\nexport const Tooltip = TooltipPrimitive.Root;\n\n/** Props for the {@link TooltipTrigger} component. */\nexport type TooltipTriggerProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>;\n\n/** The element that triggers the tooltip on hover/focus. */\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\n/**\n * Visual style variant of the tooltip content.\n *\n * - `\"tooltip\"` — simple text bubble, no border.\n * - `\"infobox\"` — richer card with a visible border, structured header, body text, and optional actions.\n */\nexport type TooltipContentVariant = \"tooltip\" | \"infobox\";\n\n/** Action button configuration for the infobox variant of {@link TooltipContent}. */\nexport interface TooltipAction {\n /** Button label. */\n label: string;\n /** Click handler. */\n onClick?: () => void;\n /**\n * Optional custom React node to be rendered for the action instead of the default button.\n * Only used in the infobox variant.\n */\n element?: React.ReactNode;\n}\n\nexport interface TooltipContentProps\n extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {\n /**\n * Visual style variant.\n *\n * `\"tooltip\"` is a lightweight text bubble. `\"infobox\"` renders a structured card\n * with optional heading, icon, pill, body text, and action buttons.\n *\n * @default \"tooltip\"\n */\n variant?: TooltipContentVariant;\n /** Whether to show the directional arrow pointer. @default true */\n showArrow?: boolean;\n /**\n * Heading text rendered in subtitle style at the top of the infobox.\n * Infobox variant only.\n */\n heading?: React.ReactNode;\n /**\n * Icon element displayed to the left of the heading.\n * Infobox variant only.\n */\n icon?: React.ReactNode;\n /**\n * Pill or badge element displayed to the right of the heading.\n * Infobox variant only.\n */\n pill?: React.ReactNode;\n /**\n * Primary action button (brand green). Rendered below the body text.\n * Infobox variant only.\n */\n primaryAction?: TooltipAction;\n /**\n * Secondary action button (ghost). Rendered next to the primary action.\n * Infobox variant only.\n */\n secondaryAction?: TooltipAction;\n}\n\nconst ActionButton = ({\n action,\n variant,\n}: {\n action: TooltipAction;\n variant: \"brand\" | \"tertiary\";\n}) =>\n action.element ? (\n action.element\n ) : (\n <Button variant={variant} size=\"32\" onClick={action.onClick}>\n {action.label}\n </Button>\n );\n\nconst InfoboxContent = ({\n icon,\n heading,\n pill,\n children,\n primaryAction,\n secondaryAction,\n hasHeader,\n hasActions,\n}: {\n icon?: React.ReactNode;\n heading?: React.ReactNode;\n pill?: React.ReactNode;\n children?: React.ReactNode;\n primaryAction?: TooltipAction;\n secondaryAction?: TooltipAction;\n hasHeader: boolean;\n hasActions: boolean;\n}) => (\n <div className=\"flex flex-col gap-3\">\n {hasHeader && (\n <div className=\"flex items-center gap-3\">\n {icon && <div className=\"size-5 shrink-0\">{icon}</div>}\n {heading && (\n <p className=\"typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse\">\n {heading}\n </p>\n )}\n {pill && <div className=\"shrink-0\">{pill}</div>}\n </div>\n )}\n {children && (\n <div className=\"typography-regular-body-md text-foreground-inverse\">{children}</div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-1\">\n {primaryAction && <ActionButton action={primaryAction} variant=\"brand\" />}\n {secondaryAction && <ActionButton action={secondaryAction} variant=\"tertiary\" />}\n </div>\n )}\n </div>\n);\n\n/**\n * The popup content of the tooltip. Renders inside a portal.\n *\n * Arrow direction is controlled via the `side` and `align` props (Radix passthrough).\n *\n * @example\n * ```tsx\n * // Simple tooltip\n * <TooltipContent>Info text</TooltipContent>\n *\n * // Infobox with structured content\n * <TooltipContent\n * variant=\"infobox\"\n * heading=\"Title\"\n * icon={<InfoCircleIcon className=\"size-5\" />}\n * primaryAction={{ label: \"OK\", onClick: () => {} }}\n * secondaryAction={{ label: \"Dismiss\" }}\n * >\n * Info text\n * </TooltipContent>\n * ```\n */\nexport const TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(\n (\n {\n className,\n variant = \"tooltip\",\n showArrow = true,\n sideOffset = 8,\n heading,\n icon,\n pill,\n primaryAction,\n secondaryAction,\n children,\n side,\n style,\n ...props\n },\n ref,\n ) => {\n const isInfobox = variant === \"infobox\";\n const hasHeader =\n isInfobox && (icon !== undefined || heading !== undefined || pill !== undefined);\n const hasActions = isInfobox && (primaryAction !== undefined || secondaryAction !== undefined);\n\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-regular-body-md max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]\",\n isInfobox && \"border border-neutral-200\",\n className,\n )}\n align=\"center\"\n arrowPadding={12}\n side={side}\n {...props}\n >\n {isInfobox ? (\n <InfoboxContent\n icon={icon}\n heading={heading}\n pill={pill}\n primaryAction={primaryAction}\n secondaryAction={secondaryAction}\n hasHeader={hasHeader}\n hasActions={hasActions}\n >\n {children}\n </InfoboxContent>\n ) : (\n children\n )}\n {showArrow && (\n <TooltipPrimitive.Arrow\n className={\n \"-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse\"\n }\n width={12}\n height={6}\n />\n )}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n );\n },\n);\nTooltipContent.displayName = \"TooltipContent\";\n"],"names":[],"mappings":";;;;;;AASO,MAAM,kBAAkB,iBAAiB;AAgBzC,MAAM,UAAU,iBAAiB;AAMjC,MAAM,iBAAiB,iBAAiB;AA+D/C,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA;AACF,MAIE,OAAO,UACL,OAAO,UAEP,oBAAC,QAAA,EAAO,SAAkB,MAAK,MAAK,SAAS,OAAO,SACjD,iBAAO,OACV;AAGJ,MAAM,iBAAiB,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAUE,qBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,EAAA,aACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,QAAQ,oBAAC,OAAA,EAAI,WAAU,mBAAmB,UAAA,MAAK;AAAA,IAC/C,WACC,oBAAC,KAAA,EAAE,WAAU,sEACV,UAAA,SACH;AAAA,IAED,QAAQ,oBAAC,OAAA,EAAI,WAAU,YAAY,UAAA,KAAA,CAAK;AAAA,EAAA,GAC3C;AAAA,EAED,YACC,oBAAC,OAAA,EAAI,WAAU,sDAAsD,UAAS;AAAA,EAE/E,cACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,iBAAiB,oBAAC,cAAA,EAAa,QAAQ,eAAe,SAAQ,SAAQ;AAAA,IACtE,mBAAmB,oBAAC,cAAA,EAAa,QAAQ,iBAAiB,SAAQ,WAAA,CAAW;AAAA,EAAA,EAAA,CAChF;AAAA,GAEJ;AAyBK,MAAM,iBAAiB,MAAM;AAAA,EAIlC,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,YAAY,YAAY;AAC9B,UAAM,YACJ,cAAc,SAAS,UAAa,YAAY,UAAa,SAAS;AACxE,UAAM,aAAa,cAAc,kBAAkB,UAAa,oBAAoB;AAEpF,WACE,oBAAC,iBAAiB,QAAjB,EACC,UAAA;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC;AAAA,QACA;AAAA,QACA,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,QAC3D,WAAW;AAAA,UACT;AAAA,UACA,aAAa;AAAA,UACb;AAAA,QAAA;AAAA,QAEF,OAAM;AAAA,QACN,cAAc;AAAA,QACd;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,YACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cAEC;AAAA,YAAA;AAAA,UAAA,IAGH;AAAA,UAED,aACC;AAAA,YAAC,iBAAiB;AAAA,YAAjB;AAAA,cACC,WACE;AAAA,cAEF,OAAO;AAAA,cACP,QAAQ;AAAA,YAAA;AAAA,UAAA;AAAA,QACV;AAAA,MAAA;AAAA,IAAA,GAGN;AAAA,EAEJ;AACF;AACA,eAAe,cAAc;"}
|
|
1
|
+
{"version":3,"file":"Tooltip.mjs","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\n\n/** Props for the {@link TooltipProvider}. Wraps Radix `Tooltip.Provider`. */\nexport type TooltipProviderProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>;\n\n/** Provides tooltip delay and skip-delay context. Wrap your app or a subtree. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\n/** Props for the {@link Tooltip} root component. */\nexport interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {\n /**\n * Controlled open state. When provided, the component is in controlled mode\n * and you must also supply `onOpenChange` to update the value.\n */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the tooltip when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a single tooltip. */\nexport const Tooltip = TooltipPrimitive.Root;\n\n/** Props for the {@link TooltipTrigger} component. */\nexport type TooltipTriggerProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>;\n\n/** The element that triggers the tooltip on hover/focus. */\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\n/**\n * Visual style variant of the tooltip content.\n *\n * - `\"tooltip\"` — simple text bubble, no border.\n * - `\"infobox\"` — richer card with a visible border, structured header, body text, and optional actions.\n */\nexport type TooltipContentVariant = \"tooltip\" | \"infobox\";\n\n/** Action button configuration for the infobox variant of {@link TooltipContent}. */\nexport interface TooltipAction {\n /** Button label. */\n label: string;\n /** Click handler. */\n onClick?: () => void;\n /**\n * Optional custom React node to be rendered for the action instead of the default button.\n * Only used in the infobox variant.\n */\n element?: React.ReactNode;\n}\n\nexport interface TooltipContentProps\n extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {\n /**\n * Visual style variant.\n *\n * `\"tooltip\"` is a lightweight text bubble. `\"infobox\"` renders a structured card\n * with optional heading, icon, pill, body text, and action buttons.\n *\n * @default \"tooltip\"\n */\n variant?: TooltipContentVariant;\n /** Whether to show the directional arrow pointer. @default true */\n showArrow?: boolean;\n /**\n * Heading text rendered in subtitle style at the top of the infobox.\n * Infobox variant only.\n */\n heading?: React.ReactNode;\n /**\n * Icon element displayed to the left of the heading.\n * Infobox variant only.\n */\n icon?: React.ReactNode;\n /**\n * Pill or badge element displayed to the right of the heading.\n * Infobox variant only.\n */\n pill?: React.ReactNode;\n /**\n * Primary action button (brand green). Rendered below the body text.\n * Infobox variant only.\n */\n primaryAction?: TooltipAction;\n /**\n * Secondary action button (ghost). Rendered next to the primary action.\n * Infobox variant only.\n */\n secondaryAction?: TooltipAction;\n}\n\nconst ActionButton = ({\n action,\n variant,\n}: {\n action: TooltipAction;\n variant: \"brand\" | \"tertiary\";\n}) =>\n action.element ? (\n action.element\n ) : (\n <Button variant={variant} size=\"32\" onClick={action.onClick}>\n {action.label}\n </Button>\n );\n\nconst InfoboxContent = ({\n icon,\n heading,\n pill,\n children,\n primaryAction,\n secondaryAction,\n hasHeader,\n hasActions,\n}: {\n icon?: React.ReactNode;\n heading?: React.ReactNode;\n pill?: React.ReactNode;\n children?: React.ReactNode;\n primaryAction?: TooltipAction;\n secondaryAction?: TooltipAction;\n hasHeader: boolean;\n hasActions: boolean;\n}) => (\n <div className=\"flex flex-col gap-3\">\n {hasHeader && (\n <div className=\"flex items-center gap-3\">\n {icon && <div className=\"size-5 shrink-0\">{icon}</div>}\n {heading && (\n <p className=\"typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse\">\n {heading}\n </p>\n )}\n {pill && <div className=\"shrink-0\">{pill}</div>}\n </div>\n )}\n {children && (\n <div className=\"typography-regular-body-md text-foreground-inverse\">{children}</div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-1\">\n {primaryAction && <ActionButton action={primaryAction} variant=\"brand\" />}\n {secondaryAction && <ActionButton action={secondaryAction} variant=\"tertiary\" />}\n </div>\n )}\n </div>\n);\n\n/**\n * The popup content of the tooltip. Renders inside a portal.\n *\n * Arrow direction is controlled via the `side` and `align` props (Radix passthrough).\n *\n * @example\n * ```tsx\n * // Simple tooltip\n * <TooltipContent>Info text</TooltipContent>\n *\n * // Infobox with structured content\n * <TooltipContent\n * variant=\"infobox\"\n * heading=\"Title\"\n * icon={<InfoCircleIcon className=\"size-5\" />}\n * primaryAction={{ label: \"OK\", onClick: () => {} }}\n * secondaryAction={{ label: \"Dismiss\" }}\n * >\n * Info text\n * </TooltipContent>\n * ```\n */\nexport const TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(\n (\n {\n className,\n variant = \"tooltip\",\n showArrow = true,\n sideOffset = 8,\n heading,\n icon,\n pill,\n primaryAction,\n secondaryAction,\n children,\n side,\n style,\n ...props\n },\n ref,\n ) => {\n const isInfobox = variant === \"infobox\";\n const hasHeader =\n isInfobox && (icon !== undefined || heading !== undefined || pill !== undefined);\n const hasActions = isInfobox && (primaryAction !== undefined || secondaryAction !== undefined);\n\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-regular-body-md max-h-[var(--radix-tooltip-content-available-height)] max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]\",\n isInfobox && \"border border-neutral-200\",\n className,\n )}\n align=\"center\"\n arrowPadding={12}\n side={side}\n {...props}\n >\n {isInfobox ? (\n <InfoboxContent\n icon={icon}\n heading={heading}\n pill={pill}\n primaryAction={primaryAction}\n secondaryAction={secondaryAction}\n hasHeader={hasHeader}\n hasActions={hasActions}\n >\n {children}\n </InfoboxContent>\n ) : (\n children\n )}\n {showArrow && (\n <TooltipPrimitive.Arrow\n className={\n \"-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse\"\n }\n width={12}\n height={6}\n />\n )}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n );\n },\n);\nTooltipContent.displayName = \"TooltipContent\";\n"],"names":[],"mappings":";;;;;;AASO,MAAM,kBAAkB,iBAAiB;AAgBzC,MAAM,UAAU,iBAAiB;AAMjC,MAAM,iBAAiB,iBAAiB;AA+D/C,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA;AACF,MAIE,OAAO,UACL,OAAO,UAEP,oBAAC,QAAA,EAAO,SAAkB,MAAK,MAAK,SAAS,OAAO,SACjD,iBAAO,OACV;AAGJ,MAAM,iBAAiB,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAUE,qBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,EAAA,aACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,QAAQ,oBAAC,OAAA,EAAI,WAAU,mBAAmB,UAAA,MAAK;AAAA,IAC/C,WACC,oBAAC,KAAA,EAAE,WAAU,sEACV,UAAA,SACH;AAAA,IAED,QAAQ,oBAAC,OAAA,EAAI,WAAU,YAAY,UAAA,KAAA,CAAK;AAAA,EAAA,GAC3C;AAAA,EAED,YACC,oBAAC,OAAA,EAAI,WAAU,sDAAsD,UAAS;AAAA,EAE/E,cACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,iBAAiB,oBAAC,cAAA,EAAa,QAAQ,eAAe,SAAQ,SAAQ;AAAA,IACtE,mBAAmB,oBAAC,cAAA,EAAa,QAAQ,iBAAiB,SAAQ,WAAA,CAAW;AAAA,EAAA,EAAA,CAChF;AAAA,GAEJ;AAyBK,MAAM,iBAAiB,MAAM;AAAA,EAIlC,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,YAAY,YAAY;AAC9B,UAAM,YACJ,cAAc,SAAS,UAAa,YAAY,UAAa,SAAS;AACxE,UAAM,aAAa,cAAc,kBAAkB,UAAa,oBAAoB;AAEpF,WACE,oBAAC,iBAAiB,QAAjB,EACC,UAAA;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC;AAAA,QACA;AAAA,QACA,kBAAkB;AAAA,QAClB,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,QAC3D,WAAW;AAAA,UACT;AAAA,UACA,aAAa;AAAA,UACb;AAAA,QAAA;AAAA,QAEF,OAAM;AAAA,QACN,cAAc;AAAA,QACd;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,YACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cAEC;AAAA,YAAA;AAAA,UAAA,IAGH;AAAA,UAED,aACC;AAAA,YAAC,iBAAiB;AAAA,YAAjB;AAAA,cACC,WACE;AAAA,cAEF,OAAO;AAAA,cACP,QAAQ;AAAA,YAAA;AAAA,UAAA;AAAA,QACV;AAAA,MAAA;AAAA,IAAA,GAGN;AAAA,EAEJ;AACF;AACA,eAAe,cAAc;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -254,6 +254,74 @@ export declare const BoltIcon: React_2.ForwardRefExoticComponent<React_2.SVGAttr
|
|
|
254
254
|
className?: string;
|
|
255
255
|
} & React_2.RefAttributes<SVGSVGElement>>;
|
|
256
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Root navigation wrapper for the breadcrumb trail.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```tsx
|
|
262
|
+
* <Breadcrumb>
|
|
263
|
+
* <BreadcrumbList>
|
|
264
|
+
* <BreadcrumbItem><BreadcrumbLink href="/">Home</BreadcrumbLink></BreadcrumbItem>
|
|
265
|
+
* <BreadcrumbSeparator />
|
|
266
|
+
* <BreadcrumbItem><BreadcrumbPage>Current Page</BreadcrumbPage></BreadcrumbItem>
|
|
267
|
+
* </BreadcrumbList>
|
|
268
|
+
* </Breadcrumb>
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
export declare const Breadcrumb: React_2.ForwardRefExoticComponent<BreadcrumbProps & React_2.RefAttributes<HTMLElement>>;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* List item wrapper for a single breadcrumb entry or separator.
|
|
275
|
+
*/
|
|
276
|
+
export declare const BreadcrumbItem: React_2.ForwardRefExoticComponent<BreadcrumbItemProps & React_2.RefAttributes<HTMLLIElement>>;
|
|
277
|
+
|
|
278
|
+
export declare interface BreadcrumbItemProps extends React_2.ComponentPropsWithoutRef<"li"> {
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Anchor element for a non-current breadcrumb step. Supports `asChild` for
|
|
283
|
+
* router-aware link components.
|
|
284
|
+
*/
|
|
285
|
+
export declare const BreadcrumbLink: React_2.ForwardRefExoticComponent<BreadcrumbLinkProps & React_2.RefAttributes<HTMLAnchorElement>>;
|
|
286
|
+
|
|
287
|
+
export declare interface BreadcrumbLinkProps extends React_2.ComponentPropsWithoutRef<"a"> {
|
|
288
|
+
/** Render the link as a child element (e.g. a router `Link`). @default false */
|
|
289
|
+
asChild?: boolean;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Ordered list container for breadcrumb items. Automatically injects a
|
|
294
|
+
* separator between each child item.
|
|
295
|
+
*/
|
|
296
|
+
export declare const BreadcrumbList: React_2.ForwardRefExoticComponent<BreadcrumbListProps & React_2.RefAttributes<HTMLOListElement>>;
|
|
297
|
+
|
|
298
|
+
export declare interface BreadcrumbListProps extends React_2.ComponentPropsWithoutRef<"ol"> {
|
|
299
|
+
/** Custom separator element rendered between items. @default ChevronRightIcon */
|
|
300
|
+
separator?: React_2.ReactNode;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Non-interactive label representing the current page in the breadcrumb trail.
|
|
305
|
+
*/
|
|
306
|
+
export declare const BreadcrumbPage: React_2.ForwardRefExoticComponent<BreadcrumbPageProps & React_2.RefAttributes<HTMLSpanElement>>;
|
|
307
|
+
|
|
308
|
+
export declare interface BreadcrumbPageProps extends React_2.ComponentPropsWithoutRef<"span"> {
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export declare interface BreadcrumbProps extends React_2.ComponentPropsWithoutRef<"nav"> {
|
|
312
|
+
/** Accessible label for the breadcrumb navigation landmark. @default "breadcrumb" */
|
|
313
|
+
"aria-label"?: string;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Visual separator rendered between breadcrumb items.
|
|
318
|
+
* Renders a right-pointing chevron icon and is hidden from assistive technology.
|
|
319
|
+
*/
|
|
320
|
+
export declare const BreadcrumbSeparator: React_2.ForwardRefExoticComponent<BreadcrumbSeparatorProps & React_2.RefAttributes<HTMLLIElement>>;
|
|
321
|
+
|
|
322
|
+
export declare interface BreadcrumbSeparatorProps extends React_2.ComponentPropsWithoutRef<"li"> {
|
|
323
|
+
}
|
|
324
|
+
|
|
257
325
|
export declare const BulbIcon: React_2.ForwardRefExoticComponent<React_2.SVGAttributes<SVGSVGElement> & {
|
|
258
326
|
className?: string;
|
|
259
327
|
} & React_2.RefAttributes<SVGSVGElement>>;
|
|
@@ -310,6 +378,75 @@ export declare const CameraIcon: React_2.ForwardRefExoticComponent<React_2.SVGAt
|
|
|
310
378
|
className?: string;
|
|
311
379
|
} & React_2.RefAttributes<SVGSVGElement>>;
|
|
312
380
|
|
|
381
|
+
/**
|
|
382
|
+
* A composable card component with multiple visual variants. Use with
|
|
383
|
+
* {@link CardHeader}, {@link CardTitle}, {@link CardDescription},
|
|
384
|
+
* {@link CardContent}, and {@link CardFooter} for structured layouts.
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```tsx
|
|
388
|
+
* <Card variant="outlined">
|
|
389
|
+
* <CardHeader action={<HomeIcon className="size-5" />}>
|
|
390
|
+
* <CardTitle>Card title</CardTitle>
|
|
391
|
+
* <CardDescription>Card description text</CardDescription>
|
|
392
|
+
* </CardHeader>
|
|
393
|
+
* <CardContent>Content goes here</CardContent>
|
|
394
|
+
* <CardFooter>
|
|
395
|
+
* <Button variant="secondary">Label</Button>
|
|
396
|
+
* <Button variant="primary">Label</Button>
|
|
397
|
+
* </CardFooter>
|
|
398
|
+
* </Card>
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
export declare const Card: React_2.ForwardRefExoticComponent<CardProps & React_2.RefAttributes<HTMLDivElement>>;
|
|
402
|
+
|
|
403
|
+
/** Flexible content area of a {@link Card}. Adds vertical padding between header and footer. */
|
|
404
|
+
export declare const CardContent: React_2.ForwardRefExoticComponent<CardContentProps & React_2.RefAttributes<HTMLDivElement>>;
|
|
405
|
+
|
|
406
|
+
export declare interface CardContentProps extends React_2.HTMLAttributes<HTMLDivElement> {
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** Description text rendered below the {@link CardTitle} inside a {@link CardHeader}. */
|
|
410
|
+
export declare const CardDescription: React_2.ForwardRefExoticComponent<CardDescriptionProps & React_2.RefAttributes<HTMLParagraphElement>>;
|
|
411
|
+
|
|
412
|
+
export declare interface CardDescriptionProps extends React_2.HTMLAttributes<HTMLParagraphElement> {
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Footer section of a {@link Card}. Renders children in a horizontal row with a gap. */
|
|
416
|
+
export declare const CardFooter: React_2.ForwardRefExoticComponent<CardFooterProps & React_2.RefAttributes<HTMLDivElement>>;
|
|
417
|
+
|
|
418
|
+
export declare interface CardFooterProps extends React_2.HTMLAttributes<HTMLDivElement> {
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Header section of a {@link Card}. Renders a flex row with text content
|
|
423
|
+
* on the left and an optional trailing action element (e.g. icon) on the right.
|
|
424
|
+
*/
|
|
425
|
+
export declare const CardHeader: React_2.ForwardRefExoticComponent<CardHeaderProps & React_2.RefAttributes<HTMLDivElement>>;
|
|
426
|
+
|
|
427
|
+
export declare interface CardHeaderProps extends React_2.HTMLAttributes<HTMLDivElement> {
|
|
428
|
+
/** Icon element displayed at the trailing end of the header. */
|
|
429
|
+
action?: React_2.ReactNode;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export declare interface CardProps extends React_2.HTMLAttributes<HTMLDivElement> {
|
|
433
|
+
/** Visual style variant of the card. @default "outlined" */
|
|
434
|
+
variant?: CardVariant;
|
|
435
|
+
/** When `true`, the card will take the full width of its container. @default true */
|
|
436
|
+
fullWidth?: boolean;
|
|
437
|
+
/** When `true`, removes all internal padding. @default false */
|
|
438
|
+
noPadding?: boolean;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** Title element rendered inside a {@link CardHeader}. */
|
|
442
|
+
export declare const CardTitle: React_2.ForwardRefExoticComponent<CardTitleProps & React_2.RefAttributes<HTMLHeadingElement>>;
|
|
443
|
+
|
|
444
|
+
export declare interface CardTitleProps extends React_2.HTMLAttributes<HTMLHeadingElement> {
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** Visual style variant of the card. */
|
|
448
|
+
export declare type CardVariant = "outlined" | "elevated" | "filled" | "ghost";
|
|
449
|
+
|
|
313
450
|
export declare const ChartIcon: React_2.ForwardRefExoticComponent<React_2.SVGAttributes<SVGSVGElement> & {
|
|
314
451
|
className?: string;
|
|
315
452
|
} & React_2.RefAttributes<SVGSVGElement>>;
|
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,9 @@ import { AudioUpload } from "./components/AudioUpload/AudioUpload.mjs";
|
|
|
4
4
|
import { useAudioRecorder } from "./components/AudioUpload/useAudioRecorder.mjs";
|
|
5
5
|
import { Avatar, AvatarFallback, AvatarImage, AvatarRoot } from "./components/Avatar/Avatar.mjs";
|
|
6
6
|
import { Badge } from "./components/Badge/Badge.mjs";
|
|
7
|
+
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "./components/Breadcrumb/Breadcrumb.mjs";
|
|
7
8
|
import { Button } from "./components/Button/Button.mjs";
|
|
9
|
+
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./components/Card/Card.mjs";
|
|
8
10
|
import { Checkbox } from "./components/Checkbox/Checkbox.mjs";
|
|
9
11
|
import { Chip } from "./components/Chip/Chip.mjs";
|
|
10
12
|
import { Count } from "./components/Count/Count.mjs";
|
|
@@ -172,11 +174,23 @@ export {
|
|
|
172
174
|
BellIcon,
|
|
173
175
|
BellOffIcon,
|
|
174
176
|
BoltIcon,
|
|
177
|
+
Breadcrumb,
|
|
178
|
+
BreadcrumbItem,
|
|
179
|
+
BreadcrumbLink,
|
|
180
|
+
BreadcrumbList,
|
|
181
|
+
BreadcrumbPage,
|
|
182
|
+
BreadcrumbSeparator,
|
|
175
183
|
BulbIcon,
|
|
176
184
|
Button,
|
|
177
185
|
Calendar2Icon,
|
|
178
186
|
CalendarIcon,
|
|
179
187
|
CameraIcon,
|
|
188
|
+
Card,
|
|
189
|
+
CardContent,
|
|
190
|
+
CardDescription,
|
|
191
|
+
CardFooter,
|
|
192
|
+
CardHeader,
|
|
193
|
+
CardTitle,
|
|
180
194
|
ChartIcon,
|
|
181
195
|
CheckCircleIcon,
|
|
182
196
|
CheckIcon,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|