@sylwellsoftware/fray 0.1.0-alpha.1

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.
Files changed (94) hide show
  1. package/EXPERIMENTAL.md +75 -0
  2. package/LICENSE +55 -0
  3. package/NOTICE +2 -0
  4. package/README.md +521 -0
  5. package/dist/Components/Placeholder.d.ts +14 -0
  6. package/dist/Components/Placeholder.d.ts.map +1 -0
  7. package/dist/Components/component.d.ts +187 -0
  8. package/dist/Components/component.d.ts.map +1 -0
  9. package/dist/Components/controlUtils.d.ts +20 -0
  10. package/dist/Components/controlUtils.d.ts.map +1 -0
  11. package/dist/Components/data/descriptionList.d.ts +21 -0
  12. package/dist/Components/data/descriptionList.d.ts.map +1 -0
  13. package/dist/Components/data/listview/listview.d.ts +39 -0
  14. package/dist/Components/data/listview/listview.d.ts.map +1 -0
  15. package/dist/Components/data/selectionhandler.d.ts +68 -0
  16. package/dist/Components/data/selectionhandler.d.ts.map +1 -0
  17. package/dist/Components/data/table/DataTable.d.ts +72 -0
  18. package/dist/Components/data/table/DataTable.d.ts.map +1 -0
  19. package/dist/Components/data/table/FilterPanel.d.ts +35 -0
  20. package/dist/Components/data/table/FilterPanel.d.ts.map +1 -0
  21. package/dist/Components/data/table/TableHeader.d.ts +21 -0
  22. package/dist/Components/data/table/TableHeader.d.ts.map +1 -0
  23. package/dist/Components/data/table/TableHeaderCell.d.ts +39 -0
  24. package/dist/Components/data/table/TableHeaderCell.d.ts.map +1 -0
  25. package/dist/Components/data/table/tableQuery.d.ts +25 -0
  26. package/dist/Components/data/table/tableQuery.d.ts.map +1 -0
  27. package/dist/Components/data/treeview/treeitem.d.ts +20 -0
  28. package/dist/Components/data/treeview/treeitem.d.ts.map +1 -0
  29. package/dist/Components/data/treeview/treeview.d.ts +42 -0
  30. package/dist/Components/data/treeview/treeview.d.ts.map +1 -0
  31. package/dist/Components/dialog/dialog.d.ts +37 -0
  32. package/dist/Components/dialog/dialog.d.ts.map +1 -0
  33. package/dist/Components/layout/panel.d.ts +20 -0
  34. package/dist/Components/layout/panel.d.ts.map +1 -0
  35. package/dist/Components/layout/sidebar.d.ts +18 -0
  36. package/dist/Components/layout/sidebar.d.ts.map +1 -0
  37. package/dist/Components/layout/splitView.d.ts +18 -0
  38. package/dist/Components/layout/splitView.d.ts.map +1 -0
  39. package/dist/Components/layout/tabpanel/tab.d.ts +12 -0
  40. package/dist/Components/layout/tabpanel/tab.d.ts.map +1 -0
  41. package/dist/Components/layout/tabpanel/tabline.d.ts +32 -0
  42. package/dist/Components/layout/tabpanel/tabline.d.ts.map +1 -0
  43. package/dist/Components/layout/tabpanel/tabpanel.d.ts +34 -0
  44. package/dist/Components/layout/tabpanel/tabpanel.d.ts.map +1 -0
  45. package/dist/Components/lineinputs/checkbox/Checkbox.d.ts +35 -0
  46. package/dist/Components/lineinputs/checkbox/Checkbox.d.ts.map +1 -0
  47. package/dist/Components/lineinputs/checkbox/QuadCheckbox.d.ts +12 -0
  48. package/dist/Components/lineinputs/checkbox/QuadCheckbox.d.ts.map +1 -0
  49. package/dist/Components/lineinputs/checkbox/TriCheckbox.d.ts +12 -0
  50. package/dist/Components/lineinputs/checkbox/TriCheckbox.d.ts.map +1 -0
  51. package/dist/Components/lineinputs/dropdown.d.ts +37 -0
  52. package/dist/Components/lineinputs/dropdown.d.ts.map +1 -0
  53. package/dist/Components/lineinputs/textbox.d.ts +36 -0
  54. package/dist/Components/lineinputs/textbox.d.ts.map +1 -0
  55. package/dist/Components/lineinputs/toggle.d.ts +30 -0
  56. package/dist/Components/lineinputs/toggle.d.ts.map +1 -0
  57. package/dist/Components/menu/button.d.ts +24 -0
  58. package/dist/Components/menu/button.d.ts.map +1 -0
  59. package/dist/Components/menu/toolbar.d.ts +15 -0
  60. package/dist/Components/menu/toolbar.d.ts.map +1 -0
  61. package/dist/Components/status/progressBar.d.ts +21 -0
  62. package/dist/Components/status/progressBar.d.ts.map +1 -0
  63. package/dist/button-BRDkmR1C.js +203 -0
  64. package/dist/button-BRDkmR1C.js.map +1 -0
  65. package/dist/experimental.d.ts +16 -0
  66. package/dist/experimental.d.ts.map +1 -0
  67. package/dist/experimental.js +1361 -0
  68. package/dist/experimental.js.map +1 -0
  69. package/dist/index.d.ts +23 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +1014 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/jsx-dev-runtime-CarwHDyL.js +1155 -0
  74. package/dist/jsx-dev-runtime-CarwHDyL.js.map +1 -0
  75. package/dist/jsx-dev-runtime.d.ts +2 -0
  76. package/dist/jsx-dev-runtime.d.ts.map +1 -0
  77. package/dist/jsx-dev-runtime.js +6 -0
  78. package/dist/jsx-dev-runtime.js.map +1 -0
  79. package/dist/jsx-runtime.d.ts +26 -0
  80. package/dist/jsx-runtime.d.ts.map +1 -0
  81. package/dist/jsx-runtime.js +9 -0
  82. package/dist/jsx-runtime.js.map +1 -0
  83. package/dist/runtime.d.ts +29 -0
  84. package/dist/runtime.d.ts.map +1 -0
  85. package/dist/styling/baseStyleDefinitions.d.ts +154 -0
  86. package/dist/styling/baseStyleDefinitions.d.ts.map +1 -0
  87. package/dist/styling/styleRegistry.d.ts +19 -0
  88. package/dist/styling/styleRegistry.d.ts.map +1 -0
  89. package/dist/util/filterMode.d.ts +13 -0
  90. package/dist/util/filterMode.d.ts.map +1 -0
  91. package/package.json +83 -0
  92. package/themes/README.md +30 -0
  93. package/themes/dark.css +39 -0
  94. package/themes/light.css +39 -0
@@ -0,0 +1,1361 @@
1
+ var ie = Object.defineProperty;
2
+ var ne = (t, r, e) => r in t ? ie(t, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[r] = e;
3
+ var o = (t, r, e) => ne(t, typeof r != "symbol" ? r + "" : r, e);
4
+ import { C as b, j as c, c as x, a as w, i as U } from "./jsx-dev-runtime-CarwHDyL.js";
5
+ import { Emitter as y, FetchState as m, DerivedEmitter as oe, QueryArg as V, LiveQuery as ae, RestQueryHandler as le } from "@sylwellsoftware/glue";
6
+ import { c as I, C as F, F as K, i as W, a as de, b as ce, B as Q } from "./button-BRDkmR1C.js";
7
+ class E extends b {
8
+ render() {
9
+ const r = he(this.props.width ?? 65), e = this.Host;
10
+ return /* @__PURE__ */ c(e, { style: { width: `${r}%` }, "aria-hidden": "true" });
11
+ }
12
+ }
13
+ o(E, "hostName", "placeholder"), o(E, "standaloneHostName", "loading-placeholder"), o(E, "baseStyles", [
14
+ ["&::after", ["after", "working"]]
15
+ ]), o(E, "css", x`
16
+ & {
17
+ display: block;
18
+ min-width: 3rem;
19
+ height: 1em;
20
+ overflow: hidden;
21
+ background: currentColor;
22
+ border-radius: var(--ui-border-radius);
23
+ opacity: 0.18;
24
+ position: relative;
25
+ }
26
+
27
+ @keyframes fray-placeholder-progress {
28
+ from { background-position: 0 0; }
29
+ to { background-position: 2rem 0; }
30
+ }
31
+ `);
32
+ function he(t) {
33
+ const r = Number(t);
34
+ if (!Number.isFinite(r)) throw new TypeError("Placeholder width must be numeric");
35
+ return Math.min(100, Math.max(10, r));
36
+ }
37
+ class J {
38
+ constructor({
39
+ getItems: r,
40
+ getKey: e = z,
41
+ selectedItemsEmitter: s,
42
+ owner: i = null
43
+ }) {
44
+ o(this, "getItems");
45
+ o(this, "getKey");
46
+ o(this, "selectedItemsEmitter");
47
+ o(this, "selectedItems$");
48
+ o(this, "ownsSelectedItemsEmitter");
49
+ o(this, "rows", []);
50
+ o(this, "rowCleanups", []);
51
+ o(this, "activeIndex", 0);
52
+ o(this, "anchorIndex", null);
53
+ o(this, "dragStartIndex", null);
54
+ o(this, "dragOriginEvent", null);
55
+ o(this, "dragMoved", !1);
56
+ o(this, "dragCleanup", null);
57
+ o(this, "suppressNextClick", !1);
58
+ o(this, "suppressClickTimer", null);
59
+ o(this, "destroyed", !1);
60
+ o(this, "ownedSelectedItemsEmitter");
61
+ if (typeof r != "function")
62
+ throw new TypeError("Selection handler getItems must be a function");
63
+ if (typeof e != "function")
64
+ throw new TypeError("Selection handler getKey must be a function");
65
+ this.getItems = r, this.getKey = e, this.ownedSelectedItemsEmitter = s == null ? new y([], { owner: i, purpose: "selected items" }) : null, this.selectedItemsEmitter = s ?? this.ownedSelectedItemsEmitter, this.selectedItems$ = this.selectedItemsEmitter, this.ownsSelectedItemsEmitter = this.ownedSelectedItemsEmitter != null;
66
+ }
67
+ rowsUpdated(r) {
68
+ this.destroyed || (this.releaseRows(), this.rows = Array.from(r ?? []), this.rows.forEach((e, s) => this.wireRow(e, s)), this.activeIndex = fe(this.activeIndex, this.rows.length), this.reconcileSelectedItems(), this.syncRows());
69
+ }
70
+ wireRow(r, e) {
71
+ const s = (l) => this.handleClick(e, l), i = (l) => this.handleKeyDown(e, l), n = (l) => this.handleMouseDown(e, l, r), a = (l) => this.handleMouseEnter(e, l);
72
+ r.addEventListener("click", s), r.addEventListener("keydown", i), r.addEventListener("mousedown", n), r.addEventListener("mouseenter", a), this.rowCleanups.push(() => {
73
+ r.removeEventListener("click", s), r.removeEventListener("keydown", i), r.removeEventListener("mousedown", n), r.removeEventListener("mouseenter", a);
74
+ });
75
+ }
76
+ handleClick(r, e) {
77
+ var s;
78
+ if (e.preventDefault(), this.suppressNextClick) {
79
+ this.clearClickSuppression();
80
+ return;
81
+ }
82
+ this.activeIndex = r, this.selectIndex(r, e), (s = this.rows[r]) == null || s.focus();
83
+ }
84
+ handleMouseDown(r, e, s) {
85
+ if (e.button !== 0 || !this.supportsDragSelection()) return;
86
+ this.finishDrag(!1), this.clearClickSuppression(), this.dragStartIndex = r, this.dragOriginEvent = e, this.dragMoved = !1;
87
+ const i = s.ownerDocument, n = () => this.finishDrag(this.dragMoved);
88
+ i.addEventListener("mouseup", n), this.dragCleanup = () => i.removeEventListener("mouseup", n);
89
+ }
90
+ handleMouseEnter(r, e) {
91
+ var s;
92
+ this.dragStartIndex != null && (r === this.dragStartIndex && !this.dragMoved || r === this.activeIndex && this.dragMoved || (e.preventDefault(), this.dragMoved = !0, this.activeIndex = r, this.selectDragRange(this.dragStartIndex, r, this.dragOriginEvent ?? e), (s = this.rows[r]) == null || s.focus()));
93
+ }
94
+ handleKeyDown(r, e) {
95
+ var n;
96
+ const s = this.rows.length - 1;
97
+ let i;
98
+ if (e.key === "ArrowDown") i = Math.min(r + 1, s);
99
+ else if (e.key === "ArrowUp") i = Math.max(r - 1, 0);
100
+ else if (e.key === "Home") i = 0;
101
+ else if (e.key === "End") i = s;
102
+ else if (e.key === " " || e.key === "Enter") {
103
+ e.preventDefault(), this.activeIndex = r, this.selectIndex(r, e);
104
+ return;
105
+ } else return;
106
+ e.preventDefault(), this.activeIndex = i, this.onKeyboardMove(i, e), this.syncRows(), (n = this.rows[i]) == null || n.focus();
107
+ }
108
+ onKeyboardMove(r, e) {
109
+ this.selectIndex(r, e);
110
+ }
111
+ supportsDragSelection() {
112
+ return !1;
113
+ }
114
+ selectDragRange(r, e, s) {
115
+ }
116
+ selectIndex(r, e) {
117
+ }
118
+ setSelectedItems(r, e = "selection changed") {
119
+ this.selectedItemsEmitter.set(r, e), this.syncRows();
120
+ }
121
+ getSelectedItems() {
122
+ return this.selectedItemsEmitter.get() ?? [];
123
+ }
124
+ getSelectedItemsEmitter() {
125
+ return this.selectedItemsEmitter;
126
+ }
127
+ reconcileSelectedItems() {
128
+ const r = this.getSelectedItems();
129
+ if (r.length === 0) return;
130
+ const e = new Set(r.map((i, n) => this.getKey(i, n))), s = this.getItems().filter((i, n) => e.has(this.getKey(i, n)));
131
+ (s.length !== r.length || s.some((i, n) => !Object.is(i, r[n]))) && this.selectedItemsEmitter.set([...s], "selection reconciled with rows");
132
+ }
133
+ syncRows() {
134
+ const r = new Set(this.getSelectedItems().map((s, i) => this.getKey(s, i))), e = this.getItems();
135
+ this.rows.forEach((s, i) => {
136
+ const n = e[i], a = n !== void 0 && r.has(this.getKey(n, i));
137
+ s.classList.toggle("selected", a), s.setAttribute("aria-selected", String(a)), s.tabIndex = i === this.activeIndex ? 0 : -1;
138
+ });
139
+ }
140
+ releaseRows() {
141
+ for (const r of this.rowCleanups.splice(0)) r();
142
+ this.rows = [];
143
+ }
144
+ finishDrag(r) {
145
+ var e;
146
+ (e = this.dragCleanup) == null || e.call(this), this.dragCleanup = null, this.dragStartIndex = null, this.dragOriginEvent = null, this.dragMoved = !1, r && (this.suppressNextClick = !0, this.suppressClickTimer != null && clearTimeout(this.suppressClickTimer), this.suppressClickTimer = setTimeout(() => this.clearClickSuppression(), 0));
147
+ }
148
+ clearClickSuppression() {
149
+ this.suppressNextClick = !1, this.suppressClickTimer != null && clearTimeout(this.suppressClickTimer), this.suppressClickTimer = null;
150
+ }
151
+ destroy() {
152
+ var r;
153
+ this.destroyed || (this.destroyed = !0, this.finishDrag(!1), this.clearClickSuppression(), this.releaseRows(), (r = this.ownedSelectedItemsEmitter) == null || r.dispose());
154
+ }
155
+ }
156
+ class ue extends J {
157
+ selectIndex(r) {
158
+ const e = this.getItems()[r];
159
+ e !== void 0 && (this.anchorIndex = r, this.setSelectedItems([e], "single selection changed"));
160
+ }
161
+ }
162
+ class pe extends J {
163
+ selectIndex(r, e) {
164
+ const s = this.getItems(), i = s[r];
165
+ if (i !== void 0) {
166
+ if (e.shiftKey && this.anchorIndex != null) {
167
+ const n = Math.min(this.anchorIndex, r), a = Math.max(this.anchorIndex, r), l = s.slice(n, a + 1), d = L(e) ? P(this.getSelectedItems(), l, this.getKey) : [...l];
168
+ this.setSelectedItems(d, "range selection changed");
169
+ return;
170
+ }
171
+ if (L(e) || "key" in e && e.key === " ") {
172
+ const n = this.getSelectedItems(), a = this.getKey(i, r), d = n.some((h, u) => Object.is(this.getKey(h, u), a)) ? n.filter((h, u) => !Object.is(this.getKey(h, u), a)) : [...n, i];
173
+ this.anchorIndex = r, this.setSelectedItems(d, "multi selection toggled");
174
+ return;
175
+ }
176
+ this.anchorIndex = r, this.setSelectedItems([i], "multi selection changed");
177
+ }
178
+ }
179
+ onKeyboardMove(r, e) {
180
+ e.shiftKey && this.selectIndex(r, e);
181
+ }
182
+ supportsDragSelection() {
183
+ return !0;
184
+ }
185
+ selectDragRange(r, e, s) {
186
+ const i = this.getItems(), n = Math.min(r, e), a = Math.max(r, e), l = i.slice(n, a + 1), d = L(s) ? P(this.getSelectedItems(), l, this.getKey) : [...l];
187
+ this.anchorIndex = r, this.setSelectedItems(d, "drag selection changed");
188
+ }
189
+ }
190
+ function Y(t) {
191
+ return t.multiSelect ? new pe(t) : new ue(t);
192
+ }
193
+ function z(t, r) {
194
+ if (t != null && typeof t == "object") {
195
+ const e = Reflect.get(t, "id");
196
+ if (e != null) return e;
197
+ }
198
+ if (typeof t == "string" || typeof t == "number") return t;
199
+ throw new TypeError(
200
+ `Selection item at index ${r} needs an id or an explicit itemKey/rowKey`
201
+ );
202
+ }
203
+ function L(t) {
204
+ return !!(t.ctrlKey || t.metaKey);
205
+ }
206
+ function fe(t, r) {
207
+ return r <= 0 ? 0 : Math.min(Math.max(t, 0), r - 1);
208
+ }
209
+ function P(t, r, e) {
210
+ const s = [...t], i = new Set(t.map((n, a) => e(n, a)));
211
+ for (const n of r) {
212
+ const a = e(n, s.length);
213
+ i.has(a) || (i.add(a), s.push(n));
214
+ }
215
+ return s;
216
+ }
217
+ class D extends b {
218
+ constructor(e = {}) {
219
+ super(e);
220
+ o(this, "itemsEmitter");
221
+ o(this, "items$");
222
+ o(this, "selectedItemsEmitter");
223
+ o(this, "selectedItems$");
224
+ o(this, "getItemKey");
225
+ o(this, "selectionHandler");
226
+ o(this, "ownedItemsEmitter");
227
+ o(this, "ownedSelectedItemsEmitter");
228
+ ge(e.items) ? (this.itemsEmitter = e.items, this.ownedItemsEmitter = null) : (this.ownedItemsEmitter = new y(e.items ?? [], {
229
+ owner: this,
230
+ purpose: "list items"
231
+ }), this.itemsEmitter = this.ownedItemsEmitter), this.items$ = this.itemsEmitter, this.ownedSelectedItemsEmitter = e.selectedItemsEmitter == null ? new y([], { owner: this, purpose: "selected list items" }) : null, this.selectedItemsEmitter = e.selectedItemsEmitter ?? this.ownedSelectedItemsEmitter, this.selectedItems$ = this.selectedItemsEmitter, this.getItemKey = me(e.itemKey), this.selectionHandler = Y({
232
+ owner: this,
233
+ multiSelect: e.multiSelect ?? !1,
234
+ selectedItemsEmitter: this.selectedItemsEmitter,
235
+ getItems: () => this.itemsEmitter.get(),
236
+ getKey: this.getItemKey
237
+ });
238
+ }
239
+ initialize() {
240
+ this.watch(this.itemsEmitter, this.selectedItemsEmitter);
241
+ }
242
+ render() {
243
+ const e = this.itemsEmitter.get();
244
+ if (!Array.isArray(e)) throw new TypeError("ListView items must be an array");
245
+ const s = this.itemsEmitter.getFetchState(), i = this.itemsEmitter.getError(), n = s === m.Initial || s === m.Loading, a = new Set(this.selectedItemsEmitter.get().map((d, h) => this.getItemKey(d, h))), l = this.Host;
246
+ return /* @__PURE__ */ w(
247
+ l,
248
+ {
249
+ className: I(this.props) || null,
250
+ children: [
251
+ s === m.Error ? /* @__PURE__ */ c("p", { role: "alert", "data-part": "error", children: be(i, "Unable to load items") }) : null,
252
+ n && e.length === 0 ? /* @__PURE__ */ w("div", { role: "status", "data-part": "loading", children: [
253
+ /* @__PURE__ */ c("span", { children: "Loading items…" }),
254
+ Array.from({ length: this.props.placeholderCount ?? 5 }, (d, h) => /* @__PURE__ */ c("div", { "data-part": "placeholder-row", children: /* @__PURE__ */ c(E, { width: 45 + h * 7 }) }, `placeholder-${h}`))
255
+ ] }) : null,
256
+ s === m.Ready && e.length === 0 ? /* @__PURE__ */ c("p", { role: "status", "data-part": "empty", children: "No items" }) : null,
257
+ e.length > 0 ? /* @__PURE__ */ c(
258
+ "div",
259
+ {
260
+ role: "listbox",
261
+ "data-part": "list",
262
+ "aria-label": this.props.label ?? "Items",
263
+ "aria-busy": n ? "true" : null,
264
+ "aria-multiselectable": this.props.multiSelect ? "true" : null,
265
+ children: e.map((d, h) => {
266
+ const u = this.getItemKey(d, h), f = a.has(u), p = this.props.renderItem ? this.props.renderItem(d, h) : ye(d);
267
+ return /* @__PURE__ */ c(
268
+ "div",
269
+ {
270
+ role: "option",
271
+ "data-part": "row",
272
+ "data-fray-selectable-row": "",
273
+ "data-index": h,
274
+ "aria-selected": String(f),
275
+ tabIndex: h === 0 ? 0 : -1,
276
+ children: p
277
+ },
278
+ String(u)
279
+ );
280
+ })
281
+ }
282
+ ) : null
283
+ ]
284
+ }
285
+ );
286
+ }
287
+ afterUpdate(e) {
288
+ const s = e instanceof Element ? e.querySelectorAll("[data-fray-selectable-row]") : [];
289
+ this.selectionHandler.rowsUpdated(s);
290
+ }
291
+ getSelectedItems() {
292
+ return this.selectionHandler.getSelectedItems();
293
+ }
294
+ getSelectedItemsEmitter() {
295
+ return this.selectedItemsEmitter;
296
+ }
297
+ onDestroy() {
298
+ var e, s;
299
+ this.selectionHandler.destroy(), (e = this.ownedItemsEmitter) == null || e.dispose(), (s = this.ownedSelectedItemsEmitter) == null || s.dispose();
300
+ }
301
+ }
302
+ o(D, "dependencies", [E]), o(D, "hostName", "list-view"), o(D, "standaloneHostName", "list-view"), o(D, "baseStyles", [
303
+ ["&", "inputlike"],
304
+ ['& > [data-part="list"] > [data-part="row"]', "inputline"]
305
+ ]), o(D, "css", x`
306
+ & {
307
+ display: flex;
308
+ flex-direction: column;
309
+ overflow-y: auto;
310
+ min-height: 0;
311
+ }
312
+
313
+ & > [data-part="list"],
314
+ & > [data-part="loading"] {
315
+ display: flex;
316
+ flex-direction: column;
317
+ }
318
+
319
+ & > [data-part="list"] > [data-part="row"] {
320
+ cursor: default;
321
+ user-select: none;
322
+ }
323
+
324
+ & > [data-part="list"] > [data-part="row"]:hover,
325
+ & > [data-part="list"] > [data-part="row"]:focus-visible {
326
+ background: var(--button-background-hover);
327
+ outline: 2px solid var(--ui-accent-color);
328
+ outline-offset: -2px;
329
+ }
330
+
331
+ & > [data-part="list"] > [data-part="row"][aria-selected="true"] {
332
+ color: var(--toggle-selected-text);
333
+ background: var(--toggle-selected-bg);
334
+ }
335
+
336
+ & > [data-part="empty"],
337
+ & > [data-part="error"] {
338
+ margin: 0;
339
+ padding: var(--ui-padding);
340
+ }
341
+
342
+ & > [data-part="error"] {
343
+ color: var(--error-color);
344
+ }
345
+ `);
346
+ function me(t) {
347
+ if (t == null) return z;
348
+ if (typeof t == "function") return t;
349
+ if (typeof t == "string" && t.length > 0)
350
+ return (r, e) => {
351
+ if (r == null || typeof r != "object" && typeof r != "function")
352
+ throw new TypeError(`ListView item at index ${e} lacks ${t}`);
353
+ const s = Reflect.get(r, t);
354
+ if (s == null)
355
+ throw new TypeError(`ListView item at index ${e} lacks ${t}`);
356
+ return s;
357
+ };
358
+ throw new TypeError("ListView itemKey must be a function or property name");
359
+ }
360
+ function ge(t) {
361
+ return t != null && (typeof t == "object" || typeof t == "function") && typeof Reflect.get(t, "get") == "function" && typeof Reflect.get(t, "subscribe") == "function";
362
+ }
363
+ function ye(t) {
364
+ if (t != null && (typeof t == "object" || typeof t == "function")) {
365
+ const r = Reflect.get(t, "label");
366
+ if (we(r)) return r;
367
+ }
368
+ return String(t);
369
+ }
370
+ function we(t) {
371
+ return t == null || typeof t == "string" || typeof t == "number";
372
+ }
373
+ function be(t, r) {
374
+ return t instanceof Error ? t.message : t == null ? r : String(t);
375
+ }
376
+ class T extends b {
377
+ constructor(e = {}) {
378
+ super(e);
379
+ o(this, "optionsEmitter");
380
+ this.optionsEmitter = ke(e.options) ? e.options : null;
381
+ }
382
+ initialize() {
383
+ this.optionsEmitter && this.watch(this.optionsEmitter);
384
+ }
385
+ render() {
386
+ var h, u, f;
387
+ const e = ((h = this.optionsEmitter) == null ? void 0 : h.get()) ?? (Array.isArray(this.props.options) ? this.props.options : []);
388
+ if (!Array.isArray(e))
389
+ throw new TypeError("FilterPanel options must be an array or emitter of arrays");
390
+ const s = ((u = this.optionsEmitter) == null ? void 0 : u.getFetchState()) ?? m.Ready, i = (f = this.optionsEmitter) == null ? void 0 : f.getError(), n = Se(this.props.filters), a = this.props.filterModes ?? F.symbols, l = this.props.defaultSemanticState ?? K.Neutral, d = this.Host;
391
+ return s === m.Error ? /* @__PURE__ */ c(
392
+ d,
393
+ {
394
+ className: I(this.props) || null,
395
+ role: "alert",
396
+ "data-state": "error",
397
+ children: ve(i, "Unable to load filter options")
398
+ }
399
+ ) : (s === m.Initial || s === m.Loading) && e.length === 0 ? /* @__PURE__ */ c(
400
+ d,
401
+ {
402
+ className: I(this.props) || null,
403
+ role: "status",
404
+ "data-state": "loading",
405
+ children: "Loading filter options…"
406
+ }
407
+ ) : /* @__PURE__ */ c(
408
+ d,
409
+ {
410
+ className: I(this.props) || null,
411
+ role: "group",
412
+ "aria-label": this.props.label ?? "Filter options",
413
+ children: e.length === 0 ? /* @__PURE__ */ c("span", { children: "No filter options" }) : e.map((p) => {
414
+ const g = X(p), S = Ie(p), C = n.get(g) ?? l;
415
+ return /* @__PURE__ */ c(
416
+ Ee,
417
+ {
418
+ label: S,
419
+ defaultValue: C,
420
+ symbols: a,
421
+ onChange: (q, k) => {
422
+ var R, M;
423
+ k == null || k.stopPropagation();
424
+ const v = new Map(n);
425
+ q === K.Neutral ? v.delete(g) : v.set(g, q), (M = (R = this.props).onChange) == null || M.call(R, v, k);
426
+ }
427
+ },
428
+ `${String(g)}:${String(C)}`
429
+ );
430
+ })
431
+ }
432
+ );
433
+ }
434
+ }
435
+ o(T, "dependencies", [F]), o(T, "hostName", "filter-panel"), o(T, "standaloneHostName", "filter-panel"), o(T, "css", x`
436
+ & {
437
+ position: absolute;
438
+ z-index: 1000;
439
+ inset-block-start: 100%;
440
+ inset-inline-end: 0;
441
+ display: flex;
442
+ min-width: 12rem;
443
+ padding: var(--ui-padding);
444
+ flex-flow: column nowrap;
445
+ align-items: stretch;
446
+ color: var(--panel-color);
447
+ background: var(--panel-bg);
448
+ border: var(--panel-border);
449
+ border-radius: var(--panel-radius);
450
+ box-shadow: var(--panel-shadow);
451
+ }
452
+ `);
453
+ const Ee = F;
454
+ function Se(t) {
455
+ if (t == null) return /* @__PURE__ */ new Map();
456
+ if (t instanceof Map) return new Map(t);
457
+ if (Array.isArray(t)) return new Map(t);
458
+ throw new TypeError("FilterPanel filters must be a Map or tuple array");
459
+ }
460
+ function X(t) {
461
+ if (typeof t == "string" || typeof t == "number") return t;
462
+ if (t != null && typeof t == "object") {
463
+ const r = Reflect.get(t, "value");
464
+ if (typeof r == "string" || typeof r == "number") return r;
465
+ }
466
+ throw new TypeError("Filter options must be strings, numbers, or value/label objects");
467
+ }
468
+ function Ie(t) {
469
+ if (t != null && typeof t == "object") {
470
+ const r = Reflect.get(t, "label");
471
+ if (r != null) return xe(r) ? r : String(r);
472
+ }
473
+ return String(X(t));
474
+ }
475
+ function xe(t) {
476
+ return typeof t == "string" || typeof t == "number";
477
+ }
478
+ function ke(t) {
479
+ return t != null && (typeof t == "object" || typeof t == "function") && typeof Reflect.get(t, "get") == "function" && typeof Reflect.get(t, "subscribe") == "function";
480
+ }
481
+ function ve(t, r) {
482
+ return t instanceof Error ? t.message : t == null ? r : String(t);
483
+ }
484
+ class N extends b {
485
+ constructor() {
486
+ super(...arguments);
487
+ o(this, "filterVisible", !1);
488
+ o(this, "onGlobalClick", (e) => {
489
+ this.filterVisible && this.dom instanceof Node && e.target instanceof Node && !this.dom.contains(e.target) && (this.filterVisible = !1, this.update());
490
+ });
491
+ }
492
+ initialize() {
493
+ this.watch(this.props.sortEmitter, this.props.filtersEmitter), this.props.filterOptions != null && this.listen(document, "click", this.onGlobalClick);
494
+ }
495
+ toggleSort() {
496
+ if (!this.props.sortable) return;
497
+ const e = this.props.sortEmitter.get();
498
+ let s;
499
+ (e == null ? void 0 : e.field) !== this.props.field ? s = { field: this.props.field, direction: "asc" } : e.direction === "asc" ? s = { field: this.props.field, direction: "desc" } : s = null, this.props.sortEmitter.set(s, "table sort changed");
500
+ }
501
+ toggleFilterPanel(e) {
502
+ e.stopPropagation(), this.filterVisible = !this.filterVisible, this.update();
503
+ }
504
+ updateFilters(e, s) {
505
+ var n, a;
506
+ const i = { ...this.props.filtersEmitter.get() };
507
+ e.size === 0 ? delete i[this.props.field] : i[this.props.field] = [...e.entries()], this.props.filtersEmitter.set(i, "table filters changed"), (a = (n = this.props).onFilterChange) == null || a.call(n, i, s);
508
+ }
509
+ render() {
510
+ const e = this.props.sortEmitter.get(), s = (e == null ? void 0 : e.field) === this.props.field ? e.direction : null, i = new Map(
511
+ (this.props.filtersEmitter.get()[this.props.field] ?? []).filter(Te)
512
+ ), n = this.props.label ?? String(this.props.field), a = `Filter ${String(n)}`;
513
+ let l = null;
514
+ return this.filterVisible && this.props.filterOptions != null && (l = /* @__PURE__ */ c(
515
+ T,
516
+ {
517
+ label: a,
518
+ options: this.props.filterOptions,
519
+ filters: i,
520
+ onChange: (d, h) => this.updateFilters(d, h),
521
+ ...this.props.filterModes == null ? {} : { filterModes: this.props.filterModes },
522
+ ...this.props.defaultSemanticState == null ? {} : { defaultSemanticState: this.props.defaultSemanticState }
523
+ },
524
+ "filter-panel"
525
+ )), /* @__PURE__ */ w(
526
+ "th",
527
+ {
528
+ scope: "col",
529
+ "data-fray-component": "table-header-cell",
530
+ "aria-sort": s === "asc" ? "ascending" : s === "desc" ? "descending" : "none",
531
+ children: [
532
+ this.props.sortable ? /* @__PURE__ */ w(
533
+ "button",
534
+ {
535
+ type: "button",
536
+ "data-part": "sort",
537
+ onClick: () => this.toggleSort(),
538
+ children: [
539
+ n,
540
+ s === "asc" ? " ▲" : s === "desc" ? " ▼" : ""
541
+ ]
542
+ }
543
+ ) : /* @__PURE__ */ c("span", { "data-part": "label", children: n }),
544
+ this.props.filterOptions == null ? null : /* @__PURE__ */ c(
545
+ "button",
546
+ {
547
+ type: "button",
548
+ "data-part": "filter-toggle",
549
+ "aria-label": a,
550
+ "aria-expanded": String(this.filterVisible),
551
+ onClick: (d) => this.toggleFilterPanel(d),
552
+ children: "Filter"
553
+ }
554
+ ),
555
+ l
556
+ ]
557
+ }
558
+ );
559
+ }
560
+ }
561
+ o(N, "dependencies", [T]), o(N, "baseStyles", [
562
+ ['th[data-fray-component="table-header-cell"]', "noselect"],
563
+ ['th[data-fray-component="table-header-cell"] > [data-part="sort"]', ["uiline", "button"]],
564
+ ['th[data-fray-component="table-header-cell"] > [data-part="filter-toggle"]', ["uiline", "button"]]
565
+ ]), o(N, "css", x`
566
+ th[data-fray-component="table-header-cell"] {
567
+ position: relative;
568
+ text-align: start;
569
+ }
570
+
571
+ th[data-fray-component="table-header-cell"] > [data-part="sort"],
572
+ th[data-fray-component="table-header-cell"] > [data-part="filter-toggle"] {
573
+ width: auto;
574
+ font-family: inherit;
575
+ }
576
+
577
+ th[data-fray-component="table-header-cell"] > [data-part="filter-toggle"] {
578
+ margin-inline-start: var(--ui-padding-h);
579
+ font-size: 0.75em;
580
+ }
581
+ `);
582
+ function Te(t) {
583
+ return typeof t[0] == "string" || typeof t[0] == "number";
584
+ }
585
+ class H extends b {
586
+ render() {
587
+ return /* @__PURE__ */ c("thead", { "data-fray-component": "table-header", children: /* @__PURE__ */ c("tr", { children: this.props.columns.map((r) => /* @__PURE__ */ c(
588
+ N,
589
+ {
590
+ field: r.field,
591
+ sortEmitter: this.props.sortEmitter,
592
+ filtersEmitter: this.props.filtersEmitter,
593
+ ...r.label == null ? {} : { label: r.label },
594
+ ...r.sortable == null ? {} : { sortable: r.sortable },
595
+ ...r.filterOptions == null ? {} : { filterOptions: r.filterOptions },
596
+ ...this.props.filterModes == null ? {} : { filterModes: this.props.filterModes },
597
+ ...this.props.defaultSemanticState == null ? {} : { defaultSemanticState: this.props.defaultSemanticState },
598
+ ...this.props.onFilterChange == null ? {} : { onFilterChange: this.props.onFilterChange }
599
+ },
600
+ String(r.field)
601
+ )) }) });
602
+ }
603
+ }
604
+ o(H, "dependencies", [N]);
605
+ function Ke(t, { sort: r = null, filters: e = {} } = {}) {
606
+ qe(t), r != null && (Z(r), t.searchParams.set("sort", `${r.field}:${r.direction}`));
607
+ for (const [s, i] of Object.entries(e))
608
+ for (const [n, a] of i) {
609
+ if (!De(a))
610
+ throw new TypeError(`Unknown filter mode for ${s}: ${String(a)}`);
611
+ t.searchParams.append(
612
+ "filter",
613
+ `${s}:${a}:${JSON.stringify(n)}`
614
+ );
615
+ }
616
+ return t;
617
+ }
618
+ function Ce(t, r, e) {
619
+ if (!Array.isArray(t)) throw new TypeError("Local table data must be an array");
620
+ const s = t.filter((n) => Re(n, e));
621
+ if (r == null) return s;
622
+ Z(r);
623
+ const i = r.direction === "asc" ? 1 : -1;
624
+ return [...s].sort((n, a) => Ne($(n, r.field), $(a, r.field)) * i);
625
+ }
626
+ function Re(t, r) {
627
+ for (const [e, s] of Object.entries(r)) {
628
+ const i = $(t, e);
629
+ if (s.filter(([, d]) => d === K.Deny).some(([d]) => Object.is(d, i))) return !1;
630
+ const a = s.filter(([, d]) => d === K.Require);
631
+ if (a.length > 0 && !a.some(([d]) => Object.is(d, i))) return !1;
632
+ const l = s.filter(([, d]) => d === K.Prefer);
633
+ if (l.length > 0 && !l.some(([d]) => Object.is(d, i))) return !1;
634
+ }
635
+ return !0;
636
+ }
637
+ function Z(t) {
638
+ if (t == null || typeof t != "object" || typeof Reflect.get(t, "field") != "string" || !Me(Reflect.get(t, "direction")))
639
+ throw new TypeError("Table sort must contain a field and asc/desc direction");
640
+ }
641
+ function Me(t) {
642
+ return t === "asc" || t === "desc";
643
+ }
644
+ function De(t) {
645
+ return Object.values(K).some((r) => r === t);
646
+ }
647
+ function Ne(t, r) {
648
+ return Object.is(t, r) ? 0 : t == null ? -1 : r == null ? 1 : typeof t == "number" && typeof r == "number" ? t - r : String(t).localeCompare(String(r));
649
+ }
650
+ function $(t, r) {
651
+ if (!(t == null || typeof t != "object" && typeof t != "function"))
652
+ return Reflect.get(t, r);
653
+ }
654
+ function qe(t) {
655
+ if (t == null || typeof t != "object" && typeof t != "function" || typeof Reflect.get(t, "toString") != "function")
656
+ throw new TypeError("Table serializer requires a URL");
657
+ const r = Reflect.get(t, "searchParams");
658
+ if (r == null || typeof Reflect.get(r, "set") != "function" || typeof Reflect.get(r, "append") != "function")
659
+ throw new TypeError("Table serializer requires URL search parameters");
660
+ }
661
+ class j extends b {
662
+ constructor(e) {
663
+ super(e);
664
+ o(this, "columns");
665
+ o(this, "rowKey");
666
+ o(this, "sortEmitter");
667
+ o(this, "filtersEmitter");
668
+ o(this, "selectedItemsEmitter");
669
+ o(this, "selectionHandler");
670
+ o(this, "query", null);
671
+ o(this, "dataSource", null);
672
+ o(this, "ownedSelectedItemsEmitter");
673
+ o(this, "ownedDataSource", null);
674
+ o(this, "ownsQuery", !1);
675
+ o(this, "queryArgs", []);
676
+ if (e.mode !== "local" && e.mode !== "remote")
677
+ throw new TypeError("DataTable mode must be local or remote");
678
+ this.columns = Oe(e.columns), this.rowKey = je(e.rowKey), this.sortEmitter = new y(null, {
679
+ owner: this,
680
+ purpose: "table sort"
681
+ }), this.filtersEmitter = new y({}, {
682
+ owner: this,
683
+ purpose: "table filters"
684
+ }), this.ownedSelectedItemsEmitter = e.selectedItemsEmitter == null ? new y([], { owner: this, purpose: "selected table rows" }) : null, this.selectedItemsEmitter = e.selectedItemsEmitter ?? this.ownedSelectedItemsEmitter, this.selectionHandler = Y({
685
+ owner: this,
686
+ multiSelect: e.multiSelect ?? !1,
687
+ selectedItemsEmitter: this.selectedItemsEmitter,
688
+ getItems: () => {
689
+ var s;
690
+ return ((s = this.query) == null ? void 0 : s.get()) ?? [];
691
+ },
692
+ getKey: this.rowKey
693
+ });
694
+ }
695
+ initialize() {
696
+ this.query = this.props.mode === "local" ? this.createLocalQuery() : this.createRemoteQuery(), this.watch(this.query, this.selectedItemsEmitter);
697
+ }
698
+ createLocalQuery() {
699
+ const e = this.props.data ?? [];
700
+ let s;
701
+ return ee(e) ? s = e : (this.ownedDataSource = new y(e, {
702
+ owner: this,
703
+ purpose: "local table data"
704
+ }), s = this.ownedDataSource), this.dataSource = s, this.ownsQuery = !0, new oe(
705
+ [s, this.sortEmitter, this.filtersEmitter],
706
+ ([i, n, a]) => Ce(i, n, a),
707
+ { owner: this, purpose: "local table view" }
708
+ );
709
+ }
710
+ createRemoteQuery() {
711
+ if (this.props.query != null)
712
+ return Ae(this.props.query), this.props.query;
713
+ const e = this.props.queryHandler ?? this.createRestHandler();
714
+ if (e == null || typeof e.fetch != "function")
715
+ throw new TypeError("Remote DataTable requires query, queryHandler, or queryUrl");
716
+ const s = new V("sort", this.sortEmitter, {
717
+ owner: this,
718
+ purpose: "remote table sort argument"
719
+ }), i = new V("filters", this.filtersEmitter, {
720
+ owner: this,
721
+ purpose: "remote table filters argument"
722
+ });
723
+ this.queryArgs.push(s, i), this.ownsQuery = !0;
724
+ const n = { sort: s, filters: i };
725
+ return new ae({
726
+ handler: e,
727
+ args: n,
728
+ owner: this,
729
+ purpose: "remote table query",
730
+ keepPreviousValue: !0
731
+ });
732
+ }
733
+ createRestHandler() {
734
+ if (this.props.queryUrl == null) return null;
735
+ const e = {
736
+ url: this.props.queryUrl,
737
+ serialize: this.props.serializeQuery ?? Ke
738
+ };
739
+ return this.props.baseUrl != null && (e.baseUrl = this.props.baseUrl), this.props.fetch != null && (e.fetch = this.props.fetch), new le(e);
740
+ }
741
+ render() {
742
+ var d, h, u, f;
743
+ const e = ((d = this.query) == null ? void 0 : d.get()) ?? [];
744
+ if (!Array.isArray(e)) throw new TypeError("DataTable query value must be an array");
745
+ const s = ((h = this.query) == null ? void 0 : h.getFetchState()) ?? m.Initial, i = (u = this.query) == null ? void 0 : u.getError(), n = s === m.Initial || s === m.Loading, a = new Set(
746
+ this.selectedItemsEmitter.get().map((p, g) => this.rowKey(p, g))
747
+ ), l = this.Host;
748
+ return /* @__PURE__ */ w(
749
+ l,
750
+ {
751
+ className: I(this.props) || null,
752
+ "data-loading": n ? "" : null,
753
+ "data-error": s === m.Error ? "" : null,
754
+ children: [
755
+ n ? /* @__PURE__ */ c("p", { role: "status", "data-part": "status", children: "Loading rows…" }) : null,
756
+ s === m.Error ? /* @__PURE__ */ w("div", { "data-part": "error", role: "alert", children: [
757
+ /* @__PURE__ */ c("span", { children: Fe(i, "Unable to load rows") }),
758
+ typeof ((f = this.query) == null ? void 0 : f.retry) == "function" ? /* @__PURE__ */ c(
759
+ "button",
760
+ {
761
+ type: "button",
762
+ onClick: () => {
763
+ var p, g;
764
+ return (g = (p = this.query) == null ? void 0 : p.retry) == null ? void 0 : g.call(p, "table retry");
765
+ },
766
+ children: "Retry"
767
+ }
768
+ ) : null
769
+ ] }) : null,
770
+ /* @__PURE__ */ w("table", { "data-part": "table", "aria-busy": n ? "true" : null, children: [
771
+ this.props.caption == null ? null : /* @__PURE__ */ c("caption", { children: this.props.caption }),
772
+ /* @__PURE__ */ c(
773
+ H,
774
+ {
775
+ columns: this.columns,
776
+ sortEmitter: this.sortEmitter,
777
+ filtersEmitter: this.filtersEmitter,
778
+ ...this.props.filterModes == null ? {} : { filterModes: this.props.filterModes },
779
+ ...this.props.defaultSemanticState == null ? {} : { defaultSemanticState: this.props.defaultSemanticState },
780
+ ...this.props.onFilterChange == null ? {} : { onFilterChange: this.props.onFilterChange }
781
+ },
782
+ "header"
783
+ ),
784
+ /* @__PURE__ */ c("tbody", { children: e.length > 0 ? e.map((p, g) => this.renderRow(p, g, a)) : n ? this.renderPlaceholders() : s === m.Error ? null : /* @__PURE__ */ c("tr", { children: /* @__PURE__ */ c("td", { colSpan: this.columns.length, children: this.props.emptyMessage ?? "No rows" }) }, "empty") })
785
+ ] })
786
+ ]
787
+ }
788
+ );
789
+ }
790
+ renderRow(e, s, i) {
791
+ const n = this.rowKey(e, s), a = i.has(n);
792
+ return /* @__PURE__ */ c(
793
+ "tr",
794
+ {
795
+ "data-fray-selectable-row": "",
796
+ "data-index": s,
797
+ "aria-selected": String(a),
798
+ tabIndex: s === 0 ? 0 : -1,
799
+ children: this.columns.map((l) => /* @__PURE__ */ c("td", { children: l.render ? l.render(e, s) : Le(e[l.field]) }, String(l.field)))
800
+ },
801
+ String(n)
802
+ );
803
+ }
804
+ renderPlaceholders() {
805
+ const e = this.props.placeholderCount ?? 5;
806
+ return Array.from({ length: e }, (s, i) => /* @__PURE__ */ c("tr", { children: this.columns.map((n, a) => /* @__PURE__ */ c("td", { children: /* @__PURE__ */ c(
807
+ E,
808
+ {
809
+ width: 45 + (i + a) % 6 * 8
810
+ }
811
+ ) }, String(n.field))) }, `placeholder-${i}`));
812
+ }
813
+ afterUpdate(e) {
814
+ const s = e instanceof Element ? e.querySelectorAll("tbody [data-fray-selectable-row]") : [];
815
+ this.selectionHandler.rowsUpdated(s);
816
+ }
817
+ getSelectedRows() {
818
+ return this.selectionHandler.getSelectedItems();
819
+ }
820
+ getSelectedRowsEmitter() {
821
+ return this.selectedItemsEmitter;
822
+ }
823
+ onDestroy() {
824
+ var e, s, i, n;
825
+ this.selectionHandler.destroy(), this.ownsQuery && ((s = (e = this.query) == null ? void 0 : e.dispose) == null || s.call(e));
826
+ for (const a of this.queryArgs) a.dispose();
827
+ (i = this.ownedDataSource) == null || i.dispose(), (n = this.ownedSelectedItemsEmitter) == null || n.dispose(), this.sortEmitter.dispose(), this.filtersEmitter.dispose();
828
+ }
829
+ }
830
+ o(j, "dependencies", [E, H]), o(j, "hostName", "data-table"), o(j, "standaloneHostName", "data-table"), o(j, "css", x`
831
+ & {
832
+ overflow: auto;
833
+ color: var(--ui-text-color);
834
+ }
835
+
836
+ & > table {
837
+ width: 100%;
838
+ border-collapse: collapse;
839
+ }
840
+
841
+ & th,
842
+ & td {
843
+ padding: var(--ui-padding-v) var(--ui-padding-h);
844
+ text-align: start;
845
+ }
846
+
847
+ & tbody tr[data-fray-selectable-row] {
848
+ cursor: default;
849
+ user-select: none;
850
+ }
851
+
852
+ & tbody tr[data-fray-selectable-row]:focus-visible {
853
+ outline: 2px solid var(--ui-accent-color);
854
+ outline-offset: -2px;
855
+ }
856
+
857
+ & tbody tr[data-fray-selectable-row][aria-selected="true"] {
858
+ color: var(--toggle-selected-text);
859
+ background: var(--toggle-selected-bg);
860
+ }
861
+
862
+ & > [data-part="error"] {
863
+ color: var(--error-color);
864
+ }
865
+ `);
866
+ function Oe(t) {
867
+ if (!Array.isArray(t) || t.length === 0)
868
+ throw new TypeError("DataTable columns must be a non-empty array");
869
+ const r = /* @__PURE__ */ new Set();
870
+ return t.map((e) => {
871
+ if (e == null || typeof e != "object")
872
+ throw new TypeError("Every DataTable column requires a field");
873
+ const s = Reflect.get(e, "field");
874
+ if (typeof s != "string" || s.length === 0)
875
+ throw new TypeError("Every DataTable column requires a field");
876
+ if (r.has(s)) throw new Error(`Duplicate DataTable column: ${s}`);
877
+ r.add(s);
878
+ const i = Reflect.get(e, "render");
879
+ if (i != null && typeof i != "function")
880
+ throw new TypeError(`DataTable column ${s} render must be a function`);
881
+ return e;
882
+ });
883
+ }
884
+ function je(t) {
885
+ if (t == null) return z;
886
+ if (typeof t == "function") return t;
887
+ if (typeof t == "string" && t.length > 0)
888
+ return (r, e) => {
889
+ const s = r[t];
890
+ if (s == null)
891
+ throw new TypeError(`DataTable row at index ${e} lacks ${t}`);
892
+ return s;
893
+ };
894
+ throw new TypeError("DataTable rowKey must be a function or property name");
895
+ }
896
+ function ee(t) {
897
+ return t != null && (typeof t == "object" || typeof t == "function") && typeof Reflect.get(t, "get") == "function" && typeof Reflect.get(t, "subscribe") == "function" && typeof Reflect.get(t, "getFetchState") == "function" && typeof Reflect.get(t, "getError") == "function";
898
+ }
899
+ function Ae(t) {
900
+ if (!ee(t))
901
+ throw new TypeError("DataTable query must be an emitter");
902
+ }
903
+ function Le(t) {
904
+ return t == null || typeof t == "string" || typeof t == "number" ? t : String(t);
905
+ }
906
+ function Fe(t, r) {
907
+ return t instanceof Error ? t.message : t == null ? r : String(t);
908
+ }
909
+ class te extends b {
910
+ render() {
911
+ return this.props.children ?? [];
912
+ }
913
+ }
914
+ class A extends b {
915
+ constructor(e) {
916
+ super(e);
917
+ o(this, "nodesEmitter");
918
+ o(this, "selectedKeyEmitter");
919
+ o(this, "expandedKeysEmitter");
920
+ o(this, "ownedNodesEmitter");
921
+ o(this, "ownedSelectedEmitter");
922
+ o(this, "ownedExpandedEmitter");
923
+ o(this, "focusedKey", null);
924
+ o(this, "typeahead", "");
925
+ o(this, "typeaheadTimer", null);
926
+ if (ze(e.nodes))
927
+ this.nodesEmitter = e.nodes, this.ownedNodesEmitter = null;
928
+ else {
929
+ const s = e.nodes ?? re(e.children);
930
+ this.ownedNodesEmitter = new y(s, {
931
+ owner: this,
932
+ purpose: "tree nodes"
933
+ }), this.nodesEmitter = this.ownedNodesEmitter;
934
+ }
935
+ this.ownedSelectedEmitter = e.selectedKeyEmitter == null ? new y(null, { owner: this, purpose: "selected tree key" }) : null, this.selectedKeyEmitter = e.selectedKeyEmitter ?? this.ownedSelectedEmitter, this.ownedExpandedEmitter = e.expandedKeysEmitter == null ? new y([], { owner: this, purpose: "expanded tree keys" }) : null, this.expandedKeysEmitter = e.expandedKeysEmitter ?? this.ownedExpandedEmitter;
936
+ }
937
+ initialize() {
938
+ this.reconcile(this.nodesEmitter.get()), this.watch(this.nodesEmitter, this.selectedKeyEmitter, this.expandedKeysEmitter), this.onCleanup(this.nodesEmitter.subscribe(({ value: e }) => this.reconcile(e), {
939
+ emitCurrent: !1
940
+ }));
941
+ }
942
+ render() {
943
+ const e = this.nodesEmitter.get();
944
+ B(e);
945
+ const s = new Set(this.expandedKeysEmitter.get()), i = _(e, s), n = this.selectedKeyEmitter.get(), a = i.find(({ node: d }) => Object.is(d.id, this.focusedKey)) ?? i.find(({ node: d }) => Object.is(d.id, n)) ?? i[0] ?? null;
946
+ this.focusedKey = (a == null ? void 0 : a.node.id) ?? null;
947
+ const l = this.Host;
948
+ return /* @__PURE__ */ c(l, { className: I(this.props) || null, children: i.length === 0 ? /* @__PURE__ */ c("p", { role: "status", "data-part": "empty", children: "No tree items" }) : /* @__PURE__ */ c("div", { role: "tree", "aria-label": this.props.label, "data-part": "tree", children: i.map((d, h) => {
949
+ var v, R, M;
950
+ const { node: u, depth: f, position: p, setSize: g } = d, S = (((v = u.children) == null ? void 0 : v.length) ?? 0) > 0, C = S && s.has(u.id), q = Object.is(u.id, n), k = ((M = (R = this.props).renderItem) == null ? void 0 : M.call(R, u, f)) ?? u.label;
951
+ return /* @__PURE__ */ w(
952
+ "div",
953
+ {
954
+ role: "treeitem",
955
+ "data-part": "item",
956
+ "data-index": h,
957
+ "data-depth": f,
958
+ "aria-level": f + 1,
959
+ "aria-posinset": p,
960
+ "aria-setsize": g,
961
+ "aria-expanded": S ? String(C) : null,
962
+ "aria-selected": String(q),
963
+ tabIndex: Object.is(u.id, a == null ? void 0 : a.node.id) ? 0 : -1,
964
+ style: { "--tree-depth": f },
965
+ onClick: (O) => {
966
+ if (this.focusedKey = u.id, Ue(O.target) && S) {
967
+ this.toggleExpanded(u.id), this.focusRow(u.id);
968
+ return;
969
+ }
970
+ this.selectNode(u, O);
971
+ },
972
+ onFocus: () => this.focusedKey = u.id,
973
+ onKeyDown: (O) => this.handleKeyDown(O, h, i),
974
+ children: [
975
+ /* @__PURE__ */ c(
976
+ "span",
977
+ {
978
+ "data-part": "expander",
979
+ "data-expandable": S ? "" : null,
980
+ "aria-hidden": "true",
981
+ children: S ? C ? "▾" : "▸" : "•"
982
+ }
983
+ ),
984
+ /* @__PURE__ */ c("span", { "data-part": "label", children: k })
985
+ ]
986
+ },
987
+ u.id
988
+ );
989
+ }) }) });
990
+ }
991
+ onDestroy() {
992
+ var e, s, i;
993
+ this.typeaheadTimer != null && clearTimeout(this.typeaheadTimer), (e = this.ownedNodesEmitter) == null || e.dispose(), (s = this.ownedSelectedEmitter) == null || s.dispose(), (i = this.ownedExpandedEmitter) == null || i.dispose();
994
+ }
995
+ reconcile(e) {
996
+ B(e);
997
+ const s = new Set(se(e).map(({ node: l }) => l.id)), i = this.selectedKeyEmitter.get();
998
+ this.ownedSelectedEmitter != null && i != null && !s.has(i) && this.selectedKeyEmitter.set(null, "selected tree item removed");
999
+ const n = this.expandedKeysEmitter.get(), a = n.filter((l) => s.has(l));
1000
+ this.ownedExpandedEmitter != null && !$e(n, a) && this.expandedKeysEmitter.set(a, "removed tree expansions reconciled"), this.focusedKey != null && !s.has(this.focusedKey) && (this.focusedKey = null);
1001
+ }
1002
+ selectNode(e, s) {
1003
+ this.selectedKeyEmitter.set(e.id, "tree item selected"), W(this.props.onSelect, e, s), this.focusRow(e.id);
1004
+ }
1005
+ toggleExpanded(e) {
1006
+ const s = this.expandedKeysEmitter.get(), i = s.some((n) => Object.is(n, e));
1007
+ this.expandedKeysEmitter.set(
1008
+ i ? s.filter((n) => !Object.is(n, e)) : [...s, e],
1009
+ i ? "tree item collapsed" : "tree item expanded"
1010
+ );
1011
+ }
1012
+ handleKeyDown(e, s, i) {
1013
+ var a, l, d, h;
1014
+ const n = i[s];
1015
+ if (n != null) {
1016
+ if (e.key === "ArrowDown") return this.move(e, (a = i[s + 1]) == null ? void 0 : a.node.id);
1017
+ if (e.key === "ArrowUp") return this.move(e, (l = i[s - 1]) == null ? void 0 : l.node.id);
1018
+ if (e.key === "Home") return this.move(e, (d = i[0]) == null ? void 0 : d.node.id);
1019
+ if (e.key === "End") return this.move(e, (h = i.at(-1)) == null ? void 0 : h.node.id);
1020
+ if (e.key === "ArrowRight") {
1021
+ e.preventDefault();
1022
+ const u = n.node.children ?? [];
1023
+ if (u.length === 0) return;
1024
+ this.expandedKeysEmitter.get().some((p) => Object.is(p, n.node.id)) ? this.focusRow(u[0].id) : this.toggleExpanded(n.node.id);
1025
+ return;
1026
+ }
1027
+ if (e.key === "ArrowLeft") {
1028
+ e.preventDefault(), this.expandedKeysEmitter.get().some((f) => Object.is(f, n.node.id)) ? this.toggleExpanded(n.node.id) : n.parentId != null && this.focusRow(n.parentId);
1029
+ return;
1030
+ }
1031
+ if (e.key === "Enter" || e.key === " ") {
1032
+ e.preventDefault(), this.selectNode(n.node, e);
1033
+ return;
1034
+ }
1035
+ e.key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey && this.handleTypeahead(e, i, s);
1036
+ }
1037
+ }
1038
+ move(e, s) {
1039
+ s !== void 0 && (e.preventDefault(), this.focusRow(s));
1040
+ }
1041
+ focusRow(e) {
1042
+ var i;
1043
+ this.focusedKey = e;
1044
+ const s = this.dom instanceof Element ? [...this.dom.querySelectorAll('[role="treeitem"]')] : [];
1045
+ for (const n of s) {
1046
+ const a = Number(n.dataset.index), l = _(
1047
+ this.nodesEmitter.get(),
1048
+ new Set(this.expandedKeysEmitter.get())
1049
+ ), d = Object.is((i = l[a]) == null ? void 0 : i.node.id, e);
1050
+ n.tabIndex = d ? 0 : -1, d && n.focus();
1051
+ }
1052
+ }
1053
+ handleTypeahead(e, s, i) {
1054
+ e.preventDefault(), this.typeaheadTimer != null && clearTimeout(this.typeaheadTimer), this.typeahead += e.key.toLocaleLowerCase(), this.typeaheadTimer = setTimeout(() => {
1055
+ this.typeahead = "", this.typeaheadTimer = null;
1056
+ }, 650);
1057
+ const a = [...s.slice(i + 1), ...s.slice(0, i + 1)].find(({ node: l }) => He(l).toLocaleLowerCase().startsWith(this.typeahead));
1058
+ a != null && this.focusRow(a.node.id);
1059
+ }
1060
+ }
1061
+ o(A, "dependencies", [te]), o(A, "hostName", "tree-view"), o(A, "standaloneHostName", "tree-view"), o(A, "css", x`
1062
+ & {
1063
+ display: flex;
1064
+ flex-direction: column;
1065
+ min-width: 0;
1066
+ min-height: 0;
1067
+ overflow: auto;
1068
+ }
1069
+
1070
+ & > [data-part="tree"] {
1071
+ display: grid;
1072
+ align-content: start;
1073
+ }
1074
+
1075
+ & [data-part="item"] {
1076
+ display: flex;
1077
+ align-items: flex-start;
1078
+ gap: 0.35rem;
1079
+ min-width: 0;
1080
+ padding: 0.38rem 0.5rem;
1081
+ padding-inline-start: calc(0.5rem + var(--tree-depth) * 1.1rem);
1082
+ cursor: default;
1083
+ user-select: none;
1084
+ }
1085
+
1086
+ & [data-part="item"]:hover {
1087
+ background: var(--button-background-hover);
1088
+ }
1089
+
1090
+ & [data-part="item"]:focus-visible {
1091
+ outline: 2px solid var(--ui-accent-color);
1092
+ outline-offset: -2px;
1093
+ }
1094
+
1095
+ & [data-part="item"][aria-selected="true"] {
1096
+ color: var(--toggle-selected-text);
1097
+ background: var(--toggle-selected-bg);
1098
+ }
1099
+
1100
+ & [data-part="expander"] {
1101
+ flex: 0 0 1rem;
1102
+ text-align: center;
1103
+ }
1104
+
1105
+ & [data-part="expander"][data-expandable] {
1106
+ cursor: pointer;
1107
+ }
1108
+
1109
+ & [data-part="label"] {
1110
+ min-width: 0;
1111
+ overflow-wrap: anywhere;
1112
+ }
1113
+
1114
+ & > [data-part="empty"] {
1115
+ margin: 0;
1116
+ padding: var(--ui-padding, 0.75rem);
1117
+ }
1118
+
1119
+ @media (forced-colors: active) {
1120
+ & [data-part="item"][aria-selected="true"] {
1121
+ outline: 2px solid Highlight;
1122
+ forced-color-adjust: auto;
1123
+ }
1124
+ }
1125
+ `);
1126
+ function re(t) {
1127
+ return (Array.isArray(t) ? t : t == null ? [] : [t]).filter((e) => U(e) && e.type === te).map((e) => {
1128
+ if (!U(e)) throw new TypeError("TreeView children must be TreeItem nodes");
1129
+ const s = e.props;
1130
+ return {
1131
+ id: s.id,
1132
+ label: s.label,
1133
+ ...s.textValue == null ? {} : { textValue: s.textValue },
1134
+ ...s.value === void 0 ? {} : { value: s.value },
1135
+ children: re(s.children)
1136
+ };
1137
+ });
1138
+ }
1139
+ function _(t, r) {
1140
+ const e = [], s = (i, n, a) => {
1141
+ i.forEach((l, d) => {
1142
+ var h;
1143
+ e.push({ node: l, depth: n, parentId: a, position: d + 1, setSize: i.length }), (((h = l.children) == null ? void 0 : h.length) ?? 0) > 0 && r.has(l.id) && s(l.children ?? [], n + 1, l.id);
1144
+ });
1145
+ };
1146
+ return s(t, 0, null), e;
1147
+ }
1148
+ function se(t) {
1149
+ const r = /* @__PURE__ */ new Set(), e = [], s = (i, n, a) => {
1150
+ i.forEach((l, d) => {
1151
+ if (r.has(l.id)) throw new Error(`Duplicate tree item id: ${String(l.id)}`);
1152
+ r.add(l.id), e.push({ node: l, depth: n, parentId: a, position: d + 1, setSize: i.length }), s(l.children ?? [], n + 1, l.id);
1153
+ });
1154
+ };
1155
+ return s(t, 0, null), e;
1156
+ }
1157
+ function B(t) {
1158
+ if (!Array.isArray(t)) throw new TypeError("TreeView nodes must be an array");
1159
+ for (const { node: r } of se(t)) {
1160
+ if (r == null || typeof r != "object" || r.id == null)
1161
+ throw new TypeError("Each tree node requires an id");
1162
+ if (!Array.isArray(r.children ?? []))
1163
+ throw new TypeError(`Tree node ${String(r.id)} children must be an array`);
1164
+ }
1165
+ }
1166
+ function He(t) {
1167
+ return t.textValue != null ? t.textValue : typeof t.label == "string" || typeof t.label == "number" ? String(t.label) : String(t.id);
1168
+ }
1169
+ function $e(t, r) {
1170
+ return t.length === r.length && t.every((e, s) => Object.is(e, r[s]));
1171
+ }
1172
+ function ze(t) {
1173
+ return t != null && (typeof t == "object" || typeof t == "function") && typeof Reflect.get(t, "get") == "function" && typeof Reflect.get(t, "subscribe") == "function";
1174
+ }
1175
+ function Ue(t) {
1176
+ return t instanceof Element && t.closest('[data-part="expander"]') != null;
1177
+ }
1178
+ class G extends b {
1179
+ constructor(e) {
1180
+ super(e);
1181
+ o(this, "openEmitter");
1182
+ o(this, "dialogId");
1183
+ o(this, "titleId");
1184
+ o(this, "descriptionId");
1185
+ o(this, "dialogElement", null);
1186
+ o(this, "restoreFocusTo", null);
1187
+ o(this, "synchronizedOpen", !1);
1188
+ this.openEmitter = de(this, e, !1, "dialog open state"), this.dialogId = ce("dialog", e.id), this.titleId = `${this.dialogId}-title`, this.descriptionId = `${this.dialogId}-description`;
1189
+ }
1190
+ initialize() {
1191
+ this.watch(this.openEmitter);
1192
+ }
1193
+ render() {
1194
+ const {
1195
+ title: e,
1196
+ description: s,
1197
+ actions: i,
1198
+ closeLabel: n = "Close",
1199
+ showCloseButton: a = !0,
1200
+ children: l = []
1201
+ } = this.props;
1202
+ return /* @__PURE__ */ w(
1203
+ "dialog",
1204
+ {
1205
+ id: this.dialogId,
1206
+ className: I(this.props) || void 0,
1207
+ "data-fray-component": "dialog",
1208
+ "aria-labelledby": this.titleId,
1209
+ "aria-describedby": s == null ? null : this.descriptionId,
1210
+ "aria-modal": "true",
1211
+ ref: (d) => this.dialogElement = d,
1212
+ children: [
1213
+ /* @__PURE__ */ c("header", { "data-part": "header", children: /* @__PURE__ */ c("h2", { id: this.titleId, children: e }) }),
1214
+ s == null ? null : /* @__PURE__ */ c("p", { id: this.descriptionId, "data-part": "description", children: s }),
1215
+ /* @__PURE__ */ c("div", { "data-part": "content", children: l }),
1216
+ i == null && !a ? null : /* @__PURE__ */ w("footer", { "data-part": "actions", children: [
1217
+ i,
1218
+ a ? /* @__PURE__ */ c(
1219
+ Q,
1220
+ {
1221
+ label: n,
1222
+ onClick: () => this.requestClose()
1223
+ }
1224
+ ) : null
1225
+ ] })
1226
+ ]
1227
+ }
1228
+ );
1229
+ }
1230
+ afterMount() {
1231
+ const e = this.dialogElement;
1232
+ e != null && (this.listen(e, "cancel", (s) => {
1233
+ s.preventDefault(), this.requestClose();
1234
+ }), this.listen(e, "close", () => {
1235
+ this.openEmitter.get() && this.openEmitter.set(!1, "native dialog closed"), this.finishClose();
1236
+ }), this.syncOpenState());
1237
+ }
1238
+ afterUpdate() {
1239
+ this.syncOpenState();
1240
+ }
1241
+ close() {
1242
+ this.requestClose();
1243
+ }
1244
+ onDestroy() {
1245
+ const e = this.dialogElement;
1246
+ (e == null ? void 0 : e.open) === !0 && typeof e.close == "function" && e.close(), this.finishClose(), this.dialogElement = null;
1247
+ }
1248
+ requestClose() {
1249
+ this.openEmitter.get() && this.openEmitter.set(!1, "dialog close requested");
1250
+ }
1251
+ syncOpenState() {
1252
+ const e = this.dialogElement;
1253
+ if (e == null) return;
1254
+ const s = this.openEmitter.get();
1255
+ if (s && !this.synchronizedOpen) {
1256
+ const i = document.activeElement;
1257
+ this.restoreFocusTo = i instanceof HTMLElement ? i : null, Ve(e), this.synchronizedOpen = !0, Qe(e, this.props.initialFocusRef);
1258
+ return;
1259
+ }
1260
+ !s && this.synchronizedOpen && (e.open && typeof e.close == "function" ? e.close() : e.removeAttribute("open"), this.finishClose());
1261
+ }
1262
+ finishClose() {
1263
+ if (!this.synchronizedOpen && this.restoreFocusTo == null) return;
1264
+ this.synchronizedOpen = !1;
1265
+ const e = this.restoreFocusTo;
1266
+ this.restoreFocusTo = null, (e == null ? void 0 : e.isConnected) === !0 && e.focus(), W(this.props.onClose);
1267
+ }
1268
+ }
1269
+ o(G, "dependencies", [Q]), o(G, "css", x`
1270
+ dialog[data-fray-component="dialog"] {
1271
+ width: min(38rem, calc(100vw - 2rem));
1272
+ max-height: min(42rem, calc(100dvh - 2rem));
1273
+ padding: 0;
1274
+ color: var(--ui-text-color);
1275
+ background: var(--panel-bg);
1276
+ border: 1px solid var(--ui-border-color);
1277
+ border-radius: var(--panel-radius, var(--ui-border-radius));
1278
+ box-shadow: 0 1.25rem 4rem rgb(0 0 0 / 35%);
1279
+ }
1280
+
1281
+ dialog[data-fray-component="dialog"]::backdrop {
1282
+ background: rgb(0 0 0 / 55%);
1283
+ }
1284
+
1285
+ dialog[data-fray-component="dialog"] > [data-part] {
1286
+ padding: var(--panel-padding, 0.75rem);
1287
+ }
1288
+
1289
+ dialog[data-fray-component="dialog"] > [data-part="header"] {
1290
+ border-block-end: 1px solid var(--ui-border-color);
1291
+ }
1292
+
1293
+ dialog[data-fray-component="dialog"] > [data-part="header"] h2,
1294
+ dialog[data-fray-component="dialog"] > [data-part="description"] {
1295
+ margin: 0;
1296
+ }
1297
+
1298
+ dialog[data-fray-component="dialog"] > [data-part="content"] {
1299
+ overflow: auto;
1300
+ }
1301
+
1302
+ dialog[data-fray-component="dialog"] > [data-part="actions"] {
1303
+ display: flex;
1304
+ justify-content: flex-end;
1305
+ gap: var(--spacing-small, 0.5rem);
1306
+ border-block-start: 1px solid var(--ui-border-color);
1307
+ }
1308
+
1309
+ @media (prefers-reduced-motion: no-preference) {
1310
+ dialog[data-fray-component="dialog"][open] {
1311
+ animation: fray-dialog-enter 120ms ease-out;
1312
+ }
1313
+ }
1314
+
1315
+ @keyframes fray-dialog-enter {
1316
+ from {
1317
+ transform: translateY(0.4rem);
1318
+ }
1319
+ }
1320
+
1321
+ @media (forced-colors: active) {
1322
+ dialog[data-fray-component="dialog"] {
1323
+ border: 2px solid CanvasText;
1324
+ }
1325
+ }
1326
+ `);
1327
+ function Ve(t) {
1328
+ if (!t.open) {
1329
+ if (typeof t.showModal == "function") {
1330
+ t.showModal();
1331
+ return;
1332
+ }
1333
+ t.setAttribute("open", "");
1334
+ }
1335
+ }
1336
+ function Qe(t, r) {
1337
+ const s = (r == null || typeof r == "function" ? null : r.current) ?? t.querySelector(
1338
+ '[autofocus], button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
1339
+ );
1340
+ s == null || s.focus();
1341
+ }
1342
+ export {
1343
+ J as BaseSelectionHandler,
1344
+ j as DataTable,
1345
+ G as Dialog,
1346
+ T as FilterPanel,
1347
+ D as ListView,
1348
+ pe as MultiSelectionHandler,
1349
+ E as Placeholder,
1350
+ ue as SingleSelectionHandler,
1351
+ H as TableHeader,
1352
+ N as TableHeaderCell,
1353
+ te as TreeItem,
1354
+ A as TreeView,
1355
+ Ce as applyLocalTableState,
1356
+ Z as assertSort,
1357
+ Y as createSelectionHandler,
1358
+ z as defaultItemKey,
1359
+ Ke as serializeTableQuery
1360
+ };
1361
+ //# sourceMappingURL=experimental.js.map