flexdesk 0.17.18 → 0.18.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.
Files changed (118) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +1 -0
  3. package/css/flexdesk.css +7544 -5916
  4. package/css/reset.css +1 -1
  5. package/css/tokens.css +23 -1
  6. package/dist/charts.js +10 -6
  7. package/dist/charts.js.map +1 -1
  8. package/dist/chunk-5W4EEKSK.js +778 -0
  9. package/dist/chunk-5W4EEKSK.js.map +7 -0
  10. package/dist/chunk-DNJ3N4T4.js +82 -0
  11. package/dist/chunk-DNJ3N4T4.js.map +7 -0
  12. package/dist/{chunk-REJ5HLIM.js → chunk-HYJYYEPK.js} +2 -2
  13. package/dist/{chunk-7U4IB65H.js → chunk-LLBJ2SJH.js} +5 -3
  14. package/dist/{chunk-7U4IB65H.js.map → chunk-LLBJ2SJH.js.map} +1 -1
  15. package/dist/{chunk-7OL6F2AM.js → chunk-P74F6I6P.js} +6 -4
  16. package/dist/{chunk-7OL6F2AM.js.map → chunk-P74F6I6P.js.map} +1 -1
  17. package/dist/chunk-PAI2ZUWV.js +260 -0
  18. package/dist/chunk-PAI2ZUWV.js.map +7 -0
  19. package/dist/chunk-Q7BALEPX.js +527 -0
  20. package/dist/chunk-Q7BALEPX.js.map +7 -0
  21. package/dist/chunk-QXAOTGCC.js +40 -0
  22. package/dist/chunk-QXAOTGCC.js.map +7 -0
  23. package/dist/{chunk-XJNADRGR.js → chunk-RKVYIXDC.js} +664 -91
  24. package/dist/chunk-RKVYIXDC.js.map +7 -0
  25. package/dist/{chunk-2Z2ENHR3.js → chunk-U5GKJUOC.js} +3 -3
  26. package/dist/{chunk-2Z2ENHR3.js.map → chunk-U5GKJUOC.js.map} +1 -1
  27. package/dist/chunk-UKP22RUG.js +219 -0
  28. package/dist/chunk-UKP22RUG.js.map +7 -0
  29. package/dist/chunk-VLOAI3HS.js +43 -0
  30. package/dist/chunk-VLOAI3HS.js.map +7 -0
  31. package/dist/{chunk-WUFLGETN.js → chunk-WVFGV5FT.js} +2 -39
  32. package/dist/{chunk-WUFLGETN.js.map → chunk-WVFGV5FT.js.map} +3 -3
  33. package/dist/{chunk-PGZ4EHSE.js → chunk-ZL3VKINP.js} +41 -390
  34. package/dist/chunk-ZL3VKINP.js.map +7 -0
  35. package/dist/editor.js +3 -2
  36. package/dist/editor.js.map +1 -1
  37. package/dist/flexdesk.css +7544 -5916
  38. package/dist/flow.js +29 -97
  39. package/dist/flow.js.map +3 -3
  40. package/dist/git.js +1356 -0
  41. package/dist/git.js.map +7 -0
  42. package/dist/reset.css +1 -1
  43. package/dist/tiles.js +20 -15
  44. package/dist/tiles.js.map +2 -2
  45. package/dist/tokens.css +23 -1
  46. package/dist/widgets.js +3967 -1188
  47. package/dist/widgets.js.map +4 -4
  48. package/dist/wm.js +120 -32
  49. package/dist/wm.js.map +2 -2
  50. package/docs/README.md +9 -4
  51. package/docs/best-practices.md +2 -2
  52. package/docs/components/chat-shell.md +198 -0
  53. package/docs/components/conversation.md +10 -0
  54. package/docs/components/filter-builder.md +246 -0
  55. package/docs/components/forms-and-dialogs.md +22 -0
  56. package/docs/components/git.md +355 -0
  57. package/docs/components/input-fields.md +167 -2
  58. package/docs/components/keymap.md +8 -0
  59. package/docs/components/menus.md +82 -2
  60. package/docs/components/panels-and-desktops.md +16 -5
  61. package/docs/components/shell.md +104 -1
  62. package/docs/components/workspace-picker.md +149 -0
  63. package/docs/concepts/building-and-packaging.md +2 -2
  64. package/docs/concepts/packages-and-entry-points.md +14 -13
  65. package/docs/concepts/state-guard.md +3 -3
  66. package/docs/quickstart.md +1 -1
  67. package/git.js +13 -0
  68. package/package.json +6 -1
  69. package/src/flow/kit/dom.js +28 -119
  70. package/src/flow/kit/step_picker.js +1 -1
  71. package/src/flow/kit/value_picker.js +1 -1
  72. package/src/flow/outline/menu.js +1 -1
  73. package/src/git/diff_viewer.js +212 -0
  74. package/src/git/diff_window.js +51 -0
  75. package/src/git/git_graph.js +401 -0
  76. package/src/git/git_ops.js +61 -0
  77. package/src/git/git_panel.js +755 -0
  78. package/src/git/index.js +9 -0
  79. package/src/git/line_diff.js +202 -0
  80. package/src/tiles/tile_base.js +5 -4
  81. package/src/tiling/desktops.js +10 -8
  82. package/src/tiling/keymap.js +6 -5
  83. package/src/tiling/kind_taxonomy.js +15 -2
  84. package/src/tiling/shell.js +124 -17
  85. package/src/tiling/tile_renderer.js +2 -3
  86. package/src/ui/components/action_dropdown.js +4 -78
  87. package/src/ui/components/anchored_layer.js +255 -0
  88. package/src/ui/components/chat_shell.js +920 -0
  89. package/src/ui/components/chat_state_machine.js +223 -0
  90. package/src/ui/components/choice_controls.js +45 -2
  91. package/src/ui/components/color_field.js +3 -2
  92. package/src/ui/components/color_list_field.js +3 -2
  93. package/src/ui/components/combobox.js +422 -0
  94. package/src/ui/components/conversation_view.js +17 -2
  95. package/src/ui/components/data_table.js +2 -2
  96. package/src/ui/components/filter_builder.js +766 -0
  97. package/src/ui/components/filter_model.js +614 -0
  98. package/src/ui/components/managed_window.js +24 -47
  99. package/src/ui/components/modal.js +79 -109
  100. package/src/ui/components/option_list.js +160 -0
  101. package/src/ui/components/popover.js +94 -0
  102. package/src/ui/components/recent_items.js +169 -0
  103. package/src/ui/components/select.js +322 -0
  104. package/src/ui/components/tag_input.js +77 -8
  105. package/src/ui/components/workspace_picker.js +1155 -0
  106. package/src/ui/utils/fire_event.js +17 -0
  107. package/src/ui/utils/focusable.js +25 -0
  108. package/src/ui/utils/modal_host.js +27 -0
  109. package/widgets.js +12 -2
  110. package/css/base.css +0 -10547
  111. package/css/overrides.css +0 -2596
  112. package/dist/chunk-7JI7HHSY.js +0 -107
  113. package/dist/chunk-7JI7HHSY.js.map +0 -7
  114. package/dist/chunk-MIW7D6WC.js +0 -526
  115. package/dist/chunk-MIW7D6WC.js.map +0 -7
  116. package/dist/chunk-PGZ4EHSE.js.map +0 -7
  117. package/dist/chunk-XJNADRGR.js.map +0 -7
  118. /package/dist/{chunk-REJ5HLIM.js.map → chunk-HYJYYEPK.js.map} +0 -0
@@ -1,3 +1,7 @@
1
+ import {
2
+ collectFocusable,
3
+ isInAnchoredLayer
4
+ } from "./chunk-Q7BALEPX.js";
1
5
  import {
2
6
  getSetting
3
7
  } from "./chunk-HNU6MM2B.js";
@@ -21,23 +25,6 @@ var DEFAULT_ICON = "web_asset";
21
25
  var _zIndexCounter = 0;
22
26
  var _activeWindows = /* @__PURE__ */ new Map();
23
27
  var _escAnswered = /* @__PURE__ */ new WeakSet();
24
- function _collectFocusable(root) {
25
- if (!root) return [];
26
- const sel = [
27
- "a[href]",
28
- "button:not([disabled])",
29
- 'input:not([disabled]):not([type="hidden"])',
30
- "select:not([disabled])",
31
- "textarea:not([disabled])",
32
- '[tabindex]:not([tabindex="-1"])'
33
- ].join(",");
34
- return Array.from(root.querySelectorAll(sel)).filter((el2) => {
35
- if (el2.hidden) return false;
36
- if (el2.closest("[hidden]")) return false;
37
- const r = el2.getBoundingClientRect();
38
- return r.width > 0 || r.height > 0;
39
- });
40
- }
41
28
  var _stateCache = null;
42
29
  function _loadState() {
43
30
  if (_stateCache) return _stateCache;
@@ -93,14 +80,14 @@ function _focusFirstIn(root) {
93
80
  '[contenteditable="true"]',
94
81
  '[tabindex]:not([tabindex="-1"])'
95
82
  ].join(",");
96
- for (const el2 of root.querySelectorAll(sel)) {
97
- if (el2.hidden || el2.closest("[hidden]")) continue;
83
+ for (const el of root.querySelectorAll(sel)) {
84
+ if (el.hidden || el.closest("[hidden]")) continue;
98
85
  try {
99
- el2.focus({ preventScroll: true });
86
+ el.focus({ preventScroll: true });
100
87
  } catch {
101
88
  continue;
102
89
  }
103
- if (el2.ownerDocument.activeElement === el2) return true;
90
+ if (el.ownerDocument.activeElement === el) return true;
104
91
  }
105
92
  return false;
106
93
  }
@@ -327,11 +314,15 @@ var ManagedWindow = class {
327
314
  this._clearTargetProperties();
328
315
  document.removeEventListener("keydown", this._boundOnKeyDown);
329
316
  this._teardownContainerResizeObserver();
330
- window.dispatchEvent(new CustomEvent("managed-window-closed", {
331
- detail: { id: this.id, container: this.container }
332
- }));
317
+ this._announce("managed-window-closed", { id: this.id, container: this.container });
333
318
  this._release();
334
319
  }
320
+ /** Every window event goes out on the page's window, and a window takes only
321
+ * an event built by its own `CustomEvent`: Node's global one is refused
322
+ * under jsdom, in the middle of the close that fired it. */
323
+ _announce(name, detail) {
324
+ window.dispatchEvent(new window.CustomEvent(name, { detail }));
325
+ }
335
326
  /** BUG-0053. A closed window leaves the registry and lets go of what it
336
327
  * held: its content, its DOM and every consumer callback (an `onClose`
337
328
  * typically captures its owner). Until now the registry kept all of it
@@ -376,14 +367,12 @@ var ManagedWindow = class {
376
367
  if (this.backdropElement) {
377
368
  this.backdropElement.style.display = "none";
378
369
  }
379
- window.dispatchEvent(new CustomEvent("managed-window-minimized", {
380
- detail: {
381
- id: this.id,
382
- title: this.title,
383
- icon: this.icon,
384
- container: this.container
385
- }
386
- }));
370
+ this._announce("managed-window-minimized", {
371
+ id: this.id,
372
+ title: this.title,
373
+ icon: this.icon,
374
+ container: this.container
375
+ });
387
376
  if (!this.element) return;
388
377
  this._cancelRestoreAnimation();
389
378
  if (!getSetting("window.animateMinimize", true)) {
@@ -484,9 +473,7 @@ var ManagedWindow = class {
484
473
  }
485
474
  this.isMinimized = false;
486
475
  this.bringToFront();
487
- window.dispatchEvent(new CustomEvent("managed-window-restored", {
488
- detail: { id: this.id, container: this.container }
489
- }));
476
+ this._announce("managed-window-restored", { id: this.id, container: this.container });
490
477
  }
491
478
  /**
492
479
  * Toggle maximize state.
@@ -547,9 +534,7 @@ var ManagedWindow = class {
547
534
  this.element?.classList.toggle("twm-managed-window--maximized", this.isMaximized);
548
535
  this._applyPosition();
549
536
  this._saveCurrentState();
550
- window.dispatchEvent(new CustomEvent("managed-window-maximized", {
551
- detail: { id: this.id, maximized: this.isMaximized, container: this.container }
552
- }));
537
+ this._announce("managed-window-maximized", { id: this.id, maximized: this.isMaximized, container: this.container });
553
538
  }
554
539
  /**
555
540
  * Find the taskbar button for this window.
@@ -864,9 +849,7 @@ var ManagedWindow = class {
864
849
  this.height = bounds.height;
865
850
  }
866
851
  this._applyPosition();
867
- window.dispatchEvent(new CustomEvent("managed-window-moved", {
868
- detail: { id: this.id, container }
869
- }));
852
+ this._announce("managed-window-moved", { id: this.id, container });
870
853
  return true;
871
854
  }
872
855
  /** R1/R3. The container this drag started in, or null when the drag did
@@ -1243,9 +1226,7 @@ var ManagedWindow = class {
1243
1226
  this.height = rect.height;
1244
1227
  this._applyPosition();
1245
1228
  this.element?.classList.add("twm-managed-window--snapped");
1246
- window.dispatchEvent(new CustomEvent("managed-window-snapped", {
1247
- detail: { id: this.id, zone, container: this.container }
1248
- }));
1229
+ this._announce("managed-window-snapped", { id: this.id, zone, container: this.container });
1249
1230
  }
1250
1231
  /** Restore the geometry a snap replaced. Called when a snapped window is
1251
1232
  * picked up again, which is the gesture that means "un-snap". */
@@ -1329,7 +1310,8 @@ var ManagedWindow = class {
1329
1310
  }
1330
1311
  if (topWindow !== this) return;
1331
1312
  if (e.key === "Tab" && this.modal && this.element) {
1332
- const focusables = _collectFocusable(this.element);
1313
+ if (isInAnchoredLayer(document.activeElement)) return;
1314
+ const focusables = collectFocusable(this.element);
1333
1315
  if (focusables.length === 0) {
1334
1316
  e.preventDefault();
1335
1317
  return;
@@ -1551,6 +1533,12 @@ var ToggleField = class {
1551
1533
  }
1552
1534
  };
1553
1535
 
1536
+ // src/ui/utils/fire_event.js
1537
+ function fireEvent(target, type, init) {
1538
+ const view = target.ownerDocument.defaultView;
1539
+ target.dispatchEvent(new view.CustomEvent(type, init));
1540
+ }
1541
+
1554
1542
  // src/ui/components/color_field.js
1555
1543
  var HEX_RE = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
1556
1544
  var RGB_RE = /^rgba?\(\s*([^)]*)\)$/i;
@@ -1691,15 +1679,15 @@ var ColorField = class {
1691
1679
  this.swatch = null;
1692
1680
  this.hex = null;
1693
1681
  }
1694
- #listen(el2, type, fn) {
1695
- el2.addEventListener(type, fn);
1696
- this._disposers.push(() => el2.removeEventListener(type, fn));
1682
+ #listen(el, type, fn) {
1683
+ el.addEventListener(type, fn);
1684
+ this._disposers.push(() => el.removeEventListener(type, fn));
1697
1685
  }
1698
1686
  /** Put `text` in the box and fire the box's own events, as typing would. */
1699
1687
  #writeBox(text, commit) {
1700
1688
  this.hex.value = text;
1701
- this.hex.dispatchEvent(new Event("input", { bubbles: true }));
1702
- if (commit) this.hex.dispatchEvent(new Event("change", { bubbles: true }));
1689
+ fireEvent(this.hex, "input", { bubbles: true });
1690
+ if (commit) fireEvent(this.hex, "change", { bubbles: true });
1703
1691
  }
1704
1692
  /** Swatch and invalid mark follow the box; `commit === null` is silent. */
1705
1693
  #sync(commit) {
@@ -1710,351 +1698,14 @@ var ColorField = class {
1710
1698
  }
1711
1699
  };
1712
1700
 
1713
- // src/ui/components/choice_controls.js
1714
- var shownValue = (v) => v === void 0 ? "" : typeof v === "string" ? v : JSON.stringify(v);
1715
- function el(tag, className, text) {
1716
- const n = document.createElement(tag);
1717
- if (className) n.className = className;
1718
- if (text !== void 0 && text !== null) n.textContent = String(text);
1719
- return n;
1720
- }
1721
- var isGroup = (o) => o !== null && typeof o === "object" && Array.isArray(o.options) && "group" in o;
1722
- function choiceOption(o) {
1723
- if (o === null || typeof o !== "object") {
1724
- return { value: o, label: shownValue(o), description: null, disabled: false, reason: null };
1725
- }
1726
- return {
1727
- value: o.value,
1728
- label: o.label != null ? String(o.label) : shownValue(o.value),
1729
- description: o.description != null ? String(o.description) : null,
1730
- disabled: Boolean(o.disabled),
1731
- reason: o.reason != null && o.reason !== "" ? String(o.reason) : null
1732
- };
1733
- }
1734
- function flatChoices(options) {
1735
- const out = [];
1736
- for (const o of options || []) {
1737
- if (isGroup(o)) for (const inner of o.options) out.push(choiceOption(inner));
1738
- else out.push(choiceOption(o));
1739
- }
1740
- return out;
1741
- }
1742
- function groupHeads(options) {
1743
- const heads = /* @__PURE__ */ new Map();
1744
- let at = 0;
1745
- for (const o of options || []) {
1746
- if (!isGroup(o)) {
1747
- at += 1;
1748
- continue;
1749
- }
1750
- if (o.options.length) heads.set(at, String(o.group ?? ""));
1751
- at += o.options.length;
1752
- }
1753
- return heads;
1754
- }
1755
- var groupHeading = (text) => el("div", "twm-choice__group", text);
1756
- function sameChoice(v, value, loose = false) {
1757
- if (v === value) return true;
1758
- if (!loose || v === void 0 || value === void 0 || v === null || value === null) return false;
1759
- return String(v) === String(value);
1760
- }
1761
- function choiceIndex(list, v, loose = false, from = 0) {
1762
- for (let i = from; i < list.length; i += 1) if (list[i].value === v) return i;
1763
- if (!loose) return -1;
1764
- for (let i = from; i < list.length; i += 1) if (sameChoice(list[i].value, v, true)) return i;
1765
- return -1;
1766
- }
1767
- function findChoice(list, v, loose = false) {
1768
- const i = choiceIndex(list, v, loose);
1769
- return i >= 0 ? list[i] : void 0;
1770
- }
1771
- var optionText = (o) => o.disabled && o.reason ? `${o.label} \u2014 ${o.reason}` : o.label;
1772
- function selectBox(options, value, {
1773
- empty = null,
1774
- label = "",
1775
- notFound = (v) => `${v} (not found)`,
1776
- keepMissing = true,
1777
- valueAttr = "index",
1778
- loose = false,
1779
- className = "twm-flow-input twm-flow-input--select"
1780
- } = {}) {
1781
- const box = el("select", className);
1782
- if (label) box.setAttribute("aria-label", label);
1783
- let entries = [];
1784
- const add = (parent, o) => {
1785
- const attr = valueAttr === "index" ? String(entries.length) : o.value === void 0 ? "" : String(o.value);
1786
- const opt = el("option", "", optionText(o));
1787
- opt.value = attr;
1788
- if (o.disabled) {
1789
- opt.disabled = true;
1790
- if (o.reason) opt.title = o.reason;
1791
- }
1792
- parent.appendChild(opt);
1793
- entries.push(o);
1794
- };
1795
- const firstEnabled = () => {
1796
- const i = entries.findIndex((e) => !e.disabled);
1797
- return i >= 0 ? i : 0;
1798
- };
1799
- const select = (v) => {
1800
- const start = empty !== null ? 1 : 0;
1801
- const at = choiceIndex(entries, v, loose, start);
1802
- if (at < 0 || entries[at].disabled || entries[at].stray) return false;
1803
- box.selectedIndex = at;
1804
- return true;
1805
- };
1806
- const place = (v) => {
1807
- if (select(v)) return;
1808
- if (keepMissing && v !== void 0 && v !== null && v !== "") {
1809
- add(box, {
1810
- value: v,
1811
- label: notFound(shownValue(v)),
1812
- description: null,
1813
- disabled: false,
1814
- reason: null,
1815
- stray: true
1816
- });
1817
- box.selectedIndex = entries.length - 1;
1818
- return;
1819
- }
1820
- box.selectedIndex = empty !== null ? 0 : firstEnabled();
1821
- };
1822
- const fill = (opts, v) => {
1823
- box.replaceChildren();
1824
- entries = [];
1825
- if (empty !== null) add(box, {
1826
- value: void 0,
1827
- label: String(empty),
1828
- description: null,
1829
- disabled: false,
1830
- reason: null
1831
- });
1832
- for (const o of opts || []) {
1833
- if (isGroup(o)) {
1834
- const g = el("optgroup");
1835
- g.label = String(o.group ?? "");
1836
- for (const inner of o.options) add(g, choiceOption(inner));
1837
- box.appendChild(g);
1838
- } else {
1839
- add(box, choiceOption(o));
1840
- }
1841
- }
1842
- place(v);
1843
- };
1844
- const entry = () => box.selectedIndex < 0 ? null : entries[box.selectedIndex] ?? null;
1845
- const valueOf = () => entry()?.value;
1846
- fill(options, value);
1847
- return {
1848
- box,
1849
- valueOf,
1850
- entry,
1851
- select,
1852
- setOptions(opts, v = valueOf()) {
1853
- fill(opts, v);
1854
- }
1855
- };
1856
- }
1857
- function toggleChips({
1858
- options,
1859
- value,
1860
- label,
1861
- readOnly,
1862
- onChange,
1863
- notFound = (v) => `${v} (not found)`,
1864
- keepMissing = true,
1865
- loose = false
1866
- }) {
1867
- const root = el("div", "twm-flow-togglechips");
1868
- root.setAttribute("role", "group");
1869
- if (label) root.setAttribute("aria-label", label);
1870
- let shown = [];
1871
- let list = [];
1872
- let chosen = /* @__PURE__ */ new Set();
1873
- let strays = [];
1874
- const emit = () => {
1875
- const out = valueOf();
1876
- onChange?.(out.length ? out : void 0);
1877
- };
1878
- const chipFor = (text, pressed, toggle, { stray = false, reason = null, disabled = false } = {}) => {
1879
- const b = el("button", `twm-flow-togglechip${stray ? " twm-flow-togglechip--missing" : ""}`, text);
1880
- b.type = "button";
1881
- b.setAttribute("aria-pressed", pressed ? "true" : "false");
1882
- b.disabled = Boolean(readOnly) || disabled;
1883
- if (reason) {
1884
- b.title = reason;
1885
- b.appendChild(el("span", "twm-choice__reason", reason));
1886
- }
1887
- b.addEventListener("click", () => {
1888
- const on = toggle();
1889
- b.setAttribute("aria-pressed", on ? "true" : "false");
1890
- emit();
1891
- });
1892
- return b;
1893
- };
1894
- const draw = (opts, stored) => {
1895
- shown = opts || [];
1896
- list = flatChoices(shown);
1897
- const heads = groupHeads(shown);
1898
- const wanted = Array.isArray(stored) ? stored : [];
1899
- const offered = (v) => {
1900
- const o = findChoice(list, v, loose);
1901
- return o && !o.disabled ? o : void 0;
1902
- };
1903
- chosen = new Set(wanted.map(offered).filter(Boolean).map((o) => o.value));
1904
- strays = keepMissing ? wanted.filter((v) => !offered(v)) : [];
1905
- root.replaceChildren();
1906
- list.forEach((o, i) => {
1907
- if (heads.has(i)) root.appendChild(groupHeading(heads.get(i)));
1908
- root.appendChild(chipFor(o.label, chosen.has(o.value), () => {
1909
- if (o.disabled) return false;
1910
- if (chosen.has(o.value)) chosen.delete(o.value);
1911
- else chosen.add(o.value);
1912
- return chosen.has(o.value);
1913
- }, { disabled: o.disabled, reason: o.disabled ? o.reason : null }));
1914
- });
1915
- for (const v of [...strays]) {
1916
- root.appendChild(chipFor(notFound(shownValue(v)), true, () => {
1917
- const i = strays.indexOf(v);
1918
- if (i >= 0) {
1919
- strays.splice(i, 1);
1920
- return false;
1921
- }
1922
- strays.push(v);
1923
- return true;
1924
- }, { stray: true }));
1925
- }
1926
- };
1927
- const valueOf = () => [...list.filter((o) => chosen.has(o.value)).map((o) => o.value), ...strays];
1928
- draw(options, value);
1929
- return {
1930
- el: root,
1931
- valueOf,
1932
- setValue: (stored) => draw(shown, stored),
1933
- setOptions: (opts) => draw(opts, valueOf())
1934
- };
1935
- }
1936
- function choiceList({
1937
- options,
1938
- value,
1939
- name,
1940
- label,
1941
- readOnly,
1942
- onChange,
1943
- notFound = (v) => `${v} (not found)`,
1944
- keepMissing = true,
1945
- loose = false
1946
- }) {
1947
- const root = el("div", "twm-flow-choices");
1948
- root.setAttribute("role", "radiogroup");
1949
- if (label) root.setAttribute("aria-label", label);
1950
- let list = [];
1951
- let radios = [];
1952
- const draw = (opts, current) => {
1953
- list = flatChoices(opts);
1954
- const heads = groupHeads(opts);
1955
- radios = [];
1956
- root.replaceChildren();
1957
- const named = choiceIndex(list, current, loose);
1958
- const at = named >= 0 && !list[named].disabled ? named : -1;
1959
- list.forEach((o, i) => {
1960
- if (heads.has(i)) root.appendChild(groupHeading(heads.get(i)));
1961
- const row = el("label", `twm-flow-choice${o.disabled ? " twm-choice--disabled" : ""}`);
1962
- const radio = el("input", "twm-flow-choice__radio");
1963
- radio.type = "radio";
1964
- radio.name = name;
1965
- radio.checked = i === at;
1966
- radio.disabled = Boolean(readOnly) || o.disabled;
1967
- radio.addEventListener("change", () => {
1968
- if (radio.checked) onChange?.(o.value);
1969
- });
1970
- radios.push(radio);
1971
- const words = el("span", "twm-flow-choice__words");
1972
- words.appendChild(el("span", "twm-flow-choice__label", o.label));
1973
- if (o.description !== null) words.appendChild(el("span", "twm-flow-choice__sub", o.description));
1974
- if (o.disabled && o.reason) words.appendChild(el("span", "twm-choice__reason", o.reason));
1975
- row.append(radio, words);
1976
- root.appendChild(row);
1977
- });
1978
- if (keepMissing && current !== void 0 && named < 0) {
1979
- root.appendChild(el("p", "twm-flow-field__note", notFound(shownValue(current))));
1980
- }
1981
- };
1982
- const checkedAt = () => radios.findIndex((r) => r.checked);
1983
- const entry = () => list[checkedAt()] ?? null;
1984
- const api = {
1985
- el: root,
1986
- focus: () => (radios.find((r) => r.checked && !r.disabled) || radios.find((r) => !r.disabled))?.focus({ preventScroll: true }),
1987
- entry,
1988
- valueOf: () => entry()?.value,
1989
- select(v) {
1990
- const named = choiceIndex(list, v, loose);
1991
- const at = named >= 0 && !list[named].disabled ? named : -1;
1992
- radios.forEach((r, i) => {
1993
- r.checked = i === at;
1994
- });
1995
- return at >= 0;
1996
- },
1997
- setOptions(opts) {
1998
- draw(opts, api.valueOf());
1999
- }
2000
- };
2001
- draw(options, value);
2002
- return api;
2003
- }
2004
-
2005
- // src/ui/components/row_activation.js
2006
- var ROW_CONTROL_SELECTOR = [
2007
- "button",
2008
- "a",
2009
- "input",
2010
- "select",
2011
- "textarea",
2012
- "label",
2013
- "summary",
2014
- '[contenteditable=""]',
2015
- '[contenteditable="true"]',
2016
- "[data-twm-action]"
2017
- ].join(", ");
2018
- function isRowControl(target, scope = null) {
2019
- const hit = target?.closest?.(ROW_CONTROL_SELECTOR);
2020
- return !!hit && (!scope || scope.contains(hit));
2021
- }
2022
- function endsTextSelection(target, scope = null) {
2023
- const doc = target?.ownerDocument || (typeof document !== "undefined" ? document : null);
2024
- const sel = doc?.getSelection?.();
2025
- if (!sel || sel.isCollapsed || !String(sel)) return false;
2026
- if (!scope) return true;
2027
- const inside = (node) => !!node && scope.contains(node);
2028
- return inside(sel.anchorNode) || inside(sel.focusNode);
2029
- }
2030
- function isRowActivation(ev, gesture = "click", { scope = null } = {}) {
2031
- const target = ev?.target;
2032
- if (!target?.closest) return false;
2033
- if (isRowControl(target, scope)) return false;
2034
- if (gesture === "click") {
2035
- if ((ev.detail ?? 0) > 1) return false;
2036
- if (endsTextSelection(target, scope)) return false;
2037
- }
2038
- return true;
2039
- }
2040
-
2041
1701
  export {
2042
1702
  DEFAULT_WINDOW_STORAGE_KEY,
2043
1703
  DEFAULT_MAX_SAVED_WINDOWS,
2044
1704
  ManagedWindow,
2045
1705
  ToggleField,
1706
+ fireEvent,
2046
1707
  isHexColor,
2047
1708
  normalizeHex,
2048
- ColorField,
2049
- shownValue,
2050
- flatChoices,
2051
- findChoice,
2052
- selectBox,
2053
- toggleChips,
2054
- choiceList,
2055
- ROW_CONTROL_SELECTOR,
2056
- isRowControl,
2057
- endsTextSelection,
2058
- isRowActivation
1709
+ ColorField
2059
1710
  };
2060
- //# sourceMappingURL=chunk-PGZ4EHSE.js.map
1711
+ //# sourceMappingURL=chunk-ZL3VKINP.js.map