@devalok/shilp-sutra 0.38.0 → 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 +118 -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/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/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/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.js +2 -2
- 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.js +1 -1
- 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/input-otp.js +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.js +2 -2
- 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.js +3 -3
- 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 +90 -1
- package/docs/recipes/customize-brand.md +85 -4
- package/docs/recipes/index.md +1 -1
- package/llms-full.txt +91 -2
- package/llms.txt +9 -1
- package/package.json +2 -1
- 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/{LICENSE → skill/LICENSE} +0 -0
package/dist/_chunks/shared.js
CHANGED
|
@@ -10,7 +10,7 @@ import { motion as d } from "framer-motion";
|
|
|
10
10
|
//#region src/composed/file-preview/shared.tsx
|
|
11
11
|
function f({ message: e, url: t }) {
|
|
12
12
|
return /* @__PURE__ */ o("div", {
|
|
13
|
-
className: "flex flex-col items-center justify-center gap-ds-04 rounded-
|
|
13
|
+
className: "flex flex-col items-center justify-center gap-ds-04 rounded-control border border-surface-border bg-surface-sunken p-ds-08 text-center",
|
|
14
14
|
children: [
|
|
15
15
|
/* @__PURE__ */ a(n, {
|
|
16
16
|
icon: s,
|
|
@@ -51,7 +51,7 @@ function p({ children: n, className: r }) {
|
|
|
51
51
|
y: 0
|
|
52
52
|
},
|
|
53
53
|
transition: e.fade,
|
|
54
|
-
className: t("flex items-center gap-ds-01 rounded-
|
|
54
|
+
className: t("flex items-center gap-ds-01 rounded-control border border-surface-border bg-surface-overlay/95 px-ds-02 py-ds-01 shadow-floating backdrop-blur-xs", r),
|
|
55
55
|
children: n
|
|
56
56
|
});
|
|
57
57
|
}
|
|
@@ -93,7 +93,7 @@ function h({ volume: e, muted: r, onVolumeChange: s, onMuteToggle: c, variant: d
|
|
|
93
93
|
className: "w-0 overflow-hidden group-hover/vol:w-20 transition-[width] duration-200 ease-productive-standard flex items-center",
|
|
94
94
|
children: /* @__PURE__ */ o("div", {
|
|
95
95
|
ref: f,
|
|
96
|
-
className: t("relative w-full h-1 rounded-
|
|
96
|
+
className: t("relative w-full h-1 rounded-pill cursor-pointer", x),
|
|
97
97
|
onPointerDown: _,
|
|
98
98
|
onPointerMove: v,
|
|
99
99
|
onPointerUp: y,
|
|
@@ -104,10 +104,10 @@ function h({ volume: e, muted: r, onVolumeChange: s, onMuteToggle: c, variant: d
|
|
|
104
104
|
"aria-valuemax": 100,
|
|
105
105
|
tabIndex: 0,
|
|
106
106
|
children: [/* @__PURE__ */ a("div", {
|
|
107
|
-
className: t("absolute left-0 top-0 h-full rounded-
|
|
107
|
+
className: t("absolute left-0 top-0 h-full rounded-pill transition-[width] duration-75", S),
|
|
108
108
|
style: { width: `${h * 100}%` }
|
|
109
109
|
}), /* @__PURE__ */ a("div", {
|
|
110
|
-
className: t("absolute top-1/2 -translate-y-1/2 h-2.5 w-2.5 rounded-
|
|
110
|
+
className: t("absolute top-1/2 -translate-y-1/2 h-2.5 w-2.5 rounded-pill shadow-raised transition-opacity", C, p ? "opacity-100 scale-110" : "opacity-0 group-hover/vol:opacity-100"),
|
|
111
111
|
style: {
|
|
112
112
|
left: `${h * 100}%`,
|
|
113
113
|
marginLeft: "-5px"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","names":[],"sources":["../../src/composed/file-preview/shared.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconAlertTriangle,\n IconDownload,\n IconVolume,\n IconVolumeOff,\n} from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport { Icon } from '../../ui/icon'\nimport { tweens } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\n\n// ============================================================\n// Shared: Error Fallback\n// ============================================================\n\nexport function ErrorFallback({ message, url }: { message: string; url: string }) {\n return (\n <div className=\"flex flex-col items-center justify-center gap-ds-04 rounded-
|
|
1
|
+
{"version":3,"file":"shared.js","names":[],"sources":["../../src/composed/file-preview/shared.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconAlertTriangle,\n IconDownload,\n IconVolume,\n IconVolumeOff,\n} from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport { Icon } from '../../ui/icon'\nimport { tweens } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\n\n// ============================================================\n// Shared: Error Fallback\n// ============================================================\n\nexport function ErrorFallback({ message, url }: { message: string; url: string }) {\n return (\n <div className=\"flex flex-col items-center justify-center gap-ds-04 rounded-control border border-surface-border bg-surface-sunken p-ds-08 text-center\">\n <Icon icon={IconAlertTriangle} size=\"2xl\" className=\"text-warning-9\" />\n <div>\n <p className=\"text-ds-md font-semibold text-surface-fg\">Preview unavailable</p>\n <p className=\"text-ds-sm text-surface-fg-muted mt-ds-01\">{message}</p>\n </div>\n <Button variant=\"outline\" size=\"xs\" startIcon={<Icon icon={IconDownload} />} asChild>\n <a href={url} download target=\"_blank\" rel=\"noopener noreferrer\">Download file</a>\n </Button>\n </div>\n )\n}\n\n// ============================================================\n// Shared: Floating Toolbar\n// ============================================================\n\nexport function Toolbar({ children, className }: { children: React.ReactNode; className?: string }) {\n return (\n <motion.div\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={tweens.fade}\n className={cn(\n 'flex items-center gap-ds-01 rounded-control border border-surface-border bg-surface-overlay/95 px-ds-02 py-ds-01 shadow-floating backdrop-blur-xs',\n className,\n )}\n >\n {children}\n </motion.div>\n )\n}\n\nexport function ToolbarDivider() {\n return <div className=\"mx-ds-01 h-4 w-px bg-surface-border-subtle\" />\n}\n\n// ============================================================\n// Shared: Volume Slider (Spotify/YouTube style)\n// Custom-built — no native input range. Consistent across browsers.\n// ============================================================\n\nexport function VolumeControl({\n volume,\n muted,\n onVolumeChange,\n onMuteToggle,\n variant = 'light',\n}: {\n volume: number\n muted: boolean\n onVolumeChange: (v: number) => void\n onMuteToggle: () => void\n variant?: 'light' | 'dark'\n}) {\n const trackRef = React.useRef<HTMLDivElement>(null)\n const [dragging, setDragging] = React.useState(false)\n const displayVolume = muted ? 0 : volume\n\n function getVolumeFromEvent(e: MouseEvent | React.MouseEvent) {\n if (!trackRef.current) return volume\n const rect = trackRef.current.getBoundingClientRect()\n return Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width))\n }\n\n function handlePointerDown(e: React.PointerEvent) {\n e.preventDefault()\n setDragging(true)\n const v = getVolumeFromEvent(e)\n onVolumeChange(v)\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n }\n\n function handlePointerMove(e: React.PointerEvent) {\n if (!dragging) return\n onVolumeChange(getVolumeFromEvent(e))\n }\n\n function handlePointerUp() {\n setDragging(false)\n }\n\n const isDark = variant === 'dark'\n const trackBg = isDark ? 'bg-white/30' : 'bg-surface-sunken'\n const fillBg = isDark ? 'bg-white' : 'bg-accent-9'\n const thumbBg = isDark ? 'bg-white' : 'bg-accent-9'\n const iconClass = isDark ? 'text-white hover:text-white/80' : 'text-surface-fg-muted hover:text-surface-fg'\n\n return (\n <div className=\"group/vol flex items-center gap-ds-02 shrink-0\">\n <button onClick={onMuteToggle} className={cn('transition-colors', iconClass)} aria-label={muted ? 'Unmute (M)' : 'Mute (M)'} title={muted ? 'Unmute' : 'Mute'}>\n {muted || volume === 0 ? <Icon icon={IconVolumeOff} size=\"sm\" /> : <Icon icon={IconVolume} size=\"sm\" />}\n </button>\n <div className=\"w-0 overflow-hidden group-hover/vol:w-20 transition-[width] duration-200 ease-productive-standard flex items-center\">\n <div\n ref={trackRef}\n className={cn('relative w-full h-1 rounded-pill cursor-pointer', trackBg)}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n role=\"slider\"\n aria-label=\"Volume\"\n aria-valuenow={Math.round(displayVolume * 100)}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n >\n {/* Fill */}\n <div\n className={cn('absolute left-0 top-0 h-full rounded-pill transition-[width] duration-75', fillBg)}\n style={{ width: `${displayVolume * 100}%` }}\n />\n {/* Thumb */}\n <div\n className={cn(\n 'absolute top-1/2 -translate-y-1/2 h-2.5 w-2.5 rounded-pill shadow-raised transition-opacity',\n thumbBg,\n dragging ? 'opacity-100 scale-110' : 'opacity-0 group-hover/vol:opacity-100',\n )}\n style={{ left: `${displayVolume * 100}%`, marginLeft: '-5px' }}\n />\n </div>\n </div>\n </div>\n )\n}\n\n// ============================================================\n// Shared: Time Formatting\n// ============================================================\n\nexport function formatTime(s: number): string {\n if (!isFinite(s) || s < 0) return '0:00'\n const h = Math.floor(s / 3600)\n const m = Math.floor((s % 3600) / 60)\n const sec = Math.floor(s % 60)\n if (h > 0) return `${h}:${m.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`\n return `${m}:${sec.toString().padStart(2, '0')}`\n}\n"],"mappings":"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"}
|
package/dist/_chunks/text.js
CHANGED
|
@@ -150,7 +150,7 @@ var P = S.memo(function({ data: e, confidence: t, onAction: n }) {
|
|
|
150
150
|
children: "Why this action?"
|
|
151
151
|
})
|
|
152
152
|
}), /* @__PURE__ */ C(l, { children: /* @__PURE__ */ C("p", {
|
|
153
|
-
className: "text-ds-sm text-surface-fg-muted mt-2 p-3 bg-surface-raised rounded-
|
|
153
|
+
className: "text-ds-sm text-surface-fg-muted mt-2 p-3 bg-surface-raised rounded-surface",
|
|
154
154
|
children: e.rationale
|
|
155
155
|
}) })]
|
|
156
156
|
})
|
|
@@ -209,7 +209,7 @@ L.displayName = "InfoBlock";
|
|
|
209
209
|
//#region src/ai/blocks/loading.tsx
|
|
210
210
|
function R() {
|
|
211
211
|
return /* @__PURE__ */ C(O.span, {
|
|
212
|
-
className: "inline-block h-4 w-4 rounded-
|
|
212
|
+
className: "inline-block h-4 w-4 rounded-pill border-2 border-current border-t-transparent text-accent-9",
|
|
213
213
|
animate: { rotate: 360 },
|
|
214
214
|
transition: {
|
|
215
215
|
repeat: Infinity,
|
package/dist/_chunks/text.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","names":[],"sources":["../../src/ai/blocks/block-table.tsx","../../src/ai/blocks/confirm.tsx","../../src/ai/blocks/divider.tsx","../../src/ai/blocks/error.tsx","../../src/ai/blocks/info.tsx","../../src/ai/blocks/loading.tsx","../../src/ai/blocks/stat-row.tsx","../../src/ai/blocks/success.tsx","../../src/ai/blocks/text.tsx"],"sourcesContent":["'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { Badge } from '../../ui/badge'\nimport { springs } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\nimport {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '../../ui/table'\nimport type { BlockComponentProps, BlockTableColumn,BlockTableData } from '../types'\n\ntype SortDir = 'asc' | 'desc' | null\n\nfunction renderCellValue(value: unknown, column: BlockTableColumn) {\n if (column.variant === 'badge') {\n if (value && typeof value === 'object' && 'label' in value) {\n const badgeObj = value as { label: string; color: string }\n return (\n <Badge variant=\"subtle\" size=\"sm\" color={badgeObj.color as 'default'}>\n {badgeObj.label}\n </Badge>\n )\n }\n return (\n <Badge variant=\"subtle\" size=\"sm\">\n {String(value ?? '')}\n </Badge>\n )\n }\n\n return String(value ?? '')\n}\n\nfunction sortRows(\n rows: Record<string, unknown>[],\n sortKey: string | null,\n sortDir: SortDir,\n): Record<string, unknown>[] {\n if (!sortKey || !sortDir) return rows\n return [...rows].sort((a, b) => {\n const aVal = a[sortKey]\n const bVal = b[sortKey]\n const aStr = String(aVal ?? '')\n const bStr = String(bVal ?? '')\n const aNum = Number(aVal)\n const bNum = Number(bVal)\n\n // If both are numeric, sort numerically\n if (!Number.isNaN(aNum) && !Number.isNaN(bNum)) {\n return sortDir === 'asc' ? aNum - bNum : bNum - aNum\n }\n\n // Otherwise sort lexicographically\n const cmp = aStr.localeCompare(bStr)\n return sortDir === 'asc' ? cmp : -cmp\n })\n}\n\nconst BlockTable = React.memo(function BlockTable({\n data,\n confidence,\n}: BlockComponentProps<BlockTableData>) {\n const { reducedMotion } = useMotion()\n const [sortKey, setSortKey] = React.useState<string | null>(null)\n const [sortDir, setSortDir] = React.useState<SortDir>(null)\n\n const handleHeaderClick = React.useCallback(\n (key: string) => {\n if (!data.sortable) return\n if (sortKey !== key) {\n setSortKey(key)\n setSortDir('asc')\n } else if (sortDir === 'asc') {\n setSortDir('desc')\n } else if (sortDir === 'desc') {\n setSortKey(null)\n setSortDir(null)\n }\n },\n [data.sortable, sortKey, sortDir],\n )\n\n const columns = data.columns ?? []\n const sortedRows = sortRows(data.rows ?? [], sortKey, sortDir)\n\n return (\n <div\n className={cn(\n 'overflow-x-auto',\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Table>\n {data.caption && <TableCaption>{data.caption}</TableCaption>}\n <TableHeader>\n <TableRow>\n {columns.map((col) => {\n const isSorted = sortKey === col.key\n const ariaSort = data.sortable\n ? isSorted\n ? sortDir === 'asc'\n ? ('ascending' as const)\n : ('descending' as const)\n : ('none' as const)\n : undefined\n\n return (\n <TableHead\n key={col.key}\n role=\"columnheader\"\n className={cn(\n col.variant === 'number' && 'text-right',\n data.sortable && 'cursor-pointer select-none',\n )}\n tabIndex={data.sortable ? 0 : undefined}\n onClick={\n data.sortable\n ? () => handleHeaderClick(col.key)\n : undefined\n }\n onKeyDown={\n data.sortable\n ? (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleHeaderClick(col.key)\n }\n }\n : undefined\n }\n aria-sort={ariaSort}\n >\n <span className=\"inline-flex items-center gap-1\">\n {col.label}\n {isSorted && sortDir === 'asc' && (\n <span aria-hidden=\"true\">▲</span>\n )}\n {isSorted && sortDir === 'desc' && (\n <span aria-hidden=\"true\">▼</span>\n )}\n </span>\n </TableHead>\n )\n })}\n </TableRow>\n </TableHeader>\n <TableBody>\n {sortedRows.map((row, rowIndex) => {\n const rowKey =\n typeof row.id === 'string' || typeof row.id === 'number'\n ? String(row.id)\n : `row-${rowIndex}`\n\n const RowWrapper = reducedMotion ? 'tr' : motion.tr\n\n const motionProps = reducedMotion\n ? {}\n : {\n initial: { opacity: 0, y: 6 } as const,\n animate: { opacity: 1, y: 0 } as const,\n transition: { ...springs.responsive, delay: rowIndex * 0.03 },\n }\n\n return (\n <RowWrapper\n key={rowKey}\n className=\"hover:bg-surface-raised-hover transition-colors\"\n {...motionProps}\n >\n {columns.map((col) => (\n <TableCell\n key={col.key}\n className={cn(\n 'text-ds-sm py-ds-02b px-ds-04',\n col.variant === 'number' &&\n 'text-right tabular-nums font-medium',\n )}\n >\n {renderCellValue(row[col.key], col)}\n </TableCell>\n ))}\n </RowWrapper>\n )\n })}\n </TableBody>\n </Table>\n </div>\n )\n})\n\nBlockTable.displayName = 'BlockTable'\n\nexport { BlockTable }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../../ui/collapsible'\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps, ConfirmBlockData } from '../types'\n\nconst ConfirmBlock = React.memo(function ConfirmBlock({\n data,\n confidence,\n onAction,\n}: BlockComponentProps<ConfirmBlockData>) {\n const handleConfirm = React.useCallback(() => {\n onAction?.(data.actionId, 'confirm')\n }, [data.actionId, onAction])\n\n const handleCancel = React.useCallback(() => {\n onAction?.(data.actionId, 'cancel')\n }, [data.actionId, onAction])\n\n return (\n <div\n className={cn(\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n {data.description && (\n <p className=\"text-ds-sm text-surface-fg-muted mb-3\">\n {data.description}\n </p>\n )}\n\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"solid\"\n color={data.destructive ? 'error' : undefined}\n onClick={handleConfirm}\n >\n {data.label}\n </Button>\n <Button variant=\"ghost\" onClick={handleCancel}>\n Cancel\n </Button>\n </div>\n\n {data.rationale && (\n <Collapsible className=\"mt-3\">\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"text-ds-xs text-surface-fg-subtle underline cursor-pointer\"\n >\n Why this action?\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <p className=\"text-ds-sm text-surface-fg-muted mt-2 p-3 bg-surface-raised rounded-ds-lg\">\n {data.rationale}\n </p>\n </CollapsibleContent>\n </Collapsible>\n )}\n </div>\n )\n})\n\nConfirmBlock.displayName = 'ConfirmBlock'\n\nexport { ConfirmBlock }\n","'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { tweens } from '../../ui/lib/motion'\nimport { Separator } from '../../ui/separator'\nimport type { BlockComponentProps } from '../types'\n\nconst DividerBlock = React.memo(function DividerBlock(\n _props: BlockComponentProps<Record<string, never>>,\n) {\n const { reducedMotion } = useMotion()\n\n if (reducedMotion) {\n return <Separator />\n }\n\n return (\n <motion.div\n initial={{ scaleX: 0 }}\n animate={{ scaleX: 1 }}\n style={{ originX: 0.5 }}\n transition={tweens.elegant}\n >\n <Separator />\n </motion.div>\n )\n})\n\nDividerBlock.displayName = 'DividerBlock'\n\nexport { DividerBlock }\n","'use client'\n\nimport * as React from 'react'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nimport { Alert } from '../../ui/alert'\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps, ErrorBlockData } from '../types'\n\nconst ErrorBlock = React.memo(function ErrorBlock({\n data,\n confidence,\n}: BlockComponentProps<ErrorBlockData>) {\n return (\n <div\n className={cn(\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Alert color=\"error\" variant=\"subtle\" title={data.title}>\n <div className=\"prose prose-sm\">\n <Markdown remarkPlugins={[remarkGfm]}>{data.message}</Markdown>\n </div>\n </Alert>\n {data.suggestion && (\n <p className=\"mt-2 text-ds-sm text-surface-fg-muted\">\n {data.suggestion}\n </p>\n )}\n </div>\n )\n})\n\nErrorBlock.displayName = 'ErrorBlock'\n\nexport { ErrorBlock }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Alert } from '../../ui/alert'\nimport type { BlockComponentProps } from '../types'\n\nconst InfoBlock = React.memo(function InfoBlock({\n data,\n}: BlockComponentProps<{ message: string }>) {\n return (\n <Alert color=\"info\" variant=\"subtle\" role=\"status\">\n {data.message}\n </Alert>\n )\n})\n\nInfoBlock.displayName = 'InfoBlock'\n\nexport { InfoBlock }\n","'use client'\n\nimport {\n IconCircle,\n IconCircleCheck,\n IconCircleX,\n} from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\nimport { Skeleton } from '../../ui/skeleton'\nimport type { BlockComponentProps, LoadingBlockData, ProcessingStep } from '../types'\n\n/** Spinning indicator for active steps */\nfunction StepSpinner() {\n return (\n <motion.span\n className=\"inline-block h-4 w-4 rounded-full border-2 border-current border-t-transparent text-accent-9\"\n animate={{ rotate: 360 }}\n transition={{ repeat: Infinity, duration: 1, ease: 'linear' }}\n aria-hidden=\"true\"\n data-testid=\"step-spinner\"\n />\n )\n}\n\n/** Icon for a processing step based on its status */\nfunction StepIcon({ status }: { status: ProcessingStep['status'] }) {\n switch (status) {\n case 'done':\n return (\n <span data-testid=\"step-icon-done\">\n <Icon icon={IconCircleCheck} size=\"sm\" className=\"text-success-11\" />\n </span>\n )\n case 'active':\n return <StepSpinner />\n case 'error':\n return (\n <span data-testid=\"step-icon-error\">\n <Icon icon={IconCircleX} size=\"sm\" className=\"text-error-11\" />\n </span>\n )\n case 'pending':\n default:\n return (\n <span data-testid=\"step-icon-pending\">\n <Icon icon={IconCircle} size=\"sm\" className=\"text-surface-fg-subtle opacity-50\" />\n </span>\n )\n }\n}\n\nconst LoadingBlock = React.memo(function LoadingBlock({\n data,\n}: BlockComponentProps<LoadingBlockData>) {\n const { reducedMotion } = useMotion()\n const isReduced = reducedMotion\n\n // Mode A: Skeleton lines\n if (data.lines != null) {\n const lineCount = Math.max(1, data.lines)\n return (\n <div\n role=\"status\"\n aria-busy=\"true\"\n aria-label=\"Loading\"\n className=\"flex flex-col gap-2\"\n >\n {Array.from({ length: lineCount }).map((_, i) => (\n <Skeleton\n key={i}\n animation=\"shimmer\"\n className={cn(\n 'h-4',\n i === lineCount - 1 ? 'w-3/5' : 'w-full',\n )}\n />\n ))}\n <span className=\"sr-only\">Loading</span>\n </div>\n )\n }\n\n // Mode B: Processing steps\n if (data.steps) {\n return (\n <div\n role=\"status\"\n aria-busy=\"true\"\n aria-label=\"Processing\"\n className=\"flex flex-col gap-2\"\n >\n {data.steps.map((step, index) => (\n <motion.div\n key={step.id}\n className=\"flex items-center gap-2\"\n initial={isReduced ? undefined : { opacity: 0, x: -8 }}\n animate={{ opacity: 1, x: 0 }}\n transition={\n isReduced\n ? { duration: 0 }\n : { duration: durations.moderate01b, delay: index * 0.06 }\n }\n >\n <StepIcon status={step.status} />\n <span\n className={cn(\n 'text-ds-sm',\n step.status === 'done' || step.status === 'active'\n ? 'text-surface-fg'\n : 'text-surface-fg-subtle',\n )}\n >\n {step.label}\n </span>\n </motion.div>\n ))}\n <span className=\"sr-only\">Processing</span>\n </div>\n )\n }\n\n // Fallback: empty status container\n return (\n <div role=\"status\" aria-busy=\"true\" aria-label=\"Loading\">\n <span className=\"sr-only\">Loading</span>\n </div>\n )\n})\n\nLoadingBlock.displayName = 'LoadingBlock'\n\nexport { LoadingBlock }\n","'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { springs } from '../../ui/lib/motion'\nimport { StatCard } from '../../ui/stat-card'\nimport type { BlockComponentProps, StatRowBlockData } from '../types'\n\nconst StatRowBlock = React.memo(function StatRowBlock({\n data,\n}: BlockComponentProps<StatRowBlockData>) {\n const { reducedMotion } = useMotion()\n const stats = data.stats ?? []\n\n if (stats.length === 0) return null\n\n return (\n <div className=\"flex flex-wrap gap-ds-05\">\n {stats.map((stat, index) => {\n const delta = stat.change\n ? {\n value: stat.change.value,\n direction: stat.change.direction,\n }\n : undefined\n\n if (reducedMotion) {\n return (\n <div key={stat.label} className=\"flex-1 min-w-[140px]\">\n <StatCard\n label={stat.label}\n value={stat.value}\n delta={delta}\n />\n </div>\n )\n }\n\n return (\n <motion.div\n key={stat.label}\n className=\"flex-1 min-w-[140px]\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.responsive, delay: index * 0.08 }}\n >\n <StatCard\n label={stat.label}\n value={stat.value}\n delta={delta}\n />\n </motion.div>\n )\n })}\n </div>\n )\n})\n\nStatRowBlock.displayName = 'StatRowBlock'\n\nexport { StatRowBlock }\n","'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { Alert } from '../../ui/alert'\nimport { Button } from '../../ui/button'\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps, SuccessBlockData } from '../types'\n\nconst DEFAULT_UNDO_TIMEOUT = 5000\n\nconst SuccessBlock = React.memo(function SuccessBlock({\n data,\n blockId,\n confidence,\n onAction,\n}: BlockComponentProps<SuccessBlockData>) {\n const { reducedMotion } = useMotion()\n const isReduced = reducedMotion\n const undoTimeout = data.undoTimeout ?? DEFAULT_UNDO_TIMEOUT\n const [remaining, setRemaining] = React.useState(undoTimeout)\n const [showUndo, setShowUndo] = React.useState(!!data.undoable)\n\n React.useEffect(() => {\n if (!data.undoable) return\n\n const interval = setInterval(() => {\n setRemaining((prev) => {\n const next = prev - 100\n if (next <= 0) {\n clearInterval(interval)\n setShowUndo(false)\n return 0\n }\n return next\n })\n }, 100)\n\n return () => clearInterval(interval)\n }, [data.undoable, undoTimeout])\n\n const handleUndo = React.useCallback(() => {\n onAction?.(blockId || 'unknown', 'undo')\n }, [blockId, onAction])\n\n const remainingSeconds = Math.ceil(remaining / 1000)\n\n // Countdown ring dimensions\n const ringSize = 20\n const ringStroke = 2\n const ringRadius = (ringSize - ringStroke) / 2\n const ringCircumference = 2 * Math.PI * ringRadius\n\n return (\n <div\n className={cn(\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Alert\n color=\"success\"\n variant=\"subtle\"\n title={data.title}\n >\n {data.message}\n </Alert>\n\n {showUndo && data.undoable && (\n <div className=\"mt-2 flex items-center gap-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleUndo}\n aria-label={`Undo action, ${remainingSeconds} seconds remaining`}\n >\n <span className=\"flex items-center gap-1.5\">\n <svg\n width={ringSize}\n height={ringSize}\n viewBox={`0 0 ${ringSize} ${ringSize}`}\n className=\"shrink-0 -rotate-90\"\n aria-hidden=\"true\"\n >\n <circle\n cx={ringSize / 2}\n cy={ringSize / 2}\n r={ringRadius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={ringStroke}\n opacity={0.2}\n />\n <motion.circle\n cx={ringSize / 2}\n cy={ringSize / 2}\n r={ringRadius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={ringStroke}\n strokeDasharray={ringCircumference}\n initial={isReduced ? undefined : { strokeDashoffset: 0 }}\n animate={{\n strokeDashoffset: ringCircumference,\n }}\n transition={\n isReduced\n ? { duration: 0 }\n : {\n duration: undoTimeout / 1000,\n ease: 'linear',\n }\n }\n />\n </svg>\n Undo\n </span>\n </Button>\n </div>\n )}\n\n </div>\n )\n})\n\nSuccessBlock.displayName = 'SuccessBlock'\n\nexport { SuccessBlock }\n","'use client'\n\nimport * as React from 'react'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps } from '../types'\n\nconst TextBlock = React.memo(function TextBlock({\n data,\n confidence,\n}: BlockComponentProps<{ content: string }>) {\n return (\n <div\n className={cn(\n 'prose prose-sm',\n 'text-surface-fg',\n 'prose-headings:text-surface-fg',\n 'prose-a:text-accent-11 prose-a:underline',\n 'prose-code:text-accent-11 prose-code:bg-surface-raised prose-code:rounded prose-code:px-1',\n 'prose-strong:text-surface-fg',\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Markdown remarkPlugins={[remarkGfm]}>{data.content}</Markdown>\n </div>\n )\n})\n\nTextBlock.displayName = 'TextBlock'\n\nexport { TextBlock }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"text.js","names":[],"sources":["../../src/ai/blocks/block-table.tsx","../../src/ai/blocks/confirm.tsx","../../src/ai/blocks/divider.tsx","../../src/ai/blocks/error.tsx","../../src/ai/blocks/info.tsx","../../src/ai/blocks/loading.tsx","../../src/ai/blocks/stat-row.tsx","../../src/ai/blocks/success.tsx","../../src/ai/blocks/text.tsx"],"sourcesContent":["'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { Badge } from '../../ui/badge'\nimport { springs } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\nimport {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '../../ui/table'\nimport type { BlockComponentProps, BlockTableColumn,BlockTableData } from '../types'\n\ntype SortDir = 'asc' | 'desc' | null\n\nfunction renderCellValue(value: unknown, column: BlockTableColumn) {\n if (column.variant === 'badge') {\n if (value && typeof value === 'object' && 'label' in value) {\n const badgeObj = value as { label: string; color: string }\n return (\n <Badge variant=\"subtle\" size=\"sm\" color={badgeObj.color as 'default'}>\n {badgeObj.label}\n </Badge>\n )\n }\n return (\n <Badge variant=\"subtle\" size=\"sm\">\n {String(value ?? '')}\n </Badge>\n )\n }\n\n return String(value ?? '')\n}\n\nfunction sortRows(\n rows: Record<string, unknown>[],\n sortKey: string | null,\n sortDir: SortDir,\n): Record<string, unknown>[] {\n if (!sortKey || !sortDir) return rows\n return [...rows].sort((a, b) => {\n const aVal = a[sortKey]\n const bVal = b[sortKey]\n const aStr = String(aVal ?? '')\n const bStr = String(bVal ?? '')\n const aNum = Number(aVal)\n const bNum = Number(bVal)\n\n // If both are numeric, sort numerically\n if (!Number.isNaN(aNum) && !Number.isNaN(bNum)) {\n return sortDir === 'asc' ? aNum - bNum : bNum - aNum\n }\n\n // Otherwise sort lexicographically\n const cmp = aStr.localeCompare(bStr)\n return sortDir === 'asc' ? cmp : -cmp\n })\n}\n\nconst BlockTable = React.memo(function BlockTable({\n data,\n confidence,\n}: BlockComponentProps<BlockTableData>) {\n const { reducedMotion } = useMotion()\n const [sortKey, setSortKey] = React.useState<string | null>(null)\n const [sortDir, setSortDir] = React.useState<SortDir>(null)\n\n const handleHeaderClick = React.useCallback(\n (key: string) => {\n if (!data.sortable) return\n if (sortKey !== key) {\n setSortKey(key)\n setSortDir('asc')\n } else if (sortDir === 'asc') {\n setSortDir('desc')\n } else if (sortDir === 'desc') {\n setSortKey(null)\n setSortDir(null)\n }\n },\n [data.sortable, sortKey, sortDir],\n )\n\n const columns = data.columns ?? []\n const sortedRows = sortRows(data.rows ?? [], sortKey, sortDir)\n\n return (\n <div\n className={cn(\n 'overflow-x-auto',\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Table>\n {data.caption && <TableCaption>{data.caption}</TableCaption>}\n <TableHeader>\n <TableRow>\n {columns.map((col) => {\n const isSorted = sortKey === col.key\n const ariaSort = data.sortable\n ? isSorted\n ? sortDir === 'asc'\n ? ('ascending' as const)\n : ('descending' as const)\n : ('none' as const)\n : undefined\n\n return (\n <TableHead\n key={col.key}\n role=\"columnheader\"\n className={cn(\n col.variant === 'number' && 'text-right',\n data.sortable && 'cursor-pointer select-none',\n )}\n tabIndex={data.sortable ? 0 : undefined}\n onClick={\n data.sortable\n ? () => handleHeaderClick(col.key)\n : undefined\n }\n onKeyDown={\n data.sortable\n ? (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleHeaderClick(col.key)\n }\n }\n : undefined\n }\n aria-sort={ariaSort}\n >\n <span className=\"inline-flex items-center gap-1\">\n {col.label}\n {isSorted && sortDir === 'asc' && (\n <span aria-hidden=\"true\">▲</span>\n )}\n {isSorted && sortDir === 'desc' && (\n <span aria-hidden=\"true\">▼</span>\n )}\n </span>\n </TableHead>\n )\n })}\n </TableRow>\n </TableHeader>\n <TableBody>\n {sortedRows.map((row, rowIndex) => {\n const rowKey =\n typeof row.id === 'string' || typeof row.id === 'number'\n ? String(row.id)\n : `row-${rowIndex}`\n\n const RowWrapper = reducedMotion ? 'tr' : motion.tr\n\n const motionProps = reducedMotion\n ? {}\n : {\n initial: { opacity: 0, y: 6 } as const,\n animate: { opacity: 1, y: 0 } as const,\n transition: { ...springs.responsive, delay: rowIndex * 0.03 },\n }\n\n return (\n <RowWrapper\n key={rowKey}\n className=\"hover:bg-surface-raised-hover transition-colors\"\n {...motionProps}\n >\n {columns.map((col) => (\n <TableCell\n key={col.key}\n className={cn(\n 'text-ds-sm py-ds-02b px-ds-04',\n col.variant === 'number' &&\n 'text-right tabular-nums font-medium',\n )}\n >\n {renderCellValue(row[col.key], col)}\n </TableCell>\n ))}\n </RowWrapper>\n )\n })}\n </TableBody>\n </Table>\n </div>\n )\n})\n\nBlockTable.displayName = 'BlockTable'\n\nexport { BlockTable }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../../ui/collapsible'\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps, ConfirmBlockData } from '../types'\n\nconst ConfirmBlock = React.memo(function ConfirmBlock({\n data,\n confidence,\n onAction,\n}: BlockComponentProps<ConfirmBlockData>) {\n const handleConfirm = React.useCallback(() => {\n onAction?.(data.actionId, 'confirm')\n }, [data.actionId, onAction])\n\n const handleCancel = React.useCallback(() => {\n onAction?.(data.actionId, 'cancel')\n }, [data.actionId, onAction])\n\n return (\n <div\n className={cn(\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n {data.description && (\n <p className=\"text-ds-sm text-surface-fg-muted mb-3\">\n {data.description}\n </p>\n )}\n\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"solid\"\n color={data.destructive ? 'error' : undefined}\n onClick={handleConfirm}\n >\n {data.label}\n </Button>\n <Button variant=\"ghost\" onClick={handleCancel}>\n Cancel\n </Button>\n </div>\n\n {data.rationale && (\n <Collapsible className=\"mt-3\">\n <CollapsibleTrigger asChild>\n <button\n type=\"button\"\n className=\"text-ds-xs text-surface-fg-subtle underline cursor-pointer\"\n >\n Why this action?\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <p className=\"text-ds-sm text-surface-fg-muted mt-2 p-3 bg-surface-raised rounded-surface\">\n {data.rationale}\n </p>\n </CollapsibleContent>\n </Collapsible>\n )}\n </div>\n )\n})\n\nConfirmBlock.displayName = 'ConfirmBlock'\n\nexport { ConfirmBlock }\n","'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { tweens } from '../../ui/lib/motion'\nimport { Separator } from '../../ui/separator'\nimport type { BlockComponentProps } from '../types'\n\nconst DividerBlock = React.memo(function DividerBlock(\n _props: BlockComponentProps<Record<string, never>>,\n) {\n const { reducedMotion } = useMotion()\n\n if (reducedMotion) {\n return <Separator />\n }\n\n return (\n <motion.div\n initial={{ scaleX: 0 }}\n animate={{ scaleX: 1 }}\n style={{ originX: 0.5 }}\n transition={tweens.elegant}\n >\n <Separator />\n </motion.div>\n )\n})\n\nDividerBlock.displayName = 'DividerBlock'\n\nexport { DividerBlock }\n","'use client'\n\nimport * as React from 'react'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nimport { Alert } from '../../ui/alert'\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps, ErrorBlockData } from '../types'\n\nconst ErrorBlock = React.memo(function ErrorBlock({\n data,\n confidence,\n}: BlockComponentProps<ErrorBlockData>) {\n return (\n <div\n className={cn(\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Alert color=\"error\" variant=\"subtle\" title={data.title}>\n <div className=\"prose prose-sm\">\n <Markdown remarkPlugins={[remarkGfm]}>{data.message}</Markdown>\n </div>\n </Alert>\n {data.suggestion && (\n <p className=\"mt-2 text-ds-sm text-surface-fg-muted\">\n {data.suggestion}\n </p>\n )}\n </div>\n )\n})\n\nErrorBlock.displayName = 'ErrorBlock'\n\nexport { ErrorBlock }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Alert } from '../../ui/alert'\nimport type { BlockComponentProps } from '../types'\n\nconst InfoBlock = React.memo(function InfoBlock({\n data,\n}: BlockComponentProps<{ message: string }>) {\n return (\n <Alert color=\"info\" variant=\"subtle\" role=\"status\">\n {data.message}\n </Alert>\n )\n})\n\nInfoBlock.displayName = 'InfoBlock'\n\nexport { InfoBlock }\n","'use client'\n\nimport {\n IconCircle,\n IconCircleCheck,\n IconCircleX,\n} from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\nimport { Skeleton } from '../../ui/skeleton'\nimport type { BlockComponentProps, LoadingBlockData, ProcessingStep } from '../types'\n\n/** Spinning indicator for active steps */\nfunction StepSpinner() {\n return (\n <motion.span\n className=\"inline-block h-4 w-4 rounded-pill border-2 border-current border-t-transparent text-accent-9\"\n animate={{ rotate: 360 }}\n transition={{ repeat: Infinity, duration: 1, ease: 'linear' }}\n aria-hidden=\"true\"\n data-testid=\"step-spinner\"\n />\n )\n}\n\n/** Icon for a processing step based on its status */\nfunction StepIcon({ status }: { status: ProcessingStep['status'] }) {\n switch (status) {\n case 'done':\n return (\n <span data-testid=\"step-icon-done\">\n <Icon icon={IconCircleCheck} size=\"sm\" className=\"text-success-11\" />\n </span>\n )\n case 'active':\n return <StepSpinner />\n case 'error':\n return (\n <span data-testid=\"step-icon-error\">\n <Icon icon={IconCircleX} size=\"sm\" className=\"text-error-11\" />\n </span>\n )\n case 'pending':\n default:\n return (\n <span data-testid=\"step-icon-pending\">\n <Icon icon={IconCircle} size=\"sm\" className=\"text-surface-fg-subtle opacity-50\" />\n </span>\n )\n }\n}\n\nconst LoadingBlock = React.memo(function LoadingBlock({\n data,\n}: BlockComponentProps<LoadingBlockData>) {\n const { reducedMotion } = useMotion()\n const isReduced = reducedMotion\n\n // Mode A: Skeleton lines\n if (data.lines != null) {\n const lineCount = Math.max(1, data.lines)\n return (\n <div\n role=\"status\"\n aria-busy=\"true\"\n aria-label=\"Loading\"\n className=\"flex flex-col gap-2\"\n >\n {Array.from({ length: lineCount }).map((_, i) => (\n <Skeleton\n key={i}\n animation=\"shimmer\"\n className={cn(\n 'h-4',\n i === lineCount - 1 ? 'w-3/5' : 'w-full',\n )}\n />\n ))}\n <span className=\"sr-only\">Loading</span>\n </div>\n )\n }\n\n // Mode B: Processing steps\n if (data.steps) {\n return (\n <div\n role=\"status\"\n aria-busy=\"true\"\n aria-label=\"Processing\"\n className=\"flex flex-col gap-2\"\n >\n {data.steps.map((step, index) => (\n <motion.div\n key={step.id}\n className=\"flex items-center gap-2\"\n initial={isReduced ? undefined : { opacity: 0, x: -8 }}\n animate={{ opacity: 1, x: 0 }}\n transition={\n isReduced\n ? { duration: 0 }\n : { duration: durations.moderate01b, delay: index * 0.06 }\n }\n >\n <StepIcon status={step.status} />\n <span\n className={cn(\n 'text-ds-sm',\n step.status === 'done' || step.status === 'active'\n ? 'text-surface-fg'\n : 'text-surface-fg-subtle',\n )}\n >\n {step.label}\n </span>\n </motion.div>\n ))}\n <span className=\"sr-only\">Processing</span>\n </div>\n )\n }\n\n // Fallback: empty status container\n return (\n <div role=\"status\" aria-busy=\"true\" aria-label=\"Loading\">\n <span className=\"sr-only\">Loading</span>\n </div>\n )\n})\n\nLoadingBlock.displayName = 'LoadingBlock'\n\nexport { LoadingBlock }\n","'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { springs } from '../../ui/lib/motion'\nimport { StatCard } from '../../ui/stat-card'\nimport type { BlockComponentProps, StatRowBlockData } from '../types'\n\nconst StatRowBlock = React.memo(function StatRowBlock({\n data,\n}: BlockComponentProps<StatRowBlockData>) {\n const { reducedMotion } = useMotion()\n const stats = data.stats ?? []\n\n if (stats.length === 0) return null\n\n return (\n <div className=\"flex flex-wrap gap-ds-05\">\n {stats.map((stat, index) => {\n const delta = stat.change\n ? {\n value: stat.change.value,\n direction: stat.change.direction,\n }\n : undefined\n\n if (reducedMotion) {\n return (\n <div key={stat.label} className=\"flex-1 min-w-[140px]\">\n <StatCard\n label={stat.label}\n value={stat.value}\n delta={delta}\n />\n </div>\n )\n }\n\n return (\n <motion.div\n key={stat.label}\n className=\"flex-1 min-w-[140px]\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.responsive, delay: index * 0.08 }}\n >\n <StatCard\n label={stat.label}\n value={stat.value}\n delta={delta}\n />\n </motion.div>\n )\n })}\n </div>\n )\n})\n\nStatRowBlock.displayName = 'StatRowBlock'\n\nexport { StatRowBlock }\n","'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useMotion } from '../../motion/motion-provider'\nimport { Alert } from '../../ui/alert'\nimport { Button } from '../../ui/button'\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps, SuccessBlockData } from '../types'\n\nconst DEFAULT_UNDO_TIMEOUT = 5000\n\nconst SuccessBlock = React.memo(function SuccessBlock({\n data,\n blockId,\n confidence,\n onAction,\n}: BlockComponentProps<SuccessBlockData>) {\n const { reducedMotion } = useMotion()\n const isReduced = reducedMotion\n const undoTimeout = data.undoTimeout ?? DEFAULT_UNDO_TIMEOUT\n const [remaining, setRemaining] = React.useState(undoTimeout)\n const [showUndo, setShowUndo] = React.useState(!!data.undoable)\n\n React.useEffect(() => {\n if (!data.undoable) return\n\n const interval = setInterval(() => {\n setRemaining((prev) => {\n const next = prev - 100\n if (next <= 0) {\n clearInterval(interval)\n setShowUndo(false)\n return 0\n }\n return next\n })\n }, 100)\n\n return () => clearInterval(interval)\n }, [data.undoable, undoTimeout])\n\n const handleUndo = React.useCallback(() => {\n onAction?.(blockId || 'unknown', 'undo')\n }, [blockId, onAction])\n\n const remainingSeconds = Math.ceil(remaining / 1000)\n\n // Countdown ring dimensions\n const ringSize = 20\n const ringStroke = 2\n const ringRadius = (ringSize - ringStroke) / 2\n const ringCircumference = 2 * Math.PI * ringRadius\n\n return (\n <div\n className={cn(\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Alert\n color=\"success\"\n variant=\"subtle\"\n title={data.title}\n >\n {data.message}\n </Alert>\n\n {showUndo && data.undoable && (\n <div className=\"mt-2 flex items-center gap-2\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={handleUndo}\n aria-label={`Undo action, ${remainingSeconds} seconds remaining`}\n >\n <span className=\"flex items-center gap-1.5\">\n <svg\n width={ringSize}\n height={ringSize}\n viewBox={`0 0 ${ringSize} ${ringSize}`}\n className=\"shrink-0 -rotate-90\"\n aria-hidden=\"true\"\n >\n <circle\n cx={ringSize / 2}\n cy={ringSize / 2}\n r={ringRadius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={ringStroke}\n opacity={0.2}\n />\n <motion.circle\n cx={ringSize / 2}\n cy={ringSize / 2}\n r={ringRadius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={ringStroke}\n strokeDasharray={ringCircumference}\n initial={isReduced ? undefined : { strokeDashoffset: 0 }}\n animate={{\n strokeDashoffset: ringCircumference,\n }}\n transition={\n isReduced\n ? { duration: 0 }\n : {\n duration: undoTimeout / 1000,\n ease: 'linear',\n }\n }\n />\n </svg>\n Undo\n </span>\n </Button>\n </div>\n )}\n\n </div>\n )\n})\n\nSuccessBlock.displayName = 'SuccessBlock'\n\nexport { SuccessBlock }\n","'use client'\n\nimport * as React from 'react'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps } from '../types'\n\nconst TextBlock = React.memo(function TextBlock({\n data,\n confidence,\n}: BlockComponentProps<{ content: string }>) {\n return (\n <div\n className={cn(\n 'prose prose-sm',\n 'text-surface-fg',\n 'prose-headings:text-surface-fg',\n 'prose-a:text-accent-11 prose-a:underline',\n 'prose-code:text-accent-11 prose-code:bg-surface-raised prose-code:rounded prose-code:px-1',\n 'prose-strong:text-surface-fg',\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Markdown remarkPlugins={[remarkGfm]}>{data.content}</Markdown>\n </div>\n )\n})\n\nTextBlock.displayName = 'TextBlock'\n\nexport { TextBlock }\n"],"mappings":"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"}
|
|
@@ -173,7 +173,7 @@ var h = r.forwardRef(({ itemId: i, label: a, icon: l, secondaryLabel: u, actions
|
|
|
173
173
|
onClick: S,
|
|
174
174
|
onKeyDown: w,
|
|
175
175
|
style: { paddingLeft: `calc(${h} * var(--spacing-ds-05b) + var(--spacing-ds-03))` },
|
|
176
|
-
className: e("flex items-center gap-ds-02 py-ds-02 px-ds-02 rounded-
|
|
176
|
+
className: e("flex items-center gap-ds-02 py-ds-02 px-ds-02 rounded-control cursor-pointer transition-colors duration-fast-01", "hover:bg-surface-raised", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9", x && "bg-accent-3 text-accent-11", p && "opacity-action-disabled cursor-not-allowed pointer-events-none", g),
|
|
177
177
|
children: [
|
|
178
178
|
y ? /* @__PURE__ */ o("button", {
|
|
179
179
|
type: "button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-view.js","names":[],"sources":["../../src/ui/tree-view/use-tree.ts","../../src/ui/tree-view/tree-view.tsx","../../src/ui/tree-view/tree-item.tsx"],"sourcesContent":["import { useCallback,useState } from 'react'\n\nexport interface TreeNode {\n id: string\n label: string\n icon?: React.ReactNode\n children?: TreeNode[]\n disabled?: boolean\n}\n\ninterface UseTreeOptions {\n defaultExpanded?: string[]\n defaultSelected?: string[]\n multiSelect?: boolean\n onSelect?: (selectedIds: string[]) => void\n onExpand?: (expandedIds: string[]) => void\n}\n\nexport function useTree(options: UseTreeOptions = {}) {\n const { defaultExpanded, defaultSelected, multiSelect, onSelect, onExpand } = options\n\n const [expanded, setExpanded] = useState<Set<string>>(\n new Set(defaultExpanded ?? []),\n )\n const [selected, setSelected] = useState<Set<string>>(\n new Set(defaultSelected ?? []),\n )\n\n const toggle = useCallback(\n (id: string) => {\n setExpanded((prev) => {\n const next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onExpand?.(Array.from(next))\n return next\n })\n },\n [onExpand],\n )\n\n const select = useCallback(\n (id: string, event?: React.MouseEvent) => {\n setSelected((prev) => {\n let next: Set<string>\n if (multiSelect && event?.ctrlKey) {\n next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n } else {\n next = new Set([id])\n }\n onSelect?.(Array.from(next))\n return next\n })\n },\n [multiSelect, onSelect],\n )\n\n return {\n expanded,\n selected,\n toggle,\n select,\n isExpanded: (id: string) => expanded.has(id),\n isSelected: (id: string) => selected.has(id),\n expandAll: (ids: string[]) => setExpanded(new Set(ids)),\n collapseAll: () => setExpanded(new Set()),\n }\n}\n","'use client'\n\nimport * as React from 'react'\n\nimport { cn } from '../lib/utils'\nimport { TreeItem } from './tree-item'\nimport { type TreeNode,useTree } from './use-tree'\n\n// ─── Context ────────────────────────────────────────────────────────\ninterface TreeContextValue {\n tree: ReturnType<typeof useTree>\n checkboxes: boolean\n}\n\nconst TreeContext = React.createContext<TreeContextValue | null>(null)\n\nexport function useTreeContext() {\n const ctx = React.useContext(TreeContext)\n if (!ctx) {\n throw new Error('TreeItem must be used within a <TreeView>')\n }\n return ctx\n}\n\n// ─── Props ──────────────────────────────────────────────────────────\nexport interface TreeViewProps extends Omit<React.HTMLAttributes<HTMLUListElement>, 'onSelect'> {\n /** Data-driven mode: pass items array */\n items?: TreeNode[]\n /** Initially expanded node IDs */\n defaultExpanded?: string[]\n /** Initially selected node IDs */\n defaultSelected?: string[]\n /** Enable multi-select */\n multiSelect?: boolean\n /** Show checkboxes before each item */\n checkboxes?: boolean\n /** Called when selection changes */\n onSelect?: (ids: string[]) => void\n /** Called when expansion changes */\n onExpand?: (ids: string[]) => void\n className?: string\n /** Declarative mode: render TreeItem children directly */\n children?: React.ReactNode\n}\n\n// ─── Render nodes recursively (data-driven mode) ───────────────────\nfunction renderNodes(nodes: TreeNode[], depth: number = 0): React.ReactNode {\n return nodes.map((node) => (\n <TreeItem\n key={node.id}\n itemId={node.id}\n label={node.label}\n icon={node.icon}\n disabled={node.disabled}\n depth={depth}\n >\n {node.children && node.children.length > 0\n ? renderNodes(node.children, depth + 1)\n : undefined}\n </TreeItem>\n ))\n}\n\n// ─── Helper: collect all visible item IDs ───────────────────────────\nfunction getVisibleItemElements(container: HTMLElement): HTMLElement[] {\n return Array.from(\n container.querySelectorAll<HTMLElement>('[data-tree-item]'),\n ).filter((el) => {\n // Items inside collapsed groups should not be focusable\n let parent = el.parentElement\n while (parent && parent !== container) {\n if (parent.getAttribute('role') === 'group') {\n const grid = parent.parentElement\n if (grid && grid.classList.contains('grid-rows-[0fr]')) {\n return false\n }\n }\n parent = parent.parentElement\n }\n return true\n })\n}\n\n// ─── Component ──────────────────────────────────────────────────────\nconst TreeView = React.forwardRef<HTMLUListElement, TreeViewProps>(\n (\n {\n items,\n defaultExpanded,\n defaultSelected,\n multiSelect = false,\n checkboxes = false,\n onSelect,\n onExpand,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const tree = useTree({\n defaultExpanded,\n defaultSelected,\n multiSelect,\n onSelect,\n onExpand,\n })\n\n const innerRef = React.useRef<HTMLUListElement>(null)\n const containerRef = (ref as React.RefObject<HTMLUListElement>) ?? innerRef\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLUListElement>) => {\n const container = containerRef.current\n if (!container) return\n\n const visibleItems = getVisibleItemElements(container)\n const currentIndex = visibleItems.findIndex(\n (el) => el === document.activeElement,\n )\n\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const next = visibleItems[currentIndex + 1]\n next?.focus()\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prev = visibleItems[currentIndex - 1]\n prev?.focus()\n break\n }\n case 'ArrowRight': {\n // Handled in TreeItem for expand; if already expanded, move to first child\n const current = visibleItems[currentIndex]\n if (current) {\n const itemId = current.getAttribute('data-tree-item')\n if (itemId && tree.isExpanded(itemId)) {\n e.preventDefault()\n const nextItem = visibleItems[currentIndex + 1]\n nextItem?.focus()\n }\n }\n break\n }\n case 'ArrowLeft': {\n // Handled in TreeItem for collapse; if already collapsed or leaf, move to parent\n const current = visibleItems[currentIndex]\n if (current) {\n const itemId = current.getAttribute('data-tree-item')\n const treeItem = current.closest('[role=\"treeitem\"]')\n const parentGroup = treeItem?.parentElement?.closest(\n '[role=\"treeitem\"]',\n )\n if (itemId && !tree.isExpanded(itemId) && parentGroup) {\n e.preventDefault()\n const parentRow = parentGroup.querySelector<HTMLElement>(\n '[data-tree-item]',\n )\n parentRow?.focus()\n }\n }\n break\n }\n case 'Home': {\n e.preventDefault()\n visibleItems[0]?.focus()\n break\n }\n case 'End': {\n e.preventDefault()\n visibleItems[visibleItems.length - 1]?.focus()\n break\n }\n }\n }\n\n const ctxValue = React.useMemo<TreeContextValue>(\n () => ({ tree, checkboxes }),\n [tree, checkboxes],\n )\n\n const content = items ? renderNodes(items) : children\n\n return (\n <TreeContext.Provider value={ctxValue}>\n <ul\n ref={containerRef}\n role=\"tree\"\n aria-multiselectable={multiSelect || undefined}\n onKeyDown={handleKeyDown}\n className={cn('m-0 list-none p-0', className)}\n {...props}\n >\n {content}\n </ul>\n </TreeContext.Provider>\n )\n },\n)\nTreeView.displayName = 'TreeView'\n\nexport { TreeView }\n","'use client'\n\nimport { IconChevronRight } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Checkbox } from '../checkbox'\nimport { Icon } from '../icon'\nimport { cn } from '../lib/utils'\nimport { useTreeContext } from './tree-view'\n\nexport interface TreeItemProps {\n /** Unique identifier for this tree item */\n itemId: string\n /** Primary label content */\n label: React.ReactNode\n /** Optional icon rendered before the label */\n icon?: React.ReactNode\n /** Secondary label rendered after the primary label */\n secondaryLabel?: React.ReactNode\n /** Action buttons rendered at the end of the row */\n actions?: React.ReactNode\n /** Whether this item is disabled */\n disabled?: boolean\n /** Nested tree items */\n children?: React.ReactNode\n /** Depth level (used internally) */\n depth?: number\n /** Additional CSS class names */\n className?: string\n}\n\nconst TreeItem = React.forwardRef<HTMLLIElement, TreeItemProps>(\n (\n {\n itemId,\n label,\n icon,\n secondaryLabel,\n actions,\n disabled = false,\n children,\n depth = 0,\n className,\n },\n ref,\n ) => {\n const ctx = useTreeContext()\n const hasChildren = React.Children.count(children) > 0\n const isExpanded = ctx.tree.isExpanded(itemId)\n const isSelected = ctx.tree.isSelected(itemId)\n\n const handleRowClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n ctx.tree.select(itemId, e)\n }\n\n const handleChevronClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation()\n if (disabled) return\n ctx.tree.toggle(itemId)\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n ctx.tree.select(itemId)\n }\n if (e.key === 'ArrowRight' && hasChildren && !isExpanded) {\n e.preventDefault()\n e.stopPropagation()\n ctx.tree.toggle(itemId)\n }\n if (e.key === 'ArrowLeft' && hasChildren && isExpanded) {\n e.preventDefault()\n e.stopPropagation()\n ctx.tree.toggle(itemId)\n }\n }\n\n // Compute indeterminate state for checkbox mode\n const checkboxState = React.useMemo(() => {\n if (!ctx.checkboxes || !hasChildren) {\n return { checked: isSelected, indeterminate: false }\n }\n // Collect all descendant IDs\n const descendants: string[] = []\n const collectIds = (nodes: React.ReactNode) => {\n React.Children.forEach(nodes, (child) => {\n if (React.isValidElement<TreeItemProps>(child) && child.props.itemId) {\n descendants.push(child.props.itemId)\n if (child.props.children) {\n collectIds(child.props.children)\n }\n }\n })\n }\n collectIds(children)\n const selectedCount = descendants.filter((id) =>\n ctx.tree.isSelected(id),\n ).length\n if (selectedCount === 0 && !isSelected) {\n return { checked: false, indeterminate: false }\n }\n if (selectedCount === descendants.length) {\n return { checked: true, indeterminate: false }\n }\n return { checked: false, indeterminate: true }\n }, [ctx.checkboxes, hasChildren, children, isSelected, ctx.tree])\n\n return (\n <li\n ref={ref}\n role=\"treeitem\"\n aria-expanded={hasChildren ? isExpanded : undefined}\n aria-selected={isSelected}\n aria-level={depth + 1}\n aria-disabled={disabled || undefined}\n className=\"list-none\"\n >\n {/* Row */}\n <div\n role=\"presentation\"\n data-tree-item={itemId}\n tabIndex={disabled ? -1 : 0}\n onClick={handleRowClick}\n onKeyDown={handleKeyDown}\n style={{ paddingLeft: `calc(${depth} * var(--spacing-ds-05b) + var(--spacing-ds-03))` }}\n className={cn(\n 'flex items-center gap-ds-02 py-ds-02 px-ds-02 rounded-ds-md cursor-pointer transition-colors duration-fast-01',\n 'hover:bg-surface-raised',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9',\n isSelected &&\n 'bg-accent-3 text-accent-11',\n disabled && 'opacity-action-disabled cursor-not-allowed pointer-events-none',\n className,\n )}\n >\n {/* Expand chevron */}\n {hasChildren ? (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onClick={handleChevronClick}\n className=\"flex shrink-0 items-center justify-center p-0 border-0 bg-transparent cursor-pointer\"\n >\n <Icon\n icon={IconChevronRight}\n size=\"sm\"\n className={cn(\n 'transition-transform duration-moderate-02',\n isExpanded && 'rotate-90',\n )}\n />\n </button>\n ) : (\n <span className=\"inline-block w-4 shrink-0\" aria-hidden=\"true\" />\n )}\n\n {/* Checkbox (optional) */}\n {ctx.checkboxes && (\n <Checkbox\n checked={checkboxState.checked}\n indeterminate={checkboxState.indeterminate}\n disabled={disabled}\n tabIndex={-1}\n onClick={(e) => e.stopPropagation()}\n onCheckedChange={() => {\n if (!disabled) ctx.tree.select(itemId)\n }}\n className=\"shrink-0\"\n />\n )}\n\n {/* Icon */}\n {icon && (\n <span className=\"flex shrink-0 items-center text-surface-fg-subtle\">\n {icon}\n </span>\n )}\n\n {/* Label */}\n <span className=\"truncate text-ds-sm\">{label}</span>\n\n {/* Secondary label */}\n {secondaryLabel && (\n <span className=\"ml-auto truncate text-ds-xs text-surface-fg-muted\">\n {secondaryLabel}\n </span>\n )}\n\n {/* Actions */}\n {actions && (\n <span\n className=\"ml-auto flex shrink-0 items-center gap-ds-01\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {actions}\n </span>\n )}\n </div>\n\n {/* Children (collapsible) */}\n {hasChildren && (\n <div\n role=\"group\"\n className={cn(\n 'grid transition-[grid-template-rows] duration-moderate-02 ease-productive-standard',\n isExpanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',\n )}\n >\n <ul role=\"group\" className=\"overflow-hidden m-0 p-0\">\n {React.Children.map(children, (child) => {\n if (React.isValidElement<TreeItemProps>(child)) {\n return React.cloneElement(child, {\n depth: depth + 1,\n })\n }\n return child\n })}\n </ul>\n </div>\n )}\n </li>\n )\n },\n)\nTreeItem.displayName = 'TreeItem'\n\nexport { TreeItem }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tree-view.js","names":[],"sources":["../../src/ui/tree-view/use-tree.ts","../../src/ui/tree-view/tree-view.tsx","../../src/ui/tree-view/tree-item.tsx"],"sourcesContent":["import { useCallback,useState } from 'react'\n\nexport interface TreeNode {\n id: string\n label: string\n icon?: React.ReactNode\n children?: TreeNode[]\n disabled?: boolean\n}\n\ninterface UseTreeOptions {\n defaultExpanded?: string[]\n defaultSelected?: string[]\n multiSelect?: boolean\n onSelect?: (selectedIds: string[]) => void\n onExpand?: (expandedIds: string[]) => void\n}\n\nexport function useTree(options: UseTreeOptions = {}) {\n const { defaultExpanded, defaultSelected, multiSelect, onSelect, onExpand } = options\n\n const [expanded, setExpanded] = useState<Set<string>>(\n new Set(defaultExpanded ?? []),\n )\n const [selected, setSelected] = useState<Set<string>>(\n new Set(defaultSelected ?? []),\n )\n\n const toggle = useCallback(\n (id: string) => {\n setExpanded((prev) => {\n const next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onExpand?.(Array.from(next))\n return next\n })\n },\n [onExpand],\n )\n\n const select = useCallback(\n (id: string, event?: React.MouseEvent) => {\n setSelected((prev) => {\n let next: Set<string>\n if (multiSelect && event?.ctrlKey) {\n next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n } else {\n next = new Set([id])\n }\n onSelect?.(Array.from(next))\n return next\n })\n },\n [multiSelect, onSelect],\n )\n\n return {\n expanded,\n selected,\n toggle,\n select,\n isExpanded: (id: string) => expanded.has(id),\n isSelected: (id: string) => selected.has(id),\n expandAll: (ids: string[]) => setExpanded(new Set(ids)),\n collapseAll: () => setExpanded(new Set()),\n }\n}\n","'use client'\n\nimport * as React from 'react'\n\nimport { cn } from '../lib/utils'\nimport { TreeItem } from './tree-item'\nimport { type TreeNode,useTree } from './use-tree'\n\n// ─── Context ────────────────────────────────────────────────────────\ninterface TreeContextValue {\n tree: ReturnType<typeof useTree>\n checkboxes: boolean\n}\n\nconst TreeContext = React.createContext<TreeContextValue | null>(null)\n\nexport function useTreeContext() {\n const ctx = React.useContext(TreeContext)\n if (!ctx) {\n throw new Error('TreeItem must be used within a <TreeView>')\n }\n return ctx\n}\n\n// ─── Props ──────────────────────────────────────────────────────────\nexport interface TreeViewProps extends Omit<React.HTMLAttributes<HTMLUListElement>, 'onSelect'> {\n /** Data-driven mode: pass items array */\n items?: TreeNode[]\n /** Initially expanded node IDs */\n defaultExpanded?: string[]\n /** Initially selected node IDs */\n defaultSelected?: string[]\n /** Enable multi-select */\n multiSelect?: boolean\n /** Show checkboxes before each item */\n checkboxes?: boolean\n /** Called when selection changes */\n onSelect?: (ids: string[]) => void\n /** Called when expansion changes */\n onExpand?: (ids: string[]) => void\n className?: string\n /** Declarative mode: render TreeItem children directly */\n children?: React.ReactNode\n}\n\n// ─── Render nodes recursively (data-driven mode) ───────────────────\nfunction renderNodes(nodes: TreeNode[], depth: number = 0): React.ReactNode {\n return nodes.map((node) => (\n <TreeItem\n key={node.id}\n itemId={node.id}\n label={node.label}\n icon={node.icon}\n disabled={node.disabled}\n depth={depth}\n >\n {node.children && node.children.length > 0\n ? renderNodes(node.children, depth + 1)\n : undefined}\n </TreeItem>\n ))\n}\n\n// ─── Helper: collect all visible item IDs ───────────────────────────\nfunction getVisibleItemElements(container: HTMLElement): HTMLElement[] {\n return Array.from(\n container.querySelectorAll<HTMLElement>('[data-tree-item]'),\n ).filter((el) => {\n // Items inside collapsed groups should not be focusable\n let parent = el.parentElement\n while (parent && parent !== container) {\n if (parent.getAttribute('role') === 'group') {\n const grid = parent.parentElement\n if (grid && grid.classList.contains('grid-rows-[0fr]')) {\n return false\n }\n }\n parent = parent.parentElement\n }\n return true\n })\n}\n\n// ─── Component ──────────────────────────────────────────────────────\nconst TreeView = React.forwardRef<HTMLUListElement, TreeViewProps>(\n (\n {\n items,\n defaultExpanded,\n defaultSelected,\n multiSelect = false,\n checkboxes = false,\n onSelect,\n onExpand,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const tree = useTree({\n defaultExpanded,\n defaultSelected,\n multiSelect,\n onSelect,\n onExpand,\n })\n\n const innerRef = React.useRef<HTMLUListElement>(null)\n const containerRef = (ref as React.RefObject<HTMLUListElement>) ?? innerRef\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLUListElement>) => {\n const container = containerRef.current\n if (!container) return\n\n const visibleItems = getVisibleItemElements(container)\n const currentIndex = visibleItems.findIndex(\n (el) => el === document.activeElement,\n )\n\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const next = visibleItems[currentIndex + 1]\n next?.focus()\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prev = visibleItems[currentIndex - 1]\n prev?.focus()\n break\n }\n case 'ArrowRight': {\n // Handled in TreeItem for expand; if already expanded, move to first child\n const current = visibleItems[currentIndex]\n if (current) {\n const itemId = current.getAttribute('data-tree-item')\n if (itemId && tree.isExpanded(itemId)) {\n e.preventDefault()\n const nextItem = visibleItems[currentIndex + 1]\n nextItem?.focus()\n }\n }\n break\n }\n case 'ArrowLeft': {\n // Handled in TreeItem for collapse; if already collapsed or leaf, move to parent\n const current = visibleItems[currentIndex]\n if (current) {\n const itemId = current.getAttribute('data-tree-item')\n const treeItem = current.closest('[role=\"treeitem\"]')\n const parentGroup = treeItem?.parentElement?.closest(\n '[role=\"treeitem\"]',\n )\n if (itemId && !tree.isExpanded(itemId) && parentGroup) {\n e.preventDefault()\n const parentRow = parentGroup.querySelector<HTMLElement>(\n '[data-tree-item]',\n )\n parentRow?.focus()\n }\n }\n break\n }\n case 'Home': {\n e.preventDefault()\n visibleItems[0]?.focus()\n break\n }\n case 'End': {\n e.preventDefault()\n visibleItems[visibleItems.length - 1]?.focus()\n break\n }\n }\n }\n\n const ctxValue = React.useMemo<TreeContextValue>(\n () => ({ tree, checkboxes }),\n [tree, checkboxes],\n )\n\n const content = items ? renderNodes(items) : children\n\n return (\n <TreeContext.Provider value={ctxValue}>\n <ul\n ref={containerRef}\n role=\"tree\"\n aria-multiselectable={multiSelect || undefined}\n onKeyDown={handleKeyDown}\n className={cn('m-0 list-none p-0', className)}\n {...props}\n >\n {content}\n </ul>\n </TreeContext.Provider>\n )\n },\n)\nTreeView.displayName = 'TreeView'\n\nexport { TreeView }\n","'use client'\n\nimport { IconChevronRight } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Checkbox } from '../checkbox'\nimport { Icon } from '../icon'\nimport { cn } from '../lib/utils'\nimport { useTreeContext } from './tree-view'\n\nexport interface TreeItemProps {\n /** Unique identifier for this tree item */\n itemId: string\n /** Primary label content */\n label: React.ReactNode\n /** Optional icon rendered before the label */\n icon?: React.ReactNode\n /** Secondary label rendered after the primary label */\n secondaryLabel?: React.ReactNode\n /** Action buttons rendered at the end of the row */\n actions?: React.ReactNode\n /** Whether this item is disabled */\n disabled?: boolean\n /** Nested tree items */\n children?: React.ReactNode\n /** Depth level (used internally) */\n depth?: number\n /** Additional CSS class names */\n className?: string\n}\n\nconst TreeItem = React.forwardRef<HTMLLIElement, TreeItemProps>(\n (\n {\n itemId,\n label,\n icon,\n secondaryLabel,\n actions,\n disabled = false,\n children,\n depth = 0,\n className,\n },\n ref,\n ) => {\n const ctx = useTreeContext()\n const hasChildren = React.Children.count(children) > 0\n const isExpanded = ctx.tree.isExpanded(itemId)\n const isSelected = ctx.tree.isSelected(itemId)\n\n const handleRowClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n ctx.tree.select(itemId, e)\n }\n\n const handleChevronClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation()\n if (disabled) return\n ctx.tree.toggle(itemId)\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n ctx.tree.select(itemId)\n }\n if (e.key === 'ArrowRight' && hasChildren && !isExpanded) {\n e.preventDefault()\n e.stopPropagation()\n ctx.tree.toggle(itemId)\n }\n if (e.key === 'ArrowLeft' && hasChildren && isExpanded) {\n e.preventDefault()\n e.stopPropagation()\n ctx.tree.toggle(itemId)\n }\n }\n\n // Compute indeterminate state for checkbox mode\n const checkboxState = React.useMemo(() => {\n if (!ctx.checkboxes || !hasChildren) {\n return { checked: isSelected, indeterminate: false }\n }\n // Collect all descendant IDs\n const descendants: string[] = []\n const collectIds = (nodes: React.ReactNode) => {\n React.Children.forEach(nodes, (child) => {\n if (React.isValidElement<TreeItemProps>(child) && child.props.itemId) {\n descendants.push(child.props.itemId)\n if (child.props.children) {\n collectIds(child.props.children)\n }\n }\n })\n }\n collectIds(children)\n const selectedCount = descendants.filter((id) =>\n ctx.tree.isSelected(id),\n ).length\n if (selectedCount === 0 && !isSelected) {\n return { checked: false, indeterminate: false }\n }\n if (selectedCount === descendants.length) {\n return { checked: true, indeterminate: false }\n }\n return { checked: false, indeterminate: true }\n }, [ctx.checkboxes, hasChildren, children, isSelected, ctx.tree])\n\n return (\n <li\n ref={ref}\n role=\"treeitem\"\n aria-expanded={hasChildren ? isExpanded : undefined}\n aria-selected={isSelected}\n aria-level={depth + 1}\n aria-disabled={disabled || undefined}\n className=\"list-none\"\n >\n {/* Row */}\n <div\n role=\"presentation\"\n data-tree-item={itemId}\n tabIndex={disabled ? -1 : 0}\n onClick={handleRowClick}\n onKeyDown={handleKeyDown}\n style={{ paddingLeft: `calc(${depth} * var(--spacing-ds-05b) + var(--spacing-ds-03))` }}\n className={cn(\n 'flex items-center gap-ds-02 py-ds-02 px-ds-02 rounded-control cursor-pointer transition-colors duration-fast-01',\n 'hover:bg-surface-raised',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9',\n isSelected &&\n 'bg-accent-3 text-accent-11',\n disabled && 'opacity-action-disabled cursor-not-allowed pointer-events-none',\n className,\n )}\n >\n {/* Expand chevron */}\n {hasChildren ? (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onClick={handleChevronClick}\n className=\"flex shrink-0 items-center justify-center p-0 border-0 bg-transparent cursor-pointer\"\n >\n <Icon\n icon={IconChevronRight}\n size=\"sm\"\n className={cn(\n 'transition-transform duration-moderate-02',\n isExpanded && 'rotate-90',\n )}\n />\n </button>\n ) : (\n <span className=\"inline-block w-4 shrink-0\" aria-hidden=\"true\" />\n )}\n\n {/* Checkbox (optional) */}\n {ctx.checkboxes && (\n <Checkbox\n checked={checkboxState.checked}\n indeterminate={checkboxState.indeterminate}\n disabled={disabled}\n tabIndex={-1}\n onClick={(e) => e.stopPropagation()}\n onCheckedChange={() => {\n if (!disabled) ctx.tree.select(itemId)\n }}\n className=\"shrink-0\"\n />\n )}\n\n {/* Icon */}\n {icon && (\n <span className=\"flex shrink-0 items-center text-surface-fg-subtle\">\n {icon}\n </span>\n )}\n\n {/* Label */}\n <span className=\"truncate text-ds-sm\">{label}</span>\n\n {/* Secondary label */}\n {secondaryLabel && (\n <span className=\"ml-auto truncate text-ds-xs text-surface-fg-muted\">\n {secondaryLabel}\n </span>\n )}\n\n {/* Actions */}\n {actions && (\n <span\n className=\"ml-auto flex shrink-0 items-center gap-ds-01\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {actions}\n </span>\n )}\n </div>\n\n {/* Children (collapsible) */}\n {hasChildren && (\n <div\n role=\"group\"\n className={cn(\n 'grid transition-[grid-template-rows] duration-moderate-02 ease-productive-standard',\n isExpanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',\n )}\n >\n <ul role=\"group\" className=\"overflow-hidden m-0 p-0\">\n {React.Children.map(children, (child) => {\n if (React.isValidElement<TreeItemProps>(child)) {\n return React.cloneElement(child, {\n depth: depth + 1,\n })\n }\n return child\n })}\n </ul>\n </div>\n )}\n </li>\n )\n },\n)\nTreeItem.displayName = 'TreeItem'\n\nexport { TreeItem }\n"],"mappings":"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"}
|
|
@@ -77,7 +77,7 @@ var T = [
|
|
|
77
77
|
F ? /* @__PURE__ */ i("span", { className: "h-ds-xs-plus w-ds-xs-plus" }) : /* @__PURE__ */ i("button", {
|
|
78
78
|
type: "button",
|
|
79
79
|
onClick: () => A(w(r, 1)),
|
|
80
|
-
className: "inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-
|
|
80
|
+
className: "inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9",
|
|
81
81
|
"aria-label": "Previous month",
|
|
82
82
|
children: /* @__PURE__ */ i(t, {
|
|
83
83
|
icon: o,
|
|
@@ -88,14 +88,14 @@ var T = [
|
|
|
88
88
|
/* @__PURE__ */ i("button", {
|
|
89
89
|
type: "button",
|
|
90
90
|
onClick: j,
|
|
91
|
-
className: e("text-ds-md font-semibold text-surface-fg", j && "cursor-pointer rounded-
|
|
91
|
+
className: e("text-ds-md font-semibold text-surface-fg", j && "cursor-pointer rounded-control px-ds-02 transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover"),
|
|
92
92
|
"aria-label": "Switch to month/year view",
|
|
93
93
|
children: f(r, "MMMM yyyy")
|
|
94
94
|
}),
|
|
95
95
|
I ? /* @__PURE__ */ i("span", { className: "h-ds-xs-plus w-ds-xs-plus" }) : /* @__PURE__ */ i("button", {
|
|
96
96
|
type: "button",
|
|
97
97
|
onClick: () => A(l(r, 1)),
|
|
98
|
-
className: "inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-
|
|
98
|
+
className: "inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9",
|
|
99
99
|
"aria-label": "Next month",
|
|
100
100
|
children: /* @__PURE__ */ i(t, {
|
|
101
101
|
icon: s,
|
|
@@ -131,12 +131,12 @@ var T = [
|
|
|
131
131
|
"aria-label": f(t, "EEEE, MMMM d, yyyy"),
|
|
132
132
|
"aria-selected": c || u || void 0,
|
|
133
133
|
"aria-disabled": !o || s || void 0,
|
|
134
|
-
className: e("relative flex h-ds-sm w-ds-sm-plus items-center justify-center rounded-
|
|
134
|
+
className: e("relative flex h-ds-sm w-ds-sm-plus items-center justify-center rounded-control text-ds-md font-body transition-colors duration-fast-01 ease-productive-standard", !o && "pointer-events-none opacity-0", o && s && "opacity-action-disabled pointer-events-none cursor-not-allowed", o && !s && !c && !u && !l && "text-surface-fg hover:bg-surface-raised-hover", l && !u && "rounded-none bg-surface-raised-hover text-surface-fg", (c || u) && "bg-accent-9 text-accent-fg hover:bg-accent-10", d && !c && !u && !s && "font-semibold text-accent-11"),
|
|
135
135
|
children: [f(t, "d"), m.length > 0 && /* @__PURE__ */ i("span", {
|
|
136
136
|
className: "flex gap-px justify-center absolute bottom-[2px] left-0 right-0",
|
|
137
137
|
children: m.slice(0, 3).map((e, t) => /* @__PURE__ */ i("span", {
|
|
138
138
|
"data-event-dot": !0,
|
|
139
|
-
className: "h-[4px] w-[4px] rounded-
|
|
139
|
+
className: "h-[4px] w-[4px] rounded-pill",
|
|
140
140
|
style: { backgroundColor: e.color ?? "var(--color-accent-9)" }
|
|
141
141
|
}, t))
|
|
142
142
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-calendar.js","names":[],"sources":["../../src/composed/date-picker/calendar-grid.tsx","../../src/composed/date-picker/use-calendar.ts"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport {\n addDays,\n addMonths,\n endOfMonth,\n endOfWeek,\n format,\n isAfter,\n isBefore,\n isSameDay,\n isSameMonth,\n isWithinInterval,\n lastDayOfMonth,\n startOfDay,\n startOfMonth,\n startOfWeek,\n subMonths,\n} from 'date-fns'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { cn } from '../../ui/lib/utils'\n\nconst WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']\n\nexport interface CalendarEvent {\n date: Date\n color?: string\n label?: string\n}\n\nexport interface CalendarGridProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'onSelect'> {\n currentMonth: Date\n selected?: Date | null\n rangeStart?: Date | null\n rangeEnd?: Date | null\n hoverDate?: Date | null\n onSelect: (date: Date) => void\n onHover?: (date: Date | null) => void\n onMonthChange: (date: Date) => void\n onHeaderClick?: () => void\n disabledDates?: (date: Date) => boolean\n minDate?: Date\n maxDate?: Date\n /** Hide the previous-month navigation arrow */\n hidePrevNav?: boolean\n /** Hide the next-month navigation arrow */\n hideNextNav?: boolean\n /** Events to display as dot indicators on dates */\n events?: CalendarEvent[]\n}\n\nexport const CalendarGrid = React.forwardRef<HTMLDivElement, CalendarGridProps>(\n function CalendarGrid({\n currentMonth,\n selected,\n rangeStart,\n rangeEnd,\n hoverDate,\n onSelect,\n onHover,\n onMonthChange,\n onHeaderClick,\n disabledDates,\n minDate,\n maxDate,\n hidePrevNav,\n hideNextNav,\n events,\n className,\n ...props\n}, forwardedRef) {\n const gridRef = React.useRef<HTMLDivElement>(null)\n\n const eventsByDate = React.useMemo(() => {\n const map = new Map<string, CalendarEvent[]>()\n if (!events) return map\n for (const evt of events) {\n const key = format(evt.date, 'yyyy-MM-dd')\n const arr = map.get(key) ?? []\n arr.push(evt)\n map.set(key, arr)\n }\n return map\n }, [events])\n\n const monthStart = startOfMonth(currentMonth)\n const monthEnd = endOfMonth(currentMonth)\n const calendarStart = startOfWeek(monthStart)\n const calendarEnd = endOfWeek(monthEnd)\n\n const days: Date[] = []\n let day = calendarStart\n while (day <= calendarEnd) {\n days.push(day)\n day = addDays(day, 1)\n }\n\n const isDateDisabled = (date: Date): boolean => {\n if (disabledDates?.(date)) return true\n if (minDate && isBefore(date, startOfDay(minDate))) return true\n if (maxDate && isAfter(date, startOfDay(maxDate))) return true\n return false\n }\n\n const isInRange = (date: Date) => {\n if (rangeStart && rangeEnd) {\n const start = isBefore(rangeStart, rangeEnd) ? rangeStart : rangeEnd\n const end = isAfter(rangeEnd, rangeStart) ? rangeEnd : rangeStart\n return isWithinInterval(date, { start, end })\n }\n if (rangeStart && hoverDate) {\n const start = isBefore(rangeStart, hoverDate) ? rangeStart : hoverDate\n const end = isAfter(hoverDate, rangeStart) ? hoverDate : rangeStart\n return isWithinInterval(date, { start, end })\n }\n return false\n }\n\n const isRangeEdge = (date: Date) => {\n if (rangeStart && isSameDay(date, rangeStart)) return true\n if (rangeEnd && isSameDay(date, rangeEnd)) return true\n return false\n }\n\n const focusDate = (target: Date) => {\n if (!gridRef.current) return\n const dateStr = format(target, 'yyyy-MM-dd')\n const btn = gridRef.current.querySelector<HTMLButtonElement>(\n `[data-date=\"${dateStr}\"]`,\n )\n if (btn) {\n btn.focus()\n } else {\n // Date is in a different month — navigate there and focus after render\n onMonthChange(startOfMonth(target))\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement\n const dateStr = target.getAttribute('data-date')\n if (!dateStr) return\n\n const current = new Date(dateStr + 'T00:00:00')\n let next: Date | null = null\n\n switch (e.key) {\n case 'ArrowLeft':\n next = addDays(current, -1)\n break\n case 'ArrowRight':\n next = addDays(current, 1)\n break\n case 'ArrowUp':\n next = addDays(current, -7)\n break\n case 'ArrowDown':\n next = addDays(current, 7)\n break\n case 'Home':\n next = startOfMonth(current)\n break\n case 'End':\n next = lastDayOfMonth(current)\n break\n case 'Enter':\n case ' ': {\n e.preventDefault()\n if (!isDateDisabled(current) && isSameMonth(current, currentMonth)) {\n onSelect(current)\n }\n return\n }\n default:\n return\n }\n\n if (next) {\n e.preventDefault()\n focusDate(next)\n }\n }\n\n return (\n <div ref={forwardedRef} {...props} className={cn(\"w-[252px]\", className)}>\n <div className=\"flex items-center justify-between px-ds-02 pb-ds-04\">\n {hidePrevNav ? (\n <span className=\"h-ds-xs-plus w-ds-xs-plus\" />\n ) : (\n <button\n type=\"button\"\n onClick={() => onMonthChange(subMonths(currentMonth, 1))}\n className=\"inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-ds-md text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9\"\n aria-label=\"Previous month\"\n >\n <Icon icon={IconChevronLeft} size=\"sm\" stroke=\"light\" />\n </button>\n )}\n <button\n type=\"button\"\n onClick={onHeaderClick}\n className={cn(\n 'text-ds-md font-semibold text-surface-fg',\n onHeaderClick &&\n 'cursor-pointer rounded-ds-md px-ds-02 transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover',\n )}\n aria-label=\"Switch to month/year view\"\n >\n {format(currentMonth, 'MMMM yyyy')}\n </button>\n {hideNextNav ? (\n <span className=\"h-ds-xs-plus w-ds-xs-plus\" />\n ) : (\n <button\n type=\"button\"\n onClick={() => onMonthChange(addMonths(currentMonth, 1))}\n className=\"inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-ds-md text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9\"\n aria-label=\"Next month\"\n >\n <Icon icon={IconChevronRight} size=\"sm\" stroke=\"light\" />\n </button>\n )}\n </div>\n\n <div\n ref={gridRef}\n className=\"grid grid-cols-7 gap-0\"\n role=\"grid\"\n tabIndex={0}\n aria-label=\"Calendar\"\n onKeyDown={handleKeyDown}\n >\n {WEEKDAYS.map((wd) => (\n <div\n key={wd}\n role=\"columnheader\"\n className=\"flex h-ds-sm items-center justify-center text-ds-xs font-semibold uppercase tracking-wider text-surface-fg-subtle\"\n >\n {wd}\n </div>\n ))}\n\n {days.map((d, i) => {\n const inMonth = isSameMonth(d, currentMonth)\n const disabled = isDateDisabled(d)\n const isSelected = selected && isSameDay(d, selected)\n const inRange = isInRange(d)\n const edge = isRangeEdge(d)\n const isToday = isSameDay(d, new Date())\n const dateKey = format(d, 'yyyy-MM-dd')\n const dayEvents = eventsByDate.get(dateKey) ?? []\n\n return (\n <button\n key={i}\n type=\"button\"\n role=\"gridcell\"\n data-date={dateKey}\n tabIndex={inMonth && !disabled ? 0 : -1}\n disabled={!inMonth || disabled}\n onClick={() => {\n if (inMonth && !disabled) onSelect(d)\n }}\n onMouseEnter={() => onHover?.(d)}\n onMouseLeave={() => onHover?.(null)}\n aria-label={format(d, 'EEEE, MMMM d, yyyy')}\n aria-selected={isSelected || edge || undefined}\n aria-disabled={!inMonth || disabled || undefined}\n className={cn(\n 'relative flex h-ds-sm w-ds-sm-plus items-center justify-center rounded-ds-md text-ds-md font-body transition-colors duration-fast-01 ease-productive-standard',\n !inMonth && 'pointer-events-none opacity-0',\n inMonth && disabled && 'opacity-action-disabled pointer-events-none cursor-not-allowed',\n inMonth && !disabled && !isSelected && !edge && !inRange &&\n 'text-surface-fg hover:bg-surface-raised-hover',\n inRange && !edge &&\n 'rounded-ds-none bg-surface-raised-hover text-surface-fg',\n (isSelected || edge) &&\n 'bg-accent-9 text-accent-fg hover:bg-accent-10',\n isToday && !isSelected && !edge && !disabled &&\n 'font-semibold text-accent-11',\n )}\n >\n {format(d, 'd')}\n {dayEvents.length > 0 && (\n <span className=\"flex gap-px justify-center absolute bottom-[2px] left-0 right-0\">\n {dayEvents.slice(0, 3).map((evt, idx) => (\n <span\n key={idx}\n data-event-dot\n className=\"h-[4px] w-[4px] rounded-ds-full\"\n style={{ backgroundColor: evt.color ?? 'var(--color-accent-9)' }}\n />\n ))}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n )\n},\n)\n\nCalendarGrid.displayName = 'CalendarGrid'\n","'use client'\n\nimport { addMonths, setMonth, setYear,subMonths } from 'date-fns'\nimport { useState } from 'react'\n\nexport function useCalendar(initialMonth?: Date) {\n const [currentMonth, setCurrentMonth] = useState(initialMonth ?? new Date())\n\n const goToPreviousMonth = () => setCurrentMonth((prev) => subMonths(prev, 1))\n const goToNextMonth = () => setCurrentMonth((prev) => addMonths(prev, 1))\n const goToMonth = (month: number) =>\n setCurrentMonth((prev) => setMonth(prev, month))\n const goToYear = (year: number) =>\n setCurrentMonth((prev) => setYear(prev, year))\n\n return {\n currentMonth,\n setCurrentMonth,\n goToPreviousMonth,\n goToNextMonth,\n goToMonth,\n goToYear,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-calendar.js","names":[],"sources":["../../src/composed/date-picker/calendar-grid.tsx","../../src/composed/date-picker/use-calendar.ts"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport {\n addDays,\n addMonths,\n endOfMonth,\n endOfWeek,\n format,\n isAfter,\n isBefore,\n isSameDay,\n isSameMonth,\n isWithinInterval,\n lastDayOfMonth,\n startOfDay,\n startOfMonth,\n startOfWeek,\n subMonths,\n} from 'date-fns'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { cn } from '../../ui/lib/utils'\n\nconst WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']\n\nexport interface CalendarEvent {\n date: Date\n color?: string\n label?: string\n}\n\nexport interface CalendarGridProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'onSelect'> {\n currentMonth: Date\n selected?: Date | null\n rangeStart?: Date | null\n rangeEnd?: Date | null\n hoverDate?: Date | null\n onSelect: (date: Date) => void\n onHover?: (date: Date | null) => void\n onMonthChange: (date: Date) => void\n onHeaderClick?: () => void\n disabledDates?: (date: Date) => boolean\n minDate?: Date\n maxDate?: Date\n /** Hide the previous-month navigation arrow */\n hidePrevNav?: boolean\n /** Hide the next-month navigation arrow */\n hideNextNav?: boolean\n /** Events to display as dot indicators on dates */\n events?: CalendarEvent[]\n}\n\nexport const CalendarGrid = React.forwardRef<HTMLDivElement, CalendarGridProps>(\n function CalendarGrid({\n currentMonth,\n selected,\n rangeStart,\n rangeEnd,\n hoverDate,\n onSelect,\n onHover,\n onMonthChange,\n onHeaderClick,\n disabledDates,\n minDate,\n maxDate,\n hidePrevNav,\n hideNextNav,\n events,\n className,\n ...props\n}, forwardedRef) {\n const gridRef = React.useRef<HTMLDivElement>(null)\n\n const eventsByDate = React.useMemo(() => {\n const map = new Map<string, CalendarEvent[]>()\n if (!events) return map\n for (const evt of events) {\n const key = format(evt.date, 'yyyy-MM-dd')\n const arr = map.get(key) ?? []\n arr.push(evt)\n map.set(key, arr)\n }\n return map\n }, [events])\n\n const monthStart = startOfMonth(currentMonth)\n const monthEnd = endOfMonth(currentMonth)\n const calendarStart = startOfWeek(monthStart)\n const calendarEnd = endOfWeek(monthEnd)\n\n const days: Date[] = []\n let day = calendarStart\n while (day <= calendarEnd) {\n days.push(day)\n day = addDays(day, 1)\n }\n\n const isDateDisabled = (date: Date): boolean => {\n if (disabledDates?.(date)) return true\n if (minDate && isBefore(date, startOfDay(minDate))) return true\n if (maxDate && isAfter(date, startOfDay(maxDate))) return true\n return false\n }\n\n const isInRange = (date: Date) => {\n if (rangeStart && rangeEnd) {\n const start = isBefore(rangeStart, rangeEnd) ? rangeStart : rangeEnd\n const end = isAfter(rangeEnd, rangeStart) ? rangeEnd : rangeStart\n return isWithinInterval(date, { start, end })\n }\n if (rangeStart && hoverDate) {\n const start = isBefore(rangeStart, hoverDate) ? rangeStart : hoverDate\n const end = isAfter(hoverDate, rangeStart) ? hoverDate : rangeStart\n return isWithinInterval(date, { start, end })\n }\n return false\n }\n\n const isRangeEdge = (date: Date) => {\n if (rangeStart && isSameDay(date, rangeStart)) return true\n if (rangeEnd && isSameDay(date, rangeEnd)) return true\n return false\n }\n\n const focusDate = (target: Date) => {\n if (!gridRef.current) return\n const dateStr = format(target, 'yyyy-MM-dd')\n const btn = gridRef.current.querySelector<HTMLButtonElement>(\n `[data-date=\"${dateStr}\"]`,\n )\n if (btn) {\n btn.focus()\n } else {\n // Date is in a different month — navigate there and focus after render\n onMonthChange(startOfMonth(target))\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement\n const dateStr = target.getAttribute('data-date')\n if (!dateStr) return\n\n const current = new Date(dateStr + 'T00:00:00')\n let next: Date | null = null\n\n switch (e.key) {\n case 'ArrowLeft':\n next = addDays(current, -1)\n break\n case 'ArrowRight':\n next = addDays(current, 1)\n break\n case 'ArrowUp':\n next = addDays(current, -7)\n break\n case 'ArrowDown':\n next = addDays(current, 7)\n break\n case 'Home':\n next = startOfMonth(current)\n break\n case 'End':\n next = lastDayOfMonth(current)\n break\n case 'Enter':\n case ' ': {\n e.preventDefault()\n if (!isDateDisabled(current) && isSameMonth(current, currentMonth)) {\n onSelect(current)\n }\n return\n }\n default:\n return\n }\n\n if (next) {\n e.preventDefault()\n focusDate(next)\n }\n }\n\n return (\n <div ref={forwardedRef} {...props} className={cn(\"w-[252px]\", className)}>\n <div className=\"flex items-center justify-between px-ds-02 pb-ds-04\">\n {hidePrevNav ? (\n <span className=\"h-ds-xs-plus w-ds-xs-plus\" />\n ) : (\n <button\n type=\"button\"\n onClick={() => onMonthChange(subMonths(currentMonth, 1))}\n className=\"inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9\"\n aria-label=\"Previous month\"\n >\n <Icon icon={IconChevronLeft} size=\"sm\" stroke=\"light\" />\n </button>\n )}\n <button\n type=\"button\"\n onClick={onHeaderClick}\n className={cn(\n 'text-ds-md font-semibold text-surface-fg',\n onHeaderClick &&\n 'cursor-pointer rounded-control px-ds-02 transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover',\n )}\n aria-label=\"Switch to month/year view\"\n >\n {format(currentMonth, 'MMMM yyyy')}\n </button>\n {hideNextNav ? (\n <span className=\"h-ds-xs-plus w-ds-xs-plus\" />\n ) : (\n <button\n type=\"button\"\n onClick={() => onMonthChange(addMonths(currentMonth, 1))}\n className=\"inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9\"\n aria-label=\"Next month\"\n >\n <Icon icon={IconChevronRight} size=\"sm\" stroke=\"light\" />\n </button>\n )}\n </div>\n\n <div\n ref={gridRef}\n className=\"grid grid-cols-7 gap-0\"\n role=\"grid\"\n tabIndex={0}\n aria-label=\"Calendar\"\n onKeyDown={handleKeyDown}\n >\n {WEEKDAYS.map((wd) => (\n <div\n key={wd}\n role=\"columnheader\"\n className=\"flex h-ds-sm items-center justify-center text-ds-xs font-semibold uppercase tracking-wider text-surface-fg-subtle\"\n >\n {wd}\n </div>\n ))}\n\n {days.map((d, i) => {\n const inMonth = isSameMonth(d, currentMonth)\n const disabled = isDateDisabled(d)\n const isSelected = selected && isSameDay(d, selected)\n const inRange = isInRange(d)\n const edge = isRangeEdge(d)\n const isToday = isSameDay(d, new Date())\n const dateKey = format(d, 'yyyy-MM-dd')\n const dayEvents = eventsByDate.get(dateKey) ?? []\n\n return (\n <button\n key={i}\n type=\"button\"\n role=\"gridcell\"\n data-date={dateKey}\n tabIndex={inMonth && !disabled ? 0 : -1}\n disabled={!inMonth || disabled}\n onClick={() => {\n if (inMonth && !disabled) onSelect(d)\n }}\n onMouseEnter={() => onHover?.(d)}\n onMouseLeave={() => onHover?.(null)}\n aria-label={format(d, 'EEEE, MMMM d, yyyy')}\n aria-selected={isSelected || edge || undefined}\n aria-disabled={!inMonth || disabled || undefined}\n className={cn(\n 'relative flex h-ds-sm w-ds-sm-plus items-center justify-center rounded-control text-ds-md font-body transition-colors duration-fast-01 ease-productive-standard',\n !inMonth && 'pointer-events-none opacity-0',\n inMonth && disabled && 'opacity-action-disabled pointer-events-none cursor-not-allowed',\n inMonth && !disabled && !isSelected && !edge && !inRange &&\n 'text-surface-fg hover:bg-surface-raised-hover',\n inRange && !edge &&\n 'rounded-none bg-surface-raised-hover text-surface-fg',\n (isSelected || edge) &&\n 'bg-accent-9 text-accent-fg hover:bg-accent-10',\n isToday && !isSelected && !edge && !disabled &&\n 'font-semibold text-accent-11',\n )}\n >\n {format(d, 'd')}\n {dayEvents.length > 0 && (\n <span className=\"flex gap-px justify-center absolute bottom-[2px] left-0 right-0\">\n {dayEvents.slice(0, 3).map((evt, idx) => (\n <span\n key={idx}\n data-event-dot\n className=\"h-[4px] w-[4px] rounded-pill\"\n style={{ backgroundColor: evt.color ?? 'var(--color-accent-9)' }}\n />\n ))}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n )\n},\n)\n\nCalendarGrid.displayName = 'CalendarGrid'\n","'use client'\n\nimport { addMonths, setMonth, setYear,subMonths } from 'date-fns'\nimport { useState } from 'react'\n\nexport function useCalendar(initialMonth?: Date) {\n const [currentMonth, setCurrentMonth] = useState(initialMonth ?? new Date())\n\n const goToPreviousMonth = () => setCurrentMonth((prev) => subMonths(prev, 1))\n const goToNextMonth = () => setCurrentMonth((prev) => addMonths(prev, 1))\n const goToMonth = (month: number) =>\n setCurrentMonth((prev) => setMonth(prev, month))\n const goToYear = (year: number) =>\n setCurrentMonth((prev) => setYear(prev, year))\n\n return {\n currentMonth,\n setCurrentMonth,\n goToPreviousMonth,\n goToNextMonth,\n goToMonth,\n goToYear,\n }\n}\n"],"mappings":"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"}
|
package/dist/ai/command-bar.js
CHANGED
|
@@ -190,10 +190,10 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
190
190
|
y: 0
|
|
191
191
|
} : void 0, X = g === "inline", Z = m === "processing", Re = m === "responded", Q = () => /* @__PURE__ */ l(pe, {
|
|
192
192
|
active: Z,
|
|
193
|
-
rounded: X ? "rounded-
|
|
193
|
+
rounded: X ? "rounded-control" : "rounded-surface",
|
|
194
194
|
reducedMotion: H,
|
|
195
195
|
children: /* @__PURE__ */ u("div", {
|
|
196
|
-
className: n("flex items-center gap-ds-04 border bg-surface-overlay transition-colors transition-shadow duration-fast-02 ease-productive-standard", X ? "rounded-
|
|
196
|
+
className: n("flex items-center gap-ds-04 border bg-surface-overlay transition-colors transition-shadow duration-fast-02 ease-productive-standard", X ? "rounded-control px-ds-04" : "rounded-surface px-ds-05", Z ? "border-transparent" : "border-surface-border-strong", R && !Z && "border-accent-7 shadow-ring", z && "animate-shake"),
|
|
197
197
|
children: [
|
|
198
198
|
/* @__PURE__ */ l(r, {
|
|
199
199
|
icon: de,
|
|
@@ -242,7 +242,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
242
242
|
}) : Re ? /* @__PURE__ */ l("button", {
|
|
243
243
|
type: "button",
|
|
244
244
|
onClick: Le,
|
|
245
|
-
className: "shrink-0 rounded-
|
|
245
|
+
className: "shrink-0 rounded-control-inner p-ds-01 text-surface-fg-subtle transition-colors duration-fast-01 hover:bg-surface-raised-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9",
|
|
246
246
|
"aria-label": "Clear",
|
|
247
247
|
title: "Clear",
|
|
248
248
|
children: /* @__PURE__ */ l(r, {
|
|
@@ -255,7 +255,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
255
255
|
animate: { opacity: 1 },
|
|
256
256
|
exit: H ? void 0 : { opacity: 0 },
|
|
257
257
|
transition: J,
|
|
258
|
-
className: "hidden shrink-0 select-none rounded-
|
|
258
|
+
className: "hidden shrink-0 select-none rounded-control border border-surface-border-strong bg-surface-raised px-ds-02b py-ds-01 text-ds-sm font-medium text-surface-fg-subtle shadow-kbd sm:inline-flex",
|
|
259
259
|
children: [ae(je), "J"]
|
|
260
260
|
}) }) : null
|
|
261
261
|
]
|
|
@@ -314,7 +314,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
314
314
|
t.onSelect(), g === "floating" && N(!1);
|
|
315
315
|
},
|
|
316
316
|
onMouseEnter: () => L(i),
|
|
317
|
-
className: n("flex w-full items-center gap-ds-04 rounded-
|
|
317
|
+
className: n("flex w-full items-center gap-ds-04 rounded-surface px-ds-03 py-ds-03 text-left transition-[color,background-color] duration-fast-02 ease-productive-standard", a ? "bg-surface-raised-hover text-surface-fg" : "text-surface-fg-muted hover:bg-surface-raised"),
|
|
318
318
|
children: [
|
|
319
319
|
t.icon && /* @__PURE__ */ l("span", {
|
|
320
320
|
className: n("[&>svg]:h-ico-sm [&>svg]:w-ico-sm shrink-0 transition-colors duration-fast-02 ease-productive-standard", a ? "text-accent-11" : "text-surface-fg-subtle"),
|
|
@@ -352,7 +352,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
352
352
|
return g === "hero" ? /* @__PURE__ */ u("div", {
|
|
353
353
|
ref: k,
|
|
354
354
|
role: "search",
|
|
355
|
-
className: n("bg-surface-raised rounded-
|
|
355
|
+
className: n("bg-surface-raised rounded-overlay-lg shadow-raised p-ds-07", D),
|
|
356
356
|
...O,
|
|
357
357
|
children: [
|
|
358
358
|
v && /* @__PURE__ */ l("p", {
|
|
@@ -368,7 +368,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
368
368
|
onClick: () => {
|
|
369
369
|
F(e), _e?.(e), B.current?.focus();
|
|
370
370
|
},
|
|
371
|
-
className: "rounded-
|
|
371
|
+
className: "rounded-control border border-surface-border-strong bg-surface-overlay px-ds-03 py-ds-01 text-ds-sm text-surface-fg-subtle transition-colors duration-fast-02 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted",
|
|
372
372
|
children: e
|
|
373
373
|
}, e))
|
|
374
374
|
}),
|
|
@@ -398,7 +398,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
398
398
|
children: /* @__PURE__ */ u(te, { children: [/* @__PURE__ */ l(ee, { className: "fixed inset-0 z-overlay bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" }), /* @__PURE__ */ u(a, {
|
|
399
399
|
ref: k,
|
|
400
400
|
...O,
|
|
401
|
-
className: n("fixed left-1/2 top-[20%] z-modal w-full max-w-[560px] -translate-x-1/2", "overflow-hidden rounded-
|
|
401
|
+
className: n("fixed left-1/2 top-[20%] z-modal w-full max-w-[560px] -translate-x-1/2", "overflow-hidden rounded-overlay-lg border border-surface-border-strong bg-surface-overlay shadow-overlay", "duration-moderate-02 data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[state=closed]:slide-out-to-left-1/2 data-[state=open]:slide-in-from-left-1/2", "data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2", D),
|
|
402
402
|
children: [
|
|
403
403
|
/* @__PURE__ */ u(re, { children: [/* @__PURE__ */ l(ne, { children: "AI Command Bar" }), /* @__PURE__ */ l(o, { children: "Search commands or ask a question" })] }),
|
|
404
404
|
/* @__PURE__ */ l("div", {
|
|
@@ -443,7 +443,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
443
443
|
/* @__PURE__ */ u("div", {
|
|
444
444
|
className: "flex items-center gap-ds-02b",
|
|
445
445
|
children: [/* @__PURE__ */ l("kbd", {
|
|
446
|
-
className: "inline-flex h-[20px] items-center justify-center rounded-
|
|
446
|
+
className: "inline-flex h-[20px] items-center justify-center rounded-control border border-surface-border-strong bg-surface-raised px-ds-02b shadow-kbd",
|
|
447
447
|
children: /* @__PURE__ */ l(r, {
|
|
448
448
|
icon: d,
|
|
449
449
|
size: "xs",
|
|
@@ -457,7 +457,7 @@ var m = s.forwardRef(function({ onSubmit: c, state: m = "idle", groups: h = [],
|
|
|
457
457
|
/* @__PURE__ */ u("div", {
|
|
458
458
|
className: "flex items-center gap-ds-02b",
|
|
459
459
|
children: [/* @__PURE__ */ l("kbd", {
|
|
460
|
-
className: "inline-flex h-[20px] items-center justify-center rounded-
|
|
460
|
+
className: "inline-flex h-[20px] items-center justify-center rounded-control border border-surface-border-strong bg-surface-raised px-ds-02b text-ds-xs font-medium text-surface-fg-subtle shadow-kbd",
|
|
461
461
|
children: "Esc"
|
|
462
462
|
}), /* @__PURE__ */ l("span", {
|
|
463
463
|
className: "text-ds-xs text-surface-fg-subtle",
|