@devalok/shilp-sutra 0.39.0 → 0.40.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/AGENTS.md +151 -0
- package/MIGRATION.md +137 -0
- package/README.md +3 -0
- package/dist/_chunks/badge-group.js +75 -74
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chart-container.js +50 -0
- package/dist/_chunks/chart-container.js.map +1 -0
- package/dist/_chunks/chat.js +231 -223
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/colors.js +30 -0
- package/dist/_chunks/colors.js.map +1 -0
- package/dist/_chunks/emoji-data.js +45 -0
- package/dist/_chunks/emoji-data.js.map +1 -0
- package/dist/_chunks/grid-lines.js +72 -0
- package/dist/_chunks/grid-lines.js.map +1 -0
- package/dist/_chunks/mention-suggestion.js +31 -259
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/normalize-icon.js +18 -0
- package/dist/_chunks/normalize-icon.js.map +1 -0
- package/dist/_chunks/oauth-button.js +227 -0
- package/dist/_chunks/oauth-button.js.map +1 -0
- package/dist/_chunks/primitives.js +107 -107
- package/dist/_chunks/primitives.js.map +1 -1
- package/dist/_chunks/{text.js → success.js} +24 -61
- package/dist/_chunks/success.js.map +1 -0
- package/dist/_chunks/tiptap.js +1952 -1949
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tooltip.js +58 -0
- package/dist/_chunks/tooltip.js.map +1 -0
- package/dist/_chunks/tree-view.js +101 -96
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/ai/ai-command-provider.d.ts +3 -2
- package/dist/ai/ai-command-provider.d.ts.map +1 -1
- package/dist/ai/ai-command-provider.js.map +1 -1
- package/dist/ai/block-renderer.js +11 -9
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/error.js +31 -0
- package/dist/ai/blocks/error.js.map +1 -0
- package/dist/ai/blocks/index.d.ts +0 -2
- package/dist/ai/blocks/index.d.ts.map +1 -1
- package/dist/ai/blocks/index.js +2 -2
- package/dist/ai/blocks/text.js +19 -0
- package/dist/ai/blocks/text.js.map +1 -0
- package/dist/ai/command-bar.d.ts.map +1 -1
- package/dist/ai/command-bar.js +192 -187
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.d.ts +2 -1
- package/dist/ai/conversation.d.ts.map +1 -1
- package/dist/ai/conversation.js +88 -83
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/index.d.ts +0 -4
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +45 -46
- package/dist/ai/index.js.map +1 -1
- package/dist/composed/activity-feed.d.ts +2 -1
- package/dist/composed/activity-feed.d.ts.map +1 -1
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/bulk-action-bar.d.ts +2 -2
- package/dist/composed/bulk-action-bar.d.ts.map +1 -1
- package/dist/composed/bulk-action-bar.js +11 -11
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.d.ts +2 -1
- package/dist/composed/command-palette.d.ts.map +1 -1
- package/dist/composed/command-palette.js +103 -98
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/date-picker/index.js +747 -3
- package/dist/composed/date-picker/index.js.map +1 -0
- package/dist/composed/empty-state.d.ts +3 -3
- package/dist/composed/empty-state.d.ts.map +1 -1
- package/dist/composed/empty-state.js +40 -31
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/extensions/emoji-node.js +81 -0
- package/dist/composed/extensions/emoji-node.js.map +1 -0
- package/dist/composed/extensions/emoji-suggestion.js +117 -0
- package/dist/composed/extensions/emoji-suggestion.js.map +1 -0
- package/dist/composed/file-preview.js +498 -2
- package/dist/{_chunks → composed}/file-preview.js.map +1 -1
- package/dist/composed/index.d.ts +0 -15
- package/dist/composed/index.d.ts.map +1 -1
- package/dist/composed/index.js +16 -24
- package/dist/composed/rich-chat-input.js +2073 -2
- package/dist/{_chunks → composed}/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +64 -61
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/status-badge.d.ts +3 -2
- package/dist/composed/status-badge.d.ts.map +1 -1
- package/dist/composed/status-badge.js +58 -53
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/shell/app-command-palette.d.ts +2 -1
- package/dist/shell/app-command-palette.d.ts.map +1 -1
- package/dist/shell/app-command-palette.js.map +1 -1
- package/dist/shell/bottom-navbar.d.ts +3 -1
- package/dist/shell/bottom-navbar.d.ts.map +1 -1
- package/dist/shell/bottom-navbar.js +90 -82
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/command-registry.d.ts +2 -1
- package/dist/shell/command-registry.d.ts.map +1 -1
- package/dist/shell/command-registry.js.map +1 -1
- package/dist/shell/sidebar.d.ts +7 -4
- package/dist/shell/sidebar.d.ts.map +1 -1
- package/dist/shell/sidebar.js +143 -129
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.d.ts +4 -3
- package/dist/shell/top-bar.d.ts.map +1 -1
- package/dist/shell/top-bar.js +114 -106
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/ui/badge.d.ts +3 -2
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/button.d.ts +3 -2
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +54 -53
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/charts/area-chart.js +177 -0
- package/dist/ui/charts/area-chart.js.map +1 -0
- package/dist/ui/charts/bar-chart.js +127 -0
- package/dist/ui/charts/bar-chart.js.map +1 -0
- package/dist/ui/charts/chart-container.js +3 -0
- package/dist/ui/charts/gauge-chart.js +72 -0
- package/dist/ui/charts/gauge-chart.js.map +1 -0
- package/dist/ui/charts/index.js +10 -1035
- package/dist/ui/charts/line-chart.js +135 -0
- package/dist/ui/charts/line-chart.js.map +1 -0
- package/dist/ui/charts/pie-chart.js +111 -0
- package/dist/ui/charts/pie-chart.js.map +1 -0
- package/dist/ui/charts/radar-chart.js +170 -0
- package/dist/ui/charts/radar-chart.js.map +1 -0
- package/dist/ui/charts/sparkline.js +119 -0
- package/dist/ui/charts/sparkline.js.map +1 -0
- package/dist/ui/chat/message.d.ts +3 -3
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/system-message.d.ts +2 -1
- package/dist/ui/chat/system-message.d.ts.map +1 -1
- package/dist/ui/combobox.d.ts +2 -1
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +97 -92
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/container.d.ts +6 -1
- package/dist/ui/container.d.ts.map +1 -1
- package/dist/ui/container.js +2 -1
- package/dist/ui/container.js.map +1 -1
- package/dist/ui/icon-button.d.ts +9 -2
- package/dist/ui/icon-button.d.ts.map +1 -1
- package/dist/ui/icon-button.js +14 -13
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/index.d.ts +1 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +31 -33
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/lib/icon-input.d.ts +42 -0
- package/dist/ui/lib/icon-input.d.ts.map +1 -0
- package/dist/ui/lib/normalize-icon.d.ts +39 -0
- package/dist/ui/lib/normalize-icon.d.ts.map +1 -0
- package/dist/ui/oauth-button/index.d.ts +3 -0
- package/dist/ui/oauth-button/index.d.ts.map +1 -0
- package/dist/ui/oauth-button/index.js +3 -0
- package/dist/ui/oauth-button/oauth-button.d.ts +208 -0
- package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -0
- package/dist/ui/progress.js +1 -1
- package/dist/ui/segmented-control.d.ts +3 -4
- package/dist/ui/segmented-control.d.ts.map +1 -1
- package/dist/ui/segmented-control.js +53 -45
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/stack.d.ts +6 -1
- package/dist/ui/stack.d.ts.map +1 -1
- package/dist/ui/stack.js +2 -1
- package/dist/ui/stack.js.map +1 -1
- package/dist/ui/stat-card.d.ts +2 -3
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +117 -115
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stepper.d.ts +2 -1
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +74 -69
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/text.d.ts +7 -2
- package/dist/ui/text.d.ts.map +1 -1
- package/dist/ui/text.js +2 -1
- package/dist/ui/text.js.map +1 -1
- package/dist/ui/toaster.d.ts +11 -2
- package/dist/ui/toaster.d.ts.map +1 -1
- package/dist/ui/toaster.js.map +1 -1
- package/dist/ui/tooltip.js +12 -12
- package/dist/ui/tree-view/tree-item.d.ts +3 -2
- package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
- package/dist/ui/tree-view/use-tree.d.ts +2 -1
- package/dist/ui/tree-view/use-tree.d.ts.map +1 -1
- package/docs/components/ui/oauth-button.md +86 -0
- package/docs/recipes/customize-brand.md +15 -0
- package/docs/recipes/index.md +5 -1
- package/docs/recipes/install-astro.md +15 -0
- package/docs/recipes/install-next-app-router.md +21 -5
- package/docs/recipes/install-next-pages.md +2 -0
- package/docs/recipes/install-remix.md +15 -0
- package/docs/recipes/install-tanstack-start.md +15 -0
- package/docs/recipes/install-vite.md +15 -0
- package/docs/recipes/troubleshoot.md +22 -0
- package/llms-full.txt +87 -1
- package/llms-quick.txt +247 -0
- package/llms.txt +107 -2
- package/package.json +79 -2
- package/scripts/welcome.mjs +219 -0
- package/skill/SKILL.md +22 -3
- package/skill/references/components-full.md +87 -1
- package/skill/references/components.md +107 -2
- package/skill/references/customize-brand.md +15 -0
- package/skill/references/setup-astro.md +15 -0
- package/skill/references/setup-next-app-router.md +21 -5
- package/skill/references/setup-next-pages.md +2 -0
- package/skill/references/setup-remix.md +15 -0
- package/skill/references/setup-tanstack-start.md +15 -0
- package/skill/references/setup-vite.md +15 -0
- package/skill/references/troubleshoot.md +22 -0
- package/dist/_chunks/date-picker.js +0 -748
- package/dist/_chunks/date-picker.js.map +0 -1
- package/dist/_chunks/file-preview.js +0 -499
- package/dist/_chunks/rich-chat-input.js +0 -2071
- package/dist/_chunks/text.js.map +0 -1
- package/dist/ui/charts/index.js.map +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../ui/lib/utils.js";
|
|
3
|
+
import { useCallback as t, useState as n } from "react";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
|
+
//#region src/ui/charts/_internal/legend.tsx
|
|
6
|
+
function a({ items: t, position: n = "bottom", className: a }) {
|
|
7
|
+
return /* @__PURE__ */ r("div", {
|
|
8
|
+
className: e("flex gap-ds-04 text-ds-sm text-surface-fg-muted", n === "left" || n === "right" ? "flex-col" : "flex-row flex-wrap justify-center", a),
|
|
9
|
+
children: t.map((e) => /* @__PURE__ */ i("div", {
|
|
10
|
+
className: "flex items-center gap-ds-02",
|
|
11
|
+
children: [/* @__PURE__ */ r("span", {
|
|
12
|
+
className: "inline-block h-3 w-3 shrink-0 rounded-control-inner",
|
|
13
|
+
style: { backgroundColor: e.color }
|
|
14
|
+
}), /* @__PURE__ */ r("span", { children: e.label })]
|
|
15
|
+
}, e.label))
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
a.displayName = "Legend";
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/ui/charts/_internal/tooltip.tsx
|
|
21
|
+
function o({ state: t, className: n }) {
|
|
22
|
+
return t.visible ? /* @__PURE__ */ r("div", {
|
|
23
|
+
className: e("pointer-events-none absolute z-tooltip", "rounded-overlay-sm border border-surface-border-strong", "bg-surface-overlay px-ds-03 py-ds-02", "shadow-raised-hover", "text-ds-sm text-surface-fg", n),
|
|
24
|
+
style: {
|
|
25
|
+
left: t.x + 12,
|
|
26
|
+
top: t.y - 12
|
|
27
|
+
},
|
|
28
|
+
children: t.content
|
|
29
|
+
}) : null;
|
|
30
|
+
}
|
|
31
|
+
o.displayName = "ChartTooltip";
|
|
32
|
+
function s() {
|
|
33
|
+
let [e, r] = n({
|
|
34
|
+
visible: !1,
|
|
35
|
+
x: 0,
|
|
36
|
+
y: 0,
|
|
37
|
+
content: null
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
tooltip: e,
|
|
41
|
+
show: t((e, t, n) => {
|
|
42
|
+
r({
|
|
43
|
+
visible: !0,
|
|
44
|
+
x: e,
|
|
45
|
+
y: t,
|
|
46
|
+
content: n
|
|
47
|
+
});
|
|
48
|
+
}, []),
|
|
49
|
+
hide: t(() => {
|
|
50
|
+
r((e) => ({
|
|
51
|
+
...e,
|
|
52
|
+
visible: !1
|
|
53
|
+
}));
|
|
54
|
+
}, [])
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { s as n, a as r, o as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip.js","names":[],"sources":["../../src/ui/charts/_internal/legend.tsx","../../src/ui/charts/_internal/tooltip.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\n\ninterface LegendItem {\n label: string\n color: string // CSS color value or var() reference\n}\n\ninterface LegendProps {\n items: LegendItem[]\n position?: 'top' | 'bottom' | 'left' | 'right'\n className?: string\n}\n\nexport function Legend({ items, position = 'bottom', className }: LegendProps) {\n const isVertical = position === 'left' || position === 'right'\n\n return (\n <div\n className={cn(\n 'flex gap-ds-04 text-ds-sm text-surface-fg-muted',\n isVertical ? 'flex-col' : 'flex-row flex-wrap justify-center',\n className,\n )}\n >\n {items.map((item) => (\n <div key={item.label} className=\"flex items-center gap-ds-02\">\n <span\n className=\"inline-block h-3 w-3 shrink-0 rounded-control-inner\"\n style={{ backgroundColor: item.color }}\n />\n <span>{item.label}</span>\n </div>\n ))}\n </div>\n )\n}\nLegend.displayName = 'Legend'\n\nexport type { LegendItem, LegendProps }\n","'use client'\n\nimport * as React from 'react'\nimport { useCallback,useState } from 'react'\n\nimport { cn } from '../../lib/utils'\n\ninterface TooltipState {\n visible: boolean\n x: number\n y: number\n content: React.ReactNode\n}\n\ninterface ChartTooltipProps {\n state: TooltipState\n className?: string\n}\n\nexport function ChartTooltip({ state, className }: ChartTooltipProps) {\n if (!state.visible) return null\n\n return (\n <div\n className={cn(\n 'pointer-events-none absolute z-tooltip',\n 'rounded-overlay-sm border border-surface-border-strong',\n 'bg-surface-overlay px-ds-03 py-ds-02',\n 'shadow-raised-hover',\n 'text-ds-sm text-surface-fg',\n className,\n )}\n style={{ left: state.x + 12, top: state.y - 12 }}\n >\n {state.content}\n </div>\n )\n}\nChartTooltip.displayName = 'ChartTooltip'\n\n/** Hook to manage chart tooltip state */\nexport function useChartTooltip() {\n const [tooltip, setTooltip] = useState<TooltipState>({\n visible: false,\n x: 0,\n y: 0,\n content: null,\n })\n\n const show = useCallback((x: number, y: number, content: React.ReactNode) => {\n setTooltip({ visible: true, x, y, content })\n }, [])\n\n const hide = useCallback(() => {\n setTooltip((prev) => ({ ...prev, visible: false }))\n }, [])\n\n return { tooltip, show, hide }\n}\n\nexport type { ChartTooltipProps,TooltipState }\n"],"mappings":";;;;AAeA,SAAgB,EAAO,EAAE,UAAO,cAAW,UAAU,gBAA0B;AAG7E,QACE,kBAAC,OAAD;EACE,WAAW,EACT,mDALa,MAAa,UAAU,MAAa,UAMpC,aAAa,qCAC1B,EACD;YAEA,EAAM,KAAK,MACV,kBAAC,OAAD;GAAsB,WAAU;aAAhC,CACE,kBAAC,QAAD;IACE,WAAU;IACV,OAAO,EAAE,iBAAiB,EAAK,OAAO;IACtC,CAAA,EACF,kBAAC,QAAD,EAAA,UAAO,EAAK,OAAa,CAAA,CACrB;KANI,EAAK,MAMT,CACN;EACE,CAAA;;AAGV,EAAO,cAAc;;;ACnBrB,SAAgB,EAAa,EAAE,UAAO,gBAAgC;AAGpE,QAFK,EAAM,UAGT,kBAAC,OAAD;EACE,WAAW,EACT,0CACA,0DACA,wCACA,uBACA,8BACA,EACD;EACD,OAAO;GAAE,MAAM,EAAM,IAAI;GAAI,KAAK,EAAM,IAAI;GAAI;YAE/C,EAAM;EACH,CAAA,GAfmB;;AAkB7B,EAAa,cAAc;AAG3B,SAAgB,IAAkB;CAChC,IAAM,CAAC,GAAS,KAAc,EAAuB;EACnD,SAAS;EACT,GAAG;EACH,GAAG;EACH,SAAS;EACV,CAAC;AAUF,QAAO;EAAE;EAAS,MARL,GAAa,GAAW,GAAW,MAA6B;AAC3E,KAAW;IAAE,SAAS;IAAM;IAAG;IAAG;IAAS,CAAC;KAC3C,EAAE,CAAC;EAMkB,MAJX,QAAkB;AAC7B,MAAY,OAAU;IAAE,GAAG;IAAM,SAAS;IAAO,EAAE;KAClD,EAAE,CAAC;EAEwB"}
|
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
2
|
+
import { IconProvider as e } from "../ui/icon-context.js";
|
|
3
|
+
import { cn as t } from "../ui/lib/utils.js";
|
|
4
|
+
import { Icon as n } from "../ui/icon.js";
|
|
5
|
+
import { t as r } from "./normalize-icon.js";
|
|
6
|
+
import { Checkbox as i } from "../ui/checkbox.js";
|
|
7
|
+
import * as a from "react";
|
|
8
|
+
import { useCallback as o, useState as s } from "react";
|
|
9
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
10
|
+
import { IconChevronRight as u } from "@tabler/icons-react";
|
|
9
11
|
//#region src/ui/tree-view/use-tree.ts
|
|
10
|
-
function
|
|
11
|
-
let { defaultExpanded: t, defaultSelected: n, multiSelect: r, onSelect:
|
|
12
|
+
function d(e = {}) {
|
|
13
|
+
let { defaultExpanded: t, defaultSelected: n, multiSelect: r, onSelect: i, onExpand: a } = e, [c, l] = s(new Set(t ?? [])), [u, d] = s(new Set(n ?? []));
|
|
12
14
|
return {
|
|
13
15
|
expanded: c,
|
|
14
16
|
selected: u,
|
|
15
|
-
toggle:
|
|
17
|
+
toggle: o((e) => {
|
|
16
18
|
l((t) => {
|
|
17
19
|
let n = new Set(t);
|
|
18
|
-
return n.has(e) ? n.delete(e) : n.add(e),
|
|
20
|
+
return n.has(e) ? n.delete(e) : n.add(e), a?.(Array.from(n)), n;
|
|
19
21
|
});
|
|
20
|
-
}, [
|
|
21
|
-
select:
|
|
22
|
+
}, [a]),
|
|
23
|
+
select: o((e, t) => {
|
|
22
24
|
d((n) => {
|
|
23
|
-
let
|
|
24
|
-
return r && t?.ctrlKey ? (
|
|
25
|
+
let a;
|
|
26
|
+
return r && t?.ctrlKey ? (a = new Set(n), a.has(e) ? a.delete(e) : a.add(e)) : a = new Set([e]), i?.(Array.from(a)), a;
|
|
25
27
|
});
|
|
26
|
-
}, [r,
|
|
28
|
+
}, [r, i]),
|
|
27
29
|
isExpanded: (e) => c.has(e),
|
|
28
30
|
isSelected: (e) => u.has(e),
|
|
29
31
|
expandAll: (e) => l(new Set(e)),
|
|
@@ -32,23 +34,23 @@ function l(e = {}) {
|
|
|
32
34
|
}
|
|
33
35
|
//#endregion
|
|
34
36
|
//#region src/ui/tree-view/tree-view.tsx
|
|
35
|
-
var
|
|
36
|
-
function
|
|
37
|
-
let e =
|
|
37
|
+
var f = a.createContext(null);
|
|
38
|
+
function p() {
|
|
39
|
+
let e = a.useContext(f);
|
|
38
40
|
if (!e) throw Error("TreeItem must be used within a <TreeView>");
|
|
39
41
|
return e;
|
|
40
42
|
}
|
|
41
|
-
function
|
|
42
|
-
return e.map((e) => /* @__PURE__ */
|
|
43
|
+
function m(e, t = 0) {
|
|
44
|
+
return e.map((e) => /* @__PURE__ */ c(_, {
|
|
43
45
|
itemId: e.id,
|
|
44
46
|
label: e.label,
|
|
45
47
|
icon: e.icon,
|
|
46
48
|
disabled: e.disabled,
|
|
47
49
|
depth: t,
|
|
48
|
-
children: e.children && e.children.length > 0 ?
|
|
50
|
+
children: e.children && e.children.length > 0 ? m(e.children, t + 1) : void 0
|
|
49
51
|
}, e.id));
|
|
50
52
|
}
|
|
51
|
-
function
|
|
53
|
+
function h(e) {
|
|
52
54
|
return Array.from(e.querySelectorAll("[data-tree-item]")).filter((t) => {
|
|
53
55
|
let n = t.parentElement;
|
|
54
56
|
for (; n && n !== e;) {
|
|
@@ -61,17 +63,17 @@ function p(e) {
|
|
|
61
63
|
return !0;
|
|
62
64
|
});
|
|
63
65
|
}
|
|
64
|
-
var
|
|
65
|
-
let v =
|
|
66
|
+
var g = a.forwardRef(({ items: e, defaultExpanded: n, defaultSelected: r, multiSelect: i = !1, checkboxes: o = !1, onSelect: s, onExpand: l, className: u, children: p, ...g }, _) => {
|
|
67
|
+
let v = d({
|
|
66
68
|
defaultExpanded: n,
|
|
67
|
-
defaultSelected:
|
|
68
|
-
multiSelect:
|
|
69
|
-
onSelect:
|
|
70
|
-
onExpand:
|
|
71
|
-
}), y =
|
|
69
|
+
defaultSelected: r,
|
|
70
|
+
multiSelect: i,
|
|
71
|
+
onSelect: s,
|
|
72
|
+
onExpand: l
|
|
73
|
+
}), y = a.useRef(null), b = _ ?? y, x = (e) => {
|
|
72
74
|
let t = b.current;
|
|
73
75
|
if (!t) return;
|
|
74
|
-
let n =
|
|
76
|
+
let n = h(t), r = n.findIndex((e) => e === document.activeElement);
|
|
75
77
|
switch (e.key) {
|
|
76
78
|
case "ArrowDown":
|
|
77
79
|
e.preventDefault(), n[r + 1]?.focus();
|
|
@@ -102,46 +104,46 @@ var m = r.forwardRef(({ items: t, defaultExpanded: n, defaultSelected: i, multiS
|
|
|
102
104
|
e.preventDefault(), n[n.length - 1]?.focus();
|
|
103
105
|
break;
|
|
104
106
|
}
|
|
105
|
-
}, S =
|
|
107
|
+
}, S = a.useMemo(() => ({
|
|
106
108
|
tree: v,
|
|
107
|
-
checkboxes:
|
|
108
|
-
}), [v,
|
|
109
|
-
return /* @__PURE__ */
|
|
109
|
+
checkboxes: o
|
|
110
|
+
}), [v, o]), C = e ? m(e) : p;
|
|
111
|
+
return /* @__PURE__ */ c(f.Provider, {
|
|
110
112
|
value: S,
|
|
111
|
-
children: /* @__PURE__ */
|
|
113
|
+
children: /* @__PURE__ */ c("ul", {
|
|
112
114
|
ref: b,
|
|
113
115
|
role: "tree",
|
|
114
|
-
"aria-multiselectable":
|
|
116
|
+
"aria-multiselectable": i || void 0,
|
|
115
117
|
onKeyDown: x,
|
|
116
|
-
className:
|
|
118
|
+
className: t("m-0 list-none p-0", u),
|
|
117
119
|
...g,
|
|
118
120
|
children: C
|
|
119
121
|
})
|
|
120
122
|
});
|
|
121
123
|
});
|
|
122
|
-
|
|
124
|
+
g.displayName = "TreeView";
|
|
123
125
|
//#endregion
|
|
124
126
|
//#region src/ui/tree-view/tree-item.tsx
|
|
125
|
-
var
|
|
126
|
-
let
|
|
127
|
-
|
|
128
|
-
},
|
|
129
|
-
e.stopPropagation(), !
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
},
|
|
133
|
-
if (!
|
|
134
|
-
checked:
|
|
127
|
+
var _ = a.forwardRef(({ itemId: o, label: s, icon: d, secondaryLabel: f, actions: m, disabled: h = !1, children: g, depth: _ = 0, className: v }, y) => {
|
|
128
|
+
let b = p(), x = a.Children.count(g) > 0, S = b.tree.isExpanded(o), C = b.tree.isSelected(o), w = (e) => {
|
|
129
|
+
h || b.tree.select(o, e);
|
|
130
|
+
}, T = (e) => {
|
|
131
|
+
e.stopPropagation(), !h && b.tree.toggle(o);
|
|
132
|
+
}, E = (e) => {
|
|
133
|
+
h || ((e.key === "Enter" || e.key === " ") && (e.preventDefault(), b.tree.select(o)), e.key === "ArrowRight" && x && !S && (e.preventDefault(), e.stopPropagation(), b.tree.toggle(o)), e.key === "ArrowLeft" && x && S && (e.preventDefault(), e.stopPropagation(), b.tree.toggle(o)));
|
|
134
|
+
}, D = a.useMemo(() => {
|
|
135
|
+
if (!b.checkboxes || !x) return {
|
|
136
|
+
checked: C,
|
|
135
137
|
indeterminate: !1
|
|
136
138
|
};
|
|
137
139
|
let e = [], t = (n) => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
a.Children.forEach(n, (n) => {
|
|
141
|
+
a.isValidElement(n) && n.props.itemId && (e.push(n.props.itemId), n.props.children && t(n.props.children));
|
|
140
142
|
});
|
|
141
143
|
};
|
|
142
|
-
t(
|
|
143
|
-
let n = e.filter((e) =>
|
|
144
|
-
return n === 0 && !
|
|
144
|
+
t(g);
|
|
145
|
+
let n = e.filter((e) => b.tree.isSelected(e)).length;
|
|
146
|
+
return n === 0 && !C ? {
|
|
145
147
|
checked: !1,
|
|
146
148
|
indeterminate: !1
|
|
147
149
|
} : n === e.length ? {
|
|
@@ -152,85 +154,88 @@ var h = r.forwardRef(({ itemId: i, label: a, icon: l, secondaryLabel: u, actions
|
|
|
152
154
|
indeterminate: !0
|
|
153
155
|
};
|
|
154
156
|
}, [
|
|
155
|
-
|
|
156
|
-
y,
|
|
157
|
-
m,
|
|
157
|
+
b.checkboxes,
|
|
158
158
|
x,
|
|
159
|
-
|
|
159
|
+
g,
|
|
160
|
+
C,
|
|
161
|
+
b.tree
|
|
160
162
|
]);
|
|
161
|
-
return /* @__PURE__ */
|
|
162
|
-
ref:
|
|
163
|
+
return /* @__PURE__ */ l("li", {
|
|
164
|
+
ref: y,
|
|
163
165
|
role: "treeitem",
|
|
164
|
-
"aria-expanded":
|
|
165
|
-
"aria-selected":
|
|
166
|
-
"aria-level":
|
|
167
|
-
"aria-disabled":
|
|
166
|
+
"aria-expanded": x ? S : void 0,
|
|
167
|
+
"aria-selected": C,
|
|
168
|
+
"aria-level": _ + 1,
|
|
169
|
+
"aria-disabled": h || void 0,
|
|
168
170
|
className: "list-none",
|
|
169
|
-
children: [/* @__PURE__ */
|
|
171
|
+
children: [/* @__PURE__ */ l("div", {
|
|
170
172
|
role: "presentation",
|
|
171
|
-
"data-tree-item":
|
|
172
|
-
tabIndex:
|
|
173
|
-
onClick:
|
|
174
|
-
onKeyDown:
|
|
175
|
-
style: { paddingLeft: `calc(${
|
|
176
|
-
className:
|
|
173
|
+
"data-tree-item": o,
|
|
174
|
+
tabIndex: h ? -1 : 0,
|
|
175
|
+
onClick: w,
|
|
176
|
+
onKeyDown: E,
|
|
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-raised", "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),
|
|
177
179
|
children: [
|
|
178
|
-
|
|
180
|
+
x ? /* @__PURE__ */ c("button", {
|
|
179
181
|
type: "button",
|
|
180
182
|
tabIndex: -1,
|
|
181
183
|
"aria-hidden": "true",
|
|
182
|
-
onClick:
|
|
184
|
+
onClick: T,
|
|
183
185
|
className: "flex shrink-0 items-center justify-center p-0 border-0 bg-transparent cursor-pointer",
|
|
184
|
-
children: /* @__PURE__ */
|
|
185
|
-
icon:
|
|
186
|
+
children: /* @__PURE__ */ c(n, {
|
|
187
|
+
icon: u,
|
|
186
188
|
size: "sm",
|
|
187
|
-
className:
|
|
189
|
+
className: t("transition-transform duration-moderate-02", S && "rotate-90")
|
|
188
190
|
})
|
|
189
|
-
}) : /* @__PURE__ */
|
|
191
|
+
}) : /* @__PURE__ */ c("span", {
|
|
190
192
|
className: "inline-block w-4 shrink-0",
|
|
191
193
|
"aria-hidden": "true"
|
|
192
194
|
}),
|
|
193
|
-
|
|
194
|
-
checked:
|
|
195
|
-
indeterminate:
|
|
196
|
-
disabled:
|
|
195
|
+
b.checkboxes && /* @__PURE__ */ c(i, {
|
|
196
|
+
checked: D.checked,
|
|
197
|
+
indeterminate: D.indeterminate,
|
|
198
|
+
disabled: h,
|
|
197
199
|
tabIndex: -1,
|
|
198
200
|
onClick: (e) => e.stopPropagation(),
|
|
199
201
|
onCheckedChange: () => {
|
|
200
|
-
|
|
202
|
+
h || b.tree.select(o);
|
|
201
203
|
},
|
|
202
204
|
className: "shrink-0"
|
|
203
205
|
}),
|
|
204
|
-
|
|
206
|
+
d && /* @__PURE__ */ c("span", {
|
|
205
207
|
className: "flex shrink-0 items-center text-surface-fg-subtle",
|
|
206
|
-
children:
|
|
208
|
+
children: /* @__PURE__ */ c(e, {
|
|
209
|
+
size: "sm",
|
|
210
|
+
children: r(d)
|
|
211
|
+
})
|
|
207
212
|
}),
|
|
208
|
-
/* @__PURE__ */
|
|
213
|
+
/* @__PURE__ */ c("span", {
|
|
209
214
|
className: "truncate text-ds-sm",
|
|
210
|
-
children:
|
|
215
|
+
children: s
|
|
211
216
|
}),
|
|
212
|
-
|
|
217
|
+
f && /* @__PURE__ */ c("span", {
|
|
213
218
|
className: "ml-auto truncate text-ds-xs text-surface-fg-muted",
|
|
214
|
-
children:
|
|
219
|
+
children: f
|
|
215
220
|
}),
|
|
216
|
-
|
|
221
|
+
m && /* @__PURE__ */ c("span", {
|
|
217
222
|
className: "ml-auto flex shrink-0 items-center gap-ds-01",
|
|
218
223
|
onClick: (e) => e.stopPropagation(),
|
|
219
224
|
role: "presentation",
|
|
220
|
-
children:
|
|
225
|
+
children: m
|
|
221
226
|
})
|
|
222
227
|
]
|
|
223
|
-
}),
|
|
228
|
+
}), x && /* @__PURE__ */ c("div", {
|
|
224
229
|
role: "group",
|
|
225
|
-
className:
|
|
226
|
-
children: /* @__PURE__ */
|
|
230
|
+
className: t("grid transition-[grid-template-rows] duration-moderate-02 ease-productive-standard", S ? "grid-rows-[1fr]" : "grid-rows-[0fr]"),
|
|
231
|
+
children: /* @__PURE__ */ c("ul", {
|
|
227
232
|
role: "group",
|
|
228
233
|
className: "overflow-hidden m-0 p-0",
|
|
229
|
-
children:
|
|
234
|
+
children: a.Children.map(g, (e) => a.isValidElement(e) ? a.cloneElement(e, { depth: _ + 1 }) : e)
|
|
230
235
|
})
|
|
231
236
|
})]
|
|
232
237
|
});
|
|
233
238
|
});
|
|
234
|
-
|
|
239
|
+
_.displayName = "TreeItem";
|
|
235
240
|
//#endregion
|
|
236
|
-
export {
|
|
241
|
+
export { g as n, d as r, _ as t };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-view.js","names":[],"sources":["../../src/ui/tree-view/use-tree.ts","../../src/ui/tree-view/tree-view.tsx","../../src/ui/tree-view/tree-item.tsx"],"sourcesContent":["import { useCallback,useState } from 'react'\n\nexport interface TreeNode {\n id: string\n label: string\n icon?: React.ReactNode\n children?: TreeNode[]\n disabled?: boolean\n}\n\ninterface UseTreeOptions {\n defaultExpanded?: string[]\n defaultSelected?: string[]\n multiSelect?: boolean\n onSelect?: (selectedIds: string[]) => void\n onExpand?: (expandedIds: string[]) => void\n}\n\nexport function useTree(options: UseTreeOptions = {}) {\n const { defaultExpanded, defaultSelected, multiSelect, onSelect, onExpand } = options\n\n const [expanded, setExpanded] = useState<Set<string>>(\n new Set(defaultExpanded ?? []),\n )\n const [selected, setSelected] = useState<Set<string>>(\n new Set(defaultSelected ?? []),\n )\n\n const toggle = useCallback(\n (id: string) => {\n setExpanded((prev) => {\n const next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onExpand?.(Array.from(next))\n return next\n })\n },\n [onExpand],\n )\n\n const select = useCallback(\n (id: string, event?: React.MouseEvent) => {\n setSelected((prev) => {\n let next: Set<string>\n if (multiSelect && event?.ctrlKey) {\n next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n } else {\n next = new Set([id])\n }\n onSelect?.(Array.from(next))\n return next\n })\n },\n [multiSelect, onSelect],\n )\n\n return {\n expanded,\n selected,\n toggle,\n select,\n isExpanded: (id: string) => expanded.has(id),\n isSelected: (id: string) => selected.has(id),\n expandAll: (ids: string[]) => setExpanded(new Set(ids)),\n collapseAll: () => setExpanded(new Set()),\n }\n}\n","'use client'\n\nimport * as React from 'react'\n\nimport { cn } from '../lib/utils'\nimport { TreeItem } from './tree-item'\nimport { type TreeNode,useTree } from './use-tree'\n\n// ─── Context ────────────────────────────────────────────────────────\ninterface TreeContextValue {\n tree: ReturnType<typeof useTree>\n checkboxes: boolean\n}\n\nconst TreeContext = React.createContext<TreeContextValue | null>(null)\n\nexport function useTreeContext() {\n const ctx = React.useContext(TreeContext)\n if (!ctx) {\n throw new Error('TreeItem must be used within a <TreeView>')\n }\n return ctx\n}\n\n// ─── Props ──────────────────────────────────────────────────────────\nexport interface TreeViewProps extends Omit<React.HTMLAttributes<HTMLUListElement>, 'onSelect'> {\n /** Data-driven mode: pass items array */\n items?: TreeNode[]\n /** Initially expanded node IDs */\n defaultExpanded?: string[]\n /** Initially selected node IDs */\n defaultSelected?: string[]\n /** Enable multi-select */\n multiSelect?: boolean\n /** Show checkboxes before each item */\n checkboxes?: boolean\n /** Called when selection changes */\n onSelect?: (ids: string[]) => void\n /** Called when expansion changes */\n onExpand?: (ids: string[]) => void\n className?: string\n /** Declarative mode: render TreeItem children directly */\n children?: React.ReactNode\n}\n\n// ─── Render nodes recursively (data-driven mode) ───────────────────\nfunction renderNodes(nodes: TreeNode[], depth: number = 0): React.ReactNode {\n return nodes.map((node) => (\n <TreeItem\n key={node.id}\n itemId={node.id}\n label={node.label}\n icon={node.icon}\n disabled={node.disabled}\n depth={depth}\n >\n {node.children && node.children.length > 0\n ? renderNodes(node.children, depth + 1)\n : undefined}\n </TreeItem>\n ))\n}\n\n// ─── Helper: collect all visible item IDs ───────────────────────────\nfunction getVisibleItemElements(container: HTMLElement): HTMLElement[] {\n return Array.from(\n container.querySelectorAll<HTMLElement>('[data-tree-item]'),\n ).filter((el) => {\n // Items inside collapsed groups should not be focusable\n let parent = el.parentElement\n while (parent && parent !== container) {\n if (parent.getAttribute('role') === 'group') {\n const grid = parent.parentElement\n if (grid && grid.classList.contains('grid-rows-[0fr]')) {\n return false\n }\n }\n parent = parent.parentElement\n }\n return true\n })\n}\n\n// ─── Component ──────────────────────────────────────────────────────\nconst TreeView = React.forwardRef<HTMLUListElement, TreeViewProps>(\n (\n {\n items,\n defaultExpanded,\n defaultSelected,\n multiSelect = false,\n checkboxes = false,\n onSelect,\n onExpand,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const tree = useTree({\n defaultExpanded,\n defaultSelected,\n multiSelect,\n onSelect,\n onExpand,\n })\n\n const innerRef = React.useRef<HTMLUListElement>(null)\n const containerRef = (ref as React.RefObject<HTMLUListElement>) ?? innerRef\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLUListElement>) => {\n const container = containerRef.current\n if (!container) return\n\n const visibleItems = getVisibleItemElements(container)\n const currentIndex = visibleItems.findIndex(\n (el) => el === document.activeElement,\n )\n\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const next = visibleItems[currentIndex + 1]\n next?.focus()\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prev = visibleItems[currentIndex - 1]\n prev?.focus()\n break\n }\n case 'ArrowRight': {\n // Handled in TreeItem for expand; if already expanded, move to first child\n const current = visibleItems[currentIndex]\n if (current) {\n const itemId = current.getAttribute('data-tree-item')\n if (itemId && tree.isExpanded(itemId)) {\n e.preventDefault()\n const nextItem = visibleItems[currentIndex + 1]\n nextItem?.focus()\n }\n }\n break\n }\n case 'ArrowLeft': {\n // Handled in TreeItem for collapse; if already collapsed or leaf, move to parent\n const current = visibleItems[currentIndex]\n if (current) {\n const itemId = current.getAttribute('data-tree-item')\n const treeItem = current.closest('[role=\"treeitem\"]')\n const parentGroup = treeItem?.parentElement?.closest(\n '[role=\"treeitem\"]',\n )\n if (itemId && !tree.isExpanded(itemId) && parentGroup) {\n e.preventDefault()\n const parentRow = parentGroup.querySelector<HTMLElement>(\n '[data-tree-item]',\n )\n parentRow?.focus()\n }\n }\n break\n }\n case 'Home': {\n e.preventDefault()\n visibleItems[0]?.focus()\n break\n }\n case 'End': {\n e.preventDefault()\n visibleItems[visibleItems.length - 1]?.focus()\n break\n }\n }\n }\n\n const ctxValue = React.useMemo<TreeContextValue>(\n () => ({ tree, checkboxes }),\n [tree, checkboxes],\n )\n\n const content = items ? renderNodes(items) : children\n\n return (\n <TreeContext.Provider value={ctxValue}>\n <ul\n ref={containerRef}\n role=\"tree\"\n aria-multiselectable={multiSelect || undefined}\n onKeyDown={handleKeyDown}\n className={cn('m-0 list-none p-0', className)}\n {...props}\n >\n {content}\n </ul>\n </TreeContext.Provider>\n )\n },\n)\nTreeView.displayName = 'TreeView'\n\nexport { TreeView }\n","'use client'\n\nimport { IconChevronRight } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Checkbox } from '../checkbox'\nimport { Icon } from '../icon'\nimport { cn } from '../lib/utils'\nimport { useTreeContext } from './tree-view'\n\nexport interface TreeItemProps {\n /** Unique identifier for this tree item */\n itemId: string\n /** Primary label content */\n label: React.ReactNode\n /** Optional icon rendered before the label */\n icon?: React.ReactNode\n /** Secondary label rendered after the primary label */\n secondaryLabel?: React.ReactNode\n /** Action buttons rendered at the end of the row */\n actions?: React.ReactNode\n /** Whether this item is disabled */\n disabled?: boolean\n /** Nested tree items */\n children?: React.ReactNode\n /** Depth level (used internally) */\n depth?: number\n /** Additional CSS class names */\n className?: string\n}\n\nconst TreeItem = React.forwardRef<HTMLLIElement, TreeItemProps>(\n (\n {\n itemId,\n label,\n icon,\n secondaryLabel,\n actions,\n disabled = false,\n children,\n depth = 0,\n className,\n },\n ref,\n ) => {\n const ctx = useTreeContext()\n const hasChildren = React.Children.count(children) > 0\n const isExpanded = ctx.tree.isExpanded(itemId)\n const isSelected = ctx.tree.isSelected(itemId)\n\n const handleRowClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n ctx.tree.select(itemId, e)\n }\n\n const handleChevronClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation()\n if (disabled) return\n ctx.tree.toggle(itemId)\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n ctx.tree.select(itemId)\n }\n if (e.key === 'ArrowRight' && hasChildren && !isExpanded) {\n e.preventDefault()\n e.stopPropagation()\n ctx.tree.toggle(itemId)\n }\n if (e.key === 'ArrowLeft' && hasChildren && isExpanded) {\n e.preventDefault()\n e.stopPropagation()\n ctx.tree.toggle(itemId)\n }\n }\n\n // Compute indeterminate state for checkbox mode\n const checkboxState = React.useMemo(() => {\n if (!ctx.checkboxes || !hasChildren) {\n return { checked: isSelected, indeterminate: false }\n }\n // Collect all descendant IDs\n const descendants: string[] = []\n const collectIds = (nodes: React.ReactNode) => {\n React.Children.forEach(nodes, (child) => {\n if (React.isValidElement<TreeItemProps>(child) && child.props.itemId) {\n descendants.push(child.props.itemId)\n if (child.props.children) {\n collectIds(child.props.children)\n }\n }\n })\n }\n collectIds(children)\n const selectedCount = descendants.filter((id) =>\n ctx.tree.isSelected(id),\n ).length\n if (selectedCount === 0 && !isSelected) {\n return { checked: false, indeterminate: false }\n }\n if (selectedCount === descendants.length) {\n return { checked: true, indeterminate: false }\n }\n return { checked: false, indeterminate: true }\n }, [ctx.checkboxes, hasChildren, children, isSelected, ctx.tree])\n\n return (\n <li\n ref={ref}\n role=\"treeitem\"\n aria-expanded={hasChildren ? isExpanded : undefined}\n aria-selected={isSelected}\n aria-level={depth + 1}\n aria-disabled={disabled || undefined}\n className=\"list-none\"\n >\n {/* Row */}\n <div\n role=\"presentation\"\n data-tree-item={itemId}\n tabIndex={disabled ? -1 : 0}\n onClick={handleRowClick}\n onKeyDown={handleKeyDown}\n style={{ paddingLeft: `calc(${depth} * var(--spacing-ds-05b) + var(--spacing-ds-03))` }}\n className={cn(\n 'flex items-center gap-ds-02 py-ds-02 px-ds-02 rounded-control cursor-pointer transition-colors duration-fast-01',\n 'hover:bg-surface-raised',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9',\n isSelected &&\n 'bg-accent-3 text-accent-11',\n disabled && 'opacity-action-disabled cursor-not-allowed pointer-events-none',\n className,\n )}\n >\n {/* Expand chevron */}\n {hasChildren ? (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onClick={handleChevronClick}\n className=\"flex shrink-0 items-center justify-center p-0 border-0 bg-transparent cursor-pointer\"\n >\n <Icon\n icon={IconChevronRight}\n size=\"sm\"\n className={cn(\n 'transition-transform duration-moderate-02',\n isExpanded && 'rotate-90',\n )}\n />\n </button>\n ) : (\n <span className=\"inline-block w-4 shrink-0\" aria-hidden=\"true\" />\n )}\n\n {/* Checkbox (optional) */}\n {ctx.checkboxes && (\n <Checkbox\n checked={checkboxState.checked}\n indeterminate={checkboxState.indeterminate}\n disabled={disabled}\n tabIndex={-1}\n onClick={(e) => e.stopPropagation()}\n onCheckedChange={() => {\n if (!disabled) ctx.tree.select(itemId)\n }}\n className=\"shrink-0\"\n />\n )}\n\n {/* Icon */}\n {icon && (\n <span className=\"flex shrink-0 items-center text-surface-fg-subtle\">\n {icon}\n </span>\n )}\n\n {/* Label */}\n <span className=\"truncate text-ds-sm\">{label}</span>\n\n {/* Secondary label */}\n {secondaryLabel && (\n <span className=\"ml-auto truncate text-ds-xs text-surface-fg-muted\">\n {secondaryLabel}\n </span>\n )}\n\n {/* Actions */}\n {actions && (\n <span\n className=\"ml-auto flex shrink-0 items-center gap-ds-01\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {actions}\n </span>\n )}\n </div>\n\n {/* Children (collapsible) */}\n {hasChildren && (\n <div\n role=\"group\"\n className={cn(\n 'grid transition-[grid-template-rows] duration-moderate-02 ease-productive-standard',\n isExpanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',\n )}\n >\n <ul role=\"group\" className=\"overflow-hidden m-0 p-0\">\n {React.Children.map(children, (child) => {\n if (React.isValidElement<TreeItemProps>(child)) {\n return React.cloneElement(child, {\n depth: depth + 1,\n })\n }\n return child\n })}\n </ul>\n </div>\n )}\n </li>\n )\n },\n)\nTreeItem.displayName = 'TreeItem'\n\nexport { TreeItem }\n"],"mappings":"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"}
|
|
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=\"truncate text-ds-sm\">{label}</span>\n\n {/* Secondary label */}\n {secondaryLabel && (\n <span className=\"ml-auto truncate text-ds-xs text-surface-fg-muted\">\n {secondaryLabel}\n </span>\n )}\n\n {/* Actions */}\n {actions && (\n <span\n className=\"ml-auto flex shrink-0 items-center gap-ds-01\"\n onClick={(e) => e.stopPropagation()}\n role=\"presentation\"\n >\n {actions}\n </span>\n )}\n </div>\n\n {/* Children (collapsible) */}\n {hasChildren && (\n <div\n role=\"group\"\n className={cn(\n 'grid transition-[grid-template-rows] duration-moderate-02 ease-productive-standard',\n isExpanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',\n )}\n >\n <ul role=\"group\" className=\"overflow-hidden m-0 p-0\">\n {React.Children.map(children, (child) => {\n if (React.isValidElement<TreeItemProps>(child)) {\n return React.cloneElement(child, {\n depth: depth + 1,\n })\n }\n return child\n })}\n </ul>\n </div>\n )}\n </li>\n )\n },\n)\nTreeItem.displayName = 'TreeItem'\n\nexport { TreeItem }\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { IconInput } from '../ui/lib/icon-input';
|
|
2
3
|
import { BlockComponentProps } from './types';
|
|
3
4
|
import * as React from 'react';
|
|
4
5
|
export interface AICommandContext {
|
|
@@ -6,7 +7,7 @@ export interface AICommandContext {
|
|
|
6
7
|
onAction?: (actionId: string, type: 'confirm' | 'cancel' | 'undo') => void;
|
|
7
8
|
agent?: {
|
|
8
9
|
name: string;
|
|
9
|
-
icon?:
|
|
10
|
+
icon?: IconInput;
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
13
|
export declare function useAICommand(): AICommandContext | null;
|
|
@@ -16,7 +17,7 @@ export interface AICommandProviderProps {
|
|
|
16
17
|
onAction?: (actionId: string, type: 'confirm' | 'cancel' | 'undo') => void;
|
|
17
18
|
agent?: {
|
|
18
19
|
name: string;
|
|
19
|
-
icon?:
|
|
20
|
+
icon?: IconInput;
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
export declare function AICommandProvider({ children, customBlocks, onAction, agent }: AICommandProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-command-provider.d.ts","sourceRoot":"","sources":["../../src/ai/ai-command-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC3E,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,KAAK,IAAI,CAAA;IAC1E,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"ai-command-provider.d.ts","sourceRoot":"","sources":["../../src/ai/ai-command-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC3E,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,KAAK,IAAI,CAAA;IAC1E,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAE,CAAA;CAC3C;AAID,wBAAgB,YAAY,IAAI,gBAAgB,GAAG,IAAI,CAEtD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC5E,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,KAAK,IAAI,CAAA;IAC1E,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAE,CAAA;CAC3C;AAID,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,sBAAsB,2CAQpG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-command-provider.js","names":[],"sources":["../../src/ai/ai-command-provider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\n\nimport type { BlockComponentProps } from './types'\n\nexport interface AICommandContext {\n customBlocks: Record<string, React.ComponentType<BlockComponentProps<any>>>\n onAction?: (actionId: string, type: 'confirm' | 'cancel' | 'undo') => void\n agent?: { name: string; icon?:
|
|
1
|
+
{"version":3,"file":"ai-command-provider.js","names":[],"sources":["../../src/ai/ai-command-provider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\n\nimport type { IconInput } from '../ui/lib/icon-input'\nimport type { BlockComponentProps } from './types'\n\nexport interface AICommandContext {\n customBlocks: Record<string, React.ComponentType<BlockComponentProps<any>>>\n onAction?: (actionId: string, type: 'confirm' | 'cancel' | 'undo') => void\n agent?: { name: string; icon?: IconInput }\n}\n\nconst AICommandCtx = React.createContext<AICommandContext | null>(null)\n\nexport function useAICommand(): AICommandContext | null {\n return React.useContext(AICommandCtx)\n}\n\nexport interface AICommandProviderProps {\n children: React.ReactNode\n customBlocks?: Record<string, React.ComponentType<BlockComponentProps<any>>>\n onAction?: (actionId: string, type: 'confirm' | 'cancel' | 'undo') => void\n agent?: { name: string; icon?: IconInput }\n}\n\nconst EMPTY_BLOCKS: Record<string, React.ComponentType<BlockComponentProps<any>>> = {}\n\nexport function AICommandProvider({ children, customBlocks, onAction, agent }: AICommandProviderProps) {\n const blocks = customBlocks ?? EMPTY_BLOCKS\n const value = React.useMemo<AICommandContext>(\n () => ({ customBlocks: blocks, onAction, agent }),\n \n [blocks, onAction, agent],\n )\n return <AICommandCtx.Provider value={value}>{children}</AICommandCtx.Provider>\n}\n"],"mappings":";;;;AAaA,IAAM,IAAe,EAAM,cAAuC,KAAK;AAEvE,SAAgB,IAAwC;AACtD,QAAO,EAAM,WAAW,EAAa;;AAUvC,IAAM,IAA8E,EAAE;AAEtF,SAAgB,EAAkB,EAAE,aAAU,iBAAc,aAAU,YAAiC;CACrG,IAAM,IAAS,KAAgB,GACzB,IAAQ,EAAM,eACX;EAAE,cAAc;EAAQ;EAAU;EAAO,GAEhD;EAAC;EAAQ;EAAU;EAAM,CAC1B;AACD,QAAO,kBAAC,EAAa,UAAd;EAA8B;EAAQ;EAAiC,CAAA"}
|
|
@@ -4,21 +4,23 @@ import { cn as t } from "../ui/lib/utils.js";
|
|
|
4
4
|
import { Alert as n } from "../ui/alert.js";
|
|
5
5
|
import { n as r } from "../_chunks/motion-provider.js";
|
|
6
6
|
import { useAICommand as i } from "./ai-command-provider.js";
|
|
7
|
-
import { a,
|
|
7
|
+
import { a, i as o, n as s, o as c, r as l, s as u, t as d } from "../_chunks/success.js";
|
|
8
|
+
import { ErrorBlock as f } from "./blocks/error.js";
|
|
9
|
+
import { TextBlock as p } from "./blocks/text.js";
|
|
8
10
|
import * as m from "react";
|
|
9
11
|
import { jsx as h } from "react/jsx-runtime";
|
|
10
12
|
import { motion as g } from "framer-motion";
|
|
11
13
|
//#region src/ai/block-renderer.tsx
|
|
12
14
|
var _ = {
|
|
13
15
|
text: p,
|
|
14
|
-
table:
|
|
15
|
-
confirm:
|
|
16
|
-
success:
|
|
17
|
-
error:
|
|
18
|
-
info:
|
|
19
|
-
loading:
|
|
20
|
-
divider:
|
|
21
|
-
stat_row:
|
|
16
|
+
table: u,
|
|
17
|
+
confirm: c,
|
|
18
|
+
success: d,
|
|
19
|
+
error: f,
|
|
20
|
+
info: o,
|
|
21
|
+
loading: l,
|
|
22
|
+
divider: a,
|
|
23
|
+
stat_row: s
|
|
22
24
|
};
|
|
23
25
|
function v({ data: e, type: t }) {
|
|
24
26
|
return /* @__PURE__ */ h(n, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-renderer.js","names":[],"sources":["../../src/ai/block-renderer.tsx"],"sourcesContent":["'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 { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport { useAICommand } from './ai-command-provider'\nimport { BlockTable } from './blocks/block-table'\nimport { ConfirmBlock } from './blocks/confirm'\nimport { DividerBlock } from './blocks/divider'\nimport { ErrorBlock } from './blocks/error'\nimport { InfoBlock } from './blocks/info'\nimport { LoadingBlock } from './blocks/loading'\nimport { StatRowBlock } from './blocks/stat-row'\nimport { SuccessBlock } from './blocks/success'\n// Import all built-in blocks\nimport { TextBlock } from './blocks/text'\nimport type { Block, BlockComponentProps } from './types'\n\nconst BUILT_IN_BLOCKS: Record<string, React.ComponentType<BlockComponentProps<any>>> = {\n text: TextBlock,\n table: BlockTable,\n confirm: ConfirmBlock,\n success: SuccessBlock,\n error: ErrorBlock,\n info: InfoBlock,\n loading: LoadingBlock,\n divider: DividerBlock,\n stat_row: StatRowBlock,\n}\n\nfunction FallbackBlock({ data, type }: { data: Record<string, unknown>; type: string }) {\n return (\n <Alert color=\"info\" variant=\"subtle\" title={`Unknown block type: ${type}`}>\n <pre className=\"mt-2 text-ds-xs whitespace-pre-wrap\">\n {JSON.stringify(data, null, 2)}\n </pre>\n </Alert>\n )\n}\n\nexport interface BlockRendererProps {\n blocks: Block[]\n onAction?: (actionId: string, type: 'confirm' | 'cancel' | 'undo') => void\n customBlocks?: Record<string, React.ComponentType<BlockComponentProps<any>>>\n staggerDelay?: number\n className?: string\n}\n\nconst BlockRenderer = React.forwardRef<HTMLDivElement, BlockRendererProps>(({\n blocks,\n onAction,\n customBlocks,\n staggerDelay = 50,\n className,\n}, ref) => {\n const ctx = useAICommand()\n const { reducedMotion } = useMotion()\n\n // Merge custom blocks: prop wins over context\n const mergedCustomBlocks = React.useMemo(() => {\n const contextBlocks = ctx?.customBlocks ?? {}\n return { ...contextBlocks, ...customBlocks }\n }, [ctx?.customBlocks, customBlocks])\n\n // Resolve onAction: prop wins over context\n const resolvedOnAction = onAction ?? ctx?.onAction\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-ds-04', className)}>\n {blocks.map((block, index) => {\n const Component =\n mergedCustomBlocks[block.type] ??\n BUILT_IN_BLOCKS[block.type] ??\n null\n\n const blockProps: BlockComponentProps<any> = {\n data: block.data,\n blockId: block.id,\n confidence: block.confidence,\n onAction: resolvedOnAction,\n }\n\n const content = Component ? (\n <Component {...blockProps} />\n ) : (\n <FallbackBlock data={block.data} type={block.type} />\n )\n\n const key = block.id ?? `${block.type}-${index}`\n\n if (reducedMotion) {\n return <div key={key}>{content}</div>\n }\n\n return (\n <motion.div\n key={key}\n initial={{ opacity: 0, y: 12 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.responsive, delay: index * (staggerDelay / 1000) }}\n >\n {content}\n </motion.div>\n )\n })}\n </div>\n )\n})\nBlockRenderer.displayName = 'BlockRenderer'\n\nexport { BlockRenderer }\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"block-renderer.js","names":[],"sources":["../../src/ai/block-renderer.tsx"],"sourcesContent":["'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 { springs } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport { useAICommand } from './ai-command-provider'\nimport { BlockTable } from './blocks/block-table'\nimport { ConfirmBlock } from './blocks/confirm'\nimport { DividerBlock } from './blocks/divider'\nimport { ErrorBlock } from './blocks/error'\nimport { InfoBlock } from './blocks/info'\nimport { LoadingBlock } from './blocks/loading'\nimport { StatRowBlock } from './blocks/stat-row'\nimport { SuccessBlock } from './blocks/success'\n// Import all built-in blocks\nimport { TextBlock } from './blocks/text'\nimport type { Block, BlockComponentProps } from './types'\n\nconst BUILT_IN_BLOCKS: Record<string, React.ComponentType<BlockComponentProps<any>>> = {\n text: TextBlock,\n table: BlockTable,\n confirm: ConfirmBlock,\n success: SuccessBlock,\n error: ErrorBlock,\n info: InfoBlock,\n loading: LoadingBlock,\n divider: DividerBlock,\n stat_row: StatRowBlock,\n}\n\nfunction FallbackBlock({ data, type }: { data: Record<string, unknown>; type: string }) {\n return (\n <Alert color=\"info\" variant=\"subtle\" title={`Unknown block type: ${type}`}>\n <pre className=\"mt-2 text-ds-xs whitespace-pre-wrap\">\n {JSON.stringify(data, null, 2)}\n </pre>\n </Alert>\n )\n}\n\nexport interface BlockRendererProps {\n blocks: Block[]\n onAction?: (actionId: string, type: 'confirm' | 'cancel' | 'undo') => void\n customBlocks?: Record<string, React.ComponentType<BlockComponentProps<any>>>\n staggerDelay?: number\n className?: string\n}\n\nconst BlockRenderer = React.forwardRef<HTMLDivElement, BlockRendererProps>(({\n blocks,\n onAction,\n customBlocks,\n staggerDelay = 50,\n className,\n}, ref) => {\n const ctx = useAICommand()\n const { reducedMotion } = useMotion()\n\n // Merge custom blocks: prop wins over context\n const mergedCustomBlocks = React.useMemo(() => {\n const contextBlocks = ctx?.customBlocks ?? {}\n return { ...contextBlocks, ...customBlocks }\n }, [ctx?.customBlocks, customBlocks])\n\n // Resolve onAction: prop wins over context\n const resolvedOnAction = onAction ?? ctx?.onAction\n\n return (\n <div ref={ref} className={cn('flex flex-col gap-ds-04', className)}>\n {blocks.map((block, index) => {\n const Component =\n mergedCustomBlocks[block.type] ??\n BUILT_IN_BLOCKS[block.type] ??\n null\n\n const blockProps: BlockComponentProps<any> = {\n data: block.data,\n blockId: block.id,\n confidence: block.confidence,\n onAction: resolvedOnAction,\n }\n\n const content = Component ? (\n <Component {...blockProps} />\n ) : (\n <FallbackBlock data={block.data} type={block.type} />\n )\n\n const key = block.id ?? `${block.type}-${index}`\n\n if (reducedMotion) {\n return <div key={key}>{content}</div>\n }\n\n return (\n <motion.div\n key={key}\n initial={{ opacity: 0, y: 12 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.responsive, delay: index * (staggerDelay / 1000) }}\n >\n {content}\n </motion.div>\n )\n })}\n </div>\n )\n})\nBlockRenderer.displayName = 'BlockRenderer'\n\nexport { BlockRenderer }\n"],"mappings":";;;;;;;;;;;;;AAsBA,IAAM,IAAiF;CACrF,MAAM;CACN,OAAO;CACP,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;CACT,UAAU;CACX;AAED,SAAS,EAAc,EAAE,SAAM,WAAyD;AACtF,QACE,kBAAC,GAAD;EAAO,OAAM;EAAO,SAAQ;EAAS,OAAO,uBAAuB;YACjE,kBAAC,OAAD;GAAK,WAAU;aACZ,KAAK,UAAU,GAAM,MAAM,EAAE;GAC1B,CAAA;EACA,CAAA;;AAYZ,IAAM,IAAgB,EAAM,YAAgD,EAC1E,WACA,aACA,iBACA,kBAAe,IACf,gBACC,MAAQ;CACT,IAAM,IAAM,GAAc,EACpB,EAAE,qBAAkB,GAAW,EAG/B,IAAqB,EAAM,eAExB;EAAE,GADa,GAAK,gBAAgB,EAAE;EAClB,GAAG;EAAc,GAC3C,CAAC,GAAK,cAAc,EAAa,CAAC,EAG/B,IAAmB,KAAY,GAAK;AAE1C,QACE,kBAAC,OAAD;EAAU;EAAK,WAAW,EAAG,2BAA2B,EAAU;YAC/D,EAAO,KAAK,GAAO,MAAU;GAC5B,IAAM,IACJ,EAAmB,EAAM,SACzB,EAAgB,EAAM,SACtB,MAEI,IAAuC;IAC3C,MAAM,EAAM;IACZ,SAAS,EAAM;IACf,YAAY,EAAM;IAClB,UAAU;IACX,EAEK,IAAU,IACd,kBAAC,GAAD,EAAW,GAAI,GAAc,CAAA,GAE7B,kBAAC,GAAD;IAAe,MAAM,EAAM;IAAM,MAAM,EAAM;IAAQ,CAAA,EAGjD,IAAM,EAAM,MAAM,GAAG,EAAM,KAAK,GAAG;AAMzC,UAJI,IACK,kBAAC,OAAD,EAAA,UAAgB,GAAc,EAApB,EAAoB,GAIrC,kBAAC,EAAO,KAAR;IAEE,SAAS;KAAE,SAAS;KAAG,GAAG;KAAI;IAC9B,SAAS;KAAE,SAAS;KAAG,GAAG;KAAG;IAC7B,YAAY;KAAE,GAAG,EAAQ;KAAY,OAAgB,IAAe,MAAxB;KAA+B;cAE1E;IACU,EANN,EAMM;IAEf;EACE,CAAA;EAER;AACF,EAAc,cAAc"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../ui/lib/utils.js";
|
|
3
|
+
import { Alert as t } from "../../ui/alert.js";
|
|
4
|
+
import * as n from "react";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
import a from "react-markdown";
|
|
7
|
+
import o from "remark-gfm";
|
|
8
|
+
//#region src/ai/blocks/error.tsx
|
|
9
|
+
var s = n.memo(function({ data: n, confidence: s }) {
|
|
10
|
+
return /* @__PURE__ */ i("div", {
|
|
11
|
+
className: e(s === "low" && "border-l-2 border-warning-7 pl-3"),
|
|
12
|
+
children: [/* @__PURE__ */ r(t, {
|
|
13
|
+
color: "error",
|
|
14
|
+
variant: "subtle",
|
|
15
|
+
title: n.title,
|
|
16
|
+
children: /* @__PURE__ */ r("div", {
|
|
17
|
+
className: "prose prose-sm",
|
|
18
|
+
children: /* @__PURE__ */ r(a, {
|
|
19
|
+
remarkPlugins: [o],
|
|
20
|
+
children: n.message
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
}), n.suggestion && /* @__PURE__ */ r("p", {
|
|
24
|
+
className: "mt-2 text-ds-sm text-surface-fg-muted",
|
|
25
|
+
children: n.suggestion
|
|
26
|
+
})]
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
s.displayName = "ErrorBlock";
|
|
30
|
+
//#endregion
|
|
31
|
+
export { s as ErrorBlock };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","names":[],"sources":["../../../src/ai/blocks/error.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nimport { Alert } from '../../ui/alert'\nimport { cn } from '../../ui/lib/utils'\nimport type { BlockComponentProps, ErrorBlockData } from '../types'\n\nconst ErrorBlock = React.memo(function ErrorBlock({\n data,\n confidence,\n}: BlockComponentProps<ErrorBlockData>) {\n return (\n <div\n className={cn(\n confidence === 'low' && 'border-l-2 border-warning-7 pl-3',\n )}\n >\n <Alert color=\"error\" variant=\"subtle\" title={data.title}>\n <div className=\"prose prose-sm\">\n <Markdown remarkPlugins={[remarkGfm]}>{data.message}</Markdown>\n </div>\n </Alert>\n {data.suggestion && (\n <p className=\"mt-2 text-ds-sm text-surface-fg-muted\">\n {data.suggestion}\n </p>\n )}\n </div>\n )\n})\n\nErrorBlock.displayName = 'ErrorBlock'\n\nexport { ErrorBlock }\n"],"mappings":";;;;;;;;AAUA,IAAM,IAAa,EAAM,KAAK,SAAoB,EAChD,SACA,iBACsC;AACtC,QACE,kBAAC,OAAD;EACE,WAAW,EACT,MAAe,SAAS,mCACzB;YAHH,CAKE,kBAAC,GAAD;GAAO,OAAM;GAAQ,SAAQ;GAAS,OAAO,EAAK;aAChD,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAU,eAAe,CAAC,EAAU;eAAG,EAAK;KAAmB,CAAA;IAC3D,CAAA;GACA,CAAA,EACP,EAAK,cACJ,kBAAC,KAAD;GAAG,WAAU;aACV,EAAK;GACJ,CAAA,CAEF;;EAER;AAEF,EAAW,cAAc"}
|