@mitcsutt/kiln-ui 0.7.0 → 0.8.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.
@@ -0,0 +1,69 @@
1
+ import { type ReactElement, type ReactNode, type RefAttributes } from 'react';
2
+ import { type TableAlign, type TableColumnWidth, type TableProps } from '../Table/index.js';
3
+ import type { VisibilityProps } from '../../../utils/visibility.js';
4
+ /** One column of a {@link TreeTable}. The first column holds the tree: indent, toggle and the row's name. */
5
+ export interface TreeTableColumn extends VisibilityProps {
6
+ /** Stable key, passed back to `renderCell`. */
7
+ id: string;
8
+ /** The header cell's content. */
9
+ header: ReactNode;
10
+ align?: TableAlign;
11
+ /** Numeric column: right-aligned with tabular figures. */
12
+ numeric?: boolean;
13
+ /** Column sizing: `fill` takes the spare width, `min` shrinks to fit. */
14
+ width?: TableColumnWidth;
15
+ }
16
+ export interface TreeTableProps<T> extends Omit<TableProps, 'children' | 'label' | 'role' | 'onChange' | 'defaultValue'> {
17
+ /** Name for the grid, read by assistive technology. */
18
+ label: string;
19
+ /** The columns, in order. The first holds the tree. */
20
+ columns: readonly TreeTableColumn[];
21
+ /** The top-level rows. */
22
+ rows: readonly T[];
23
+ /** A stable, unique id for a row. It is what `expanded` holds and what keeps focus on a row across renders. */
24
+ getRowId: (row: T) => string;
25
+ /** The row's children, or `undefined` when it has none. */
26
+ getChildren: (row: T) => readonly T[] | undefined;
27
+ /**
28
+ * Whether the row can be opened. Defaults to `getChildren(row)` having entries. Return `true` for a
29
+ * row whose children load when it opens.
30
+ */
31
+ hasChildren?: (row: T) => boolean;
32
+ /** The ids of the open rows (controlled). */
33
+ expanded?: readonly string[];
34
+ /** The ids of the rows that start open (uncontrolled). */
35
+ defaultExpanded?: readonly string[];
36
+ /** Called with the ids of the open rows when one opens or closes. */
37
+ onExpandedChange?: (expanded: string[]) => void;
38
+ /** The content of one cell. The first column's content sits beside the toggle. */
39
+ renderCell: (row: T, column: TreeTableColumn) => ReactNode;
40
+ }
41
+ /**
42
+ * A table of rows in a hierarchy, with a toggle on each parent and keyboard navigation like a file
43
+ * tree.
44
+ *
45
+ * @remarks
46
+ * `TreeTable` is a WAI-ARIA `treegrid` set in `Table`'s styles. Hand it the top-level `rows`, how to
47
+ * find a row's `children`, and `renderCell`; it handles the indent, the toggles, and the
48
+ * `aria-level`, `aria-expanded`, `aria-setsize` and `aria-posinset` on every row.
49
+ *
50
+ * ## Keyboard
51
+ *
52
+ * The grid is one tab stop, and the arrow keys move between rows: Up and Down step by row, Right
53
+ * opens a closed row and then steps into its first child, Left closes an open row and then steps
54
+ * out to its parent, Home and End jump to the first and last visible row, and Enter follows the
55
+ * first link in the row. Links and buttons in a row's cells are reached by Enter, not Tab, so put
56
+ * the row's main link in its first column.
57
+ *
58
+ * ## Open rows
59
+ *
60
+ * `expanded` holds the ids of the open rows, as `getRowId` returns them. Pass it with
61
+ * `onExpandedChange` to control them, for example to keep them in the URL, or `defaultExpanded` to
62
+ * choose which start open. For children that load when a row opens, return `true` from
63
+ * `hasChildren` and give the row a placeholder child while they load.
64
+ *
65
+ * @privateRemarks
66
+ * A separate export, not `Table.Tree`, so a plain `import { Table }` never carries the key handling
67
+ * (docs/adr/0044). Ref and native props go to the `<table>`.
68
+ */
69
+ export declare const TreeTable: <T>(props: TreeTableProps<T> & RefAttributes<HTMLTableElement>) => ReactElement;
@@ -0,0 +1,152 @@
1
+ import { cx as e } from "../../../utils/cx.js";
2
+ import { ChevronRightIcon as t } from "../../../icons/icons.js";
3
+ import { useLatest as n } from "../../inputs/internal/useLatest.js";
4
+ import { Table as r } from "../Table/Table.js";
5
+ import i from "./TreeTable.module.js";
6
+ import { forwardRef as a, useCallback as o, useLayoutEffect as s, useMemo as c, useRef as l, useState as u } from "react";
7
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
8
+ //#region src/components/display/TreeTable/TreeTable.tsx
9
+ function p({ label: a, columns: p, rows: m, getRowId: h, getChildren: g, hasChildren: _, expanded: v, defaultExpanded: y, onExpandedChange: b, renderCell: x, className: S, ...C }, w) {
10
+ let [T, E] = u(y ?? []), D = v !== void 0, O = D ? v : T, k = n(b), [A, j] = u(), M = l(/* @__PURE__ */ new Map()), N = l(null), P = c(() => {
11
+ let e = new Set(O), t = [], n = (r, i, a) => {
12
+ r.forEach((o, s) => {
13
+ let c = h(o), l = g(o), u = _ ? _(o) : (l?.length ?? 0) > 0, d = u && e.has(c);
14
+ t.push({
15
+ row: o,
16
+ id: c,
17
+ level: i + 1,
18
+ setSize: r.length,
19
+ posInSet: s + 1,
20
+ parentId: a,
21
+ expandable: u,
22
+ open: d
23
+ }), d && l && n(l, i + 1, c);
24
+ });
25
+ };
26
+ return n(m, 0, void 0), t;
27
+ }, [
28
+ m,
29
+ O,
30
+ h,
31
+ g,
32
+ _
33
+ ]), F = P.some((e) => e.id === A) ? A : P[0]?.id, I = o((e, t) => {
34
+ let n = O.filter((t) => t !== e);
35
+ t && n.push(e), D || E(n), k.current?.(n);
36
+ }, [
37
+ D,
38
+ O,
39
+ k
40
+ ]);
41
+ s(() => {
42
+ N.current?.querySelectorAll("a[href], button").forEach((e) => {
43
+ e.setAttribute("tabindex", "-1");
44
+ });
45
+ });
46
+ let L = (e) => {
47
+ e !== void 0 && (j(e), M.current.get(e)?.focus());
48
+ }, R = (e) => {
49
+ let t = e.target.closest("tr");
50
+ if (e.target !== t || e.altKey || e.ctrlKey || e.metaKey) return;
51
+ let n = P.findIndex((e) => M.current.get(e.id) === t), r = P[n];
52
+ if (!r) return;
53
+ let i = (t) => {
54
+ e.preventDefault();
55
+ let r = {
56
+ next: P[n + 1],
57
+ prev: P[n - 1],
58
+ first: P[0],
59
+ last: P[P.length - 1]
60
+ }[t];
61
+ L(r?.id);
62
+ };
63
+ switch (e.key) {
64
+ case "ArrowDown":
65
+ i("next");
66
+ return;
67
+ case "ArrowUp":
68
+ i("prev");
69
+ return;
70
+ case "Home":
71
+ i("first");
72
+ return;
73
+ case "End":
74
+ i("last");
75
+ return;
76
+ case "ArrowRight":
77
+ if (!r.expandable) return;
78
+ e.preventDefault(), r.open ? P[n + 1]?.parentId === r.id && L(P[n + 1]?.id) : I(r.id, !0);
79
+ return;
80
+ case "ArrowLeft":
81
+ r.open ? (e.preventDefault(), I(r.id, !1)) : r.parentId !== void 0 && (e.preventDefault(), L(r.parentId));
82
+ return;
83
+ case "Enter": {
84
+ let n = t.querySelector("a[href]");
85
+ if (!n) return;
86
+ e.preventDefault(), n.click();
87
+ return;
88
+ }
89
+ }
90
+ }, z = (e) => {
91
+ let t = e.target.closest("tr"), n = P.find((e) => M.current.get(e.id) === t);
92
+ n && j(n.id);
93
+ };
94
+ return /* @__PURE__ */ f(r, {
95
+ ref: w,
96
+ role: "treegrid",
97
+ "aria-label": a,
98
+ className: e(i.treeTable, S),
99
+ ...C,
100
+ children: [/* @__PURE__ */ d(r.Head, { children: /* @__PURE__ */ d(r.Row, { children: p.map((e) => /* @__PURE__ */ d(r.HeaderCell, {
101
+ align: e.align,
102
+ numeric: e.numeric,
103
+ width: e.width,
104
+ hideBelow: e.hideBelow,
105
+ hideAbove: e.hideAbove,
106
+ children: e.header
107
+ }, e.id)) }) }), /* @__PURE__ */ d(r.Body, {
108
+ ref: N,
109
+ onKeyDown: R,
110
+ onFocus: z,
111
+ children: P.map((e) => /* @__PURE__ */ d(r.Row, {
112
+ ref: (t) => {
113
+ t ? M.current.set(e.id, t) : M.current.delete(e.id);
114
+ },
115
+ className: i.row,
116
+ interactive: !0,
117
+ tabIndex: e.id === F ? 0 : -1,
118
+ "aria-level": e.level,
119
+ "aria-setsize": e.setSize,
120
+ "aria-posinset": e.posInSet,
121
+ "aria-expanded": e.expandable ? e.open : void 0,
122
+ children: p.map((n, a) => /* @__PURE__ */ d(r.Cell, {
123
+ rowHeader: a === 0,
124
+ align: n.align,
125
+ numeric: n.numeric,
126
+ hideBelow: n.hideBelow,
127
+ hideAbove: n.hideAbove,
128
+ children: a === 0 ? /* @__PURE__ */ f("span", {
129
+ className: i.treeCellContent,
130
+ style: { "--_level": e.level - 1 },
131
+ children: [/* @__PURE__ */ d("button", {
132
+ type: "button",
133
+ className: i.toggle,
134
+ tabIndex: -1,
135
+ "aria-hidden": "true",
136
+ "data-leaf": e.expandable ? void 0 : "",
137
+ onClick: () => {
138
+ L(e.id), I(e.id, !e.open);
139
+ },
140
+ children: /* @__PURE__ */ d(t, { className: i.chevron })
141
+ }), x(e.row, n)]
142
+ }) : x(e.row, n)
143
+ }, n.id))
144
+ }, e.id))
145
+ })]
146
+ });
147
+ }
148
+ var m = a(p);
149
+ //#endregion
150
+ export { m as TreeTable };
151
+
152
+ //# sourceMappingURL=TreeTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeTable.js","names":["styles","TreeTable_module_default","TreeTableInner","expandedProp","rest","inner","setInner","useState","defaultExpanded","controlled","expandedIds","onChange","useLatest","onExpandedChange","activeId","setActiveId","elements","useRef","body","nodes","useMemo","open","out","walk","id","getRowId","row","children","getChildren","expandable","hasChildren","isOpen","level","siblings","index","rows","tabId","node","setExpanded","useCallback","next","existing","moveTo","onKeyDown","rowElement","event","go","target","to","link","onFocus","found","Table","label","cx","className","columns","column","element","columnIndex","ChevronRightIcon","renderCell","TreeTable","forwardRef"],"sources":["../../../../src/components/display/TreeTable/TreeTable.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefAttributes,\n} from 'react'\nimport {\n Table,\n type TableAlign,\n type TableColumnWidth,\n type TableProps,\n} from '#components/display/Table'\nimport { ChevronRightIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport type { VisibilityProps } from '#utils/visibility'\nimport { useLatest } from '#components/inputs/internal/useLatest'\nimport styles from './TreeTable.module.css'\n\n/** One column of a {@link TreeTable}. The first column holds the tree: indent, toggle and the row's name. */\nexport interface TreeTableColumn extends VisibilityProps {\n /** Stable key, passed back to `renderCell`. */\n id: string\n /** The header cell's content. */\n header: ReactNode\n align?: TableAlign\n /** Numeric column: right-aligned with tabular figures. */\n numeric?: boolean\n /** Column sizing: `fill` takes the spare width, `min` shrinks to fit. */\n width?: TableColumnWidth\n}\n\nexport interface TreeTableProps<T> extends Omit<\n TableProps,\n 'children' | 'label' | 'role' | 'onChange' | 'defaultValue'\n> {\n /** Name for the grid, read by assistive technology. */\n label: string\n /** The columns, in order. The first holds the tree. */\n columns: readonly TreeTableColumn[]\n /** The top-level rows. */\n rows: readonly T[]\n /** A stable, unique id for a row. It is what `expanded` holds and what keeps focus on a row across renders. */\n getRowId: (row: T) => string\n /** The row's children, or `undefined` when it has none. */\n getChildren: (row: T) => readonly T[] | undefined\n /**\n * Whether the row can be opened. Defaults to `getChildren(row)` having entries. Return `true` for a\n * row whose children load when it opens.\n */\n hasChildren?: (row: T) => boolean\n /** The ids of the open rows (controlled). */\n expanded?: readonly string[]\n /** The ids of the rows that start open (uncontrolled). */\n defaultExpanded?: readonly string[]\n /** Called with the ids of the open rows when one opens or closes. */\n onExpandedChange?: (expanded: string[]) => void\n /** The content of one cell. The first column's content sits beside the toggle. */\n renderCell: (row: T, column: TreeTableColumn) => ReactNode\n}\n\ninterface Node<T> {\n row: T\n id: string\n level: number\n setSize: number\n posInSet: number\n parentId: string | undefined\n expandable: boolean\n open: boolean\n}\n\ntype Dispatch = 'next' | 'prev' | 'first' | 'last'\n\nfunction TreeTableInner<T>(\n {\n label,\n columns,\n rows,\n getRowId,\n getChildren,\n hasChildren,\n expanded: expandedProp,\n defaultExpanded,\n onExpandedChange,\n renderCell,\n className,\n ...rest\n }: TreeTableProps<T>,\n ref: Ref<HTMLTableElement>,\n) {\n const [inner, setInner] = useState<readonly string[]>(defaultExpanded ?? [])\n const controlled = expandedProp !== undefined\n const expandedIds = controlled ? expandedProp : inner\n const onChange = useLatest(onExpandedChange)\n const [activeId, setActiveId] = useState<string>()\n const elements = useRef(new Map<string, HTMLTableRowElement>())\n const body = useRef<HTMLTableSectionElement>(null)\n\n const nodes = useMemo(() => {\n const open = new Set(expandedIds)\n const out: Node<T>[] = []\n const walk = (siblings: readonly T[], level: number, parentId: string | undefined) => {\n siblings.forEach((row, index) => {\n const id = getRowId(row)\n const children = getChildren(row)\n const expandable = hasChildren ? hasChildren(row) : (children?.length ?? 0) > 0\n const isOpen = expandable && open.has(id)\n out.push({\n row,\n id,\n level: level + 1,\n setSize: siblings.length,\n posInSet: index + 1,\n parentId,\n expandable,\n open: isOpen,\n })\n if (isOpen && children) walk(children, level + 1, id)\n })\n }\n walk(rows, 0, undefined)\n return out\n }, [rows, expandedIds, getRowId, getChildren, hasChildren])\n\n const tabId = nodes.some((node) => node.id === activeId) ? activeId : nodes[0]?.id\n\n const setExpanded = useCallback(\n (id: string, open: boolean) => {\n const next = expandedIds.filter((existing) => existing !== id)\n if (open) next.push(id)\n if (!controlled) setInner(next)\n onChange.current?.(next)\n },\n [controlled, expandedIds, onChange],\n )\n\n // Links and buttons inside a row are reached with Enter on the row, so they stay out of the tab\n // order: the grid is one tab stop, however many rows are open.\n useLayoutEffect(() => {\n body.current?.querySelectorAll<HTMLElement>('a[href], button').forEach((element) => {\n element.setAttribute('tabindex', '-1')\n })\n })\n\n const moveTo = (id: string | undefined) => {\n if (id === undefined) return\n setActiveId(id)\n elements.current.get(id)?.focus()\n }\n\n const onKeyDown = (event: KeyboardEvent<HTMLTableSectionElement>) => {\n const rowElement = (event.target as HTMLElement).closest('tr')\n if (event.target !== rowElement || event.altKey || event.ctrlKey || event.metaKey) return\n const index = nodes.findIndex((node) => elements.current.get(node.id) === rowElement)\n const node = nodes[index]\n if (!node) return\n const go = (to: Dispatch) => {\n event.preventDefault()\n const target = {\n next: nodes[index + 1],\n prev: nodes[index - 1],\n first: nodes[0],\n last: nodes[nodes.length - 1],\n }[to]\n moveTo(target?.id)\n }\n switch (event.key) {\n case 'ArrowDown':\n go('next')\n return\n case 'ArrowUp':\n go('prev')\n return\n case 'Home':\n go('first')\n return\n case 'End':\n go('last')\n return\n case 'ArrowRight':\n if (!node.expandable) return\n event.preventDefault()\n if (!node.open) setExpanded(node.id, true)\n else if (nodes[index + 1]?.parentId === node.id) moveTo(nodes[index + 1]?.id)\n return\n case 'ArrowLeft':\n if (node.open) {\n event.preventDefault()\n setExpanded(node.id, false)\n } else if (node.parentId !== undefined) {\n event.preventDefault()\n moveTo(node.parentId)\n }\n return\n case 'Enter': {\n const link = rowElement.querySelector<HTMLElement>('a[href]')\n if (!link) return\n event.preventDefault()\n link.click()\n return\n }\n }\n }\n\n // Clicking inside a row (or focusing a link in it) makes that row the one tab stop.\n const onFocus = (event: FocusEvent<HTMLTableSectionElement>) => {\n const rowElement = (event.target as HTMLElement).closest('tr')\n const found = nodes.find((node) => elements.current.get(node.id) === rowElement)\n if (found) setActiveId(found.id)\n }\n\n return (\n <Table\n ref={ref}\n role=\"treegrid\"\n aria-label={label}\n className={cx(styles.treeTable, className)}\n {...rest}\n >\n <Table.Head>\n <Table.Row>\n {columns.map((column) => (\n <Table.HeaderCell\n key={column.id}\n align={column.align}\n numeric={column.numeric}\n width={column.width}\n hideBelow={column.hideBelow}\n hideAbove={column.hideAbove}\n >\n {column.header}\n </Table.HeaderCell>\n ))}\n </Table.Row>\n </Table.Head>\n <Table.Body ref={body} onKeyDown={onKeyDown} onFocus={onFocus}>\n {nodes.map((node) => (\n <Table.Row\n key={node.id}\n ref={(element) => {\n if (element) elements.current.set(node.id, element)\n else elements.current.delete(node.id)\n }}\n className={styles.row}\n interactive\n tabIndex={node.id === tabId ? 0 : -1}\n aria-level={node.level}\n aria-setsize={node.setSize}\n aria-posinset={node.posInSet}\n aria-expanded={node.expandable ? node.open : undefined}\n >\n {columns.map((column, columnIndex) => {\n return (\n <Table.Cell\n key={column.id}\n rowHeader={columnIndex === 0}\n align={column.align}\n numeric={column.numeric}\n hideBelow={column.hideBelow}\n hideAbove={column.hideAbove}\n >\n {columnIndex === 0 ? (\n <span\n className={styles.treeCellContent}\n style={{ '--_level': node.level - 1 } as CSSProperties}\n >\n <button\n type=\"button\"\n className={styles.toggle}\n tabIndex={-1}\n aria-hidden=\"true\"\n data-leaf={node.expandable ? undefined : ''}\n onClick={() => {\n moveTo(node.id)\n setExpanded(node.id, !node.open)\n }}\n >\n <ChevronRightIcon className={styles.chevron} />\n </button>\n {renderCell(node.row, column)}\n </span>\n ) : (\n renderCell(node.row, column)\n )}\n </Table.Cell>\n )\n })}\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n )\n}\n\n/**\n * A table of rows in a hierarchy, with a toggle on each parent and keyboard navigation like a file\n * tree.\n *\n * @remarks\n * `TreeTable` is a WAI-ARIA `treegrid` set in `Table`'s styles. Hand it the top-level `rows`, how to\n * find a row's `children`, and `renderCell`; it handles the indent, the toggles, and the\n * `aria-level`, `aria-expanded`, `aria-setsize` and `aria-posinset` on every row.\n *\n * ## Keyboard\n *\n * The grid is one tab stop, and the arrow keys move between rows: Up and Down step by row, Right\n * opens a closed row and then steps into its first child, Left closes an open row and then steps\n * out to its parent, Home and End jump to the first and last visible row, and Enter follows the\n * first link in the row. Links and buttons in a row's cells are reached by Enter, not Tab, so put\n * the row's main link in its first column.\n *\n * ## Open rows\n *\n * `expanded` holds the ids of the open rows, as `getRowId` returns them. Pass it with\n * `onExpandedChange` to control them, for example to keep them in the URL, or `defaultExpanded` to\n * choose which start open. For children that load when a row opens, return `true` from\n * `hasChildren` and give the row a placeholder child while they load.\n *\n * @privateRemarks\n * A separate export, not `Table.Tree`, so a plain `import { Table }` never carries the key handling\n * (docs/adr/0044). Ref and native props go to the `<table>`.\n */\nexport const TreeTable = forwardRef(TreeTableInner) as <T>(\n props: TreeTableProps<T> & RefAttributes<HTMLTableElement>,\n) => ReactElement\n"],"mappings":";;;;;;;;AAkFA,SAASE,EACP,EACE,UACA,YACA,SACA,aACA,gBACA,gBACA,UAAUC,GACV,oBACA,qBACA,eACA,cACA,GAAGC,KAEL,GACA;CACA,IAAM,CAACC,GAAOC,KAAYC,EAA4BC,KAAmB,CAAC,CAAC,GACrEC,IAAaN,MAAiB,KAAA,GAC9BO,IAAcD,IAAaN,IAAeE,GAC1CM,IAAWC,EAAUC,CAAgB,GACrC,CAACC,GAAUC,KAAeR,EAAiB,GAC3CS,IAAWC,kBAAO,IAAI,IAAiC,CAAC,GACxDC,IAAOD,EAAgC,IAAI,GAE3CE,IAAQC,QAAc;EAC1B,IAAMC,IAAO,IAAI,IAAIX,CAAW,GAC1BY,IAAiB,CAAC,GAClBC,KAAQ,GAAwB,GAAe,MAAiC;GACpF,EAAS,SAAS,GAAK,MAAU;IAC/B,IAAMC,IAAKC,EAASC,CAAG,GACjBC,IAAWC,EAAYF,CAAG,GAC1BG,IAAaC,IAAcA,EAAYJ,CAAG,KAAKC,GAAU,UAAU,KAAK,GACxEI,IAASF,KAAcR,EAAK,IAAIG,CAAE;IAWxC,AAVAF,EAAI,KAAK;KACP;KACA;KACA,OAAOU,IAAQ;KACf,SAASC,EAAS;KAClB,UAAUC,IAAQ;KAClB;KACA;KACA,MAAMH;IACR,CAAC,GACGA,KAAUJ,KAAUJ,EAAKI,GAAUK,IAAQ,GAAGR,CAAE;GACtD,CAAC;EACH;EAEA,OADAD,EAAKY,GAAM,GAAG,KAAA,CAAS,GAChBb;CACT,GAAG;EAACa;EAAMzB;EAAae;EAAUG;EAAaE;CAAW,CAAC,GAEpDM,IAAQjB,EAAM,MAAM,MAASkB,EAAK,OAAOvB,CAAQ,IAAIA,IAAWK,EAAM,EAAE,EAAE,IAE1EmB,IAAcC,GACjB,GAAY,MAAkB;EAC7B,IAAMC,IAAO9B,EAAY,QAAQ,MAAa+B,MAAajB,CAAE;EAG7D,AAFIH,KAAMmB,EAAK,KAAKhB,CAAE,GACjBf,KAAYH,EAASkC,CAAI,GAC9B7B,EAAS,UAAU6B,CAAI;CACzB,GACA;EAAC/B;EAAYC;EAAaC;CAAQ,CACpC;CAIA,QAAsB;EACpB,EAAK,SAAS,iBAA8B,iBAAiB,CAAC,CAAC,SAAS,MAAY;GAClF,EAAQ,aAAa,YAAY,IAAI;EACvC,CAAC;CACH,CAAC;CAED,IAAM+B,KAAU,MAA2B;EACzC,AAAIlB,MAAO,KAAA,MACXT,EAAYS,CAAE,GACdR,EAAS,QAAQ,IAAIQ,CAAE,CAAC,EAAE,MAAM;CAClC,GAEMmB,KAAa,MAAkD;EACnE,IAAMC,IAAcC,EAAM,OAAuB,QAAQ,IAAI;EAC7D,IAAIA,EAAM,WAAWD,KAAcC,EAAM,UAAUA,EAAM,WAAWA,EAAM,SAAS;EACnF,IAAMX,IAAQf,EAAM,WAAW,MAASH,EAAS,QAAQ,IAAIqB,EAAK,EAAE,MAAMO,CAAU,GAC9EP,IAAOlB,EAAMe;EACnB,IAAI,CAACG,GAAM;EACX,IAAMS,KAAM,MAAiB;GAC3B,EAAM,eAAe;GACrB,IAAMC,IAAS;IACb,MAAM5B,EAAMe,IAAQ;IACpB,MAAMf,EAAMe,IAAQ;IACpB,OAAOf,EAAM;IACb,MAAMA,EAAMA,EAAM,SAAS;GAC7B,EAAE6B;GACF,EAAOD,GAAQ,EAAE;EACnB;EACA,QAAQF,EAAM,KAAd;GACE,KAAK;IACH,EAAG,MAAM;IACT;GACF,KAAK;IACH,EAAG,MAAM;IACT;GACF,KAAK;IACH,EAAG,OAAO;IACV;GACF,KAAK;IACH,EAAG,MAAM;IACT;GACF,KAAK;IACH,IAAI,CAACR,EAAK,YAAY;IAEtB,AADAQ,EAAM,eAAe,GAChBR,EAAK,OACDlB,EAAMe,IAAQ,EAAE,EAAE,aAAaG,EAAK,MAAIK,EAAOvB,EAAMe,IAAQ,EAAE,EAAE,EAAE,IAD5DI,EAAYD,EAAK,IAAI,EAAI;IAEzC;GACF,KAAK;IACH,AAAIA,EAAK,QACPQ,EAAM,eAAe,GACrBP,EAAYD,EAAK,IAAI,EAAK,KACjBA,EAAK,aAAa,KAAA,MAC3BQ,EAAM,eAAe,GACrBH,EAAOL,EAAK,QAAQ;IAEtB;GACF,KAAK,SAAS;IACZ,IAAMY,IAAOL,EAAW,cAA2B,SAAS;IAC5D,IAAI,CAACK,GAAM;IAEX,AADAJ,EAAM,eAAe,GACrBI,EAAK,MAAM;IACX;GACF;EACF;CACF,GAGMC,KAAW,MAA+C;EAC9D,IAAMN,IAAcC,EAAM,OAAuB,QAAQ,IAAI,GACvDM,IAAQhC,EAAM,MAAM,MAASH,EAAS,QAAQ,IAAIqB,EAAK,EAAE,MAAMO,CAAU;EAC/E,AAAIO,KAAOpC,EAAYoC,EAAM,EAAE;CACjC;CAEA,OACE,kBAACC,GAAD;EACO;EACL,MAAK;EACL,cAAYC;EACZ,WAAWC,EAAGtD,EAAO,WAAWuD,CAAS;EACzC,GAAInD;EALN,UAAA,CAOE,kBAACgD,EAAM,MAAP,EAAA,UACE,kBAACA,EAAM,KAAP,EAAA,UACGI,EAAQ,KAAK,MACZ,kBAACJ,EAAM,YAAP;GAEE,OAAOK,EAAO;GACd,SAASA,EAAO;GAChB,OAAOA,EAAO;GACd,WAAWA,EAAO;GAClB,WAAWA,EAAO;GAEjB,UAAAA,EAAO;EACQ,GARXA,EAAO,EAQI,CACnB,EACQ,CAAA,EACD,CAAA,GACZ,kBAACL,EAAM,MAAP;GAAY,KAAKlC;GAAiB;GAAoB;GACnD,UAAAC,EAAM,KAAK,MACV,kBAACiC,EAAM,KAAP;IAEE,MAAM,MAAY;KAChB,AAAIM,IAAS1C,EAAS,QAAQ,IAAIqB,EAAK,IAAIqB,CAAO,IAC7C1C,EAAS,QAAQ,OAAOqB,EAAK,EAAE;IACtC;IACA,WAAWrC,EAAO;IAClB,aAAA;IACA,UAAUqC,EAAK,OAAOD,IAAQ,IAAI;IAClC,cAAYC,EAAK;IACjB,gBAAcA,EAAK;IACnB,iBAAeA,EAAK;IACpB,iBAAeA,EAAK,aAAaA,EAAK,OAAO,KAAA;IAE5C,UAAAmB,EAAQ,KAAK,GAAQ,MAElB,kBAACJ,EAAM,MAAP;KAEE,WAAWO,MAAgB;KAC3B,OAAOF,EAAO;KACd,SAASA,EAAO;KAChB,WAAWA,EAAO;KAClB,WAAWA,EAAO;KAEjB,UAAAE,MAAgB,IACf,kBAAC,QAAD;MACE,WAAW3D,EAAO;MAClB,OAAO,EAAE,YAAYqC,EAAK,QAAQ,EAAE;MAFtC,UAAA,CAIE,kBAAC,UAAD;OACE,MAAK;OACL,WAAWrC,EAAO;OAClB,UAAU;OACV,eAAY;OACZ,aAAWqC,EAAK,aAAa,KAAA,IAAY;OACzC,eAAe;QAEb,AADAK,EAAOL,EAAK,EAAE,GACdC,EAAYD,EAAK,IAAI,CAACA,EAAK,IAAI;OACjC;OAEA,UAAA,kBAACuB,GAAD,EAAkB,WAAW5D,EAAO,QAAU,CAAA;MACxC,CAAA,GACP6D,EAAWxB,EAAK,KAAKoB,CAAM,CACxB;KAEN,CAAA,IAAAI,EAAWxB,EAAK,KAAKoB,CAAM;IAEnB,GA9BLA,EAAO,EA8BF,CAEf;GACQ,GAjDJpB,EAAK,EAiDD,CACZ;EACS,CAAA,CACP;;AAEX;AA8BA,IAAayB,IAAYC,EAAW7D,CAAc"}
@@ -0,0 +1,12 @@
1
+ //#region src/components/display/TreeTable/TreeTable.module.css
2
+ var e = "kiln-TreeTable__treeTable", t = "kiln-TreeTable__row", n = "kiln-TreeTable__treeCellContent", r = "kiln-TreeTable__toggle", i = "kiln-TreeTable__chevron", a = {
3
+ treeTable: e,
4
+ row: t,
5
+ treeCellContent: n,
6
+ toggle: r,
7
+ chevron: i
8
+ };
9
+ //#endregion
10
+ export { i as chevron, a as default, t as row, r as toggle, n as treeCellContent, e as treeTable };
11
+
12
+ //# sourceMappingURL=TreeTable.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeTable.module.js","names":["treeTable","row","treeCellContent","toggle","chevron","TreeTable_module_default"],"sources":["../../../../src/components/display/TreeTable/TreeTable.module.css"],"sourcesContent":["/*\n * Component tokens (themes may set any of these on [data-theme]):\n * --tree-table-indent default var(--space-5) — how far each level steps in\n *\n * The table itself is styled by Table; this file adds the indent, the toggle and the row focus.\n */\n.treeTable {\n --_indent: var(--tree-table-indent, var(--space-5));\n}\n\n.row:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: -2px;\n}\n\n.treeCellContent {\n --_level: 0;\n margin-inline-start: calc(var(--_level) * var(--_indent));\n display: inline-flex;\n align-items: baseline;\n gap: var(--space-1);\n min-inline-size: 0;\n}\n\n.toggle {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n inline-size: 1.25rem;\n block-size: 1.25rem;\n padding: 0;\n border: 0;\n background: none;\n color: var(--color-ink-muted);\n cursor: pointer;\n align-self: center;\n}\n\n.toggle[data-leaf] {\n visibility: hidden;\n}\n\n.chevron {\n inline-size: 1rem;\n block-size: 1rem;\n transition: transform var(--dur-3) var(--ease-out);\n}\n\n.row[aria-expanded='true'] .chevron {\n transform: rotate(90deg);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .chevron {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export { TreeTable } from './TreeTable.js';
2
+ export type { TreeTableProps, TreeTableColumn } from './TreeTable.js';
package/dist/index.d.ts CHANGED
@@ -197,6 +197,8 @@ export type { DataListProps, DataListItemProps, DataListOrientation, } from './c
197
197
  export { List } from './components/display/List/index.js';
198
198
  export type { ListProps, ListItemProps, ListDensity, ListElement, ListSurface, } from './components/display/List/index.js';
199
199
  export { Table } from './components/display/Table/index.js';
200
+ export { TreeTable } from './components/display/TreeTable/index.js';
201
+ export type { TreeTableProps, TreeTableColumn } from './components/display/TreeTable/index.js';
200
202
  export type { TableProps, TableDensity, TableVariant, TableSurface, TableAlign, TableVerticalAlign, TableSort, TableRowProps, TableHeaderCellProps, TableCellProps, TableColumnWidth, } from './components/display/Table/index.js';
201
203
  export { Media } from './components/display/Media/index.js';
202
204
  export type { MediaProps, MediaRatio, MediaFit, MediaRadius, MediaSize, } from './components/display/Media/index.js';
package/dist/index.js CHANGED
@@ -111,33 +111,34 @@ import { Stat as Xt } from "./components/display/Stat/Stat.js";
111
111
  import { DataList as Zt } from "./components/display/DataList/DataList.js";
112
112
  import { List as Qt } from "./components/display/List/List.js";
113
113
  import { Table as $t } from "./components/display/Table/Table.js";
114
- import { Media as en } from "./components/display/Media/Media.js";
115
- import { Marquee as tn } from "./components/display/Marquee/Marquee.js";
116
- import { CodeBlock as nn } from "./components/display/CodeBlock/CodeBlock.js";
117
- import { Stamp as rn } from "./components/display/Stamp/Stamp.js";
118
- import { Progress as an } from "./components/display/Progress/Progress.js";
119
- import { meterTone as on } from "./components/display/Meter/meterTone.js";
120
- import { Meter as sn } from "./components/display/Meter/Meter.js";
121
- import { Skeleton as cn } from "./components/display/Skeleton/Skeleton.js";
122
- import { EmptyState as ln } from "./components/display/EmptyState/EmptyState.js";
123
- import { Tabs as un } from "./components/navigation/Tabs/Tabs.js";
124
- import { NavLinks as dn } from "./components/navigation/NavLinks/NavLinks.js";
125
- import { NavLinksGroup as fn } from "./components/navigation/NavLinks/NavLinksGroup.js";
126
- import { BottomNav as pn } from "./components/navigation/BottomNav/BottomNav.js";
127
- import { Accordion as mn } from "./components/navigation/Accordion/Accordion.js";
128
- import { Collapsible as hn } from "./components/navigation/Collapsible/Collapsible.js";
129
- import { Stepper as gn } from "./components/navigation/Stepper/Stepper.js";
130
- import { Alert as _n } from "./components/feedback/Alert/Alert.js";
131
- import { toast as vn } from "./components/feedback/Toaster/toast.js";
132
- import { Toaster as yn } from "./components/feedback/Toaster/Toaster.js";
133
- import { LiveIndicator as bn } from "./components/feedback/LiveIndicator/LiveIndicator.js";
134
- import { Flash as xn } from "./components/feedback/Flash/Flash.js";
135
- import { StatusDot as Sn } from "./components/feedback/StatusDot/StatusDot.js";
136
- import { Indicator as Cn } from "./components/feedback/Indicator/Indicator.js";
137
- import { formatAbsoluteTime as wn, formatRelativeTime as Tn } from "./components/feedback/RelativeTime/format.js";
138
- import { RelativeTime as En } from "./components/feedback/RelativeTime/RelativeTime.js";
139
- import { Dialog as Dn } from "./components/overlays/Dialog/Dialog.js";
140
- import { Sheet as On } from "./components/overlays/Sheet/Sheet.js";
141
- import { DropdownMenu as kn } from "./components/overlays/DropdownMenu/DropdownMenu.js";
142
- import { CommandPalette as An } from "./components/overlays/CommandPalette/CommandPalette.js";
143
- export { mn as Accordion, oe as ActionBar, _n as Alert, Se as Amount, et as AmountField, $e as AmountInput, ie as AppShell, u as ArrowLeftIcon, d as ArrowRightIcon, f as ArrowUpRightIcon, ne as AspectRatio, qt as Avatar, Jt as AvatarGroup, Wt as Badge, pn as BottomNav, X as Box, Te as Button, ct as Calendar, p as CalendarIcon, Ut as Card, m as CheckIcon, Ve as Checkbox, Je as CheckboxField, gt as CheckboxGroup, _t as CheckboxGroupField, h as ChevronDownIcon, g as ChevronLeftIcon, _ as ChevronRightIcon, v as ChevronUpIcon, Pe as ChipGroup, bt as ChipGroupField, xt as ChoiceCards, St as ChoiceCardsField, y as CircleCheckIcon, b as ClockIcon, x as CloseIcon, me as Code, nn as CodeBlock, se as Collapse, hn as Collapsible, it as ColorField, rt as ColorInput, jt as Combobox, Mt as ComboboxField, An as CommandPalette, $ as Container, Ae as CopyButton, S as CopyIcon, ue as DEFAULT_HEADING_SIZE, e as DEFAULT_THEME, Zt as DataList, pt as DateField, lt as DateInput, ot as DateRangeField, ft as DateRangePickerField, ht as DateTimeField, dt as DateTimeInput, Yt as Delta, Dn as Dialog, te as Divider, kn as DropdownMenu, ln as EmptyState, C as ErrorIcon, w as EyeIcon, T as EyeOffIcon, Le as Field, We as Fieldset, Ft as FileDrop, It as FileField, xn as Flash, Z as Grid, de as Heading, E as HelpIcon, Ee as IconButton, Cn as Indicator, D as InfoIcon, Y as Inline, Re as Input, Vt as JsonField, zt as JsonInput, he as Kbd, pe as Link, Qt as List, bn as LiveIndicator, t as MODES, tn as Marquee, en as Media, O as MenuIcon, k as MessageIcon, sn as Meter, A as MinusIcon, Ie as ModeToggle, j as MoonIcon, M as MoreIcon, dn as NavLinks, fn as NavLinksGroup, Qe as NumberField, Ze as NumberInput, xe as Numeral, nt as OneTimeCodeField, tt as OneTimeCodeInput, Xe as PasswordField, Ye as PasswordInput, N as PlusIcon, st as Popover, an as Progress, ge as Prose, _e as Quote, He as RadioGroup, vt as RadioGroupField, P as RadioIcon, Tt as RangeSlider, Et as RangeSliderField, Dt as Rating, Ot as RatingField, En as RelativeTime, ae as ScrollArea, F as SearchIcon, ee as Section, Ce as SectionHeader, Fe as SegmentedControl, yt as SegmentedField, Be as Select, qe as SelectField, On as Sheet, I as ShieldIcon, le as ShowMore, cn as Skeleton, Ct as Slider, wt as SliderField, we as Spinner, Q as Split, J as Stack, rn as Stamp, L as StarIcon, Xt as Stat, Sn as StatusDot, gn as Stepper, R as SunIcon, je as Swatch, Ue as Switch, at as SwitchField, z as SwordsIcon, B as SystemIcon, n as THEMES, r as THEME_META, $t as Table, un as Tabs, kt as Tag, At as TagList, Pt as TagsField, Nt as TagsInput, V as TargetIcon, fe as Text, Ge as TextField, ze as Textarea, Ke as TextareaField, o as ThemeProvider, s as ThemeScope, mt as TimeField, ut as TimeInput, yn as Toaster, Me as ToggleChip, De as Tooltip, Oe as TooltipProvider, ce as Transition, H as TrendingUpIcon, U as TrophyIcon, W as UploadIcon, G as UsersIcon, re as VisuallyHidden, K as WarningIcon, q as ZapIcon, Gt as avatarColor, l as createIcon, c as cx, Ht as describeJsonError, wn as formatAbsoluteTime, Lt as formatJson, ve as formatNumeral, ye as formatNumeralParts, Tn as formatRelativeTime, Kt as getInitials, on as meterTone, Rt as minifyJson, be as signOf, a as themeScript, vn as toast, ke as useClipboard, Ne as useFieldControl, i as useTheme, Bt as validateJson };
114
+ import { TreeTable as en } from "./components/display/TreeTable/TreeTable.js";
115
+ import { Media as tn } from "./components/display/Media/Media.js";
116
+ import { Marquee as nn } from "./components/display/Marquee/Marquee.js";
117
+ import { CodeBlock as rn } from "./components/display/CodeBlock/CodeBlock.js";
118
+ import { Stamp as an } from "./components/display/Stamp/Stamp.js";
119
+ import { Progress as on } from "./components/display/Progress/Progress.js";
120
+ import { meterTone as sn } from "./components/display/Meter/meterTone.js";
121
+ import { Meter as cn } from "./components/display/Meter/Meter.js";
122
+ import { Skeleton as ln } from "./components/display/Skeleton/Skeleton.js";
123
+ import { EmptyState as un } from "./components/display/EmptyState/EmptyState.js";
124
+ import { Tabs as dn } from "./components/navigation/Tabs/Tabs.js";
125
+ import { NavLinks as fn } from "./components/navigation/NavLinks/NavLinks.js";
126
+ import { NavLinksGroup as pn } from "./components/navigation/NavLinks/NavLinksGroup.js";
127
+ import { BottomNav as mn } from "./components/navigation/BottomNav/BottomNav.js";
128
+ import { Accordion as hn } from "./components/navigation/Accordion/Accordion.js";
129
+ import { Collapsible as gn } from "./components/navigation/Collapsible/Collapsible.js";
130
+ import { Stepper as _n } from "./components/navigation/Stepper/Stepper.js";
131
+ import { Alert as vn } from "./components/feedback/Alert/Alert.js";
132
+ import { toast as yn } from "./components/feedback/Toaster/toast.js";
133
+ import { Toaster as bn } from "./components/feedback/Toaster/Toaster.js";
134
+ import { LiveIndicator as xn } from "./components/feedback/LiveIndicator/LiveIndicator.js";
135
+ import { Flash as Sn } from "./components/feedback/Flash/Flash.js";
136
+ import { StatusDot as Cn } from "./components/feedback/StatusDot/StatusDot.js";
137
+ import { Indicator as wn } from "./components/feedback/Indicator/Indicator.js";
138
+ import { formatAbsoluteTime as Tn, formatRelativeTime as En } from "./components/feedback/RelativeTime/format.js";
139
+ import { RelativeTime as Dn } from "./components/feedback/RelativeTime/RelativeTime.js";
140
+ import { Dialog as On } from "./components/overlays/Dialog/Dialog.js";
141
+ import { Sheet as kn } from "./components/overlays/Sheet/Sheet.js";
142
+ import { DropdownMenu as An } from "./components/overlays/DropdownMenu/DropdownMenu.js";
143
+ import { CommandPalette as jn } from "./components/overlays/CommandPalette/CommandPalette.js";
144
+ export { hn as Accordion, oe as ActionBar, vn as Alert, Se as Amount, et as AmountField, $e as AmountInput, ie as AppShell, u as ArrowLeftIcon, d as ArrowRightIcon, f as ArrowUpRightIcon, ne as AspectRatio, qt as Avatar, Jt as AvatarGroup, Wt as Badge, mn as BottomNav, X as Box, Te as Button, ct as Calendar, p as CalendarIcon, Ut as Card, m as CheckIcon, Ve as Checkbox, Je as CheckboxField, gt as CheckboxGroup, _t as CheckboxGroupField, h as ChevronDownIcon, g as ChevronLeftIcon, _ as ChevronRightIcon, v as ChevronUpIcon, Pe as ChipGroup, bt as ChipGroupField, xt as ChoiceCards, St as ChoiceCardsField, y as CircleCheckIcon, b as ClockIcon, x as CloseIcon, me as Code, rn as CodeBlock, se as Collapse, gn as Collapsible, it as ColorField, rt as ColorInput, jt as Combobox, Mt as ComboboxField, jn as CommandPalette, $ as Container, Ae as CopyButton, S as CopyIcon, ue as DEFAULT_HEADING_SIZE, e as DEFAULT_THEME, Zt as DataList, pt as DateField, lt as DateInput, ot as DateRangeField, ft as DateRangePickerField, ht as DateTimeField, dt as DateTimeInput, Yt as Delta, On as Dialog, te as Divider, An as DropdownMenu, un as EmptyState, C as ErrorIcon, w as EyeIcon, T as EyeOffIcon, Le as Field, We as Fieldset, Ft as FileDrop, It as FileField, Sn as Flash, Z as Grid, de as Heading, E as HelpIcon, Ee as IconButton, wn as Indicator, D as InfoIcon, Y as Inline, Re as Input, Vt as JsonField, zt as JsonInput, he as Kbd, pe as Link, Qt as List, xn as LiveIndicator, t as MODES, nn as Marquee, tn as Media, O as MenuIcon, k as MessageIcon, cn as Meter, A as MinusIcon, Ie as ModeToggle, j as MoonIcon, M as MoreIcon, fn as NavLinks, pn as NavLinksGroup, Qe as NumberField, Ze as NumberInput, xe as Numeral, nt as OneTimeCodeField, tt as OneTimeCodeInput, Xe as PasswordField, Ye as PasswordInput, N as PlusIcon, st as Popover, on as Progress, ge as Prose, _e as Quote, He as RadioGroup, vt as RadioGroupField, P as RadioIcon, Tt as RangeSlider, Et as RangeSliderField, Dt as Rating, Ot as RatingField, Dn as RelativeTime, ae as ScrollArea, F as SearchIcon, ee as Section, Ce as SectionHeader, Fe as SegmentedControl, yt as SegmentedField, Be as Select, qe as SelectField, kn as Sheet, I as ShieldIcon, le as ShowMore, ln as Skeleton, Ct as Slider, wt as SliderField, we as Spinner, Q as Split, J as Stack, an as Stamp, L as StarIcon, Xt as Stat, Cn as StatusDot, _n as Stepper, R as SunIcon, je as Swatch, Ue as Switch, at as SwitchField, z as SwordsIcon, B as SystemIcon, n as THEMES, r as THEME_META, $t as Table, dn as Tabs, kt as Tag, At as TagList, Pt as TagsField, Nt as TagsInput, V as TargetIcon, fe as Text, Ge as TextField, ze as Textarea, Ke as TextareaField, o as ThemeProvider, s as ThemeScope, mt as TimeField, ut as TimeInput, bn as Toaster, Me as ToggleChip, De as Tooltip, Oe as TooltipProvider, ce as Transition, en as TreeTable, H as TrendingUpIcon, U as TrophyIcon, W as UploadIcon, G as UsersIcon, re as VisuallyHidden, K as WarningIcon, q as ZapIcon, Gt as avatarColor, l as createIcon, c as cx, Ht as describeJsonError, Tn as formatAbsoluteTime, Lt as formatJson, ve as formatNumeral, ye as formatNumeralParts, En as formatRelativeTime, Kt as getInitials, sn as meterTone, Rt as minifyJson, be as signOf, a as themeScript, yn as toast, ke as useClipboard, Ne as useFieldControl, i as useTheme, Bt as validateJson };