@devalok/shilp-sutra 0.55.1 → 0.57.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/BREAKING.json +13 -0
- package/MIGRATION.md +163 -0
- package/README.md +16 -1
- package/dist/_chunks/badge-group.js +92 -78
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chat.js +91 -75
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/document-preview.js +1 -1
- package/dist/_chunks/document-preview.js.map +1 -1
- package/dist/_chunks/emoji-suggestion.js +32 -30
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +36 -35
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/oauth-button.js +1 -1
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/primitives-internal.js +437 -537
- package/dist/_chunks/primitives-internal.js.map +1 -1
- package/dist/_chunks/success.js +2 -2
- package/dist/_chunks/success.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 +4 -4
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/ai/blocks/text.js +1 -1
- package/dist/ai/blocks/text.js.map +1 -1
- package/dist/ai/command-bar.js +9 -9
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +2 -2
- package/dist/ai/conversation.js.map +1 -1
- package/dist/composed/activity-feed.js +1 -1
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.d.ts +7 -2
- package/dist/composed/avatar-group.d.ts.map +1 -1
- package/dist/composed/avatar-group.js +3 -3
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/command-palette.js +7 -7
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +20 -20
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/date-picker/index.js +4 -4
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/diff.d.ts +23 -2
- package/dist/composed/diff.d.ts.map +1 -1
- package/dist/composed/diff.js +341 -260
- package/dist/composed/diff.js.map +1 -1
- package/dist/composed/emoji-picker.js +3 -3
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/error-boundary.js +2 -2
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/extensions/emoji-node.js +8 -7
- package/dist/composed/extensions/emoji-node.js.map +1 -1
- package/dist/composed/file-preview.js +1 -1
- package/dist/composed/file-preview.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 +3 -3
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/master-detail.js +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/member-picker.js +1 -1
- package/dist/composed/member-picker.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-skeletons.js +4 -4
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/responsive-modal.js +1 -1
- package/dist/composed/responsive-modal.js.map +1 -1
- package/dist/composed/rich-chat-input.js +549 -540
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +206 -198
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js +5 -5
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +4 -3
- package/dist/hooks/use-container-size.d.ts +18 -0
- package/dist/hooks/use-container-size.d.ts.map +1 -0
- package/dist/hooks/use-container-size.js +28 -0
- package/dist/hooks/use-container-size.js.map +1 -0
- package/dist/shell/app-shell.d.ts +101 -0
- package/dist/shell/app-shell.d.ts.map +1 -0
- package/dist/shell/app-shell.js +76 -0
- package/dist/shell/app-shell.js.map +1 -0
- package/dist/shell/bottom-navbar.js +2 -2
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/index.d.ts +1 -0
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +6 -5
- package/dist/shell/notification-center.js +4 -4
- 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/top-bar.js +7 -7
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/generate-scale.d.ts +49 -0
- package/dist/tokens/generate-scale.d.ts.map +1 -1
- package/dist/tokens/primitives.css +29 -26
- package/dist/tokens/semantic.css +98 -39
- package/dist/tokens/variants.css +1 -1
- package/dist/ui/accordion.js +1 -1
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.d.ts.map +1 -1
- package/dist/ui/alert.js +36 -36
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/avatar.js +44 -44
- 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/badge.d.ts +47 -33
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/banner.js +26 -26
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/button.js +35 -35
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +42 -42
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/chat/date-separator.d.ts +8 -1
- package/dist/ui/chat/date-separator.d.ts.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 +3 -3
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/combobox.js +139 -139
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +4 -4
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.d.ts +3 -1
- package/dist/ui/data-table-body.d.ts.map +1 -1
- package/dist/ui/data-table-body.js +93 -92
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.d.ts +7 -1
- package/dist/ui/data-table-bulk-actions.d.ts.map +1 -1
- package/dist/ui/data-table-bulk-actions.js +14 -8
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.d.ts.map +1 -1
- package/dist/ui/data-table-card.js +66 -47
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-context.d.ts +4 -0
- package/dist/ui/data-table-context.d.ts.map +1 -1
- package/dist/ui/data-table-context.js.map +1 -1
- package/dist/ui/data-table-header.d.ts.map +1 -1
- package/dist/ui/data-table-header.js +18 -15
- 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.d.ts +11 -1
- package/dist/ui/data-table-toolbar.d.ts.map +1 -1
- package/dist/ui/data-table-toolbar.js +7 -7
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.d.ts +52 -5
- package/dist/ui/data-table.d.ts.map +1 -1
- package/dist/ui/data-table.js +181 -169
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/dialog.js +1 -1
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.js +13 -13
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.js +4 -4
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.js +3 -3
- package/dist/ui/file-upload.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 +30 -30
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/lib/utils.js +2 -1
- package/dist/ui/lib/utils.js.map +1 -1
- package/dist/ui/menubar.js +5 -5
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +1 -1
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/number-input.js +36 -36
- 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-ring.js +2 -2
- package/dist/ui/progress-ring.js.map +1 -1
- package/dist/ui/progress.d.ts.map +1 -1
- package/dist/ui/progress.js +66 -62
- 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/select.js +61 -61
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sheet.js +47 -47
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +132 -132
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/skeleton.js +39 -39
- package/dist/ui/slider.js +18 -18
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/split-button.js +3 -3
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.js +1 -1
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stepper.js +2 -2
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/surface.d.ts.map +1 -1
- package/dist/ui/surface.js +11 -11
- package/dist/ui/surface.js.map +1 -1
- package/dist/ui/switch.js +1 -1
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/table.js +1 -1
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tabs.d.ts.map +1 -1
- package/dist/ui/tabs.js +48 -48
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/text.js +8 -8
- package/dist/ui/textarea.js +17 -17
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.js +1 -1
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toggle.js +15 -15
- package/dist/ui/toggle.js.map +1 -1
- package/docs/components/composed/avatar-group.md +4 -4
- package/docs/components/composed/diff.md +10 -2
- package/docs/components/composed/schedule-view.md +1 -1
- package/docs/components/shell/app-shell.md +132 -0
- package/docs/components/ui/avatar.md +1 -1
- package/docs/components/ui/button.md +1 -1
- package/docs/components/ui/chat.md +7 -1
- package/docs/components/ui/color-swatch.md +1 -1
- package/docs/components/ui/data-table-toolbar.md +6 -2
- package/docs/components/ui/data-table.md +41 -7
- package/docs/components/ui/dot.md +1 -1
- package/docs/components/ui/progress.md +1 -0
- package/docs/components/ui/surface.md +3 -3
- package/docs/components/ui/table.md +2 -2
- package/docs/recipes/install-astro.md +3 -2
- package/docs/recipes/install-next-app-router.md +3 -2
- package/docs/recipes/install-remix.md +3 -2
- package/docs/recipes/install-tanstack-start.md +3 -2
- package/docs/recipes/install-vite.md +3 -2
- package/docs/recipes/troubleshoot.md +26 -5
- package/llms.txt +2 -1
- package/make-kit/Guidelines.md +2 -2
- package/make-kit/components/button.md +1 -1
- package/make-kit/components/card.md +6 -6
- package/make-kit/components/surface.md +4 -4
- package/make-kit/foundations/color.md +4 -4
- package/make-kit/foundations/dark-mode.md +1 -1
- package/make-kit/foundations/radius.md +1 -1
- package/make-kit/foundations/surfaces.md +9 -9
- package/mcp-manifest.json +373 -34
- package/package.json +43 -13
- package/skill/SKILL.md +12 -6
- package/skill/references/components.md +2 -1
- package/skill/references/setup-astro.md +3 -2
- package/skill/references/setup-next-app-router.md +3 -2
- package/skill/references/setup-remix.md +3 -2
- package/skill/references/setup-tanstack-start.md +3 -2
- package/skill/references/setup-vite.md +3 -2
- package/skill/references/troubleshoot.md +26 -5
- package/dist/_chunks/tiptap.js +0 -18809
- package/dist/_chunks/tiptap.js.map +0 -1
- package/dist/_chunks/vendor-utils.js +0 -1766
- package/dist/_chunks/vendor-utils.js.map +0 -1
- package/dist/primitives/react-toast.d.ts +0 -120
- package/dist/ui/charts/_internal/scales.d.ts +0 -5
- package/dist/ui/charts/_internal/scales.d.ts.map +0 -1
- package/dist/ui/lib/slot.d.ts +0 -8
- package/dist/ui/lib/slot.d.ts.map +0 -1
- package/scripts/welcome.mjs +0 -312
package/dist/_chunks/success.js
CHANGED
|
@@ -87,7 +87,7 @@ var M = C.memo(function({ data: e, confidence: n }) {
|
|
|
87
87
|
/* @__PURE__ */ w(m, { children: f.map((e, n) => {
|
|
88
88
|
let a = typeof e.id == "string" || typeof e.id == "number" ? String(e.id) : `row-${n}`;
|
|
89
89
|
return /* @__PURE__ */ w(i ? "tr" : k.tr, {
|
|
90
|
-
className: "hover:bg-surface-
|
|
90
|
+
className: "hover:bg-surface-panel-hover transition-colors",
|
|
91
91
|
...i ? {} : {
|
|
92
92
|
initial: {
|
|
93
93
|
opacity: 0,
|
|
@@ -150,7 +150,7 @@ var N = C.memo(function({ data: e, confidence: t, onAction: n }) {
|
|
|
150
150
|
children: "Why this action?"
|
|
151
151
|
})
|
|
152
152
|
}), /* @__PURE__ */ w(d, { children: /* @__PURE__ */ w("p", {
|
|
153
|
-
className: "text-body-sm text-surface-fg-muted mt-2 p-3 bg-surface-
|
|
153
|
+
className: "text-body-sm text-surface-fg-muted mt-2 p-3 bg-surface-panel rounded-surface",
|
|
154
154
|
children: e.rationale
|
|
155
155
|
}) })]
|
|
156
156
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"success.js","names":[],"sources":["../../src/ai/blocks/block-table.tsx","../../src/ai/blocks/confirm.tsx","../../src/ai/blocks/divider.tsx","../../src/ai/blocks/info.tsx","../../src/ai/blocks/loading.tsx","../../src/ai/blocks/stat-row.tsx","../../src/ai/blocks/success.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'\nimport { BlockShell } from './block-shell'\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 <BlockShell confidence={confidence} className=\"overflow-x-auto\">\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-body-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 </BlockShell>\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 type { BlockComponentProps, ConfirmBlockData } from '../types'\nimport { BlockShell } from './block-shell'\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 <BlockShell confidence={confidence}>\n {data.description && (\n <p className=\"text-body-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-caption text-surface-fg-subtle underline cursor-pointer\"\n >\n Why this action?\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <p className=\"text-body-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 </BlockShell>\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'\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-body-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={{ 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 type { BlockComponentProps, SuccessBlockData } from '../types'\nimport { BlockShell } from './block-shell'\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 <BlockShell confidence={confidence}>\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 </BlockShell>\n )\n})\n\nSuccessBlock.displayName = 'SuccessBlock'\n\nexport { SuccessBlock }\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA,SAAS,EAAgB,GAAgB,GAA0B;CACjE,IAAI,EAAO,YAAY,SAAS;EAC9B,IAAI,KAAS,OAAO,KAAU,YAAY,WAAW,GAAO;GAC1D,IAAM,IAAW;GACjB,OACE,kBAAC,GAAD;IAAO,SAAQ;IAAS,MAAK;IAAK,OAAO,EAAS;cAC/C,EAAS;GACL,CAAA;EAEX;EACA,OACE,kBAAC,GAAD;GAAO,SAAQ;GAAS,MAAK;aAC1B,OAAO,KAAS,EAAE;EACd,CAAA;CAEX;CAEA,OAAO,OAAO,KAAS,EAAE;AAC3B;AAEA,SAAS,EACP,GACA,GACA,GAC2B;CAE3B,OADI,CAAC,KAAW,CAAC,IAAgB,IAC1B,CAAC,GAAG,CAAI,CAAC,CAAC,MAAM,GAAG,MAAM;EAC9B,IAAM,IAAO,EAAE,IACT,IAAO,EAAE,IACT,IAAO,OAAO,KAAQ,EAAE,GACxB,IAAO,OAAO,KAAQ,EAAE,GACxB,IAAO,OAAO,CAAI,GAClB,IAAO,OAAO,CAAI;EAGxB,IAAI,CAAC,OAAO,MAAM,CAAI,KAAK,CAAC,OAAO,MAAM,CAAI,GAC3C,OAAO,MAAY,QAAQ,IAAO,IAAO,IAAO;EAIlD,IAAM,IAAM,EAAK,cAAc,CAAI;EACnC,OAAO,MAAY,QAAQ,IAAM,CAAC;CACpC,CAAC;AACH;AAEA,IAAM,IAAa,EAAM,KAAK,SAAoB,EAChD,SACA,iBACsC;CACtC,IAAM,EAAE,qBAAkB,EAAU,GAC9B,CAAC,GAAS,KAAc,EAAM,SAAwB,IAAI,GAC1D,CAAC,GAAS,KAAc,EAAM,SAAkB,IAAI,GAEpD,IAAoB,EAAM,aAC7B,MAAgB;EACV,EAAK,aACN,MAAY,IAGL,MAAY,QACrB,EAAW,MAAM,IACR,MAAY,WACrB,EAAW,IAAI,GACf,EAAW,IAAI,MANf,EAAW,CAAG,GACd,EAAW,KAAK;CAOpB,GACA;EAAC,EAAK;EAAU;EAAS;CAAO,CAClC,GAEM,IAAU,EAAK,WAAW,CAAC,GAC3B,IAAa,EAAS,EAAK,QAAQ,CAAC,GAAG,GAAS,CAAO;CAE7D,OACE,kBAAC,GAAD;EAAwB;EAAY,WAAU;YAC5C,kBAAC,GAAD,EAAA,UAAA;GACG,EAAK,WAAW,kBAAC,GAAD,EAAA,UAAe,EAAK,QAAsB,CAAA;GAC3D,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACG,EAAQ,KAAK,MAAQ;IACpB,IAAM,IAAW,MAAY,EAAI,KAC3B,IAAW,EAAK,WAClB,IACE,MAAY,QACT,cACA,eACF,SACH,KAAA;IAEJ,OACE,kBAAC,GAAD;KAEE,MAAK;KACL,WAAW,EACT,EAAI,YAAY,YAAY,cAC5B,EAAK,YAAY,4BACnB;KACA,UAAU,EAAK,WAAW,IAAI,KAAA;KAC9B,SACE,EAAK,iBACK,EAAkB,EAAI,GAAG,IAC/B,KAAA;KAEN,WACE,EAAK,YACA,MAA2B;MAC1B,CAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,eAAe,GACjB,EAAkB,EAAI,GAAG;KAE7B,IACA,KAAA;KAEN,aAAW;eAEX,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACG,EAAI;OACJ,KAAY,MAAY,SACvB,kBAAC,QAAD;QAAM,eAAY;kBAAO;OAAa,CAAA;OAEvC,KAAY,MAAY,UACvB,kBAAC,QAAD;QAAM,eAAY;kBAAO;OAAa,CAAA;MAEpC;;IACG,GAjCJ,EAAI,GAiCA;GAEf,CAAC,EACO,CAAA,EACC,CAAA;GACb,kBAAC,GAAD,EAAA,UACG,EAAW,KAAK,GAAK,MAAa;IACjC,IAAM,IACJ,OAAO,EAAI,MAAO,YAAY,OAAO,EAAI,MAAO,WAC5C,OAAO,EAAI,EAAE,IACb,OAAO;IAYb,OACE,kBAXiB,IAAgB,OAAO,EAAO,IAW/C;KAEE,WAAU;KACV,GAZgB,IAChB,CAAC,IACD;MACE,SAAS;OAAE,SAAS;OAAG,GAAG;MAAE;MAC5B,SAAS;OAAE,SAAS;OAAG,GAAG;MAAE;MAC5B,YAAY;OAAE,GAAG,EAAQ;OAAY,OAAO,IAAW;MAAK;KAC9D;eAQC,EAAQ,KAAK,MACZ,kBAAC,GAAD;MAEE,WAAW,EACT,mCACA,EAAI,YAAY,YACd,qCACJ;gBAEC,EAAgB,EAAI,EAAI,MAAM,CAAG;KACzB,GARJ,EAAI,GAQA,CACZ;IACS,GAhBL,CAgBK;GAEhB,CAAC,EACQ,CAAA;EACN,EAAA,CAAA;CACG,CAAA;AAEhB,CAAC;AAED,EAAW,cAAc;;;ACtLzB,IAAM,IAAe,EAAM,KAAK,SAAsB,EACpD,SACA,eACA,eACwC;CACxC,IAAM,IAAgB,EAAM,kBAAkB;EAC5C,IAAW,EAAK,UAAU,SAAS;CACrC,GAAG,CAAC,EAAK,UAAU,CAAQ,CAAC,GAEtB,IAAe,EAAM,kBAAkB;EAC3C,IAAW,EAAK,UAAU,QAAQ;CACpC,GAAG,CAAC,EAAK,UAAU,CAAQ,CAAC;CAE5B,OACE,kBAAC,GAAD;EAAwB;YAAxB;GACG,EAAK,eACJ,kBAAC,KAAD;IAAG,WAAU;cACV,EAAK;GACL,CAAA;GAGL,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,SAAQ;KACR,OAAO,EAAK,cAAc,UAAU,KAAA;KACpC,SAAS;eAER,EAAK;IACA,CAAA,GACR,kBAAC,GAAD;KAAQ,SAAQ;KAAQ,SAAS;eAAc;IAEvC,CAAA,CACL;;GAEJ,EAAK,aACJ,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,GAAD;KAAoB,SAAA;eAClB,kBAAC,UAAD;MACE,MAAK;MACL,WAAU;gBACX;KAEO,CAAA;IACU,CAAA,GACpB,kBAAC,GAAD,EAAA,UACE,kBAAC,KAAD;KAAG,WAAU;eACV,EAAK;IACL,CAAA,EACe,CAAA,CACT;;EAEL;;AAEhB,CAAC;AAED,EAAa,cAAc;;;AC1D3B,IAAM,IAAe,EAAM,KAAK,SAC9B,GACA;CACA,IAAM,EAAE,qBAAkB,EAAU;CAMpC,OAJI,IACK,kBAAC,GAAD,CAAY,CAAA,IAInB,kBAAC,EAAO,KAAR;EACE,SAAS,EAAE,QAAQ,EAAE;EACrB,SAAS,EAAE,QAAQ,EAAE;EACrB,OAAO,EAAE,SAAS,GAAI;EACtB,YAAY,EAAO;YAEnB,kBAAC,GAAD,CAAY,CAAA;CACF,CAAA;AAEhB,CAAC;AAED,EAAa,cAAc;;;ACxB3B,IAAM,IAAY,EAAM,KAAK,SAAmB,EAC9C,WAC2C;CAC3C,OACE,kBAAC,GAAD;EAAO,OAAM;EAAO,SAAQ;EAAS,MAAK;YACvC,EAAK;CACD,CAAA;AAEX,CAAC;AAED,EAAU,cAAc;;;ACCxB,SAAS,IAAc;CACrB,OACE,kBAAC,EAAO,MAAR;EACE,WAAU;EACV,SAAS,EAAE,QAAQ,IAAI;EACvB,YAAY;GAAE,QAAQ;GAAU,UAAU;GAAG,MAAM;EAAS;EAC5D,eAAY;EACZ,eAAY;CACb,CAAA;AAEL;AAGA,SAAS,EAAS,EAAE,aAAgD;CAClE,QAAQ,GAAR;EACE,KAAK,QACH,OACE,kBAAC,QAAD;GAAM,eAAY;aAChB,kBAAC,GAAD;IAAM,MAAM;IAAiB,MAAK;IAAK,WAAU;GAAmB,CAAA;EAChE,CAAA;EAEV,KAAK,UACH,OAAO,kBAAC,GAAD,CAAc,CAAA;EACvB,KAAK,SACH,OACE,kBAAC,QAAD;GAAM,eAAY;aAChB,kBAAC,GAAD;IAAM,MAAM;IAAa,MAAK;IAAK,WAAU;GAAiB,CAAA;EAC1D,CAAA;EAGV,SACE,OACE,kBAAC,QAAD;GAAM,eAAY;aAChB,kBAAC,GAAD;IAAM,MAAM;IAAY,MAAK;IAAK,WAAU;GAAqC,CAAA;EAC7E,CAAA;CAEZ;AACF;AAEA,IAAM,IAAe,EAAM,KAAK,SAAsB,EACpD,WACwC;CACxC,IAAM,EAAE,qBAAkB,EAAU,GAC9B,IAAY;CAGlB,IAAI,EAAK,SAAS,MAAM;EACtB,IAAM,IAAY,KAAK,IAAI,GAAG,EAAK,KAAK;EACxC,OACE,kBAAC,OAAD;GACE,MAAK;GACL,aAAU;GACV,cAAW;GACX,WAAU;aAJZ,CAMG,MAAM,KAAK,EAAE,QAAQ,EAAU,CAAC,CAAC,CAAC,KAAK,GAAG,MACzC,kBAAC,GAAD;IAEE,WAAU;IACV,WAAW,EACT,OACA,MAAM,IAAY,IAAI,UAAU,QAClC;GACD,GANM,CAMN,CACF,GACD,kBAAC,QAAD;IAAM,WAAU;cAAU;GAAa,CAAA,CACpC;;CAET;CA0CA,OAvCI,EAAK,QAEL,kBAAC,OAAD;EACE,MAAK;EACL,aAAU;EACV,cAAW;EACX,WAAU;YAJZ,CAMG,EAAK,MAAM,KAAK,GAAM,MACrB,kBAAC,EAAO,KAAR;GAEE,WAAU;GACV,SAAS,IAAY,KAAA,IAAY;IAAE,SAAS;IAAG,GAAG;GAAG;GACrD,SAAS;IAAE,SAAS;IAAG,GAAG;GAAE;GAC5B,YACE,IACI,EAAE,UAAU,EAAE,IACd;IAAE,UAAU,EAAU;IAAa,OAAO,IAAQ;GAAK;aAR/D,CAWE,kBAAC,GAAD,EAAU,QAAQ,EAAK,OAAS,CAAA,GAChC,kBAAC,QAAD;IACE,WAAW,EACT,gBACA,EAAK,WAAW,UAAU,EAAK,WAAW,WACtC,oBACA,wBACN;cAEC,EAAK;GACF,CAAA,CACI;KArBL,EAAK,EAqBA,CACb,GACD,kBAAC,QAAD;GAAM,WAAU;aAAU;EAAgB,CAAA,CACvC;MAMP,kBAAC,OAAD;EAAK,MAAK;EAAS,aAAU;EAAO,cAAW;YAC7C,kBAAC,QAAD;GAAM,WAAU;aAAU;EAAa,CAAA;CACpC,CAAA;AAET,CAAC;AAED,EAAa,cAAc;;;AC7H3B,IAAM,IAAe,EAAM,KAAK,SAAsB,EACpD,WACwC;CACxC,IAAM,EAAE,qBAAkB,EAAU,GAC9B,IAAQ,EAAK,SAAS,CAAC;CAI7B,OAFI,EAAM,WAAW,IAAU,OAG7B,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAM,KAAK,GAAM,MAAU;GAC1B,IAAM,IAAQ,EAAK,SACf;IACE,OAAO,EAAK,OAAO;IACnB,WAAW,EAAK,OAAO;GACzB,IACA,KAAA;GAcJ,OAZI,IAEA,kBAAC,OAAD;IAAsB,WAAU;cAC9B,kBAAC,GAAD;KACE,OAAO,EAAK;KACZ,OAAO,EAAK;KACL;IACR,CAAA;GACE,GANK,EAAK,KAMV,IAKP,kBAAC,EAAO,KAAR;IAEE,WAAU;IACV,SAAS,EAAE,GAAG,EAAE;IAChB,SAAS;KAAE,SAAS;KAAG,GAAG;IAAE;IAC5B,YAAY;KAAE,GAAG,EAAQ;KAAY,OAAO,IAAQ;IAAK;cAEzD,kBAAC,GAAD;KACE,OAAO,EAAK;KACZ,OAAO,EAAK;KACL;IACR,CAAA;GACS,GAXL,EAAK,KAWA;EAEhB,CAAC;CACE,CAAA;AAET,CAAC;AAED,EAAa,cAAc;;;ACjD3B,IAAM,IAAuB,KAEvB,IAAe,EAAM,KAAK,SAAsB,EACpD,SACA,YACA,eACA,eACwC;CACxC,IAAM,EAAE,qBAAkB,EAAU,GAC9B,IAAY,GACZ,IAAc,EAAK,eAAe,GAClC,CAAC,GAAW,KAAgB,EAAM,SAAS,CAAW,GACtD,CAAC,GAAU,KAAe,EAAM,SAAS,CAAC,CAAC,EAAK,QAAQ;CAE9D,EAAM,gBAAgB;EACpB,IAAI,CAAC,EAAK,UAAU;EAEpB,IAAM,IAAW,kBAAkB;GACjC,GAAc,MAAS;IACrB,IAAM,IAAO,IAAO;IAMpB,OALI,KAAQ,KACV,cAAc,CAAQ,GACtB,EAAY,EAAK,GACV,KAEF;GACT,CAAC;EACH,GAAG,GAAG;EAEN,aAAa,cAAc,CAAQ;CACrC,GAAG,CAAC,EAAK,UAAU,CAAW,CAAC;CAE/B,IAAM,IAAa,EAAM,kBAAkB;EACzC,IAAW,KAAW,WAAW,MAAM;CACzC,GAAG,CAAC,GAAS,CAAQ,CAAC,GAEhB,IAAmB,KAAK,KAAK,IAAY,GAAI,GAM7C,IAAoB,IAAI,KAAK,KAAK;CAExC,OACE,kBAAC,GAAD;EAAwB;YAAxB,CACE,kBAAC,GAAD;GACE,OAAM;GACN,SAAQ;GACR,OAAO,EAAK;aAEX,EAAK;EACD,CAAA,GAEN,KAAY,EAAK,YAChB,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IACE,SAAQ;IACR,MAAK;IACL,SAAS;IACT,cAAY,gBAAgB,EAAiB;cAE7C,kBAAC,QAAD;KAAM,WAAU;eAAhB,CACE,kBAAC,OAAD;MACE,OAAO;MACP,QAAQ;MACR,SAAS;MACT,WAAU;MACV,eAAY;gBALd,CAOE,kBAAC,UAAD;OACE,IAAI,KAAW;OACf,IAAI,KAAW;OACf,GAAG;OACH,MAAK;OACL,QAAO;OACP,aAAa;OACb,SAAS;MACV,CAAA,GACD,kBAAC,EAAO,QAAR;OACE,IAAI,KAAW;OACf,IAAI,KAAW;OACf,GAAG;OACH,MAAK;OACL,QAAO;OACP,aAAa;OACb,iBAAiB;OACjB,SAAS,IAAY,KAAA,IAAY,EAAE,kBAAkB,EAAE;OACvD,SAAS,EACP,kBAAkB,EACpB;OACA,YACE,IACI,EAAE,UAAU,EAAE,IACd;QACE,UAAU,IAAc;QACxB,MAAM;OACR;MAEP,CAAA,CACE;SAAC,MAEF;;GACA,CAAA;EACL,CAAA,CAGG;;AAEhB,CAAC;AAED,EAAa,cAAc"}
|
|
1
|
+
{"version":3,"file":"success.js","names":[],"sources":["../../src/ai/blocks/block-table.tsx","../../src/ai/blocks/confirm.tsx","../../src/ai/blocks/divider.tsx","../../src/ai/blocks/info.tsx","../../src/ai/blocks/loading.tsx","../../src/ai/blocks/stat-row.tsx","../../src/ai/blocks/success.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'\nimport { BlockShell } from './block-shell'\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 <BlockShell confidence={confidence} className=\"overflow-x-auto\">\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-panel-hover transition-colors\"\n {...motionProps}\n >\n {columns.map((col) => (\n <TableCell\n key={col.key}\n className={cn(\n 'text-body-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 </BlockShell>\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 type { BlockComponentProps, ConfirmBlockData } from '../types'\nimport { BlockShell } from './block-shell'\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 <BlockShell confidence={confidence}>\n {data.description && (\n <p className=\"text-body-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-caption text-surface-fg-subtle underline cursor-pointer\"\n >\n Why this action?\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <p className=\"text-body-sm text-surface-fg-muted mt-2 p-3 bg-surface-panel rounded-surface\">\n {data.rationale}\n </p>\n </CollapsibleContent>\n </Collapsible>\n )}\n </BlockShell>\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'\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-body-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={{ 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 type { BlockComponentProps, SuccessBlockData } from '../types'\nimport { BlockShell } from './block-shell'\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 <BlockShell confidence={confidence}>\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 </BlockShell>\n )\n})\n\nSuccessBlock.displayName = 'SuccessBlock'\n\nexport { SuccessBlock }\n"],"mappings":"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"}
|
|
@@ -175,7 +175,7 @@ var _ = a.forwardRef(({ itemId: o, label: s, icon: d, secondaryLabel: f, actions
|
|
|
175
175
|
onClick: w,
|
|
176
176
|
onKeyDown: E,
|
|
177
177
|
style: { paddingLeft: `calc(${_} * var(--spacing-ds-05b) + var(--spacing-ds-03))` },
|
|
178
|
-
className: t("flex items-center gap-ds-02 py-ds-02 px-ds-02 rounded-control cursor-pointer transition-colors duration-fast-01", "hover:bg-surface-
|
|
178
|
+
className: t("flex items-center gap-ds-02 py-ds-02 px-ds-02 rounded-control cursor-pointer transition-colors duration-fast-01", "hover:bg-surface-panel-hover", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9", C && "bg-accent-3 text-accent-11", h && "opacity-action-disabled cursor-not-allowed pointer-events-none", v),
|
|
179
179
|
children: [
|
|
180
180
|
x ? /* @__PURE__ */ c("button", {
|
|
181
181
|
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\nimport type { IconInput } from '../lib/icon-input'\n\nexport interface TreeNode {\n id: string\n label: string\n icon?: IconInput\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 { IconProvider } from '../icon-context'\nimport type { IconInput } from '../lib/icon-input'\nimport { normalizeIcon } from '../lib/normalize-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. Accepts any `IconInput`. */\n icon?: IconInput\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 <IconProvider size=\"sm\">{normalizeIcon(icon)}</IconProvider>\n </span>\n )}\n\n {/* Label */}\n <span className=\"min-w-0 truncate text-body-sm\">{label}</span>\n\n {/* Secondary label */}\n {secondaryLabel && (\n <span className=\"ml-auto truncate text-caption 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":";;;;;;;;;;AAoBA,SAAgB,EAAQ,IAA0B,CAAC,GAAG;CACpD,IAAM,EAAE,oBAAiB,oBAAiB,gBAAa,aAAU,gBAAa,GAExE,CAAC,GAAU,KAAe,EAC9B,IAAI,IAAI,KAAmB,CAAC,CAAC,CAC/B,GACM,CAAC,GAAU,KAAe,EAC9B,IAAI,IAAI,KAAmB,CAAC,CAAC,CAC/B;CAiCA,OAAO;EACL;EACA;EACA,QAlCa,GACZ,MAAe;GACd,GAAa,MAAS;IACpB,IAAM,IAAO,IAAI,IAAI,CAAI;IAIzB,OAHI,EAAK,IAAI,CAAE,IAAG,EAAK,OAAO,CAAE,IAC3B,EAAK,IAAI,CAAE,GAChB,IAAW,MAAM,KAAK,CAAI,CAAC,GACpB;GACT,CAAC;EACH,GACA,CAAC,CAAQ,CAwBT;EACA,QAtBa,GACZ,GAAY,MAA6B;GACxC,GAAa,MAAS;IACpB,IAAI;IASJ,OARI,KAAe,GAAO,WACxB,IAAO,IAAI,IAAI,CAAI,GACf,EAAK,IAAI,CAAE,IAAG,EAAK,OAAO,CAAE,IAC3B,EAAK,IAAI,CAAE,KAEhB,oBAAO,IAAI,IAAI,CAAC,CAAE,CAAC,GAErB,IAAW,MAAM,KAAK,CAAI,CAAC,GACpB;GACT,CAAC;EACH,GACA,CAAC,GAAa,CAAQ,CAOtB;EACA,aAAa,MAAe,EAAS,IAAI,CAAE;EAC3C,aAAa,MAAe,EAAS,IAAI,CAAE;EAC3C,YAAY,MAAkB,EAAY,IAAI,IAAI,CAAG,CAAC;EACtD,mBAAmB,kBAAY,IAAI,IAAI,CAAC;CAC1C;AACF;;;ACzDA,IAAM,IAAc,EAAM,cAAuC,IAAI;AAErE,SAAgB,IAAiB;CAC/B,IAAM,IAAM,EAAM,WAAW,CAAW;CACxC,IAAI,CAAC,GACH,MAAU,MAAM,2CAA2C;CAE7D,OAAO;AACT;AAwBA,SAAS,EAAY,GAAmB,IAAgB,GAAoB;CAC1E,OAAO,EAAM,KAAK,MAChB,kBAAC,GAAD;EAEE,QAAQ,EAAK;EACb,OAAO,EAAK;EACZ,MAAM,EAAK;EACX,UAAU,EAAK;EACR;YAEN,EAAK,YAAY,EAAK,SAAS,SAAS,IACrC,EAAY,EAAK,UAAU,IAAQ,CAAC,IACpC,KAAA;CACI,GAVH,EAAK,EAUF,CACX;AACH;AAGA,SAAS,EAAuB,GAAuC;CACrE,OAAO,MAAM,KACX,EAAU,iBAA8B,kBAAkB,CAC5D,CAAC,CAAC,QAAQ,MAAO;EAEf,IAAI,IAAS,EAAG;EAChB,OAAO,KAAU,MAAW,IAAW;GACrC,IAAI,EAAO,aAAa,MAAM,MAAM,SAAS;IAC3C,IAAM,IAAO,EAAO;IACpB,IAAI,KAAQ,EAAK,UAAU,SAAS,iBAAiB,GACnD,OAAO;GAEX;GACA,IAAS,EAAO;EAClB;EACA,OAAO;CACT,CAAC;AACH;AAGA,IAAM,IAAW,EAAM,YAEnB,EACE,UACA,oBACA,oBACA,iBAAc,IACd,gBAAa,IACb,aACA,aACA,cACA,aACA,GAAG,KAEL,MACG;CACH,IAAM,IAAO,EAAQ;EACnB;EACA;EACA;EACA;EACA;CACF,CAAC,GAEK,IAAW,EAAM,OAAyB,IAAI,GAC9C,IAAgB,KAA6C,GAE7D,KAAiB,MAA6C;EAClE,IAAM,IAAY,EAAa;EAC/B,IAAI,CAAC,GAAW;EAEhB,IAAM,IAAe,EAAuB,CAAS,GAC/C,IAAe,EAAa,WAC/B,MAAO,MAAO,SAAS,aAC1B;EAEA,QAAQ,EAAE,KAAV;GACE,KAAK;IAGH,AAFA,EAAE,eAAe,GAEjB,EAD0B,IAAe,EACzC,EAAM,MAAM;IACZ;GAEF,KAAK;IAGH,AAFA,EAAE,eAAe,GAEjB,EAD0B,IAAe,EACzC,EAAM,MAAM;IACZ;GAEF,KAAK,cAAc;IAEjB,IAAM,IAAU,EAAa;IAC7B,IAAI,GAAS;KACX,IAAM,IAAS,EAAQ,aAAa,gBAAgB;KACpD,AAAI,KAAU,EAAK,WAAW,CAAM,MAClC,EAAE,eAAe,GAEjB,EAD8B,IAAe,EAC7C,EAAU,MAAM;IAEpB;IACA;GACF;GACA,KAAK,aAAa;IAEhB,IAAM,IAAU,EAAa;IAC7B,IAAI,GAAS;KACX,IAAM,IAAS,EAAQ,aAAa,gBAAgB,GAE9C,IADW,EAAQ,QAAQ,qBACb,CAAA,EAAU,eAAe,QAC3C,qBACF;KACA,AAAI,KAAU,CAAC,EAAK,WAAW,CAAM,KAAK,MACxC,EAAE,eAAe,GAIjB,EAH8B,cAC5B,kBAEF,CAAA,EAAW,MAAM;IAErB;IACA;GACF;GACA,KAAK;IAEH,AADA,EAAE,eAAe,GACjB,EAAa,EAAE,EAAE,MAAM;IACvB;GAEF,KAAK;IAEH,AADA,EAAE,eAAe,GACjB,EAAa,EAAa,SAAS,EAAE,EAAE,MAAM;IAC7C;EAEJ;CACF,GAEM,IAAW,EAAM,eACd;EAAE;EAAM;CAAW,IAC1B,CAAC,GAAM,CAAU,CACnB,GAEM,IAAU,IAAQ,EAAY,CAAK,IAAI;CAE7C,OACE,kBAAC,EAAY,UAAb;EAAsB,OAAO;YAC3B,kBAAC,MAAD;GACE,KAAK;GACL,MAAK;GACL,wBAAsB,KAAe,KAAA;GACrC,WAAW;GACX,WAAW,EAAG,qBAAqB,CAAS;GAC5C,GAAI;aAEH;EACC,CAAA;CACgB,CAAA;AAE1B,CACF;AACA,EAAS,cAAc;;;ACvKvB,IAAM,IAAW,EAAM,YAEnB,EACE,WACA,UACA,SACA,mBACA,YACA,cAAW,IACX,aACA,WAAQ,GACR,gBAEF,MACG;CACH,IAAM,IAAM,EAAe,GACrB,IAAc,EAAM,SAAS,MAAM,CAAQ,IAAI,GAC/C,IAAa,EAAI,KAAK,WAAW,CAAM,GACvC,IAAa,EAAI,KAAK,WAAW,CAAM,GAEvC,KAAkB,MAAwC;EAC1D,KACJ,EAAI,KAAK,OAAO,GAAQ,CAAC;CAC3B,GAEM,KAAsB,MAA2C;EACrE,EAAE,gBAAgB,GACd,MACJ,EAAI,KAAK,OAAO,CAAM;CACxB,GAEM,KAAiB,MAA2C;EAC5D,OACA,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,eAAe,GACjB,EAAI,KAAK,OAAO,CAAM,IAEpB,EAAE,QAAQ,gBAAgB,KAAe,CAAC,MAC5C,EAAE,eAAe,GACjB,EAAE,gBAAgB,GAClB,EAAI,KAAK,OAAO,CAAM,IAEpB,EAAE,QAAQ,eAAe,KAAe,MAC1C,EAAE,eAAe,GACjB,EAAE,gBAAgB,GAClB,EAAI,KAAK,OAAO,CAAM;CAE1B,GAGM,IAAgB,EAAM,cAAc;EACxC,IAAI,CAAC,EAAI,cAAc,CAAC,GACtB,OAAO;GAAE,SAAS;GAAY,eAAe;EAAM;EAGrD,IAAM,IAAwB,CAAC,GACzB,KAAc,MAA2B;GAC7C,EAAM,SAAS,QAAQ,IAAQ,MAAU;IACvC,AAAI,EAAM,eAA8B,CAAK,KAAK,EAAM,MAAM,WAC5D,EAAY,KAAK,EAAM,MAAM,MAAM,GAC/B,EAAM,MAAM,YACd,EAAW,EAAM,MAAM,QAAQ;GAGrC,CAAC;EACH;EACA,EAAW,CAAQ;EACnB,IAAM,IAAgB,EAAY,QAAQ,MACxC,EAAI,KAAK,WAAW,CAAE,CACxB,CAAC,CAAC;EAOF,OANI,MAAkB,KAAK,CAAC,IACnB;GAAE,SAAS;GAAO,eAAe;EAAM,IAE5C,MAAkB,EAAY,SACzB;GAAE,SAAS;GAAM,eAAe;EAAM,IAExC;GAAE,SAAS;GAAO,eAAe;EAAK;CAC/C,GAAG;EAAC,EAAI;EAAY;EAAa;EAAU;EAAY,EAAI;CAAI,CAAC;CAEhE,OACE,kBAAC,MAAD;EACO;EACL,MAAK;EACL,iBAAe,IAAc,IAAa,KAAA;EAC1C,iBAAe;EACf,cAAY,IAAQ;EACpB,iBAAe,KAAY,KAAA;EAC3B,WAAU;YAPZ,CAUE,kBAAC,OAAD;GACE,MAAK;GACL,kBAAgB;GAChB,UAAU,IAAW,KAAK;GAC1B,SAAS;GACT,WAAW;GACX,OAAO,EAAE,aAAa,QAAQ,EAAM,kDAAkD;GACtF,WAAW,EACT,mHACA,2BACA,iFACA,KACE,8BACF,KAAY,kEACZ,CACF;aAfF;IAkBG,IACC,kBAAC,UAAD;KACE,MAAK;KACL,UAAU;KACV,eAAY;KACZ,SAAS;KACT,WAAU;eAEV,kBAAC,GAAD;MACE,MAAM;MACN,MAAK;MACL,WAAW,EACT,6CACA,KAAc,WAChB;KACD,CAAA;IACK,CAAA,IAER,kBAAC,QAAD;KAAM,WAAU;KAA4B,eAAY;IAAQ,CAAA;IAIjE,EAAI,cACH,kBAAC,GAAD;KACE,SAAS,EAAc;KACvB,eAAe,EAAc;KACnB;KACV,UAAU;KACV,UAAU,MAAM,EAAE,gBAAgB;KAClC,uBAAuB;MACrB,AAAK,KAAU,EAAI,KAAK,OAAO,CAAM;KACvC;KACA,WAAU;IACX,CAAA;IAIF,KACC,kBAAC,QAAD;KAAM,WAAU;eACd,kBAAC,GAAD;MAAc,MAAK;gBAAM,EAAc,CAAI;KAAgB,CAAA;IACvD,CAAA;IAIR,kBAAC,QAAD;KAAM,WAAU;eAAiC;IAAY,CAAA;IAG5D,KACC,kBAAC,QAAD;KAAM,WAAU;eACb;IACG,CAAA;IAIP,KACC,kBAAC,QAAD;KACE,WAAU;KACV,UAAU,MAAM,EAAE,gBAAgB;KAClC,MAAK;eAEJ;IACG,CAAA;GAEL;MAGJ,KACC,kBAAC,OAAD;GACE,MAAK;GACL,WAAW,EACT,sFACA,IAAa,oBAAoB,iBACnC;aAEA,kBAAC,MAAD;IAAI,MAAK;IAAQ,WAAU;cACxB,EAAM,SAAS,IAAI,IAAW,MACzB,EAAM,eAA8B,CAAK,IACpC,EAAM,aAAa,GAAO,EAC/B,OAAO,IAAQ,EACjB,CAAC,IAEI,CACR;GACC,CAAA;EACD,CAAA,CAEL;;AAER,CACF;AACA,EAAS,cAAc"}
|
|
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\nimport type { IconInput } from '../lib/icon-input'\n\nexport interface TreeNode {\n id: string\n label: string\n icon?: IconInput\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 { IconProvider } from '../icon-context'\nimport type { IconInput } from '../lib/icon-input'\nimport { normalizeIcon } from '../lib/normalize-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. Accepts any `IconInput`. */\n icon?: IconInput\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-panel-hover',\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 <IconProvider size=\"sm\">{normalizeIcon(icon)}</IconProvider>\n </span>\n )}\n\n {/* Label */}\n <span className=\"min-w-0 truncate text-body-sm\">{label}</span>\n\n {/* Secondary label */}\n {secondaryLabel && (\n <span className=\"ml-auto truncate text-caption 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-control text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-
|
|
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-panel-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-body-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-
|
|
91
|
+
className: e("text-body-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-panel-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-control text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-
|
|
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-panel-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,7 +131,7 @@ 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-control text-body-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-
|
|
134
|
+
className: e("relative flex h-ds-sm w-ds-sm-plus items-center justify-center rounded-control text-body-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-panel-hover", l && !u && "rounded-none bg-surface-panel-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", {
|
|
@@ -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-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-body-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-label-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-body-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-ds-02 w-ds-02 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":";;;;;;;;AAyBA,IAAM,IAAW;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,GA6B7C,IAAe,EAAM,WAChC,SAAsB,EACtB,iBACA,aACA,eACA,aACA,cACA,aACA,YACA,kBACA,kBACA,kBACA,YACA,YACA,gBACA,gBACA,WACA,cACA,GAAG,KACF,GAAc;CACf,IAAM,IAAU,EAAM,OAAuB,IAAI,GAE3C,IAAe,EAAM,cAAc;EACvC,IAAM,oBAAM,IAAI,IAA6B;EAC7C,IAAI,CAAC,GAAQ,OAAO;EACpB,KAAK,IAAM,KAAO,GAAQ;GACxB,IAAM,IAAM,EAAO,EAAI,MAAM,YAAY,GACnC,IAAM,EAAI,IAAI,CAAG,KAAK,CAAC;GAE7B,AADA,EAAI,KAAK,CAAG,GACZ,EAAI,IAAI,GAAK,CAAG;EAClB;EACA,OAAO;CACT,GAAG,CAAC,CAAM,CAAC,GAEL,IAAa,EAAa,CAAY,GACtC,IAAW,EAAW,CAAY,GAClC,IAAgB,EAAY,CAAU,GACtC,IAAc,EAAU,CAAQ,GAEhC,IAAe,CAAC,GAClB,IAAM;CACV,OAAO,KAAO,IAEZ,AADA,EAAK,KAAK,CAAG,GACb,IAAM,EAAQ,GAAK,CAAC;CAGtB,IAAM,KAAkB,MAGtB,GAFI,IAAgB,CAAI,KACpB,KAAW,EAAS,GAAM,EAAW,CAAO,CAAC,KAC7C,KAAW,EAAQ,GAAM,EAAW,CAAO,CAAC,IAI5C,KAAa,MACb,KAAc,IAGT,EAAiB,GAAM;EAAE,OAFlB,EAAS,GAAY,CAAQ,IAAI,IAAa;EAErB,KAD3B,EAAQ,GAAU,CAAU,IAAI,IAAW;CACZ,CAAC,IAE1C,KAAc,IAGT,EAAiB,GAAM;EAAE,OAFlB,EAAS,GAAY,CAAS,IAAI,IAAa;EAEtB,KAD3B,EAAQ,GAAW,CAAU,IAAI,IAAY;CACd,CAAC,IAEvC,IAGH,KAAe,MAEnB,GADI,KAAc,EAAU,GAAM,CAAU,KACxC,KAAY,EAAU,GAAM,CAAQ,IAIpC,KAAa,MAAiB;EAClC,IAAI,CAAC,EAAQ,SAAS;EACtB,IAAM,IAAU,EAAO,GAAQ,YAAY,GACrC,IAAM,EAAQ,QAAQ,cAC1B,eAAe,EAAQ,GACzB;EACA,AAAI,IACF,EAAI,MAAM,IAGV,EAAc,EAAa,CAAM,CAAC;CAEtC,GAEM,KAAiB,MAA2C;EAEhE,IAAM,IADS,EAAE,OACM,aAAa,WAAW;EAC/C,IAAI,CAAC,GAAS;EAEd,IAAM,oBAAU,IAAI,KAAK,IAAU,WAAW,GAC1C,IAAoB;EAExB,QAAQ,EAAE,KAAV;GACE,KAAK;IACH,IAAO,EAAQ,GAAS,EAAE;IAC1B;GACF,KAAK;IACH,IAAO,EAAQ,GAAS,CAAC;IACzB;GACF,KAAK;IACH,IAAO,EAAQ,GAAS,EAAE;IAC1B;GACF,KAAK;IACH,IAAO,EAAQ,GAAS,CAAC;IACzB;GACF,KAAK;IACH,IAAO,EAAa,CAAO;IAC3B;GACF,KAAK;IACH,IAAO,EAAe,CAAO;IAC7B;GACF,KAAK;GACL,KAAK;IAEH,AADA,EAAE,eAAe,GACb,CAAC,EAAe,CAAO,KAAK,EAAY,GAAS,CAAY,KAC/D,EAAS,CAAO;IAElB;GAEF,SACE;EACJ;EAEA,AAAI,MACF,EAAE,eAAe,GACjB,EAAU,CAAI;CAElB;CAEA,OACE,kBAAC,OAAD;EAAK,KAAK;EAAc,GAAI;EAAO,WAAW,EAAG,aAAa,CAAS;YAAvE,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACG,IACC,kBAAC,QAAD,EAAM,WAAU,4BAA6B,CAAA,IAE7C,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAc,EAAU,GAAc,CAAC,CAAC;KACvD,WAAU;KACV,cAAW;eAEX,kBAAC,GAAD;MAAM,MAAM;MAAiB,MAAK;MAAK,QAAO;KAAS,CAAA;IACjD,CAAA;IAEV,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAW,EACT,8CACA,KACE,mIACJ;KACA,cAAW;eAEV,EAAO,GAAc,WAAW;IAC3B,CAAA;IACP,IACC,kBAAC,QAAD,EAAM,WAAU,4BAA6B,CAAA,IAE7C,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAc,EAAU,GAAc,CAAC,CAAC;KACvD,WAAU;KACV,cAAW;eAEX,kBAAC,GAAD;MAAM,MAAM;MAAkB,MAAK;MAAK,QAAO;KAAS,CAAA;IAClD,CAAA;GAEP;MAEL,kBAAC,OAAD;GACE,KAAK;GACL,WAAU;GACV,MAAK;GACL,UAAU;GACV,cAAW;GACX,WAAW;aANb,CAQG,EAAS,KAAK,MACb,kBAAC,OAAD;IAEE,MAAK;IACL,WAAU;cAET;GACE,GALE,CAKF,CACN,GAEA,EAAK,KAAK,GAAG,MAAM;IAClB,IAAM,IAAU,EAAY,GAAG,CAAY,GACrC,IAAW,EAAe,CAAC,GAC3B,IAAa,KAAY,EAAU,GAAG,CAAQ,GAC9C,IAAU,EAAU,CAAC,GACrB,IAAO,EAAY,CAAC,GACpB,IAAU,EAAU,mBAAG,IAAI,KAAK,CAAC,GACjC,IAAU,EAAO,GAAG,YAAY,GAChC,IAAY,EAAa,IAAI,CAAO,KAAK,CAAC;IAEhD,OACE,kBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,aAAW;KACX,UAAU,KAAW,CAAC,IAAW,IAAI;KACrC,UAAU,CAAC,KAAW;KACtB,eAAe;MACb,AAAI,KAAW,CAAC,KAAU,EAAS,CAAC;KACtC;KACA,oBAAoB,IAAU,CAAC;KAC/B,oBAAoB,IAAU,IAAI;KAClC,cAAY,EAAO,GAAG,oBAAoB;KAC1C,iBAAe,KAAc,KAAQ,KAAA;KACrC,iBAAe,CAAC,KAAW,KAAY,KAAA;KACvC,WAAW,EACT,qKACA,CAAC,KAAW,iCACZ,KAAW,KAAY,kEACvB,KAAW,CAAC,KAAY,CAAC,KAAc,CAAC,KAAQ,CAAC,KAC/C,iDACF,KAAW,CAAC,KACV,yDACD,KAAc,MACb,iDACF,KAAW,CAAC,KAAc,CAAC,KAAQ,CAAC,KAClC,8BACJ;eA3BF,CA6BG,EAAO,GAAG,GAAG,GACb,EAAU,SAAS,KAClB,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAU,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,GAAK,MAC/B,kBAAC,QAAD;OAEE,kBAAA;OACA,WAAU;OACV,OAAO,EAAE,iBAAiB,EAAI,SAAS,wBAAwB;MAChE,GAJM,CAIN,CACF;KACG,CAAA,CAEF;OAzCD,CAyCC;GAEZ,CAAC,CACE;IACF;;AAET,CACA;AAEA,EAAa,cAAc;;;AC9S3B,SAAgB,EAAY,GAAqB;CAC/C,IAAM,CAAC,GAAc,KAAmB,EAAS,qBAAgB,IAAI,KAAK,CAAC;CAS3E,OAAO;EACL;EACA;EACA,yBAV8B,GAAiB,MAAS,EAAU,GAAM,CAAC,CAAC;EAW1E,qBAV0B,GAAiB,MAAS,EAAU,GAAM,CAAC,CAAC;EAWtE,YAViB,MACjB,GAAiB,MAAS,EAAS,GAAM,CAAK,CAAC;EAU/C,WATgB,MAChB,GAAiB,MAAS,EAAQ,GAAM,CAAI,CAAC;CAS/C;AACF"}
|
|
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-panel-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-body-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-panel-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-panel-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-label-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-body-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-panel-hover',\n inRange && !edge &&\n 'rounded-none bg-surface-panel-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-ds-02 w-ds-02 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/blocks/text.js
CHANGED
|
@@ -8,7 +8,7 @@ import i from "remark-gfm";
|
|
|
8
8
|
var a = t.memo(function({ data: t, confidence: a }) {
|
|
9
9
|
return /* @__PURE__ */ n(e, {
|
|
10
10
|
confidence: a,
|
|
11
|
-
className: "prose prose-sm text-surface-fg prose-headings:text-surface-fg prose-a:text-accent-11 prose-a:underline prose-code:text-accent-11 prose-code:bg-surface-
|
|
11
|
+
className: "prose prose-sm text-surface-fg prose-headings:text-surface-fg prose-a:text-accent-11 prose-a:underline prose-code:text-accent-11 prose-code:bg-surface-panel prose-code:rounded prose-code:px-1 prose-strong:text-surface-fg",
|
|
12
12
|
children: /* @__PURE__ */ n(r, {
|
|
13
13
|
remarkPlugins: [i],
|
|
14
14
|
children: t.content
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","names":[],"sources":["../../../src/ai/blocks/text.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nimport type { BlockComponentProps } from '../types'\nimport { BlockShell } from './block-shell'\n\nconst TextBlock = React.memo(function TextBlock({\n data,\n confidence,\n}: BlockComponentProps<{ content: string }>) {\n return (\n <BlockShell\n confidence={confidence}\n className=\"prose prose-sm text-surface-fg prose-headings:text-surface-fg prose-a:text-accent-11 prose-a:underline prose-code:text-accent-11 prose-code:bg-surface-
|
|
1
|
+
{"version":3,"file":"text.js","names":[],"sources":["../../../src/ai/blocks/text.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nimport type { BlockComponentProps } from '../types'\nimport { BlockShell } from './block-shell'\n\nconst TextBlock = React.memo(function TextBlock({\n data,\n confidence,\n}: BlockComponentProps<{ content: string }>) {\n return (\n <BlockShell\n confidence={confidence}\n className=\"prose prose-sm text-surface-fg prose-headings:text-surface-fg prose-a:text-accent-11 prose-a:underline prose-code:text-accent-11 prose-code:bg-surface-panel prose-code:rounded prose-code:px-1 prose-strong:text-surface-fg\"\n >\n <Markdown remarkPlugins={[remarkGfm]}>{data.content}</Markdown>\n </BlockShell>\n )\n})\n\nTextBlock.displayName = 'TextBlock'\n\nexport { TextBlock }\n"],"mappings":";;;;;;;AASA,IAAM,IAAY,EAAM,KAAK,SAAmB,EAC9C,SACA,iBAC2C;CAC3C,OACE,kBAAC,GAAD;EACc;EACZ,WAAU;YAEV,kBAAC,GAAD;GAAU,eAAe,CAAC,CAAS;aAAI,EAAK;EAAkB,CAAA;CACpD,CAAA;AAEhB,CAAC;AAED,EAAU,cAAc"}
|
package/dist/ai/command-bar.js
CHANGED
|
@@ -213,7 +213,7 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
213
213
|
}) : Be ? /* @__PURE__ */ u("button", {
|
|
214
214
|
type: "button",
|
|
215
215
|
onClick: ze,
|
|
216
|
-
className: "shrink-0 rounded-control-inner p-ds-01 text-surface-fg-subtle transition-colors duration-fast-01 hover:bg-surface-
|
|
216
|
+
className: "shrink-0 rounded-control-inner p-ds-01 text-surface-fg-subtle transition-colors duration-fast-01 hover:bg-surface-panel-hover hover:text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9",
|
|
217
217
|
"aria-label": "Clear",
|
|
218
218
|
title: "Clear",
|
|
219
219
|
children: /* @__PURE__ */ u(i, {
|
|
@@ -226,7 +226,7 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
226
226
|
animate: { opacity: 1 },
|
|
227
227
|
exit: H ? void 0 : { opacity: 0 },
|
|
228
228
|
transition: J,
|
|
229
|
-
className: "hidden shrink-0 select-none rounded-control border border-card-strong bg-surface-
|
|
229
|
+
className: "hidden shrink-0 select-none rounded-control border border-card-strong bg-surface-panel px-ds-02b py-ds-01 text-body-sm font-medium text-surface-fg-subtle shadow-kbd sm:inline-flex",
|
|
230
230
|
children: [se(Ne), "J"]
|
|
231
231
|
}) }) : null
|
|
232
232
|
]
|
|
@@ -285,7 +285,7 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
285
285
|
n.onSelect(), g === "floating" && N(!1);
|
|
286
286
|
},
|
|
287
287
|
onMouseEnter: () => L(a),
|
|
288
|
-
className: r("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", s ? "bg-surface-
|
|
288
|
+
className: r("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", s ? "bg-surface-panel-hover text-surface-fg" : "text-surface-fg-muted hover:bg-surface-panel-hover"),
|
|
289
289
|
children: [
|
|
290
290
|
n.icon && /* @__PURE__ */ u("span", {
|
|
291
291
|
className: r("[&>svg]:h-ico-sm [&>svg]:w-ico-sm shrink-0 transition-colors duration-fast-02 ease-productive-standard", s ? "text-accent-11" : "text-surface-fg-subtle"),
|
|
@@ -326,7 +326,7 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
326
326
|
return g === "hero" ? /* @__PURE__ */ d("div", {
|
|
327
327
|
ref: k,
|
|
328
328
|
role: "search",
|
|
329
|
-
className: r("bg-surface-
|
|
329
|
+
className: r("bg-surface-panel rounded-overlay-lg shadow-raised p-ds-07", D),
|
|
330
330
|
...O,
|
|
331
331
|
children: [
|
|
332
332
|
v && /* @__PURE__ */ u("p", {
|
|
@@ -342,7 +342,7 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
342
342
|
onClick: () => {
|
|
343
343
|
F(e), ye?.(e), B.current?.focus();
|
|
344
344
|
},
|
|
345
|
-
className: "rounded-control border border-card-strong bg-surface-overlay px-ds-03 py-ds-01 text-body-sm text-surface-fg-subtle transition-colors duration-fast-02 ease-productive-standard hover:bg-surface-
|
|
345
|
+
className: "rounded-control border border-card-strong bg-surface-overlay px-ds-03 py-ds-01 text-body-sm text-surface-fg-subtle transition-colors duration-fast-02 ease-productive-standard hover:bg-surface-panel-hover hover:text-surface-fg-muted",
|
|
346
346
|
children: e
|
|
347
347
|
}, e))
|
|
348
348
|
}),
|
|
@@ -395,14 +395,14 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
395
395
|
children: [/* @__PURE__ */ d("div", {
|
|
396
396
|
className: "flex items-center gap-ds-01",
|
|
397
397
|
children: [/* @__PURE__ */ u("kbd", {
|
|
398
|
-
className: "inline-flex h-ico-md w-ico-md items-center justify-center rounded border border-card-strong bg-surface-
|
|
398
|
+
className: "inline-flex h-ico-md w-ico-md items-center justify-center rounded border border-card-strong bg-surface-panel shadow-kbd",
|
|
399
399
|
children: /* @__PURE__ */ u(i, {
|
|
400
400
|
icon: ue,
|
|
401
401
|
size: "xs",
|
|
402
402
|
className: "text-surface-fg-subtle"
|
|
403
403
|
})
|
|
404
404
|
}), /* @__PURE__ */ u("kbd", {
|
|
405
|
-
className: "inline-flex h-ico-md w-ico-md items-center justify-center rounded border border-card-strong bg-surface-
|
|
405
|
+
className: "inline-flex h-ico-md w-ico-md items-center justify-center rounded border border-card-strong bg-surface-panel shadow-kbd",
|
|
406
406
|
children: /* @__PURE__ */ u(i, {
|
|
407
407
|
icon: le,
|
|
408
408
|
size: "xs",
|
|
@@ -417,7 +417,7 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
417
417
|
/* @__PURE__ */ d("div", {
|
|
418
418
|
className: "flex items-center gap-ds-02b",
|
|
419
419
|
children: [/* @__PURE__ */ u("kbd", {
|
|
420
|
-
className: "inline-flex h-[20px] items-center justify-center rounded-control border border-card-strong bg-surface-
|
|
420
|
+
className: "inline-flex h-[20px] items-center justify-center rounded-control border border-card-strong bg-surface-panel px-ds-02b shadow-kbd",
|
|
421
421
|
children: /* @__PURE__ */ u(i, {
|
|
422
422
|
icon: de,
|
|
423
423
|
size: "xs",
|
|
@@ -431,7 +431,7 @@ var m = c.forwardRef(function({ onSubmit: l, state: m = "idle", groups: h = [],
|
|
|
431
431
|
/* @__PURE__ */ d("div", {
|
|
432
432
|
className: "flex items-center gap-ds-02b",
|
|
433
433
|
children: [/* @__PURE__ */ u("kbd", {
|
|
434
|
-
className: "inline-flex h-[20px] items-center justify-center rounded-control border border-card-strong bg-surface-
|
|
434
|
+
className: "inline-flex h-[20px] items-center justify-center rounded-control border border-card-strong bg-surface-panel px-ds-02b text-caption font-medium text-surface-fg-subtle shadow-kbd",
|
|
435
435
|
children: "Esc"
|
|
436
436
|
}), /* @__PURE__ */ u("span", {
|
|
437
437
|
className: "text-caption text-surface-fg-subtle",
|