@devalok/shilp-sutra 0.37.1 → 0.39.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/MIGRATION.md +185 -0
- package/dist/_chunks/badge-group.js +4 -4
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chat.js +14 -14
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/date-picker.js +9 -9
- package/dist/_chunks/date-picker.js.map +1 -1
- package/dist/_chunks/document-preview.js +2 -2
- package/dist/_chunks/document-preview.js.map +1 -1
- package/dist/_chunks/file-preview.js +11 -11
- package/dist/_chunks/file-preview.js.map +1 -1
- package/dist/_chunks/image-preview.js +2 -2
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +5 -5
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/popover.js +3 -3
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/rich-chat-input.js +33 -33
- package/dist/_chunks/rich-chat-input.js.map +1 -1
- package/dist/_chunks/shared.js +5 -5
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/text.js +2 -2
- package/dist/_chunks/text.js.map +1 -1
- package/dist/_chunks/tiptap.js +977 -968
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/_chunks/use-calendar.js +5 -5
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/ai/command-bar.js +10 -10
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +4 -4
- package/dist/ai/conversation.js.map +1 -1
- package/dist/composed/activity-feed.js +5 -5
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.js +4 -4
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.js +1 -1
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js +5 -5
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/emoji-picker.js +4 -4
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/empty-state.js +1 -1
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/error-boundary.js +3 -3
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/filter-bar.js +1 -1
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/index.d.ts +0 -2
- package/dist/composed/index.d.ts.map +1 -1
- package/dist/composed/index.js +5 -6
- package/dist/composed/inline-edit.js +1 -1
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/composed/loading-skeleton.js +9 -9
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/markdown-viewer.js +3 -3
- package/dist/composed/markdown-viewer.js.map +1 -1
- package/dist/composed/multi-select-popover.js +1 -1
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/page-header.js +1 -1
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/page-skeletons.js +15 -15
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/priority-indicator.js +3 -3
- package/dist/composed/priority-indicator.js.map +1 -1
- package/dist/composed/rich-text-editor.js +11 -11
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js +3 -3
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/composed/status-badge.js +3 -3
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +0 -1
- package/dist/shell/bottom-navbar.js +6 -6
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/notification-center.js +8 -8
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js +1 -1
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/shell/sidebar.js +6 -6
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.js +4 -4
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +82 -9
- package/dist/ui/accordion.js +1 -1
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.js +3 -3
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.d.ts +1 -2
- package/dist/ui/alert.d.ts.map +1 -1
- package/dist/ui/alert.js +3 -29
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/autocomplete.js +2 -2
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.js +11 -11
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge-indicator.js +1 -1
- package/dist/ui/badge-indicator.js.map +1 -1
- package/dist/ui/banner.d.ts +3 -5
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +14 -14
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/breadcrumb.js +1 -1
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button.d.ts +2 -2
- package/dist/ui/button.js +14 -14
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +5 -5
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/charts/index.js +5 -5
- package/dist/ui/charts/index.js.map +1 -1
- package/dist/ui/checkbox.js +1 -1
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/code.js +2 -2
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/color-input.js +10 -10
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/color-swatch.js +3 -3
- package/dist/ui/color-swatch.js.map +1 -1
- package/dist/ui/combobox.js +5 -5
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +6 -6
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.js +1 -1
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.js +2 -2
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.js +2 -2
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-header.js +2 -2
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.js +3 -3
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/data-table-toolbar.js +1 -1
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.js +1 -1
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/devalok-grain.d.ts +1 -1
- package/dist/ui/devalok-grain.js.map +1 -1
- package/dist/ui/dialog.js +2 -2
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dropdown-menu.js +6 -6
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.js +4 -4
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/hover-card.js +1 -1
- package/dist/ui/hover-card.js.map +1 -1
- package/dist/ui/icon-button.js +1 -1
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -2
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-otp.js +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.d.ts +1 -9
- package/dist/ui/input.d.ts.map +1 -1
- package/dist/ui/input.js +28 -29
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/link.js +1 -1
- package/dist/ui/link.js.map +1 -1
- package/dist/ui/menubar.js +8 -8
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +3 -3
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/number-input.js +3 -3
- package/dist/ui/number-input.js.map +1 -1
- package/dist/ui/pagination.js +1 -1
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/progress.js +1 -1
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/radio.js +1 -1
- package/dist/ui/radio.js.map +1 -1
- package/dist/ui/segmented-control.d.ts +1 -1
- package/dist/ui/segmented-control.d.ts.map +1 -1
- package/dist/ui/segmented-control.js +5 -7
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/select.js +3 -3
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sheet.js +2 -2
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +11 -11
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/skeleton.js +9 -9
- package/dist/ui/skeleton.js.map +1 -1
- package/dist/ui/slider.js +2 -2
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/split-button.js +7 -7
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.js +7 -7
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/status-dot.js +2 -2
- package/dist/ui/status-dot.js.map +1 -1
- package/dist/ui/stepper.js +2 -2
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/switch.js +2 -2
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/tabs.js +3 -3
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/textarea.js +1 -1
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.js +8 -8
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toggle.js +1 -1
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.js +1 -1
- package/dist/ui/tooltip.js.map +1 -1
- package/docs/components/_header.md +91 -2
- package/docs/components/ui/alert.md +4 -1
- package/docs/components/ui/banner.md +3 -1
- package/docs/components/ui/input.md +4 -2
- package/docs/components/ui/segmented-control.md +13 -6
- package/docs/recipes/customize-brand.md +297 -0
- package/docs/recipes/index.md +51 -0
- package/docs/recipes/install-astro.md +178 -0
- package/docs/recipes/install-next-app-router.md +230 -0
- package/docs/recipes/install-next-pages.md +123 -0
- package/docs/recipes/install-remix.md +171 -0
- package/docs/recipes/install-tanstack-start.md +143 -0
- package/docs/recipes/install-vite.md +170 -0
- package/docs/recipes/server-components.md +209 -0
- package/docs/recipes/troubleshoot.md +217 -0
- package/llms-full.txt +116 -54
- package/llms.txt +42 -17
- package/package.json +46 -35
- package/skill/README.md +99 -0
- package/skill/SKILL.md +144 -0
- package/skill/install.sh +59 -0
- package/skill/references/components-full.md +6997 -0
- package/skill/references/components.md +673 -0
- package/skill/references/customize-brand.md +299 -0
- package/skill/references/server-components.md +211 -0
- package/skill/references/setup-astro.md +180 -0
- package/skill/references/setup-next-app-router.md +232 -0
- package/skill/references/setup-next-pages.md +125 -0
- package/skill/references/setup-remix.md +173 -0
- package/skill/references/setup-tanstack-start.md +145 -0
- package/skill/references/setup-vite.md +172 -0
- package/skill/references/troubleshoot.md +219 -0
- package/dist/composed/responsive-overlay.d.ts +0 -23
- package/dist/composed/responsive-overlay.d.ts.map +0 -1
- package/dist/composed/responsive-overlay.js +0 -40
- package/dist/composed/responsive-overlay.js.map +0 -1
- package/dist/hooks/use-toast.d.ts +0 -17
- package/dist/hooks/use-toast.d.ts.map +0 -1
- package/dist/hooks/use-toast.js +0 -3
- package/dist/tailwind/index.cjs +0 -41
- package/dist/tailwind/index.d.ts +0 -2
- package/dist/tailwind/index.d.ts.map +0 -1
- package/dist/tailwind/index.js +0 -2
- package/dist/tailwind/preset.d.ts +0 -25
- package/dist/tailwind/preset.d.ts.map +0 -1
- package/dist/tailwind/preset.js +0 -17
- package/dist/tailwind/preset.js.map +0 -1
- package/docs/components/composed/responsive-overlay.md +0 -41
- /package/{LICENSE → skill/LICENSE} +0 -0
package/dist/ui/stat-card.js
CHANGED
|
@@ -80,14 +80,14 @@ function h({ data: e, colorClass: t }) {
|
|
|
80
80
|
function g({ progress: e, label: t }) {
|
|
81
81
|
let r = Math.max(0, Math.min(100, e)), i = r >= 90 ? "bg-success-9" : r >= 70 ? "bg-warning-9" : "bg-accent-9";
|
|
82
82
|
return /* @__PURE__ */ s("div", {
|
|
83
|
-
className: "h-1 w-full rounded-
|
|
83
|
+
className: "h-1 w-full rounded-pill bg-surface-raised mt-ds-04",
|
|
84
84
|
role: "progressbar",
|
|
85
85
|
"aria-label": `${t} progress`,
|
|
86
86
|
"aria-valuenow": r,
|
|
87
87
|
"aria-valuemin": 0,
|
|
88
88
|
"aria-valuemax": 100,
|
|
89
89
|
children: /* @__PURE__ */ s("div", {
|
|
90
|
-
className: n("h-full rounded-
|
|
90
|
+
className: n("h-full rounded-pill transition-[width] duration-moderate-02 ease-productive-standard", i),
|
|
91
91
|
style: { width: `${r}%` }
|
|
92
92
|
})
|
|
93
93
|
});
|
|
@@ -96,12 +96,12 @@ var _ = a.forwardRef(({ className: a, label: m, title: _, value: v, prefix: y, s
|
|
|
96
96
|
let P = i(), F = _ ?? m ?? "", I = !!(k || A), L = I && !M["aria-label"] ? `View ${F}` : M["aria-label"];
|
|
97
97
|
if (C) return /* @__PURE__ */ c("div", {
|
|
98
98
|
ref: N,
|
|
99
|
-
className: n("rounded-
|
|
99
|
+
className: n("rounded-surface border border-surface-border bg-surface-raised shadow-raised p-ds-05b", D && `border-l-[3px] ${p[D]}`, a),
|
|
100
100
|
...M,
|
|
101
101
|
children: [
|
|
102
|
-
/* @__PURE__ */ s("div", { className: "h-ds-04 w-24 rounded-
|
|
103
|
-
/* @__PURE__ */ s("div", { className: "h-ds-sm w-32 rounded-
|
|
104
|
-
/* @__PURE__ */ s("div", { className: "h-3 w-16 rounded-
|
|
102
|
+
/* @__PURE__ */ s("div", { className: "h-ds-04 w-24 rounded-control-inner bg-skeleton-base animate-pulse mb-ds-05" }),
|
|
103
|
+
/* @__PURE__ */ s("div", { className: "h-ds-sm w-32 rounded-control bg-skeleton-base animate-pulse mb-ds-03" }),
|
|
104
|
+
/* @__PURE__ */ s("div", { className: "h-3 w-16 rounded-control-inner bg-skeleton-base animate-pulse" })
|
|
105
105
|
]
|
|
106
106
|
});
|
|
107
107
|
let R = x?.direction === "up" ? d : x?.direction === "down" ? u : l, z = x?.direction === "up" ? "text-success-11" : x?.direction === "down" ? "text-error-11" : "text-surface-fg-muted", B = x?.direction === "up" ? "text-success-11" : x?.direction === "down" ? "text-error-11" : "text-accent-11", V = /* @__PURE__ */ c(o, { children: [
|
|
@@ -236,7 +236,7 @@ var _ = a.forwardRef(({ className: a, label: m, title: _, value: v, prefix: y, s
|
|
|
236
236
|
},
|
|
237
237
|
children: j
|
|
238
238
|
})
|
|
239
|
-
] }), H = n("rounded-
|
|
239
|
+
] }), H = n("rounded-surface border border-surface-border bg-surface-raised shadow-raised p-ds-05b", D && `border-l-[3px] ${p[D]}`, I && "cursor-pointer hover:shadow-raised-hover hover:border-surface-border-strong transition-[box-shadow,border-color] duration-fast-02 ease-productive-standard group", a);
|
|
240
240
|
return A ? /* @__PURE__ */ s(P, {
|
|
241
241
|
ref: N,
|
|
242
242
|
href: A,
|
package/dist/ui/stat-card.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stat-card.js","names":[],"sources":["../../src/ui/stat-card.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconTrendingDown, IconTrendingUp } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { useLink } from './lib/link-context'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/**\n * Props for StatCard — a dashboard metric tile displaying a label, a large numeric value,\n * an optional trend delta (with directional arrow icon), and an optional header icon.\n *\n * **Delta direction:** `'up'` renders a green trending-up arrow, `'down'` renders a red\n * trending-down arrow, `'neutral'` renders a grey dash. The `delta.value` is a formatted\n * string (e.g. `\"+8%\"` or `\"−120\"`).\n *\n * **Loading state:** Pass `loading={true}` to render a pulse-skeleton placeholder instead of data.\n *\n * @example\n * // Revenue metric with a positive trend:\n * <StatCard\n * label=\"Monthly Revenue\"\n * value=\"$48,200\"\n * delta={{ value: \"+12%\", direction: \"up\" }}\n * icon={<IconCurrencyDollar />}\n * />\n *\n * @example\n * // Open ticket count with a downward trend (good for support queues):\n * <StatCard\n * label=\"Open Tickets\"\n * value={142}\n * delta={{ value: \"−18\", direction: \"down\" }}\n * />\n *\n * @example\n * // Loading skeleton while data is fetching:\n * <StatCard label=\"Users\" value={0} loading={isFetching} />\n *\n * @example\n * // Simple metric with no trend (stable, neutral):\n * <StatCard\n * label=\"Storage Used\"\n * value=\"4.2 GB\"\n * delta={{ value: \"No change\", direction: \"neutral\" }}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface StatCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Heading text for the metric. `title` is an alias for `label`. */\n label?: string\n /** Alias for `label` — use whichever feels natural. */\n title?: string\n value: string | number\n /** Prefix before value, e.g. \"$\" */\n prefix?: string\n /** Suffix after value, e.g. \"users\" */\n suffix?: string\n delta?: {\n value: string\n direction: 'up' | 'down' | 'neutral'\n }\n icon?: React.ReactNode | React.ComponentType<{ className?: string }>\n loading?: boolean\n /** Comparison period label shown after delta, e.g. \"vs last month\" */\n comparisonLabel?: string\n /** Secondary metric below main value, e.g. \"of $50,000 target\" */\n secondaryLabel?: string\n /** Progress toward a target (0-100). Renders a thin progress bar below the value. */\n progress?: number\n /** Color accent for the left border decoration */\n accent?: 'default' | 'success' | 'warning' | 'error' | 'info'\n /** Sparkline data points. Renders a mini SVG line chart in the card. */\n sparkline?: number[]\n /** Make the card clickable with hover state */\n onClick?: () => void\n /** Href — makes the card a link (uses the LinkContext Link component) */\n href?: string\n /** Footer content rendered below the card body, e.g. \"View details →\" */\n footer?: React.ReactNode\n}\n\nconst accentBorderMap: Record<NonNullable<StatCardProps['accent']>, string> = {\n default: 'border-l-accent-9',\n success: 'border-l-success-9',\n warning: 'border-l-warning-9',\n error: 'border-l-error-9',\n info: 'border-l-info-9',\n}\n\nfunction buildSparklinePath(raw: number[], width: number, height: number): string {\n const data = raw.filter((v) => Number.isFinite(v))\n if (data.length < 2) return ''\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const stepX = width / (data.length - 1)\n return data\n .map((v, i) => {\n const x = i * stepX\n const y = height - ((v - min) / range) * height\n return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`\n })\n .join(' ')\n}\n\nfunction Sparkline({\n data,\n colorClass,\n}: {\n data: number[]\n colorClass: string\n}) {\n const id = React.useId()\n const pathRef = React.useRef<SVGPathElement>(null)\n const [pathLength, setPathLength] = React.useState(0)\n const svgWidth = 80\n const svgHeight = 32\n const path = buildSparklinePath(data, svgWidth, svgHeight)\n\n React.useEffect(() => {\n if (pathRef.current) {\n setPathLength(pathRef.current.getTotalLength())\n }\n }, [path])\n\n if (!path) return null\n\n // Build area fill path (close to bottom-right then bottom-left)\n const areaPath = `${path} L${svgWidth.toFixed(1)},${svgHeight.toFixed(1)} L0,${svgHeight.toFixed(1)} Z`\n\n return (\n <div className={cn('w-20 h-8', colorClass)} aria-hidden=\"true\">\n <svg\n viewBox={`0 0 ${svgWidth} ${svgHeight}`}\n className=\"w-full h-full overflow-visible\"\n preserveAspectRatio=\"none\"\n >\n <defs>\n <linearGradient id={`sparkline-fill-${id}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"currentColor\" stopOpacity=\"0.1\" />\n <stop offset=\"100%\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill={`url(#sparkline-fill-${id})`} />\n <path\n ref={pathRef}\n d={path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n opacity: pathLength === 0 ? 0 : 1,\n strokeDasharray: pathLength,\n strokeDashoffset: pathLength,\n animation: pathLength > 0 ? `sparkline-draw-${id.replace(/:/g, '')} 1s ease-out forwards` : 'none',\n }}\n />\n </svg>\n {pathLength > 0 && (\n <style>{`@keyframes sparkline-draw-${id.replace(/:/g, '')} { to { stroke-dashoffset: 0; } }`}</style>\n )}\n </div>\n )\n}\n\nfunction ProgressBar({ progress, label }: { progress: number; label: string }) {\n const clamped = Math.max(0, Math.min(100, progress))\n const barColor =\n clamped >= 90 ? 'bg-success-9' : clamped >= 70 ? 'bg-warning-9' : 'bg-accent-9'\n\n return (\n <div className=\"h-1 w-full rounded-ds-full bg-surface-raised mt-ds-04\" role=\"progressbar\" aria-label={`${label} progress`} aria-valuenow={clamped} aria-valuemin={0} aria-valuemax={100}>\n <div\n className={cn('h-full rounded-ds-full transition-[width] duration-moderate-02 ease-productive-standard', barColor)}\n style={{ width: `${clamped}%` }}\n />\n </div>\n )\n}\n\nconst StatCard = React.forwardRef<HTMLDivElement, StatCardProps>(\n (\n {\n className,\n label,\n title,\n value,\n prefix,\n suffix,\n delta,\n icon,\n loading,\n comparisonLabel,\n secondaryLabel,\n progress,\n accent,\n sparkline,\n onClick,\n href,\n footer,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const resolvedLabel = title ?? label ?? ''\n const isClickable = !!(onClick || href)\n const computedAriaLabel =\n isClickable && !props['aria-label'] ? `View ${resolvedLabel}` : props['aria-label']\n\n if (loading) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-ds-lg border border-surface-border bg-surface-raised shadow-raised p-ds-05b',\n accent && `border-l-[3px] ${accentBorderMap[accent]}`,\n className,\n )}\n {...props}\n >\n <div className=\"h-ds-04 w-24 rounded-ds-sm bg-skeleton-base animate-pulse mb-ds-05\" />\n <div className=\"h-ds-sm w-32 rounded-ds-md bg-skeleton-base animate-pulse mb-ds-03\" />\n <div className=\"h-3 w-16 rounded-ds-sm bg-skeleton-base animate-pulse\" />\n </div>\n )\n }\n\n const DeltaIcon =\n delta?.direction === 'up'\n ? IconTrendingUp\n : delta?.direction === 'down'\n ? IconTrendingDown\n : IconMinus\n\n const deltaColour =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-surface-fg-muted'\n\n const sparklineColor =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-accent-11'\n\n const cardContent = (\n <>\n <div className=\"flex items-center justify-between mb-ds-04\">\n <motion.p\n className=\"text-ds-md font-medium text-surface-fg-muted\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n >\n {resolvedLabel}\n </motion.p>\n <div className=\"flex items-center gap-ds-03\">\n {sparkline && sparkline.length >= 2 && (\n <Sparkline data={sparkline} colorClass={sparklineColor} />\n )}\n {icon && (\n <motion.span\n className=\"text-surface-fg-muted\"\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n {typeof icon === 'function'\n ? <Icon icon={icon as React.ForwardRefExoticComponent<any>} size=\"lg\" />\n : icon}\n </motion.span>\n )}\n </div>\n </div>\n <div className=\"overflow-hidden\">\n <motion.p\n className=\"inline-block text-ds-3xl font-semibold text-surface-fg\"\n initial={{ opacity: 0, y: '100%' }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.smooth}\n >\n {prefix && (\n <span className=\"text-surface-fg-muted text-ds-lg\">{prefix}</span>\n )}\n <span className=\"tabular-nums\">{value}</span>\n {suffix && (\n <span className=\"text-surface-fg-muted text-ds-lg\">{suffix}</span>\n )}\n </motion.p>\n </div>\n {secondaryLabel && (\n <motion.p\n className=\"text-ds-sm text-surface-fg-subtle mt-ds-01\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.1 }}\n >\n {secondaryLabel}\n </motion.p>\n )}\n {progress != null && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.15 }}\n >\n <ProgressBar progress={progress} label={resolvedLabel} />\n </motion.div>\n )}\n {delta && (\n <motion.div\n className={cn(\n 'mt-ds-03 flex items-center gap-ds-02 text-ds-sm font-medium',\n deltaColour,\n )}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.smooth, delay: 0.2 }}\n >\n <motion.span\n className=\"inline-flex\"\n initial={{ opacity: 0.5, scale: 1.4 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.bouncy}\n >\n <Icon icon={DeltaIcon} size=\"sm\" />\n </motion.span>\n <span>{delta.value}</span>\n {comparisonLabel && (\n <span className=\"text-surface-fg-subtle font-normal\">{comparisonLabel}</span>\n )}\n </motion.div>\n )}\n {footer && (\n <motion.div\n className=\"mt-ds-04 pt-ds-04 border-t border-surface-border text-ds-sm\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.25 }}\n >\n {footer}\n </motion.div>\n )}\n </>\n )\n\n const cardClasses = cn(\n 'rounded-ds-lg border border-surface-border bg-surface-raised shadow-raised p-ds-05b',\n accent && `border-l-[3px] ${accentBorderMap[accent]}`,\n isClickable &&\n 'cursor-pointer hover:shadow-raised-hover hover:border-surface-border-strong transition-[box-shadow,border-color] duration-fast-02 ease-productive-standard group',\n className,\n )\n\n if (href) {\n return (\n <Link\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n onClick={onClick}\n className={cn(cardClasses, 'block no-underline')}\n aria-label={computedAriaLabel}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n {cardContent}\n </Link>\n )\n }\n\n return (\n <div\n ref={ref}\n className={cardClasses}\n onClick={onClick}\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n aria-label={computedAriaLabel}\n onKeyDown={\n onClick\n ? (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onClick()\n }\n }\n : undefined\n }\n {...props}\n >\n {cardContent}\n </div>\n )\n },\n)\n\nStatCard.displayName = 'StatCard'\n\nexport { StatCard }\n"],"mappings":";;;;;;;;;;AAqFA,IAAM,IAAwE;CAC5E,SAAS;CACT,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACP;AAED,SAAS,EAAmB,GAAe,GAAe,GAAwB;CAChF,IAAM,IAAO,EAAI,QAAQ,MAAM,OAAO,SAAS,EAAE,CAAC;AAClD,KAAI,EAAK,SAAS,EAAG,QAAO;CAC5B,IAAM,IAAM,KAAK,IAAI,GAAG,EAAK,EAEvB,IADM,KAAK,IAAI,GAAG,EAAK,GACT,KAAO,GACrB,IAAQ,KAAS,EAAK,SAAS;AACrC,QAAO,EACJ,KAAK,GAAG,MAAM;EACb,IAAM,IAAI,IAAI,GACR,IAAI,KAAW,IAAI,KAAO,IAAS;AACzC,SAAO,GAAG,MAAM,IAAI,MAAM,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE;GAC5D,CACD,KAAK,IAAI;;AAGd,SAAS,EAAU,EACjB,SACA,iBAIC;CACD,IAAM,IAAK,EAAM,OAAO,EAClB,IAAU,EAAM,OAAuB,KAAK,EAC5C,CAAC,GAAY,KAAiB,EAAM,SAAS,EAAE,EAG/C,IAAO,EAAmB,GAAM,IAAU,GAAU;AAQ1D,KANA,EAAM,gBAAgB;AACpB,EAAI,EAAQ,WACV,EAAc,EAAQ,QAAQ,gBAAgB,CAAC;IAEhD,CAAC,EAAK,CAAC,EAEN,CAAC,EAAM,QAAO;CAGlB,IAAM,IAAW,GAAG,EAAK,IAAI,IAAS,QAAQ,EAAE,CAAC,GAAG,IAAU,QAAQ,EAAE,CAAC,MAAM,IAAU,QAAQ,EAAE,CAAC;AAEpG,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,YAAY,EAAW;EAAE,eAAY;YAAxD,CACE,kBAAC,OAAD;GACE,SAAS;GACT,WAAU;GACV,qBAAoB;aAHtB;IAKE,kBAAC,QAAD,EAAA,UACE,kBAAC,kBAAD;KAAgB,IAAI,kBAAkB;KAAM,IAAG;KAAI,IAAG;KAAI,IAAG;KAAI,IAAG;eAApE,CACE,kBAAC,QAAD;MAAM,QAAO;MAAK,WAAU;MAAe,aAAY;MAAQ,CAAA,EAC/D,kBAAC,QAAD;MAAM,QAAO;MAAO,WAAU;MAAe,aAAY;MAAM,CAAA,CAChD;QACZ,CAAA;IACP,kBAAC,QAAD;KAAS;KAAU,MAAM,uBAAuB,EAAG;KAAM,CAAA;IACzD,kBAAC,QAAD;KACE,KAAK;KACL,GAAG;KACH,MAAK;KACL,QAAO;KACP,aAAY;KACZ,eAAc;KACd,gBAAe;KACf,OAAO;MACL,SAAS,MAAe,IAAI,IAAI;MAChC,iBAAiB;MACjB,kBAAkB;MAClB,WAAW,IAAa,IAAI,kBAAkB,EAAG,QAAQ,MAAM,GAAG,CAAC,yBAAyB;MAC7F;KACD,CAAA;IACE;MACL,IAAa,KACZ,kBAAC,SAAD,EAAA,UAAQ,6BAA6B,EAAG,QAAQ,MAAM,GAAG,CAAC,oCAA2C,CAAA,CAEnG;;;AAIV,SAAS,EAAY,EAAE,aAAU,YAA8C;CAC7E,IAAM,IAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,EAAS,CAAC,EAC9C,IACJ,KAAW,KAAK,iBAAiB,KAAW,KAAK,iBAAiB;AAEpE,QACE,kBAAC,OAAD;EAAK,WAAU;EAAwD,MAAK;EAAc,cAAY,GAAG,EAAM;EAAY,iBAAe;EAAS,iBAAe;EAAG,iBAAe;YAClL,kBAAC,OAAD;GACE,WAAW,EAAG,2FAA2F,EAAS;GAClH,OAAO,EAAE,OAAO,GAAG,EAAQ,IAAI;GAC/B,CAAA;EACE,CAAA;;AAIV,IAAM,IAAW,EAAM,YAEnB,EACE,cACA,UACA,UACA,UACA,WACA,WACA,UACA,SACA,YACA,oBACA,mBACA,aACA,WACA,cACA,YACA,SACA,WACA,GAAG,KAEL,MACG;CACH,IAAM,IAAO,GAAS,EAChB,IAAgB,KAAS,KAAS,IAClC,IAAc,CAAC,EAAE,KAAW,IAC5B,IACJ,KAAe,CAAC,EAAM,gBAAgB,QAAQ,MAAkB,EAAM;AAExE,KAAI,EACF,QACE,kBAAC,OAAD;EACO;EACL,WAAW,EACT,uFACA,KAAU,kBAAkB,EAAgB,MAC5C,EACD;EACD,GAAI;YAPN;GASE,kBAAC,OAAD,EAAK,WAAU,sEAAuE,CAAA;GACtF,kBAAC,OAAD,EAAK,WAAU,sEAAuE,CAAA;GACtF,kBAAC,OAAD,EAAK,WAAU,yDAA0D,CAAA;GACrE;;CAIV,IAAM,IACJ,GAAO,cAAc,OACjB,IACA,GAAO,cAAc,SACnB,IACA,GAEF,IACJ,GAAO,cAAc,OACjB,oBACA,GAAO,cAAc,SACnB,kBACA,yBAEF,IACJ,GAAO,cAAc,OACjB,oBACA,GAAO,cAAc,SACnB,kBACA,kBAEF,IACJ,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,EAAO,GAAR;IACE,WAAU;IACV,SAAS,EAAE,SAAS,GAAG;IACvB,SAAS,EAAE,SAAS,GAAG;IACvB,YAAY,EAAO;cAElB;IACQ,CAAA,EACX,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KAAa,EAAU,UAAU,KAChC,kBAAC,GAAD;KAAW,MAAM;KAAW,YAAY;KAAkB,CAAA,EAE3D,KACC,kBAAC,EAAO,MAAR;KACE,WAAU;KACV,SAAS;MAAE,SAAS;MAAG,OAAO;MAAM;KACpC,SAAS;MAAE,SAAS;MAAG,OAAO;MAAG;KACjC,YAAY,EAAQ;KACpB,eAAY;eAEX,OAAO,KAAS,aACb,kBAAC,GAAD;MAAY;MAA8C,MAAK;MAAO,CAAA,GACtE;KACQ,CAAA,CAEZ;MACF;;EACN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,EAAO,GAAR;IACE,WAAU;IACV,SAAS;KAAE,SAAS;KAAG,GAAG;KAAQ;IAClC,SAAS;KAAE,SAAS;KAAG,GAAG;KAAG;IAC7B,YAAY,EAAQ;cAJtB;KAMG,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAoC;MAAc,CAAA;KAEpE,kBAAC,QAAD;MAAM,WAAU;gBAAgB;MAAa,CAAA;KAC5C,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAoC;MAAc,CAAA;KAE3D;;GACP,CAAA;EACL,KACC,kBAAC,EAAO,GAAR;GACE,WAAU;GACV,SAAS,EAAE,SAAS,GAAG;GACvB,SAAS,EAAE,SAAS,GAAG;GACvB,YAAY;IAAE,GAAG,EAAO;IAAM,OAAO;IAAK;aAEzC;GACQ,CAAA;EAEZ,KAAY,QACX,kBAAC,EAAO,KAAR;GACE,SAAS,EAAE,SAAS,GAAG;GACvB,SAAS,EAAE,SAAS,GAAG;GACvB,YAAY;IAAE,GAAG,EAAO;IAAM,OAAO;IAAM;aAE3C,kBAAC,GAAD;IAAuB;IAAU,OAAO;IAAiB,CAAA;GAC9C,CAAA;EAEd,KACC,kBAAC,EAAO,KAAR;GACE,WAAW,EACT,+DACA,EACD;GACD,SAAS;IAAE,SAAS;IAAG,GAAG;IAAG;GAC7B,SAAS;IAAE,SAAS;IAAG,GAAG;IAAG;GAC7B,YAAY;IAAE,GAAG,EAAQ;IAAQ,OAAO;IAAK;aAP/C;IASE,kBAAC,EAAO,MAAR;KACE,WAAU;KACV,SAAS;MAAE,SAAS;MAAK,OAAO;MAAK;KACrC,SAAS;MAAE,SAAS;MAAG,OAAO;MAAG;KACjC,YAAY,EAAQ;eAEpB,kBAAC,GAAD;MAAM,MAAM;MAAW,MAAK;MAAO,CAAA;KACvB,CAAA;IACd,kBAAC,QAAD,EAAA,UAAO,EAAM,OAAa,CAAA;IACzB,KACC,kBAAC,QAAD;KAAM,WAAU;eAAsC;KAAuB,CAAA;IAEpE;;EAEd,KACC,kBAAC,EAAO,KAAR;GACE,WAAU;GACV,SAAS,EAAE,SAAS,GAAG;GACvB,SAAS,EAAE,SAAS,GAAG;GACvB,YAAY;IAAE,GAAG,EAAO;IAAM,OAAO;IAAM;aAE1C;GACU,CAAA;EAEd,EAAA,CAAA,EAGC,IAAc,EAClB,uFACA,KAAU,kBAAkB,EAAgB,MAC5C,KACE,oKACF,EACD;AAiBD,QAfI,IAEA,kBAAC,GAAD;EACO;EACC;EACG;EACT,WAAW,EAAG,GAAa,qBAAqB;EAChD,cAAY;EACZ,GAAK;YAEJ;EACI,CAAA,GAKT,kBAAC,OAAD;EACO;EACL,WAAW;EACF;EACT,MAAM,IAAU,WAAW,KAAA;EAC3B,UAAU,IAAU,IAAI,KAAA;EACxB,cAAY;EACZ,WACE,KACK,MAA2B;AAC1B,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,GAAS;MAGb,KAAA;EAEN,GAAI;YAEH;EACG,CAAA;EAGX;AAED,EAAS,cAAc"}
|
|
1
|
+
{"version":3,"file":"stat-card.js","names":[],"sources":["../../src/ui/stat-card.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconTrendingDown, IconTrendingUp } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { useLink } from './lib/link-context'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/**\n * Props for StatCard — a dashboard metric tile displaying a label, a large numeric value,\n * an optional trend delta (with directional arrow icon), and an optional header icon.\n *\n * **Delta direction:** `'up'` renders a green trending-up arrow, `'down'` renders a red\n * trending-down arrow, `'neutral'` renders a grey dash. The `delta.value` is a formatted\n * string (e.g. `\"+8%\"` or `\"−120\"`).\n *\n * **Loading state:** Pass `loading={true}` to render a pulse-skeleton placeholder instead of data.\n *\n * @example\n * // Revenue metric with a positive trend:\n * <StatCard\n * label=\"Monthly Revenue\"\n * value=\"$48,200\"\n * delta={{ value: \"+12%\", direction: \"up\" }}\n * icon={<IconCurrencyDollar />}\n * />\n *\n * @example\n * // Open ticket count with a downward trend (good for support queues):\n * <StatCard\n * label=\"Open Tickets\"\n * value={142}\n * delta={{ value: \"−18\", direction: \"down\" }}\n * />\n *\n * @example\n * // Loading skeleton while data is fetching:\n * <StatCard label=\"Users\" value={0} loading={isFetching} />\n *\n * @example\n * // Simple metric with no trend (stable, neutral):\n * <StatCard\n * label=\"Storage Used\"\n * value=\"4.2 GB\"\n * delta={{ value: \"No change\", direction: \"neutral\" }}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface StatCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Heading text for the metric. `title` is an alias for `label`. */\n label?: string\n /** Alias for `label` — use whichever feels natural. */\n title?: string\n value: string | number\n /** Prefix before value, e.g. \"$\" */\n prefix?: string\n /** Suffix after value, e.g. \"users\" */\n suffix?: string\n delta?: {\n value: string\n direction: 'up' | 'down' | 'neutral'\n }\n icon?: React.ReactNode | React.ComponentType<{ className?: string }>\n loading?: boolean\n /** Comparison period label shown after delta, e.g. \"vs last month\" */\n comparisonLabel?: string\n /** Secondary metric below main value, e.g. \"of $50,000 target\" */\n secondaryLabel?: string\n /** Progress toward a target (0-100). Renders a thin progress bar below the value. */\n progress?: number\n /** Color accent for the left border decoration */\n accent?: 'default' | 'success' | 'warning' | 'error' | 'info'\n /** Sparkline data points. Renders a mini SVG line chart in the card. */\n sparkline?: number[]\n /** Make the card clickable with hover state */\n onClick?: () => void\n /** Href — makes the card a link (uses the LinkContext Link component) */\n href?: string\n /** Footer content rendered below the card body, e.g. \"View details →\" */\n footer?: React.ReactNode\n}\n\nconst accentBorderMap: Record<NonNullable<StatCardProps['accent']>, string> = {\n default: 'border-l-accent-9',\n success: 'border-l-success-9',\n warning: 'border-l-warning-9',\n error: 'border-l-error-9',\n info: 'border-l-info-9',\n}\n\nfunction buildSparklinePath(raw: number[], width: number, height: number): string {\n const data = raw.filter((v) => Number.isFinite(v))\n if (data.length < 2) return ''\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const stepX = width / (data.length - 1)\n return data\n .map((v, i) => {\n const x = i * stepX\n const y = height - ((v - min) / range) * height\n return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`\n })\n .join(' ')\n}\n\nfunction Sparkline({\n data,\n colorClass,\n}: {\n data: number[]\n colorClass: string\n}) {\n const id = React.useId()\n const pathRef = React.useRef<SVGPathElement>(null)\n const [pathLength, setPathLength] = React.useState(0)\n const svgWidth = 80\n const svgHeight = 32\n const path = buildSparklinePath(data, svgWidth, svgHeight)\n\n React.useEffect(() => {\n if (pathRef.current) {\n setPathLength(pathRef.current.getTotalLength())\n }\n }, [path])\n\n if (!path) return null\n\n // Build area fill path (close to bottom-right then bottom-left)\n const areaPath = `${path} L${svgWidth.toFixed(1)},${svgHeight.toFixed(1)} L0,${svgHeight.toFixed(1)} Z`\n\n return (\n <div className={cn('w-20 h-8', colorClass)} aria-hidden=\"true\">\n <svg\n viewBox={`0 0 ${svgWidth} ${svgHeight}`}\n className=\"w-full h-full overflow-visible\"\n preserveAspectRatio=\"none\"\n >\n <defs>\n <linearGradient id={`sparkline-fill-${id}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"currentColor\" stopOpacity=\"0.1\" />\n <stop offset=\"100%\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill={`url(#sparkline-fill-${id})`} />\n <path\n ref={pathRef}\n d={path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n opacity: pathLength === 0 ? 0 : 1,\n strokeDasharray: pathLength,\n strokeDashoffset: pathLength,\n animation: pathLength > 0 ? `sparkline-draw-${id.replace(/:/g, '')} 1s ease-out forwards` : 'none',\n }}\n />\n </svg>\n {pathLength > 0 && (\n <style>{`@keyframes sparkline-draw-${id.replace(/:/g, '')} { to { stroke-dashoffset: 0; } }`}</style>\n )}\n </div>\n )\n}\n\nfunction ProgressBar({ progress, label }: { progress: number; label: string }) {\n const clamped = Math.max(0, Math.min(100, progress))\n const barColor =\n clamped >= 90 ? 'bg-success-9' : clamped >= 70 ? 'bg-warning-9' : 'bg-accent-9'\n\n return (\n <div className=\"h-1 w-full rounded-pill bg-surface-raised mt-ds-04\" role=\"progressbar\" aria-label={`${label} progress`} aria-valuenow={clamped} aria-valuemin={0} aria-valuemax={100}>\n <div\n className={cn('h-full rounded-pill transition-[width] duration-moderate-02 ease-productive-standard', barColor)}\n style={{ width: `${clamped}%` }}\n />\n </div>\n )\n}\n\nconst StatCard = React.forwardRef<HTMLDivElement, StatCardProps>(\n (\n {\n className,\n label,\n title,\n value,\n prefix,\n suffix,\n delta,\n icon,\n loading,\n comparisonLabel,\n secondaryLabel,\n progress,\n accent,\n sparkline,\n onClick,\n href,\n footer,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const resolvedLabel = title ?? label ?? ''\n const isClickable = !!(onClick || href)\n const computedAriaLabel =\n isClickable && !props['aria-label'] ? `View ${resolvedLabel}` : props['aria-label']\n\n if (loading) {\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-surface border border-surface-border bg-surface-raised shadow-raised p-ds-05b',\n accent && `border-l-[3px] ${accentBorderMap[accent]}`,\n className,\n )}\n {...props}\n >\n <div className=\"h-ds-04 w-24 rounded-control-inner bg-skeleton-base animate-pulse mb-ds-05\" />\n <div className=\"h-ds-sm w-32 rounded-control bg-skeleton-base animate-pulse mb-ds-03\" />\n <div className=\"h-3 w-16 rounded-control-inner bg-skeleton-base animate-pulse\" />\n </div>\n )\n }\n\n const DeltaIcon =\n delta?.direction === 'up'\n ? IconTrendingUp\n : delta?.direction === 'down'\n ? IconTrendingDown\n : IconMinus\n\n const deltaColour =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-surface-fg-muted'\n\n const sparklineColor =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-accent-11'\n\n const cardContent = (\n <>\n <div className=\"flex items-center justify-between mb-ds-04\">\n <motion.p\n className=\"text-ds-md font-medium text-surface-fg-muted\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n >\n {resolvedLabel}\n </motion.p>\n <div className=\"flex items-center gap-ds-03\">\n {sparkline && sparkline.length >= 2 && (\n <Sparkline data={sparkline} colorClass={sparklineColor} />\n )}\n {icon && (\n <motion.span\n className=\"text-surface-fg-muted\"\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n {typeof icon === 'function'\n ? <Icon icon={icon as React.ForwardRefExoticComponent<any>} size=\"lg\" />\n : icon}\n </motion.span>\n )}\n </div>\n </div>\n <div className=\"overflow-hidden\">\n <motion.p\n className=\"inline-block text-ds-3xl font-semibold text-surface-fg\"\n initial={{ opacity: 0, y: '100%' }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.smooth}\n >\n {prefix && (\n <span className=\"text-surface-fg-muted text-ds-lg\">{prefix}</span>\n )}\n <span className=\"tabular-nums\">{value}</span>\n {suffix && (\n <span className=\"text-surface-fg-muted text-ds-lg\">{suffix}</span>\n )}\n </motion.p>\n </div>\n {secondaryLabel && (\n <motion.p\n className=\"text-ds-sm text-surface-fg-subtle mt-ds-01\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.1 }}\n >\n {secondaryLabel}\n </motion.p>\n )}\n {progress != null && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.15 }}\n >\n <ProgressBar progress={progress} label={resolvedLabel} />\n </motion.div>\n )}\n {delta && (\n <motion.div\n className={cn(\n 'mt-ds-03 flex items-center gap-ds-02 text-ds-sm font-medium',\n deltaColour,\n )}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.smooth, delay: 0.2 }}\n >\n <motion.span\n className=\"inline-flex\"\n initial={{ opacity: 0.5, scale: 1.4 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.bouncy}\n >\n <Icon icon={DeltaIcon} size=\"sm\" />\n </motion.span>\n <span>{delta.value}</span>\n {comparisonLabel && (\n <span className=\"text-surface-fg-subtle font-normal\">{comparisonLabel}</span>\n )}\n </motion.div>\n )}\n {footer && (\n <motion.div\n className=\"mt-ds-04 pt-ds-04 border-t border-surface-border text-ds-sm\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.25 }}\n >\n {footer}\n </motion.div>\n )}\n </>\n )\n\n const cardClasses = cn(\n 'rounded-surface border border-surface-border bg-surface-raised shadow-raised p-ds-05b',\n accent && `border-l-[3px] ${accentBorderMap[accent]}`,\n isClickable &&\n 'cursor-pointer hover:shadow-raised-hover hover:border-surface-border-strong transition-[box-shadow,border-color] duration-fast-02 ease-productive-standard group',\n className,\n )\n\n if (href) {\n return (\n <Link\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n onClick={onClick}\n className={cn(cardClasses, 'block no-underline')}\n aria-label={computedAriaLabel}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n {cardContent}\n </Link>\n )\n }\n\n return (\n <div\n ref={ref}\n className={cardClasses}\n onClick={onClick}\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n aria-label={computedAriaLabel}\n onKeyDown={\n onClick\n ? (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onClick()\n }\n }\n : undefined\n }\n {...props}\n >\n {cardContent}\n </div>\n )\n },\n)\n\nStatCard.displayName = 'StatCard'\n\nexport { StatCard }\n"],"mappings":"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"}
|
package/dist/ui/status-dot.js
CHANGED
|
@@ -44,7 +44,7 @@ var i = {
|
|
|
44
44
|
text: "text-ds-sm"
|
|
45
45
|
}
|
|
46
46
|
}, l = t.forwardRef(({ status: t, size: l = "md", variant: u = "filled", pulse: d, label: f, labelClassName: p, className: m, "aria-label": h, ...g }, _) => {
|
|
47
|
-
let v = d ?? t === "healthy", y = c[l], b = f ? `${f} \u2014 ${t}` : `Status: ${t}`, x = u === "ring" ? e("relative inline-flex rounded-
|
|
47
|
+
let v = d ?? t === "healthy", y = c[l], b = f ? `${f} \u2014 ${t}` : `Status: ${t}`, x = u === "ring" ? e("relative inline-flex rounded-pill border-[1.5px]", y.dot, o[t], "bg-transparent") : e("relative inline-flex rounded-pill", y.dot, i[t]);
|
|
48
48
|
return /* @__PURE__ */ r("span", {
|
|
49
49
|
ref: _,
|
|
50
50
|
role: "status",
|
|
@@ -55,7 +55,7 @@ var i = {
|
|
|
55
55
|
className: "relative inline-flex shrink-0",
|
|
56
56
|
children: [v && /* @__PURE__ */ n("span", {
|
|
57
57
|
"data-pulse": "",
|
|
58
|
-
className: e("absolute inline-flex rounded-
|
|
58
|
+
className: e("absolute inline-flex rounded-pill animate-ping motion-reduce:animate-none", y.pulse, s[t])
|
|
59
59
|
}), /* @__PURE__ */ n("span", { className: x })]
|
|
60
60
|
}), f && /* @__PURE__ */ n("span", {
|
|
61
61
|
className: e(y.text, a[t], "font-sans", p),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-dot.js","names":[],"sources":["../../src/ui/status-dot.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\ntype Status = 'healthy' | 'warning' | 'critical' | 'neutral' | 'inactive'\n\nconst dotColorMap: Record<Status, string> = {\n healthy: 'bg-success-9',\n warning: 'bg-warning-9',\n critical: 'bg-error-9',\n neutral: 'bg-neutral-8',\n inactive: 'bg-neutral-6',\n}\n\nconst textColorMap: Record<Status, string> = {\n healthy: 'text-success-11',\n warning: 'text-warning-11',\n critical: 'text-error-11',\n neutral: 'text-surface-fg-muted',\n inactive: 'text-surface-fg-subtle',\n}\n\nconst ringBorderColorMap: Record<Status, string> = {\n healthy: 'border-success-9',\n warning: 'border-warning-9',\n critical: 'border-error-9',\n neutral: 'border-neutral-8',\n inactive: 'border-neutral-6',\n}\n\nconst pulseColorMap: Record<Status, string> = {\n healthy: 'bg-success-9/40',\n warning: 'bg-warning-9/40',\n critical: 'bg-error-9/40',\n neutral: 'bg-neutral-8/40',\n inactive: 'bg-neutral-6/40',\n}\n\nconst sizeMap = {\n sm: { dot: 'h-1.5 w-1.5', pulse: 'h-1.5 w-1.5', text: 'text-ds-xs' },\n md: { dot: 'h-2 w-2', pulse: 'h-2 w-2', text: 'text-ds-sm' },\n lg: { dot: 'h-2.5 w-2.5', pulse: 'h-2.5 w-2.5', text: 'text-ds-sm' },\n} as const\n\n/**\n * A semantic health/presence indicator dot with optional pulse animation and inline label.\n *\n * @example\n * <StatusDot status=\"healthy\" />\n * <StatusDot status=\"critical\" label=\"Service down\" pulse />\n * <StatusDot status=\"warning\" size=\"lg\" label=\"Elevated load\" />\n */\nexport interface StatusDotProps extends React.HTMLAttributes<HTMLSpanElement> {\n status: Status\n /** @default 'md' */\n size?: 'sm' | 'md' | 'lg'\n /** @default 'filled' */\n variant?: 'filled' | 'ring'\n /** Pulse animation. Defaults to true for 'healthy', false for others. */\n pulse?: boolean\n /** Inline label text rendered after the dot */\n label?: string\n labelClassName?: string\n}\n\nconst StatusDot = React.forwardRef<HTMLSpanElement, StatusDotProps>(\n ({ status, size = 'md', variant = 'filled', pulse, label, labelClassName, className, 'aria-label': ariaLabelProp, ...props }, ref) => {\n const shouldPulse = pulse ?? status === 'healthy'\n const s = sizeMap[size]\n const autoAriaLabel = label ? `${label} \\u2014 ${status}` : `Status: ${status}`\n\n const dotClasses = variant === 'ring'\n ? cn('relative inline-flex rounded-
|
|
1
|
+
{"version":3,"file":"status-dot.js","names":[],"sources":["../../src/ui/status-dot.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\ntype Status = 'healthy' | 'warning' | 'critical' | 'neutral' | 'inactive'\n\nconst dotColorMap: Record<Status, string> = {\n healthy: 'bg-success-9',\n warning: 'bg-warning-9',\n critical: 'bg-error-9',\n neutral: 'bg-neutral-8',\n inactive: 'bg-neutral-6',\n}\n\nconst textColorMap: Record<Status, string> = {\n healthy: 'text-success-11',\n warning: 'text-warning-11',\n critical: 'text-error-11',\n neutral: 'text-surface-fg-muted',\n inactive: 'text-surface-fg-subtle',\n}\n\nconst ringBorderColorMap: Record<Status, string> = {\n healthy: 'border-success-9',\n warning: 'border-warning-9',\n critical: 'border-error-9',\n neutral: 'border-neutral-8',\n inactive: 'border-neutral-6',\n}\n\nconst pulseColorMap: Record<Status, string> = {\n healthy: 'bg-success-9/40',\n warning: 'bg-warning-9/40',\n critical: 'bg-error-9/40',\n neutral: 'bg-neutral-8/40',\n inactive: 'bg-neutral-6/40',\n}\n\nconst sizeMap = {\n sm: { dot: 'h-1.5 w-1.5', pulse: 'h-1.5 w-1.5', text: 'text-ds-xs' },\n md: { dot: 'h-2 w-2', pulse: 'h-2 w-2', text: 'text-ds-sm' },\n lg: { dot: 'h-2.5 w-2.5', pulse: 'h-2.5 w-2.5', text: 'text-ds-sm' },\n} as const\n\n/**\n * A semantic health/presence indicator dot with optional pulse animation and inline label.\n *\n * @example\n * <StatusDot status=\"healthy\" />\n * <StatusDot status=\"critical\" label=\"Service down\" pulse />\n * <StatusDot status=\"warning\" size=\"lg\" label=\"Elevated load\" />\n */\nexport interface StatusDotProps extends React.HTMLAttributes<HTMLSpanElement> {\n status: Status\n /** @default 'md' */\n size?: 'sm' | 'md' | 'lg'\n /** @default 'filled' */\n variant?: 'filled' | 'ring'\n /** Pulse animation. Defaults to true for 'healthy', false for others. */\n pulse?: boolean\n /** Inline label text rendered after the dot */\n label?: string\n labelClassName?: string\n}\n\nconst StatusDot = React.forwardRef<HTMLSpanElement, StatusDotProps>(\n ({ status, size = 'md', variant = 'filled', pulse, label, labelClassName, className, 'aria-label': ariaLabelProp, ...props }, ref) => {\n const shouldPulse = pulse ?? status === 'healthy'\n const s = sizeMap[size]\n const autoAriaLabel = label ? `${label} \\u2014 ${status}` : `Status: ${status}`\n\n const dotClasses = variant === 'ring'\n ? cn('relative inline-flex rounded-pill border-[1.5px]', s.dot, ringBorderColorMap[status], 'bg-transparent')\n : cn('relative inline-flex rounded-pill', s.dot, dotColorMap[status])\n\n return (\n <span\n ref={ref}\n role=\"status\"\n aria-label={ariaLabelProp ?? autoAriaLabel}\n className={cn('inline-flex items-center gap-ds-02', className)}\n {...props}\n >\n <span className=\"relative inline-flex shrink-0\">\n {shouldPulse && (\n <span\n data-pulse=\"\"\n className={cn('absolute inline-flex rounded-pill animate-ping motion-reduce:animate-none', s.pulse, pulseColorMap[status])}\n />\n )}\n <span className={dotClasses} />\n </span>\n {label && (\n <span className={cn(s.text, textColorMap[status], 'font-sans', labelClassName)}>\n {label}\n </span>\n )}\n </span>\n )\n },\n)\nStatusDot.displayName = 'StatusDot'\n\nexport { StatusDot }\nexport type { Status as StatusDotStatus }\n"],"mappings":";;;;;AAQA,IAAM,IAAsC;CAC1C,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACX,EAEK,IAAuC;CAC3C,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACX,EAEK,IAA6C;CACjD,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACX,EAEK,IAAwC;CAC5C,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACX,EAEK,IAAU;CACd,IAAI;EAAE,KAAK;EAAe,OAAO;EAAe,MAAM;EAAc;CACpE,IAAI;EAAE,KAAK;EAAW,OAAO;EAAW,MAAM;EAAc;CAC5D,IAAI;EAAE,KAAK;EAAe,OAAO;EAAe,MAAM;EAAc;CACrE,EAuBK,IAAY,EAAM,YACrB,EAAE,WAAQ,UAAO,MAAM,aAAU,UAAU,UAAO,UAAO,mBAAgB,cAAW,cAAc,GAAe,GAAG,KAAS,MAAQ;CACpI,IAAM,IAAc,KAAS,MAAW,WAClC,IAAI,EAAQ,IACZ,IAAgB,IAAQ,GAAG,EAAM,UAAU,MAAW,WAAW,KAEjE,IAAa,MAAY,SAC3B,EAAG,oDAAoD,EAAE,KAAK,EAAmB,IAAS,iBAAiB,GAC3G,EAAG,qCAAqC,EAAE,KAAK,EAAY,GAAQ;AAEvE,QACE,kBAAC,QAAD;EACO;EACL,MAAK;EACL,cAAY,KAAiB;EAC7B,WAAW,EAAG,sCAAsC,EAAU;EAC9D,GAAI;YALN,CAOE,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,KACC,kBAAC,QAAD;IACE,cAAW;IACX,WAAW,EAAG,6EAA6E,EAAE,OAAO,EAAc,GAAQ;IAC1H,CAAA,EAEJ,kBAAC,QAAD,EAAM,WAAW,GAAc,CAAA,CAC1B;MACN,KACC,kBAAC,QAAD;GAAM,WAAW,EAAG,EAAE,MAAM,EAAa,IAAS,aAAa,EAAe;aAC3E;GACI,CAAA,CAEJ;;EAGZ;AACD,EAAU,cAAc"}
|
package/dist/ui/stepper.js
CHANGED
|
@@ -40,7 +40,7 @@ var c = n.createContext({
|
|
|
40
40
|
});
|
|
41
41
|
}), u = n.forwardRef(({ label: e, description: o, icon: s, className: l, ...u }, d) => {
|
|
42
42
|
let { _index: f = 0, ...p } = u, { activeStep: m, orientation: h, stepperId: g, onStepClick: _ } = n.useContext(c), v = f < m ? "completed" : f === m ? "active" : "pending", y = v === "completed" && !!_, b = /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i("div", {
|
|
43
|
-
className: t("relative shrink-0 flex items-center justify-center w-ds-sm h-ds-sm rounded-
|
|
43
|
+
className: t("relative shrink-0 flex items-center justify-center w-ds-sm h-ds-sm rounded-pill text-ds-sm font-semibold", "transition-[background-color,border-color,color] duration-moderate-01 ease-productive-standard", v === "completed" && "bg-accent-9 text-accent-fg", v === "active" && "bg-accent-9 text-accent-fg", v === "pending" && "bg-surface-raised text-surface-fg-subtle border border-surface-border-strong"),
|
|
44
44
|
children: s || (v === "completed" ? /* @__PURE__ */ i("svg", {
|
|
45
45
|
className: "w-ico-sm h-ico-sm",
|
|
46
46
|
viewBox: "0 0 24 24",
|
|
@@ -73,7 +73,7 @@ var c = n.createContext({
|
|
|
73
73
|
tabIndex: 0,
|
|
74
74
|
"aria-label": `Go to step ${f + 1}: ${e}`,
|
|
75
75
|
onClick: () => _(f),
|
|
76
|
-
className: t("flex items-center gap-ds-03 cursor-pointer select-none", "rounded-
|
|
76
|
+
className: t("flex items-center gap-ds-03 cursor-pointer select-none", "rounded-control px-ds-02 py-ds-01 -mx-ds-02 -my-ds-01", "bg-transparent border-0", "hover:bg-surface-raised-hover active:bg-surface-raised-active", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-8 focus-visible:ring-offset-2", "transition-colors duration-fast-01 ease-productive-standard"),
|
|
77
77
|
children: b
|
|
78
78
|
})
|
|
79
79
|
}) : /* @__PURE__ */ i("div", {
|
package/dist/ui/stepper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stepper.js","names":[],"sources":["../../src/ui/stepper.tsx"],"sourcesContent":["'use client'\n\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\ntype StepState = 'completed' | 'active' | 'pending'\n\ntype StepperContextValue = {\n activeStep: number\n orientation: 'horizontal' | 'vertical'\n stepperId: string\n onStepClick?: (stepIndex: number) => void\n}\n\nconst StepperContext = React.createContext<StepperContextValue>({\n activeStep: 0,\n orientation: 'horizontal',\n stepperId: '',\n})\n\n/**\n * Props for Stepper — a multi-step progress indicator that renders a connected series of `<Step>`\n * children with connector lines, showing completed/active/pending states automatically.\n *\n * **`activeStep`:** 0-indexed. Step at `activeStep` is \"active\", steps before it are \"completed\",\n * steps after it are \"pending\". Update this value to advance the stepper.\n *\n * **Orientation:** `'horizontal'` (default, left-to-right) | `'vertical'` (top-to-bottom, for sidebars).\n *\n * **Children:** Must be `<Step>` components. The Stepper injects `_index` into each child automatically.\n *\n * @example\n * // Horizontal 3-step form wizard:\n * <Stepper activeStep={currentStep}>\n * <Step label=\"Account\" description=\"Create your credentials\" />\n * <Step label=\"Profile\" description=\"Add your details\" />\n * <Step label=\"Review\" description=\"Confirm and submit\" />\n * </Stepper>\n *\n * @example\n * // Vertical onboarding checklist in a sidebar:\n * <Stepper activeStep={completedSteps} orientation=\"vertical\">\n * <Step label=\"Connect workspace\" />\n * <Step label=\"Invite teammates\" />\n * <Step label=\"Set up billing\" />\n * </Stepper>\n *\n * @example\n * // Clickable completed steps — user can navigate back:\n * <Stepper activeStep={step} onStepClick={(i) => setStep(i)}>\n * <Step label=\"Account\" />\n * <Step label=\"Profile\" />\n * <Step label=\"Review\" />\n * </Stepper>\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface StepperProps extends React.HTMLAttributes<HTMLDivElement> {\n activeStep: number\n orientation?: 'horizontal' | 'vertical'\n /** Called when a completed step is clicked. Receives the 0-based step index. */\n onStepClick?: (stepIndex: number) => void\n children: React.ReactNode\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n ({ activeStep, orientation = 'horizontal', onStepClick, className, children, ...props }, ref) => {\n const steps = React.Children.toArray(children)\n const stepperId = React.useId()\n const contextValue = React.useMemo(\n () => ({ activeStep, orientation, stepperId, onStepClick }),\n [activeStep, orientation, stepperId, onStepClick],\n )\n return (\n <StepperContext.Provider value={contextValue}>\n <div\n ref={ref}\n className={cn(\n 'flex gap-ds-02',\n orientation === 'vertical' ? 'flex-col' : 'flex-row items-center',\n className,\n )}\n role=\"list\"\n {...props}\n >\n {steps.map((child, index) => (\n <React.Fragment key={index}>\n {React.isValidElement<StepInternalProps>(child)\n ? React.cloneElement(child, { _index: index })\n : child}\n {index < steps.length - 1 && (\n <div\n className={cn(\n 'relative flex-1 overflow-hidden',\n orientation === 'vertical'\n ? 'ml-ds-04 w-ds-01 min-h-ds-05'\n : 'h-ds-01 min-w-ds-05',\n 'bg-surface-border',\n )}\n aria-hidden=\"true\"\n >\n {/* Filled portion — smooth CSS transition */}\n <div\n className={cn(\n 'absolute inset-0 bg-accent-9 transition-transform duration-moderate-02 ease-productive-standard',\n orientation === 'vertical' ? 'origin-top' : 'origin-left',\n )}\n style={{\n transform: `${orientation === 'vertical' ? 'scaleY' : 'scaleX'}(${index < activeStep ? 1 : 0})`,\n }}\n />\n </div>\n )}\n </React.Fragment>\n ))}\n </div>\n </StepperContext.Provider>\n )\n },\n)\n\n/**\n * Props for Step — a single step within a `<Stepper>`. The visual state (completed/active/pending)\n * is derived from the parent Stepper's `activeStep` and this step's position — you don't set it manually.\n *\n * @example\n * // Basic step with label and description:\n * <Step label=\"Payment\" description=\"Enter your card details\" />\n *\n * @example\n * // Step with a custom icon (overrides the default number/checkmark):\n * <Step label=\"Verified\" icon={<IconShieldCheck className=\"h-ico-sm w-ico-sm\" />} />\n */\ninterface StepProps extends React.HTMLAttributes<HTMLDivElement> {\n label: string\n description?: string\n icon?: React.ReactNode\n}\n\ntype StepInternalProps = StepProps & { _index?: number }\n\nconst Step = React.forwardRef<HTMLDivElement, StepProps>(\n ({ label, description, icon, className, ...props }, ref) => {\n const { _index = 0, ...restProps } = props as StepInternalProps\n const { activeStep, orientation, stepperId, onStepClick } = React.useContext(StepperContext)\n const state: StepState = _index < activeStep ? 'completed' : _index === activeStep ? 'active' : 'pending'\n const isClickable = state === 'completed' && !!onStepClick\n\n const stepContent = (\n <>\n <div\n className={cn(\n 'relative shrink-0 flex items-center justify-center w-ds-sm h-ds-sm rounded-ds-full text-ds-sm font-semibold',\n 'transition-[background-color,border-color,color] duration-moderate-01 ease-productive-standard',\n state === 'completed' && 'bg-accent-9 text-accent-fg',\n state === 'active' && 'bg-accent-9 text-accent-fg',\n state === 'pending' && 'bg-surface-raised text-surface-fg-subtle border border-surface-border-strong',\n )}\n >\n {icon || (state === 'completed' ? (\n <svg\n className=\"w-ico-sm h-ico-sm\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n ) : (\n _index + 1\n ))}\n </div>\n <div className=\"flex flex-col\">\n <span\n className={cn(\n 'text-ds-md font-medium leading-ds-snug',\n state === 'pending'\n ? 'text-surface-fg-subtle'\n : 'text-surface-fg',\n )}\n >\n {label}\n </span>\n {description && (\n <span className=\"text-ds-sm text-surface-fg-muted leading-ds-relaxed\">\n {description}\n </span>\n )}\n </div>\n </>\n )\n\n if (isClickable) {\n return (\n <div\n ref={ref}\n data-step=\"\"\n data-state={state}\n role=\"listitem\"\n className={cn(\n orientation === 'vertical' && 'py-ds-02',\n className,\n )}\n {...restProps}\n >\n <button\n type=\"button\"\n tabIndex={0}\n aria-label={`Go to step ${_index + 1}: ${label}`}\n onClick={() => onStepClick(_index)}\n className={cn(\n 'flex items-center gap-ds-03 cursor-pointer select-none',\n 'rounded-ds-md px-ds-02 py-ds-01 -mx-ds-02 -my-ds-01',\n 'bg-transparent border-0',\n 'hover:bg-surface-raised-hover active:bg-surface-raised-active',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-8 focus-visible:ring-offset-2',\n 'transition-colors duration-fast-01 ease-productive-standard',\n )}\n >\n {stepContent}\n </button>\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-step=\"\"\n data-state={state}\n role=\"listitem\"\n aria-current={state === 'active' ? 'step' : undefined}\n aria-label={`Step ${_index + 1}: ${label}, ${state === 'completed' ? 'completed' : state === 'active' ? 'current' : 'upcoming'}`}\n className={cn(\n 'flex items-center gap-ds-03',\n orientation === 'vertical' && 'py-ds-02',\n className,\n )}\n {...restProps}\n >\n {stepContent}\n </div>\n )\n },\n)\n\n/**\n * Props for StepperContent — wraps the content panel for the active step, animating\n * slide transitions when `activeStep` changes. Detects forward vs backward navigation\n * and slides content accordingly.\n *\n * @example\n * <StepperContent activeStep={currentStep}>\n * {currentStep === 0 && <AccountForm />}\n * {currentStep === 1 && <ProfileForm />}\n * {currentStep === 2 && <ReviewPanel />}\n * </StepperContent>\n */\ninterface StepperContentProps {\n activeStep: number\n children: React.ReactNode\n className?: string\n}\n\nconst SLIDE_OFFSET = 40\n\nconst stepContentVariants = {\n enter: (direction: number) => ({\n opacity: 0,\n x: direction * SLIDE_OFFSET,\n }),\n center: {\n opacity: 1,\n x: 0,\n },\n exit: (direction: number) => ({\n opacity: 0,\n x: direction * -SLIDE_OFFSET,\n }),\n}\n\nfunction StepperContent({ activeStep, children, className }: StepperContentProps) {\n const prevStepRef = React.useRef(activeStep)\n const direction = activeStep >= prevStepRef.current ? 1 : -1\n\n React.useEffect(() => {\n prevStepRef.current = activeStep\n }, [activeStep])\n\n return (\n <div className={cn('relative overflow-hidden', className)}>\n <AnimatePresence mode=\"wait\" custom={direction}>\n <motion.div\n key={activeStep}\n custom={direction}\n variants={stepContentVariants}\n initial=\"enter\"\n animate=\"center\"\n exit=\"exit\"\n transition={springs.smooth}\n >\n {children}\n </motion.div>\n </AnimatePresence>\n </div>\n )\n}\n\nStepper.displayName = 'Stepper'\nStep.displayName = 'Step'\nStepperContent.displayName = 'StepperContent'\n\nexport { Step, Stepper, StepperContent, type StepperContentProps,type StepperProps, type StepProps }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stepper.js","names":[],"sources":["../../src/ui/stepper.tsx"],"sourcesContent":["'use client'\n\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\ntype StepState = 'completed' | 'active' | 'pending'\n\ntype StepperContextValue = {\n activeStep: number\n orientation: 'horizontal' | 'vertical'\n stepperId: string\n onStepClick?: (stepIndex: number) => void\n}\n\nconst StepperContext = React.createContext<StepperContextValue>({\n activeStep: 0,\n orientation: 'horizontal',\n stepperId: '',\n})\n\n/**\n * Props for Stepper — a multi-step progress indicator that renders a connected series of `<Step>`\n * children with connector lines, showing completed/active/pending states automatically.\n *\n * **`activeStep`:** 0-indexed. Step at `activeStep` is \"active\", steps before it are \"completed\",\n * steps after it are \"pending\". Update this value to advance the stepper.\n *\n * **Orientation:** `'horizontal'` (default, left-to-right) | `'vertical'` (top-to-bottom, for sidebars).\n *\n * **Children:** Must be `<Step>` components. The Stepper injects `_index` into each child automatically.\n *\n * @example\n * // Horizontal 3-step form wizard:\n * <Stepper activeStep={currentStep}>\n * <Step label=\"Account\" description=\"Create your credentials\" />\n * <Step label=\"Profile\" description=\"Add your details\" />\n * <Step label=\"Review\" description=\"Confirm and submit\" />\n * </Stepper>\n *\n * @example\n * // Vertical onboarding checklist in a sidebar:\n * <Stepper activeStep={completedSteps} orientation=\"vertical\">\n * <Step label=\"Connect workspace\" />\n * <Step label=\"Invite teammates\" />\n * <Step label=\"Set up billing\" />\n * </Stepper>\n *\n * @example\n * // Clickable completed steps — user can navigate back:\n * <Stepper activeStep={step} onStepClick={(i) => setStep(i)}>\n * <Step label=\"Account\" />\n * <Step label=\"Profile\" />\n * <Step label=\"Review\" />\n * </Stepper>\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface StepperProps extends React.HTMLAttributes<HTMLDivElement> {\n activeStep: number\n orientation?: 'horizontal' | 'vertical'\n /** Called when a completed step is clicked. Receives the 0-based step index. */\n onStepClick?: (stepIndex: number) => void\n children: React.ReactNode\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n ({ activeStep, orientation = 'horizontal', onStepClick, className, children, ...props }, ref) => {\n const steps = React.Children.toArray(children)\n const stepperId = React.useId()\n const contextValue = React.useMemo(\n () => ({ activeStep, orientation, stepperId, onStepClick }),\n [activeStep, orientation, stepperId, onStepClick],\n )\n return (\n <StepperContext.Provider value={contextValue}>\n <div\n ref={ref}\n className={cn(\n 'flex gap-ds-02',\n orientation === 'vertical' ? 'flex-col' : 'flex-row items-center',\n className,\n )}\n role=\"list\"\n {...props}\n >\n {steps.map((child, index) => (\n <React.Fragment key={index}>\n {React.isValidElement<StepInternalProps>(child)\n ? React.cloneElement(child, { _index: index })\n : child}\n {index < steps.length - 1 && (\n <div\n className={cn(\n 'relative flex-1 overflow-hidden',\n orientation === 'vertical'\n ? 'ml-ds-04 w-ds-01 min-h-ds-05'\n : 'h-ds-01 min-w-ds-05',\n 'bg-surface-border',\n )}\n aria-hidden=\"true\"\n >\n {/* Filled portion — smooth CSS transition */}\n <div\n className={cn(\n 'absolute inset-0 bg-accent-9 transition-transform duration-moderate-02 ease-productive-standard',\n orientation === 'vertical' ? 'origin-top' : 'origin-left',\n )}\n style={{\n transform: `${orientation === 'vertical' ? 'scaleY' : 'scaleX'}(${index < activeStep ? 1 : 0})`,\n }}\n />\n </div>\n )}\n </React.Fragment>\n ))}\n </div>\n </StepperContext.Provider>\n )\n },\n)\n\n/**\n * Props for Step — a single step within a `<Stepper>`. The visual state (completed/active/pending)\n * is derived from the parent Stepper's `activeStep` and this step's position — you don't set it manually.\n *\n * @example\n * // Basic step with label and description:\n * <Step label=\"Payment\" description=\"Enter your card details\" />\n *\n * @example\n * // Step with a custom icon (overrides the default number/checkmark):\n * <Step label=\"Verified\" icon={<IconShieldCheck className=\"h-ico-sm w-ico-sm\" />} />\n */\ninterface StepProps extends React.HTMLAttributes<HTMLDivElement> {\n label: string\n description?: string\n icon?: React.ReactNode\n}\n\ntype StepInternalProps = StepProps & { _index?: number }\n\nconst Step = React.forwardRef<HTMLDivElement, StepProps>(\n ({ label, description, icon, className, ...props }, ref) => {\n const { _index = 0, ...restProps } = props as StepInternalProps\n const { activeStep, orientation, stepperId, onStepClick } = React.useContext(StepperContext)\n const state: StepState = _index < activeStep ? 'completed' : _index === activeStep ? 'active' : 'pending'\n const isClickable = state === 'completed' && !!onStepClick\n\n const stepContent = (\n <>\n <div\n className={cn(\n 'relative shrink-0 flex items-center justify-center w-ds-sm h-ds-sm rounded-pill text-ds-sm font-semibold',\n 'transition-[background-color,border-color,color] duration-moderate-01 ease-productive-standard',\n state === 'completed' && 'bg-accent-9 text-accent-fg',\n state === 'active' && 'bg-accent-9 text-accent-fg',\n state === 'pending' && 'bg-surface-raised text-surface-fg-subtle border border-surface-border-strong',\n )}\n >\n {icon || (state === 'completed' ? (\n <svg\n className=\"w-ico-sm h-ico-sm\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n ) : (\n _index + 1\n ))}\n </div>\n <div className=\"flex flex-col\">\n <span\n className={cn(\n 'text-ds-md font-medium leading-ds-snug',\n state === 'pending'\n ? 'text-surface-fg-subtle'\n : 'text-surface-fg',\n )}\n >\n {label}\n </span>\n {description && (\n <span className=\"text-ds-sm text-surface-fg-muted leading-ds-relaxed\">\n {description}\n </span>\n )}\n </div>\n </>\n )\n\n if (isClickable) {\n return (\n <div\n ref={ref}\n data-step=\"\"\n data-state={state}\n role=\"listitem\"\n className={cn(\n orientation === 'vertical' && 'py-ds-02',\n className,\n )}\n {...restProps}\n >\n <button\n type=\"button\"\n tabIndex={0}\n aria-label={`Go to step ${_index + 1}: ${label}`}\n onClick={() => onStepClick(_index)}\n className={cn(\n 'flex items-center gap-ds-03 cursor-pointer select-none',\n 'rounded-control px-ds-02 py-ds-01 -mx-ds-02 -my-ds-01',\n 'bg-transparent border-0',\n 'hover:bg-surface-raised-hover active:bg-surface-raised-active',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-8 focus-visible:ring-offset-2',\n 'transition-colors duration-fast-01 ease-productive-standard',\n )}\n >\n {stepContent}\n </button>\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-step=\"\"\n data-state={state}\n role=\"listitem\"\n aria-current={state === 'active' ? 'step' : undefined}\n aria-label={`Step ${_index + 1}: ${label}, ${state === 'completed' ? 'completed' : state === 'active' ? 'current' : 'upcoming'}`}\n className={cn(\n 'flex items-center gap-ds-03',\n orientation === 'vertical' && 'py-ds-02',\n className,\n )}\n {...restProps}\n >\n {stepContent}\n </div>\n )\n },\n)\n\n/**\n * Props for StepperContent — wraps the content panel for the active step, animating\n * slide transitions when `activeStep` changes. Detects forward vs backward navigation\n * and slides content accordingly.\n *\n * @example\n * <StepperContent activeStep={currentStep}>\n * {currentStep === 0 && <AccountForm />}\n * {currentStep === 1 && <ProfileForm />}\n * {currentStep === 2 && <ReviewPanel />}\n * </StepperContent>\n */\ninterface StepperContentProps {\n activeStep: number\n children: React.ReactNode\n className?: string\n}\n\nconst SLIDE_OFFSET = 40\n\nconst stepContentVariants = {\n enter: (direction: number) => ({\n opacity: 0,\n x: direction * SLIDE_OFFSET,\n }),\n center: {\n opacity: 1,\n x: 0,\n },\n exit: (direction: number) => ({\n opacity: 0,\n x: direction * -SLIDE_OFFSET,\n }),\n}\n\nfunction StepperContent({ activeStep, children, className }: StepperContentProps) {\n const prevStepRef = React.useRef(activeStep)\n const direction = activeStep >= prevStepRef.current ? 1 : -1\n\n React.useEffect(() => {\n prevStepRef.current = activeStep\n }, [activeStep])\n\n return (\n <div className={cn('relative overflow-hidden', className)}>\n <AnimatePresence mode=\"wait\" custom={direction}>\n <motion.div\n key={activeStep}\n custom={direction}\n variants={stepContentVariants}\n initial=\"enter\"\n animate=\"center\"\n exit=\"exit\"\n transition={springs.smooth}\n >\n {children}\n </motion.div>\n </AnimatePresence>\n </div>\n )\n}\n\nStepper.displayName = 'Stepper'\nStep.displayName = 'Step'\nStepperContent.displayName = 'StepperContent'\n\nexport { Step, Stepper, StepperContent, type StepperContentProps,type StepperProps, type StepProps }\n"],"mappings":"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"}
|
package/dist/ui/switch.js
CHANGED
|
@@ -32,7 +32,7 @@ var c = {
|
|
|
32
32
|
h === void 0 && T(e), _?.(e);
|
|
33
33
|
}, [h, _]);
|
|
34
34
|
return /* @__PURE__ */ o(t, {
|
|
35
|
-
className: r("touch-target peer inline-flex shrink-0 cursor-pointer items-center rounded-
|
|
35
|
+
className: r("touch-target peer inline-flex shrink-0 cursor-pointer items-center rounded-pill border-2 border-surface-border-strong shadow-raised transition-colors duration-fast-01 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled data-[state=checked]:border-transparent data-[state=unchecked]:bg-surface-border-strong data-[state=unchecked]:hover:bg-surface-raised-active", D, l[p], x && "border-error-7 data-[state=checked]:bg-error-9", u),
|
|
36
36
|
checked: h,
|
|
37
37
|
defaultChecked: g,
|
|
38
38
|
onCheckedChange: A,
|
|
@@ -44,7 +44,7 @@ var c = {
|
|
|
44
44
|
children: /* @__PURE__ */ o(e, {
|
|
45
45
|
asChild: !0,
|
|
46
46
|
children: /* @__PURE__ */ o(s.span, {
|
|
47
|
-
className: r("pointer-events-none flex items-center justify-center rounded-
|
|
47
|
+
className: r("pointer-events-none flex items-center justify-center rounded-pill bg-accent-fg shadow-raised-hover ring-0", O),
|
|
48
48
|
animate: { x: E ? k : 0 },
|
|
49
49
|
whileTap: { scale: .85 },
|
|
50
50
|
transition: n.snappy,
|
package/dist/ui/switch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.js","names":[],"sources":["../../src/ui/switch.tsx"],"sourcesContent":["'use client'\n\nimport * as SwitchPrimitives from \"@primitives/react-switch\"\nimport { motion } from 'framer-motion'\nimport * as React from \"react\"\n\nimport { useFormField } from './form'\nimport { springs } from './lib/motion'\nimport { cn } from \"./lib/utils\"\n\nconst sizeConfig = {\n sm: { track: 'h-6 w-[38px]', thumb: 'h-5 w-5', travel: 16 },\n md: { track: 'h-6 w-11', thumb: 'h-ico-md w-ico-md', travel: 20 },\n lg: { track: 'h-7 w-[52px]', thumb: 'h-6 w-6', travel: 24 },\n} as const\n\nconst colorMap = {\n accent: 'data-[state=checked]:bg-accent-9',\n success: 'data-[state=checked]:bg-success-9',\n warning: 'data-[state=checked]:bg-warning-9',\n} as const\n\nexport interface SwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> {\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n color?: 'accent' | 'success' | 'warning'\n thumbIcon?: React.ReactNode\n}\n\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitives.Root>,\n SwitchProps\n>(({ className, error, size = 'md', color = 'accent', thumbIcon, checked, defaultChecked, onCheckedChange, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError = error ?? fieldCtx.state === 'error'\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n // Track checked state internally to drive Framer Motion animation\n const [internalChecked, setInternalChecked] = React.useState(defaultChecked ?? false)\n const isChecked = checked !== undefined ? checked : internalChecked\n const { track, thumb, travel } = sizeConfig[size]\n\n const handleCheckedChange = React.useCallback(\n (value: boolean) => {\n if (checked === undefined) {\n setInternalChecked(value)\n }\n onCheckedChange?.(value)\n },\n [checked, onCheckedChange],\n )\n\n return (\n <SwitchPrimitives.Root\n className={cn(\n \"touch-target peer inline-flex shrink-0 cursor-pointer items-center rounded-
|
|
1
|
+
{"version":3,"file":"switch.js","names":[],"sources":["../../src/ui/switch.tsx"],"sourcesContent":["'use client'\n\nimport * as SwitchPrimitives from \"@primitives/react-switch\"\nimport { motion } from 'framer-motion'\nimport * as React from \"react\"\n\nimport { useFormField } from './form'\nimport { springs } from './lib/motion'\nimport { cn } from \"./lib/utils\"\n\nconst sizeConfig = {\n sm: { track: 'h-6 w-[38px]', thumb: 'h-5 w-5', travel: 16 },\n md: { track: 'h-6 w-11', thumb: 'h-ico-md w-ico-md', travel: 20 },\n lg: { track: 'h-7 w-[52px]', thumb: 'h-6 w-6', travel: 24 },\n} as const\n\nconst colorMap = {\n accent: 'data-[state=checked]:bg-accent-9',\n success: 'data-[state=checked]:bg-success-9',\n warning: 'data-[state=checked]:bg-warning-9',\n} as const\n\nexport interface SwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> {\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n color?: 'accent' | 'success' | 'warning'\n thumbIcon?: React.ReactNode\n}\n\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitives.Root>,\n SwitchProps\n>(({ className, error, size = 'md', color = 'accent', thumbIcon, checked, defaultChecked, onCheckedChange, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError = error ?? fieldCtx.state === 'error'\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n // Track checked state internally to drive Framer Motion animation\n const [internalChecked, setInternalChecked] = React.useState(defaultChecked ?? false)\n const isChecked = checked !== undefined ? checked : internalChecked\n const { track, thumb, travel } = sizeConfig[size]\n\n const handleCheckedChange = React.useCallback(\n (value: boolean) => {\n if (checked === undefined) {\n setInternalChecked(value)\n }\n onCheckedChange?.(value)\n },\n [checked, onCheckedChange],\n )\n\n return (\n <SwitchPrimitives.Root\n className={cn(\n \"touch-target peer inline-flex shrink-0 cursor-pointer items-center rounded-pill border-2 border-surface-border-strong shadow-raised transition-colors duration-fast-01 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled data-[state=checked]:border-transparent data-[state=unchecked]:bg-surface-border-strong data-[state=unchecked]:hover:bg-surface-raised-active\",\n track,\n colorMap[color],\n isError && \"border-error-7 data-[state=checked]:bg-error-9\",\n className\n )}\n checked={checked}\n defaultChecked={defaultChecked}\n onCheckedChange={handleCheckedChange}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n ref={ref}\n >\n <SwitchPrimitives.Thumb asChild>\n <motion.span\n className={cn(\n \"pointer-events-none flex items-center justify-center rounded-pill bg-accent-fg shadow-raised-hover ring-0\",\n thumb\n )}\n animate={{ x: isChecked ? travel : 0 }}\n whileTap={{ scale: 0.85 }}\n transition={springs.snappy}\n >\n {thumbIcon}\n </motion.span>\n </SwitchPrimitives.Thumb>\n </SwitchPrimitives.Root>\n )\n})\nSwitch.displayName = SwitchPrimitives.Root.displayName\n\nexport { Switch }\n"],"mappings":";;;;;;;;;AAUA,IAAM,IAAa;CACjB,IAAI;EAAE,OAAO;EAAgB,OAAO;EAAW,QAAQ;EAAI;CAC3D,IAAI;EAAE,OAAO;EAAY,OAAO;EAAqB,QAAQ;EAAI;CACjE,IAAI;EAAE,OAAO;EAAgB,OAAO;EAAW,QAAQ;EAAI;CAC5D,EAEK,IAAW;CACf,QAAQ;CACR,SAAS;CACT,SAAS;CACV,EASK,IAAS,EAAM,YAGlB,EAAE,cAAW,UAAO,UAAO,MAAM,WAAQ,UAAU,cAAW,YAAS,mBAAgB,oBAAiB,GAAG,KAAS,MAAQ;CAC7H,IAAM,IAAW,GAAc,EACzB,IAAU,KAAS,EAAS,UAAU,SACtC,IAAkB,EAAM,uBAAuB,EAAS,cACxD,IAAe,EAAM,oBAAoB,EAAS,UAGlD,CAAC,GAAiB,KAAsB,EAAM,SAAS,KAAkB,GAAM,EAC/E,IAAY,MAAY,KAAA,IAAsB,IAAV,GACpC,EAAE,UAAO,UAAO,cAAW,EAAW,IAEtC,IAAsB,EAAM,aAC/B,MAAmB;AAIlB,EAHI,MAAY,KAAA,KACd,EAAmB,EAAM,EAE3B,IAAkB,EAAM;IAE1B,CAAC,GAAS,EAAgB,CAC3B;AAED,QACE,kBAAC,GAAD;EACE,WAAW,EACT,+dACA,GACA,EAAS,IACT,KAAW,kDACX,EACD;EACQ;EACO;EAChB,iBAAiB;EACjB,gBAAc,KAAW,KAAA;EACzB,oBAAkB;EAClB,iBAAe,KAAgB,KAAA;EAC/B,GAAI;EACC;YAEL,kBAAC,GAAD;GAAwB,SAAA;aACtB,kBAAC,EAAO,MAAR;IACE,WAAW,EACT,6GACA,EACD;IACD,SAAS,EAAE,GAAG,IAAY,IAAS,GAAG;IACtC,UAAU,EAAE,OAAO,KAAM;IACzB,YAAY,EAAQ;cAEnB;IACW,CAAA;GACS,CAAA;EACH,CAAA;EAE1B;AACF,EAAO,cAAA,EAAoC"}
|
package/dist/ui/tabs.js
CHANGED
|
@@ -41,7 +41,7 @@ var g = c.createContext({
|
|
|
41
41
|
variants: {
|
|
42
42
|
variant: {
|
|
43
43
|
line: "border-b border-surface-border-strong w-full gap-0",
|
|
44
|
-
contained: "bg-surface-raised p-ds-02 rounded-
|
|
44
|
+
contained: "bg-surface-raised p-ds-02 rounded-surface gap-ds-02"
|
|
45
45
|
},
|
|
46
46
|
size: {
|
|
47
47
|
sm: "h-8",
|
|
@@ -72,7 +72,7 @@ var g = c.createContext({
|
|
|
72
72
|
variant: {
|
|
73
73
|
line: ["-mb-px", "text-surface-fg-muted hover:text-surface-fg"],
|
|
74
74
|
contained: [
|
|
75
|
-
"rounded-
|
|
75
|
+
"rounded-control",
|
|
76
76
|
"text-surface-fg-muted hover:text-surface-fg",
|
|
77
77
|
"data-[state=active]:text-surface-fg"
|
|
78
78
|
]
|
|
@@ -131,7 +131,7 @@ var b = {
|
|
|
131
131
|
children: [
|
|
132
132
|
y === "contained" && w && /* @__PURE__ */ l(f.span, {
|
|
133
133
|
layoutId: `${d.layoutId}-contained`,
|
|
134
|
-
className: "absolute inset-0 rounded-
|
|
134
|
+
className: "absolute inset-0 rounded-control bg-surface-overlay shadow-raised",
|
|
135
135
|
transition: i.smooth
|
|
136
136
|
}),
|
|
137
137
|
/* @__PURE__ */ l("span", {
|
package/dist/ui/tabs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","names":[],"sources":["../../src/ui/tabs.tsx"],"sourcesContent":["'use client'\n\nimport * as TabsPrimitive from '@primitives/react-tabs'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { LayoutGroup,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/* ── Active-value context (drives layoutId indicator) ────── */\ntype TabsOrientation = 'horizontal' | 'vertical'\nconst TabsValueContext = React.createContext<string | undefined>(undefined)\nconst TabsOrientationContext = React.createContext<TabsOrientation>('horizontal')\n\n/**\n * Tabs compound component — accessible tabbed navigation with keyboard support and two visual\n * variants (line underline and contained pill styles).\n *\n * **Parts (in composition order):**\n * - `Tabs` — manages active tab state (this root; takes `defaultValue`, `value`, `onValueChange`)\n * - `TabsList` — tab bar container (takes `variant=\"line\"|\"contained\"`, default `\"line\"`)\n * - `TabsTrigger` — individual tab button (requires `value`; inherits `variant` from TabsList via context)\n * - `TabsContent` — the panel shown when its tab is active (requires `value` matching a TabsTrigger)\n *\n * **Critical behavior:** `variant` set on `TabsList` propagates automatically via React context to\n * all `TabsTrigger` children. You do NOT need to repeat `variant` on each trigger — but you CAN\n * override it per-trigger if needed.\n *\n * The active tab indicator animates between tabs using Framer Motion `layoutId`. Line variant\n * shows a sliding underline; contained variant shows a sliding pill background.\n *\n * @compound\n * @example\n * // Default line variant:\n * <Tabs defaultValue=\"overview\">\n * <TabsList>\n * <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n * <TabsTrigger value=\"activity\">Activity</TabsTrigger>\n * <TabsTrigger value=\"settings\">Settings</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"overview\">Overview content</TabsContent>\n * <TabsContent value=\"activity\">Activity content</TabsContent>\n * <TabsContent value=\"settings\">Settings content</TabsContent>\n * </Tabs>\n *\n * @example\n * // Contained pill variant (controlled):\n * const [tab, setTab] = useState('members')\n * <Tabs value={tab} onValueChange={setTab}>\n * <TabsList variant=\"contained\">\n * <TabsTrigger value=\"members\">Members</TabsTrigger>\n * <TabsTrigger value=\"roles\">Roles</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"members\">Members list here.</TabsContent>\n * <TabsContent value=\"roles\">Roles list here.</TabsContent>\n * </Tabs>\n */\nconst Tabs = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>\n>(({ value: valueProp, defaultValue, onValueChange, orientation, ...props }, ref) => {\n // Track the active value so TabsTrigger can conditionally render the motion indicator.\n // For controlled usage, mirror the prop; for uncontrolled, manage internal state.\n const [activeValue, setActiveValue] = React.useState(valueProp ?? defaultValue ?? '')\n\n // Sync controlled value\n React.useEffect(() => {\n if (valueProp !== undefined) setActiveValue(valueProp)\n }, [valueProp])\n\n const handleValueChange = React.useCallback(\n (newValue: string) => {\n setActiveValue(newValue)\n onValueChange?.(newValue)\n },\n [onValueChange],\n )\n\n const resolvedOrientation: TabsOrientation = orientation ?? 'horizontal'\n\n return (\n <TabsValueContext.Provider value={activeValue}>\n <TabsOrientationContext.Provider value={resolvedOrientation}>\n <TabsPrimitive.Root\n ref={ref}\n value={valueProp}\n defaultValue={valueProp === undefined ? defaultValue : undefined}\n onValueChange={handleValueChange}\n orientation={orientation}\n {...props}\n className={cn(\n resolvedOrientation === 'vertical' && 'flex flex-row gap-ds-05',\n props.className,\n )}\n />\n </TabsOrientationContext.Provider>\n </TabsValueContext.Provider>\n )\n})\nTabs.displayName = 'Tabs'\n\n/** Props for the Tabs root (defaultValue, value, onValueChange, etc.). */\nexport type TabsProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>\n\ntype TabsVariant = 'line' | 'contained'\ntype TabsSize = 'sm' | 'md' | 'lg'\ntype TabsColor = 'accent' | 'neutral'\n\ninterface TabsListContextValue {\n variant: TabsVariant\n size: TabsSize\n color: TabsColor\n layoutId: string\n}\n\nconst TabsListContext = React.createContext<TabsListContextValue>({\n variant: 'line',\n size: 'md',\n color: 'accent',\n layoutId: 'tab-indicator',\n})\n\nconst tabsListVariants = cva('inline-flex items-center', {\n variants: {\n variant: {\n line: 'border-b border-surface-border-strong w-full gap-0',\n contained:\n 'bg-surface-raised p-ds-02 rounded-ds-lg gap-ds-02',\n },\n size: {\n sm: 'h-8',\n md: 'h-10',\n lg: 'h-12',\n },\n orientation: {\n horizontal: '',\n vertical: 'flex-col',\n },\n },\n compoundVariants: [\n // Vertical line: left border instead of bottom, fixed width, auto height\n { variant: 'line', orientation: 'vertical', class: 'border-b-0 border-l border-surface-border-strong w-48 shrink-0 h-auto gap-0' },\n // Vertical contained: column layout, fixed width, auto height\n { variant: 'contained', orientation: 'vertical', class: 'h-auto w-48 shrink-0' },\n ],\n defaultVariants: { variant: 'line', size: 'md', orientation: 'horizontal' },\n})\n\nconst tabsTriggerVariants = cva(\n 'relative inline-flex items-center justify-center gap-ds-02 whitespace-nowrap font-sans font-medium transition-colors duration-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-action-disabled',\n {\n variants: {\n variant: {\n line: [\n '-mb-px',\n 'text-surface-fg-muted hover:text-surface-fg',\n ],\n contained: [\n 'rounded-ds-md',\n 'text-surface-fg-muted hover:text-surface-fg',\n 'data-[state=active]:text-surface-fg',\n ],\n },\n size: {\n sm: 'px-ds-03 py-ds-02 text-ds-xs',\n md: 'px-ds-05 py-ds-03 text-ds-sm',\n lg: 'px-ds-06 py-ds-04 text-ds-md',\n },\n },\n defaultVariants: { variant: 'line', size: 'md' },\n },\n)\n\n/**\n * TabsList — container for tab triggers. Sets `variant` for all child TabsTriggers via context.\n *\n * **Compound structure — variant propagates automatically:**\n * ```tsx\n * <Tabs defaultValue=\"overview\">\n * <TabsList variant=\"contained\">\n * <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n * <TabsTrigger value=\"activity\">Activity</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"overview\">Overview content</TabsContent>\n * <TabsContent value=\"activity\">Activity content</TabsContent>\n * </Tabs>\n * ```\n *\n * `variant` on `TabsList` flows to all `TabsTrigger` children via React context.\n * You do NOT need to repeat `variant` on each `TabsTrigger`.\n */\nexport interface TabsListProps\n extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>,\n VariantProps<typeof tabsListVariants> {\n /** Color axis — affects active tab indicator and text color. @default \"accent\" */\n color?: TabsColor\n}\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, variant, size, color, ...props }, ref) => {\n const orientation = React.useContext(TabsOrientationContext)\n const resolvedVariant: TabsVariant = variant ?? 'line'\n const resolvedSize: TabsSize = size ?? 'md'\n const resolvedColor: TabsColor = color ?? 'accent'\n const layoutId = React.useId()\n const contextValue = React.useMemo(\n () => ({\n variant: resolvedVariant,\n size: resolvedSize,\n color: resolvedColor,\n layoutId: `tab-indicator-${layoutId}`,\n }),\n [resolvedVariant, resolvedSize, resolvedColor, layoutId],\n )\n return (\n <TabsListContext.Provider value={contextValue}>\n <LayoutGroup>\n <TabsPrimitive.List\n ref={ref}\n className={cn(tabsListVariants({ variant: resolvedVariant, size: resolvedSize, orientation }), className)}\n {...props}\n />\n </LayoutGroup>\n </TabsListContext.Provider>\n )\n})\nTabsList.displayName = TabsPrimitive.List.displayName\n\nexport interface TabsTriggerProps\n extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>,\n VariantProps<typeof tabsTriggerVariants> {}\n\n/* ── Color classes for active state ────── */\nconst lineActiveColorMap: Record<TabsColor, string> = {\n accent: 'data-[state=active]:text-accent-11',\n neutral: 'data-[state=active]:text-surface-fg',\n}\n\nconst lineIndicatorColorMap: Record<TabsColor, string> = {\n accent: 'bg-accent-9',\n neutral: 'bg-surface-fg',\n}\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, variant: variantProp, children, ...props }, ref) => {\n const listContext = React.useContext(TabsListContext)\n const activeValue = React.useContext(TabsValueContext)\n const orientation = React.useContext(TabsOrientationContext)\n const variant = variantProp ?? listContext.variant\n const size = listContext.size\n const color = listContext.color\n const isActive = props.value === activeValue\n const isVertical = orientation === 'vertical'\n\n return (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n tabsTriggerVariants({ variant, size }),\n variant === 'line' && lineActiveColorMap[color],\n // Vertical: full width triggers, left margin instead of bottom\n isVertical && 'w-full justify-start',\n variant === 'line' && isVertical && '-ml-px -mb-0',\n className,\n )}\n {...props}\n >\n {/* Contained variant: sliding pill background */}\n {variant === 'contained' && isActive && (\n <motion.span\n layoutId={`${listContext.layoutId}-contained`}\n className=\"absolute inset-0 rounded-ds-md bg-surface-overlay shadow-raised\"\n transition={springs.smooth}\n />\n )}\n {/* Content sits above the indicator */}\n <span className=\"relative z-[1] inline-flex items-center gap-ds-02\">{children}</span>\n {/* Line variant: sliding indicator -- bottom underline (horizontal) or left bar (vertical) */}\n {variant === 'line' && isActive && (\n <motion.span\n layoutId={`${listContext.layoutId}-line`}\n className={cn(\n 'absolute',\n isVertical\n ? 'left-0 top-0 bottom-0 w-0.5'\n : 'bottom-0 left-0 right-0 h-0.5',\n lineIndicatorColorMap[color],\n )}\n transition={springs.smooth}\n />\n )}\n </TabsPrimitive.Trigger>\n )\n})\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName\n\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, children, ...props }, ref) => {\n const orientation = React.useContext(TabsOrientationContext)\n const isVertical = orientation === 'vertical'\n\n return (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n 'ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n isVertical ? 'mt-0 flex-1 min-w-0' : 'mt-ds-05',\n className,\n )}\n {...props}\n >\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n >\n {children}\n </motion.div>\n </TabsPrimitive.Content>\n )\n})\nTabsContent.displayName = TabsPrimitive.Content.displayName\n\n/** Props for TabsContent. The `value` prop must match a TabsTrigger's `value`. */\nexport type TabsContentProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n\nexport { Tabs, TabsContent,TabsList, TabsTrigger }\nexport type { TabsColor, TabsOrientation,TabsSize }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tabs.js","names":[],"sources":["../../src/ui/tabs.tsx"],"sourcesContent":["'use client'\n\nimport * as TabsPrimitive from '@primitives/react-tabs'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { LayoutGroup,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/* ── Active-value context (drives layoutId indicator) ────── */\ntype TabsOrientation = 'horizontal' | 'vertical'\nconst TabsValueContext = React.createContext<string | undefined>(undefined)\nconst TabsOrientationContext = React.createContext<TabsOrientation>('horizontal')\n\n/**\n * Tabs compound component — accessible tabbed navigation with keyboard support and two visual\n * variants (line underline and contained pill styles).\n *\n * **Parts (in composition order):**\n * - `Tabs` — manages active tab state (this root; takes `defaultValue`, `value`, `onValueChange`)\n * - `TabsList` — tab bar container (takes `variant=\"line\"|\"contained\"`, default `\"line\"`)\n * - `TabsTrigger` — individual tab button (requires `value`; inherits `variant` from TabsList via context)\n * - `TabsContent` — the panel shown when its tab is active (requires `value` matching a TabsTrigger)\n *\n * **Critical behavior:** `variant` set on `TabsList` propagates automatically via React context to\n * all `TabsTrigger` children. You do NOT need to repeat `variant` on each trigger — but you CAN\n * override it per-trigger if needed.\n *\n * The active tab indicator animates between tabs using Framer Motion `layoutId`. Line variant\n * shows a sliding underline; contained variant shows a sliding pill background.\n *\n * @compound\n * @example\n * // Default line variant:\n * <Tabs defaultValue=\"overview\">\n * <TabsList>\n * <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n * <TabsTrigger value=\"activity\">Activity</TabsTrigger>\n * <TabsTrigger value=\"settings\">Settings</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"overview\">Overview content</TabsContent>\n * <TabsContent value=\"activity\">Activity content</TabsContent>\n * <TabsContent value=\"settings\">Settings content</TabsContent>\n * </Tabs>\n *\n * @example\n * // Contained pill variant (controlled):\n * const [tab, setTab] = useState('members')\n * <Tabs value={tab} onValueChange={setTab}>\n * <TabsList variant=\"contained\">\n * <TabsTrigger value=\"members\">Members</TabsTrigger>\n * <TabsTrigger value=\"roles\">Roles</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"members\">Members list here.</TabsContent>\n * <TabsContent value=\"roles\">Roles list here.</TabsContent>\n * </Tabs>\n */\nconst Tabs = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>\n>(({ value: valueProp, defaultValue, onValueChange, orientation, ...props }, ref) => {\n // Track the active value so TabsTrigger can conditionally render the motion indicator.\n // For controlled usage, mirror the prop; for uncontrolled, manage internal state.\n const [activeValue, setActiveValue] = React.useState(valueProp ?? defaultValue ?? '')\n\n // Sync controlled value\n React.useEffect(() => {\n if (valueProp !== undefined) setActiveValue(valueProp)\n }, [valueProp])\n\n const handleValueChange = React.useCallback(\n (newValue: string) => {\n setActiveValue(newValue)\n onValueChange?.(newValue)\n },\n [onValueChange],\n )\n\n const resolvedOrientation: TabsOrientation = orientation ?? 'horizontal'\n\n return (\n <TabsValueContext.Provider value={activeValue}>\n <TabsOrientationContext.Provider value={resolvedOrientation}>\n <TabsPrimitive.Root\n ref={ref}\n value={valueProp}\n defaultValue={valueProp === undefined ? defaultValue : undefined}\n onValueChange={handleValueChange}\n orientation={orientation}\n {...props}\n className={cn(\n resolvedOrientation === 'vertical' && 'flex flex-row gap-ds-05',\n props.className,\n )}\n />\n </TabsOrientationContext.Provider>\n </TabsValueContext.Provider>\n )\n})\nTabs.displayName = 'Tabs'\n\n/** Props for the Tabs root (defaultValue, value, onValueChange, etc.). */\nexport type TabsProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>\n\ntype TabsVariant = 'line' | 'contained'\ntype TabsSize = 'sm' | 'md' | 'lg'\ntype TabsColor = 'accent' | 'neutral'\n\ninterface TabsListContextValue {\n variant: TabsVariant\n size: TabsSize\n color: TabsColor\n layoutId: string\n}\n\nconst TabsListContext = React.createContext<TabsListContextValue>({\n variant: 'line',\n size: 'md',\n color: 'accent',\n layoutId: 'tab-indicator',\n})\n\nconst tabsListVariants = cva('inline-flex items-center', {\n variants: {\n variant: {\n line: 'border-b border-surface-border-strong w-full gap-0',\n contained:\n 'bg-surface-raised p-ds-02 rounded-surface gap-ds-02',\n },\n size: {\n sm: 'h-8',\n md: 'h-10',\n lg: 'h-12',\n },\n orientation: {\n horizontal: '',\n vertical: 'flex-col',\n },\n },\n compoundVariants: [\n // Vertical line: left border instead of bottom, fixed width, auto height\n { variant: 'line', orientation: 'vertical', class: 'border-b-0 border-l border-surface-border-strong w-48 shrink-0 h-auto gap-0' },\n // Vertical contained: column layout, fixed width, auto height\n { variant: 'contained', orientation: 'vertical', class: 'h-auto w-48 shrink-0' },\n ],\n defaultVariants: { variant: 'line', size: 'md', orientation: 'horizontal' },\n})\n\nconst tabsTriggerVariants = cva(\n 'relative inline-flex items-center justify-center gap-ds-02 whitespace-nowrap font-sans font-medium transition-colors duration-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-action-disabled',\n {\n variants: {\n variant: {\n line: [\n '-mb-px',\n 'text-surface-fg-muted hover:text-surface-fg',\n ],\n contained: [\n 'rounded-control',\n 'text-surface-fg-muted hover:text-surface-fg',\n 'data-[state=active]:text-surface-fg',\n ],\n },\n size: {\n sm: 'px-ds-03 py-ds-02 text-ds-xs',\n md: 'px-ds-05 py-ds-03 text-ds-sm',\n lg: 'px-ds-06 py-ds-04 text-ds-md',\n },\n },\n defaultVariants: { variant: 'line', size: 'md' },\n },\n)\n\n/**\n * TabsList — container for tab triggers. Sets `variant` for all child TabsTriggers via context.\n *\n * **Compound structure — variant propagates automatically:**\n * ```tsx\n * <Tabs defaultValue=\"overview\">\n * <TabsList variant=\"contained\">\n * <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n * <TabsTrigger value=\"activity\">Activity</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"overview\">Overview content</TabsContent>\n * <TabsContent value=\"activity\">Activity content</TabsContent>\n * </Tabs>\n * ```\n *\n * `variant` on `TabsList` flows to all `TabsTrigger` children via React context.\n * You do NOT need to repeat `variant` on each `TabsTrigger`.\n */\nexport interface TabsListProps\n extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>,\n VariantProps<typeof tabsListVariants> {\n /** Color axis — affects active tab indicator and text color. @default \"accent\" */\n color?: TabsColor\n}\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, variant, size, color, ...props }, ref) => {\n const orientation = React.useContext(TabsOrientationContext)\n const resolvedVariant: TabsVariant = variant ?? 'line'\n const resolvedSize: TabsSize = size ?? 'md'\n const resolvedColor: TabsColor = color ?? 'accent'\n const layoutId = React.useId()\n const contextValue = React.useMemo(\n () => ({\n variant: resolvedVariant,\n size: resolvedSize,\n color: resolvedColor,\n layoutId: `tab-indicator-${layoutId}`,\n }),\n [resolvedVariant, resolvedSize, resolvedColor, layoutId],\n )\n return (\n <TabsListContext.Provider value={contextValue}>\n <LayoutGroup>\n <TabsPrimitive.List\n ref={ref}\n className={cn(tabsListVariants({ variant: resolvedVariant, size: resolvedSize, orientation }), className)}\n {...props}\n />\n </LayoutGroup>\n </TabsListContext.Provider>\n )\n})\nTabsList.displayName = TabsPrimitive.List.displayName\n\nexport interface TabsTriggerProps\n extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>,\n VariantProps<typeof tabsTriggerVariants> {}\n\n/* ── Color classes for active state ────── */\nconst lineActiveColorMap: Record<TabsColor, string> = {\n accent: 'data-[state=active]:text-accent-11',\n neutral: 'data-[state=active]:text-surface-fg',\n}\n\nconst lineIndicatorColorMap: Record<TabsColor, string> = {\n accent: 'bg-accent-9',\n neutral: 'bg-surface-fg',\n}\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, variant: variantProp, children, ...props }, ref) => {\n const listContext = React.useContext(TabsListContext)\n const activeValue = React.useContext(TabsValueContext)\n const orientation = React.useContext(TabsOrientationContext)\n const variant = variantProp ?? listContext.variant\n const size = listContext.size\n const color = listContext.color\n const isActive = props.value === activeValue\n const isVertical = orientation === 'vertical'\n\n return (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n tabsTriggerVariants({ variant, size }),\n variant === 'line' && lineActiveColorMap[color],\n // Vertical: full width triggers, left margin instead of bottom\n isVertical && 'w-full justify-start',\n variant === 'line' && isVertical && '-ml-px -mb-0',\n className,\n )}\n {...props}\n >\n {/* Contained variant: sliding pill background */}\n {variant === 'contained' && isActive && (\n <motion.span\n layoutId={`${listContext.layoutId}-contained`}\n className=\"absolute inset-0 rounded-control bg-surface-overlay shadow-raised\"\n transition={springs.smooth}\n />\n )}\n {/* Content sits above the indicator */}\n <span className=\"relative z-[1] inline-flex items-center gap-ds-02\">{children}</span>\n {/* Line variant: sliding indicator -- bottom underline (horizontal) or left bar (vertical) */}\n {variant === 'line' && isActive && (\n <motion.span\n layoutId={`${listContext.layoutId}-line`}\n className={cn(\n 'absolute',\n isVertical\n ? 'left-0 top-0 bottom-0 w-0.5'\n : 'bottom-0 left-0 right-0 h-0.5',\n lineIndicatorColorMap[color],\n )}\n transition={springs.smooth}\n />\n )}\n </TabsPrimitive.Trigger>\n )\n})\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName\n\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, children, ...props }, ref) => {\n const orientation = React.useContext(TabsOrientationContext)\n const isVertical = orientation === 'vertical'\n\n return (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n 'ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n isVertical ? 'mt-0 flex-1 min-w-0' : 'mt-ds-05',\n className,\n )}\n {...props}\n >\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n >\n {children}\n </motion.div>\n </TabsPrimitive.Content>\n )\n})\nTabsContent.displayName = TabsPrimitive.Content.displayName\n\n/** Props for TabsContent. The `value` prop must match a TabsTrigger's `value`. */\nexport type TabsContentProps = React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n\nexport { Tabs, TabsContent,TabsList, TabsTrigger }\nexport type { TabsColor, TabsOrientation,TabsSize }\n"],"mappings":"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"}
|
package/dist/ui/textarea.js
CHANGED
|
@@ -10,7 +10,7 @@ import { motion as o } from "framer-motion";
|
|
|
10
10
|
var s = t([
|
|
11
11
|
"flex w-full font-sans resize-y",
|
|
12
12
|
"bg-surface-raised-hover text-surface-fg",
|
|
13
|
-
"border border-surface-border-strong rounded-
|
|
13
|
+
"border border-surface-border-strong rounded-control",
|
|
14
14
|
"placeholder:text-surface-fg-subtle",
|
|
15
15
|
"hover:bg-surface-raised-active",
|
|
16
16
|
"transition-colors duration-fast-01 ease-productive-standard",
|
package/dist/ui/textarea.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.js","names":[],"sources":["../../src/ui/textarea.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport type { InputState } from './input'\nimport { motionProps } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst textareaVariants = cva(\n [\n 'flex w-full font-sans resize-y',\n 'bg-surface-raised-hover text-surface-fg',\n 'border border-surface-border-strong rounded-
|
|
1
|
+
{"version":3,"file":"textarea.js","names":[],"sources":["../../src/ui/textarea.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport type { InputState } from './input'\nimport { motionProps } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst textareaVariants = cva(\n [\n 'flex w-full font-sans resize-y',\n 'bg-surface-raised-hover text-surface-fg',\n 'border border-surface-border-strong rounded-control',\n 'placeholder:text-surface-fg-subtle',\n 'hover:bg-surface-raised-active',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 focus-visible:border-accent-7',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n 'read-only:bg-surface-raised read-only:cursor-default',\n ],\n {\n variants: {\n size: {\n xs: 'min-h-[48px] text-ds-sm px-ds-02 py-ds-02',\n sm: 'min-h-[60px] text-ds-sm px-ds-03 py-ds-02',\n md: 'min-h-[80px] text-ds-md px-ds-04 py-ds-03',\n lg: 'min-h-[120px] text-ds-md px-ds-05 py-ds-04',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\n/**\n * Props for Textarea — a resizable multi-line text input with size variants and validation state coloring,\n * sharing the same `InputState` type as `<Input>`.\n *\n * **Sizes:** `sm` (min 60px) | `md` (min 80px, default) | `lg` (min 120px) — all are vertically resizable.\n *\n * **Validation states:** `state=\"error\"` | `\"warning\"` | `\"success\"` — changes border color and focus ring.\n * HTML's native `size` attribute is omitted; use `rows` for initial height or CSS `min-height`.\n *\n * **Pair with FormField:** Use inside `<FormField>` to get a label, helper text, and associated `state`.\n *\n * @example\n * // Basic description textarea in a form:\n * <Textarea placeholder=\"Describe the issue...\" rows={4} />\n *\n * @example\n * // Error state when validation fails:\n * <Textarea state=\"error\" value={bio} onChange={(e) => setBio(e.target.value)} />\n *\n * @example\n * // Large textarea for a full email draft composer:\n * <Textarea size=\"lg\" placeholder=\"Write your message...\" className=\"min-h-[200px]\" />\n *\n * @example\n * // Read-only view of a previously submitted note:\n * <Textarea readOnly value={submission.notes} size=\"md\" />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface TextareaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>,\n VariantProps<typeof textareaVariants> {\n state?: InputState\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, state: stateProp, size, ...props }, ref) => {\n const fieldCtx = useFormField()\n // Merge FormField context — explicit props always win\n const state = stateProp ?? (fieldCtx.state === 'helper' ? undefined : fieldCtx.state as InputState | undefined)\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <motion.textarea\n aria-invalid={state === 'error' || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n className={cn(\n textareaVariants({ size }),\n state === 'error' && 'border-error-7 focus-visible:ring-error-7',\n state === 'warning' && 'border-warning-7 focus-visible:ring-warning-7',\n state === 'success' && 'border-success-7 focus-visible:ring-success-7',\n className,\n )}\n ref={ref}\n {...motionProps(props)}\n />\n )\n },\n)\nTextarea.displayName = 'Textarea'\n\nexport { Textarea, textareaVariants }\n"],"mappings":";;;;;;;;;AAWA,IAAM,IAAmB,EACvB;CACE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EACD;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,EACF;CACD,iBAAiB,EAAE,MAAM,MAAM;CAChC,CACF,EAoCK,IAAW,EAAM,YACpB,EAAE,cAAW,OAAO,GAAW,SAAM,GAAG,KAAS,MAAQ;CACxD,IAAM,IAAW,GAAc,EAEzB,IAAQ,MAAc,EAAS,UAAU,WAAW,KAAA,IAAY,EAAS,QACzE,IAAkB,EAAM,uBAAuB,EAAS,cACxD,IAAe,EAAM,oBAAoB,EAAS;AAExD,QACE,kBAAC,EAAO,UAAR;EACE,gBAAc,MAAU,WAAW,KAAA;EACnC,oBAAkB;EAClB,iBAAe,KAAgB,KAAA;EAC/B,WAAW,EACT,EAAiB,EAAE,SAAM,CAAC,EAC1B,MAAU,WAAW,6CACrB,MAAU,aAAa,iDACvB,MAAU,aAAa,iDACvB,EACD;EACI;EACL,GAAI,EAAY,EAAM;EACtB,CAAA;EAGP;AACD,EAAS,cAAc"}
|
package/dist/ui/toast.js
CHANGED
|
@@ -87,14 +87,14 @@ function k({ type: a, title: o, description: u, action: d, cancel: f, duration:
|
|
|
87
87
|
role: j ? "alert" : "status",
|
|
88
88
|
"aria-live": j ? "assertive" : "polite",
|
|
89
89
|
"aria-atomic": "true",
|
|
90
|
-
className: "group relative flex w-full overflow-hidden rounded-
|
|
90
|
+
className: "group relative flex w-full overflow-hidden rounded-overlay-sm border border-surface-border-strong bg-surface-overlay shadow-floating",
|
|
91
91
|
onMouseEnter: () => _(!0),
|
|
92
92
|
onMouseLeave: () => _(!1),
|
|
93
93
|
onFocusCapture: () => y(!0),
|
|
94
94
|
onBlurCapture: () => y(!1),
|
|
95
95
|
transition: e.smooth,
|
|
96
96
|
children: [
|
|
97
|
-
T.accentClass && /* @__PURE__ */ c("div", { className: n("w-1 shrink-0 rounded-l-
|
|
97
|
+
T.accentClass && /* @__PURE__ */ c("div", { className: n("w-1 shrink-0 rounded-l-overlay-sm", T.accentClass) }),
|
|
98
98
|
/* @__PURE__ */ l("div", {
|
|
99
99
|
className: "flex min-w-0 flex-1 items-start gap-ds-03 p-ds-04",
|
|
100
100
|
children: [/* @__PURE__ */ c(x, {
|
|
@@ -155,12 +155,12 @@ function k({ type: a, title: o, description: u, action: d, cancel: f, duration:
|
|
|
155
155
|
children: [d && /* @__PURE__ */ c("button", {
|
|
156
156
|
type: "button",
|
|
157
157
|
onClick: d.onClick,
|
|
158
|
-
className: "text-ds-sm font-medium text-accent-11 underline-offset-2 hover:underline hover:bg-surface-raised-hover rounded-
|
|
158
|
+
className: "text-ds-sm font-medium text-accent-11 underline-offset-2 hover:underline hover:bg-surface-raised-hover rounded-control-inner px-ds-02 py-ds-01 transition-[color,background-color] duration-fast-01 ease-productive-standard focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:rounded-control-inner",
|
|
159
159
|
children: d.label
|
|
160
160
|
}), f && /* @__PURE__ */ c("button", {
|
|
161
161
|
type: "button",
|
|
162
162
|
onClick: f.onClick,
|
|
163
|
-
className: "text-ds-sm text-surface-fg-muted hover:text-surface-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:rounded-
|
|
163
|
+
className: "text-ds-sm text-surface-fg-muted hover:text-surface-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:rounded-control-inner",
|
|
164
164
|
children: f.label
|
|
165
165
|
})]
|
|
166
166
|
})
|
|
@@ -329,7 +329,7 @@ function F({ file: n, onRetry: o, onRemove: s }) {
|
|
|
329
329
|
n.status === "error" && o && /* @__PURE__ */ c("button", {
|
|
330
330
|
type: "button",
|
|
331
331
|
onClick: () => o(n.id),
|
|
332
|
-
className: "touch-target flex min-h-6 min-w-6 items-center justify-center rounded-
|
|
332
|
+
className: "touch-target flex min-h-6 min-w-6 items-center justify-center rounded-control-inner text-surface-fg-muted hover:text-surface-fg",
|
|
333
333
|
"aria-label": `Retry ${n.name}`,
|
|
334
334
|
title: "Retry",
|
|
335
335
|
children: /* @__PURE__ */ c(v, { className: "h-3.5 w-3.5" })
|
|
@@ -337,7 +337,7 @@ function F({ file: n, onRetry: o, onRemove: s }) {
|
|
|
337
337
|
!d && s && /* @__PURE__ */ c("button", {
|
|
338
338
|
type: "button",
|
|
339
339
|
onClick: () => s(n.id),
|
|
340
|
-
className: "touch-target flex min-h-6 min-w-6 items-center justify-center rounded-
|
|
340
|
+
className: "touch-target flex min-h-6 min-w-6 items-center justify-center rounded-control-inner text-surface-fg-muted hover:text-surface-fg",
|
|
341
341
|
"aria-label": `Cancel ${n.name}`,
|
|
342
342
|
title: "Remove",
|
|
343
343
|
children: /* @__PURE__ */ c(b, { className: "h-3.5 w-3.5" })
|
|
@@ -370,14 +370,14 @@ function I({ files: r, onRetry: a, onRemove: o, selfDismissId: d }) {
|
|
|
370
370
|
role: j ? "alert" : "status",
|
|
371
371
|
"aria-live": j ? "assertive" : "polite",
|
|
372
372
|
"aria-label": "File uploads",
|
|
373
|
-
className: "group relative flex w-full overflow-hidden rounded-
|
|
373
|
+
className: "group relative flex w-full overflow-hidden rounded-overlay-sm border border-surface-border-strong bg-surface-overlay shadow-floating",
|
|
374
374
|
onMouseEnter: () => m(!0),
|
|
375
375
|
onMouseLeave: () => m(!1),
|
|
376
376
|
onFocusCapture: () => g(!0),
|
|
377
377
|
onBlurCapture: () => g(!1),
|
|
378
378
|
transition: e.smooth,
|
|
379
379
|
children: [
|
|
380
|
-
/* @__PURE__ */ c("div", { className: n("w-1 shrink-0 rounded-l-
|
|
380
|
+
/* @__PURE__ */ c("div", { className: n("w-1 shrink-0 rounded-l-overlay-sm", k) }),
|
|
381
381
|
/* @__PURE__ */ l("div", {
|
|
382
382
|
className: "min-w-0 flex-1 p-ds-04",
|
|
383
383
|
children: [
|