flexdesk 0.16.1 → 0.17.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.
- package/CHANGELOG.md +112 -0
- package/LICENSE +0 -0
- package/README.md +2435 -42
- package/THIRD_PARTY_LICENSES.md +0 -0
- package/canvas.js +18 -0
- package/charts.js +21 -0
- package/core.js +14 -0
- package/css/base.css +1834 -75
- package/css/flexdesk.css +3165 -159
- package/css/overrides.css +16 -0
- package/css/reset.css +0 -0
- package/css/tokens.css +0 -0
- package/dist/canvas.js +6 -239
- package/dist/canvas.js.map +3 -3
- package/dist/charts.js +707 -18
- package/dist/charts.js.map +4 -4
- package/dist/chunk-3PHCPZHT.js +0 -0
- package/dist/chunk-3PHCPZHT.js.map +0 -0
- package/dist/chunk-4A7SJC3T.js +503 -0
- package/dist/chunk-4A7SJC3T.js.map +7 -0
- package/dist/{chunk-6JSOVNID.js → chunk-CVMCZZX2.js} +635 -10
- package/dist/chunk-CVMCZZX2.js.map +7 -0
- package/dist/chunk-D3COLZZ2.js +1311 -0
- package/dist/chunk-D3COLZZ2.js.map +7 -0
- package/dist/chunk-FOOS3T5L.js +0 -0
- package/dist/chunk-FOOS3T5L.js.map +0 -0
- package/dist/{chunk-SN4LSOAR.js → chunk-GOQLR5WR.js} +452 -2
- package/dist/chunk-GOQLR5WR.js.map +7 -0
- package/dist/{chunk-FL5KFNQH.js → chunk-HNU6MM2B.js} +52 -17
- package/dist/chunk-HNU6MM2B.js.map +7 -0
- package/dist/chunk-HYJYYEPK.js +375 -0
- package/dist/chunk-HYJYYEPK.js.map +7 -0
- package/dist/chunk-JKZLNKG6.js +2041 -0
- package/dist/chunk-JKZLNKG6.js.map +7 -0
- package/dist/chunk-JYWURG5T.js +0 -0
- package/dist/chunk-JYWURG5T.js.map +0 -0
- package/dist/{chunk-FBGP5KN5.js → chunk-LWV23YVE.js} +5073 -532
- package/dist/chunk-LWV23YVE.js.map +7 -0
- package/dist/chunk-N7HC3ADV.js +30 -0
- package/dist/chunk-N7HC3ADV.js.map +7 -0
- package/dist/{chunk-RQM5Z2MU.js → chunk-RMTRWWEO.js} +633 -311
- package/dist/chunk-RMTRWWEO.js.map +7 -0
- package/dist/{chunk-NLTOY57M.js → chunk-UURZ37SD.js} +28 -48
- package/dist/chunk-UURZ37SD.js.map +7 -0
- package/dist/{chunk-B5Q53LAJ.js → chunk-UWO43BZU.js} +2 -2
- package/dist/chunk-UWO43BZU.js.map +7 -0
- package/dist/chunk-WVFGV5FT.js +0 -0
- package/dist/chunk-WVFGV5FT.js.map +0 -0
- package/dist/core.js +170 -118
- package/dist/core.js.map +2 -2
- package/dist/editor.js +156 -70
- package/dist/editor.js.map +2 -2
- package/dist/flexdesk.css +3165 -159
- package/dist/flow.js +2789 -306
- package/dist/flow.js.map +4 -4
- package/dist/host.js +109 -3
- package/dist/host.js.map +3 -3
- package/dist/reset.css +0 -0
- package/dist/tile_registry-6WZPTUZV.js +0 -0
- package/dist/tile_registry-6WZPTUZV.js.map +0 -0
- package/dist/tiles.js +657 -234
- package/dist/tiles.js.map +4 -4
- package/dist/tokens.css +0 -0
- package/dist/widgets.js +3290 -2124
- package/dist/widgets.js.map +4 -4
- package/dist/wm.js +1227 -347
- package/dist/wm.js.map +4 -4
- package/editor.js +20 -0
- package/flow.js +21 -0
- package/host.js +14 -0
- package/package.json +12 -1
- package/src/canvas/canvas_adapter.js +5 -0
- package/src/canvas/edge_router.js +0 -0
- package/src/canvas/graph/connector_router.js +0 -0
- package/src/canvas/graph/history_service.js +0 -0
- package/src/canvas/graph/node_platform.js +0 -0
- package/src/canvas/index.js +1 -0
- package/src/canvas/layered_layout.js +244 -0
- package/src/charts/chart_types.js +0 -0
- package/src/charts/data_series_plot_window.js +0 -0
- package/src/charts/downsample.js +2 -2
- package/src/charts/plot_config.js +53 -29
- package/src/charts/plot_config_editor.js +627 -0
- package/src/charts/plot_grid.js +449 -0
- package/src/charts/plot_popout_window.js +103 -317
- package/src/charts/plotly_wrapper.js +22 -2
- package/src/charts/series_transforms.js +206 -0
- package/src/core/event_bus.js +0 -0
- package/src/core/logging.js +1 -1
- package/src/core/settings.js +105 -19
- package/src/core/state_guard.js +93 -51
- package/src/core/state_guard_config.js +85 -74
- package/src/core/state_machine.js +0 -0
- package/src/editor/editor_pane.js +3 -3
- package/src/editor/monaco_editor_factory.js +124 -60
- package/src/editor/monaco_loader.js +103 -28
- package/src/editor/notebook_search.js +0 -0
- package/src/editor/notebook_tab_bar.js +38 -52
- package/src/editor/notebook_undo_manager.js +0 -0
- package/src/editor/split_pane_container.js +6 -3
- package/src/flow/canvas_editor/connections.js +90 -0
- package/src/flow/canvas_editor/editor.js +2351 -153
- package/src/flow/canvas_editor/index.js +2 -1
- package/src/flow/canvas_editor/layout.js +119 -12
- package/src/flow/canvas_editor/strings.js +80 -0
- package/src/flow/kit/always_before.js +0 -0
- package/src/flow/kit/catalogue.js +97 -3
- package/src/flow/kit/chip_input.js +0 -0
- package/src/flow/kit/dom.js +0 -0
- package/src/flow/kit/findings.js +0 -0
- package/src/flow/kit/history.js +0 -0
- package/src/flow/kit/index.js +3 -3
- package/src/flow/kit/keys.js +7 -1
- package/src/flow/kit/logic_graph.js +97 -15
- package/src/flow/kit/references.js +0 -0
- package/src/flow/kit/settings_panel.js +0 -0
- package/src/flow/kit/settings_schema.js +2 -1
- package/src/flow/kit/step_picker.js +0 -0
- package/src/flow/kit/strings.js +3 -1
- package/src/flow/kit/value_picker.js +0 -0
- package/src/flow/kit/widgets.js +86 -109
- package/src/flow/lanes/editor.js +136 -14
- package/src/flow/lanes/index.js +3 -1
- package/src/flow/lanes/layout.js +0 -0
- package/src/flow/lanes/pipeline.js +44 -2
- package/src/flow/lanes/preview.js +0 -0
- package/src/flow/lanes/strings.js +1 -0
- package/src/flow/outline/editor.js +0 -0
- package/src/flow/outline/index.js +0 -0
- package/src/flow/outline/mapping.js +0 -0
- package/src/flow/outline/menu.js +0 -0
- package/src/flow/outline/operations.js +0 -0
- package/src/flow/outline/recognise.js +0 -0
- package/src/flow/outline/strings.js +0 -0
- package/src/help/help_modal.js +168 -42
- package/src/help/help_registry.js +12 -1
- package/src/host/external_links.js +0 -0
- package/src/host/file_picker.js +117 -0
- package/src/host/host.js +10 -2
- package/src/host/photino_host.js +9 -0
- package/src/host/photino_host.md +21 -3
- package/src/host/pywebview_host.js +10 -0
- package/src/tiles/chart_tiles.js +53 -245
- package/src/tiles/config_schema.js +8 -0
- package/src/tiles/figure_tile.js +322 -0
- package/src/tiles/layout_persistence.js +3 -3
- package/src/tiles/list_tiles.js +7 -7
- package/src/tiles/scope_picker.js +0 -0
- package/src/tiles/tile_base.js +1 -1
- package/src/tiles/tile_config_form.js +442 -0
- package/src/tiles/tile_grid.js +2 -0
- package/src/tiles/tile_registry.js +0 -0
- package/src/tiling/bottom_panel_tabs.js +67 -99
- package/src/tiling/command_palette.js +64 -19
- package/src/tiling/content_registry.js +4 -1
- package/src/tiling/desktops.js +11 -1
- package/src/tiling/entity_sources.js +0 -0
- package/src/tiling/keymap.js +403 -128
- package/src/tiling/kind_taxonomy.js +78 -0
- package/src/tiling/landing_table.js +0 -0
- package/src/tiling/loading_overlay.js +0 -0
- package/src/tiling/nav_panel.js +59 -10
- package/src/tiling/page_factory.js +5 -5
- package/src/tiling/panel_availability.js +49 -0
- package/src/tiling/panel_keys.js +0 -0
- package/src/tiling/shell.js +114 -12
- package/src/tiling/tab_strip.js +0 -0
- package/src/tiling/tile_breadcrumb.js +0 -0
- package/src/tiling/tile_renderer.js +105 -9
- package/src/tiling/tile_tab_menu.js +0 -0
- package/src/tiling/tile_tree.js +0 -0
- package/src/tiling/wm.js +562 -30
- package/src/tiling/zoom.js +0 -0
- package/src/ui/base/component_base.js +0 -0
- package/src/ui/base/controller_base.js +0 -0
- package/src/ui/base/page_base.js +0 -0
- package/src/ui/components/about_dialog.js +0 -0
- package/src/ui/components/action_dropdown.js +30 -2
- package/src/ui/components/alert_log.js +0 -0
- package/src/ui/components/alerts_pane.js +0 -0
- package/src/ui/components/attribute_list_editor.js +0 -0
- package/src/ui/components/autocomplete_field.js +0 -0
- package/src/ui/components/cell_editor_host.js +293 -0
- package/src/ui/components/cell_editors.js +480 -0
- package/src/ui/components/cell_grid.js +761 -0
- package/src/ui/components/cell_paste.js +243 -0
- package/src/ui/components/cell_selection.js +220 -0
- package/src/ui/components/choice_controls.js +351 -0
- package/src/ui/components/color_field.js +211 -0
- package/src/ui/components/color_list_field.js +210 -0
- package/src/ui/components/column_fit.js +0 -0
- package/src/ui/components/column_groups.js +314 -0
- package/src/ui/components/column_order.js +142 -0
- package/src/ui/components/computing_status_window.js +98 -25
- package/src/ui/components/confirm_dialog.js +81 -38
- package/src/ui/components/context_menu.js +2 -2
- package/src/ui/components/conversation_view.js +440 -0
- package/src/ui/components/crosstab.js +289 -0
- package/src/ui/components/data_table.js +696 -71
- package/src/ui/components/detail_header.js +22 -11
- package/src/ui/components/document_outline.js +397 -0
- package/src/ui/components/drag_reorder.js +0 -0
- package/src/ui/components/fact_table.js +0 -0
- package/src/ui/components/fill_handle.js +322 -0
- package/src/ui/components/gallery_picker.js +19 -8
- package/src/ui/components/header_actions.js +55 -0
- package/src/ui/components/inline_renamer.js +0 -0
- package/src/ui/components/job_progress.js +51 -0
- package/src/ui/components/managed_window.js +27 -4
- package/src/ui/components/menu_bar.js +745 -0
- package/src/ui/components/modal.js +449 -75
- package/src/ui/components/notification_history.js +3 -3
- package/src/ui/components/progress.js +483 -0
- package/src/ui/components/record_list.js +0 -0
- package/src/ui/components/row_activation.js +0 -0
- package/src/ui/components/section_stack.js +298 -0
- package/src/ui/components/series.js +173 -0
- package/src/ui/components/settings_view.js +634 -0
- package/src/ui/components/slide_out_panel.js +43 -6
- package/src/ui/components/slider_field.js +275 -18
- package/src/ui/components/sortable_list.js +0 -0
- package/src/ui/components/staged_edits.js +361 -0
- package/src/ui/components/staged_history.js +172 -0
- package/src/ui/components/table_filter_chips.js +0 -0
- package/src/ui/components/table_state_store.js +0 -0
- package/src/ui/components/table_structure.js +182 -0
- package/src/ui/components/table_values.js +0 -0
- package/src/ui/components/tabs.js +497 -0
- package/src/ui/components/tag_input.js +215 -0
- package/src/ui/components/toast.js +25 -8
- package/src/ui/components/toggle_field.js +175 -0
- package/src/ui/components/tree_view.js +55 -34
- package/src/ui/components/tsv.js +74 -0
- package/src/ui/components/window_taskbar.js +0 -0
- package/src/ui/components/wizard.js +563 -0
- package/src/ui/controllers/window_chrome_controller.js +2 -2
- package/src/ui/notification_center.js +375 -119
- package/src/ui/utils/auto_scrollbars.js +0 -0
- package/src/ui/utils/markdown.js +709 -0
- package/src/ui/utils/native_context_menu.js +0 -0
- package/src/ui/utils/overlay_scrollbar.js +16 -12
- package/src/ui/utils/raf_resize_observer.js +0 -0
- package/src/ui/utils/scroll_lock.js +0 -0
- package/src/ui/utils/strip_scroll.js +55 -0
- package/src/ui/utils/tooltip_service.js +0 -8
- package/tiles.js +27 -0
- package/widgets.js +69 -0
- package/wm.js +28 -0
- package/dist/chunk-6JSOVNID.js.map +0 -7
- package/dist/chunk-B5Q53LAJ.js.map +0 -7
- package/dist/chunk-FBGP5KN5.js.map +0 -7
- package/dist/chunk-FL5KFNQH.js.map +0 -7
- package/dist/chunk-NLTOY57M.js.map +0 -7
- package/dist/chunk-NNFTETK3.js +0 -633
- package/dist/chunk-NNFTETK3.js.map +0 -7
- package/dist/chunk-O5OHMWBB.js +0 -284
- package/dist/chunk-O5OHMWBB.js.map +0 -7
- package/dist/chunk-RQM5Z2MU.js.map +0 -7
- package/dist/chunk-SN4LSOAR.js.map +0 -7
- package/dist/chunk-W6FBJLPW.js +0 -367
- package/dist/chunk-W6FBJLPW.js.map +0 -7
- package/src/ui/controllers/panel_state_machine.js +0 -634
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSetting
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HNU6MM2B.js";
|
|
4
4
|
|
|
5
5
|
// src/ui/components/managed_window.js
|
|
6
|
-
var
|
|
6
|
+
var DEFAULT_WINDOW_STORAGE_KEY = "flexdesk.managedWindows.v1";
|
|
7
|
+
var _storageKey = DEFAULT_WINDOW_STORAGE_KEY;
|
|
7
8
|
var BASE_Z_INDEX = 6e3;
|
|
8
9
|
var MAX_Z_INDEX = 6999;
|
|
9
10
|
var TOP_BAR_HEIGHT = 35;
|
|
@@ -22,10 +23,10 @@ function _collectFocusable(root) {
|
|
|
22
23
|
"textarea:not([disabled])",
|
|
23
24
|
'[tabindex]:not([tabindex="-1"])'
|
|
24
25
|
].join(",");
|
|
25
|
-
return Array.from(root.querySelectorAll(sel)).filter((
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
28
|
-
const r =
|
|
26
|
+
return Array.from(root.querySelectorAll(sel)).filter((el2) => {
|
|
27
|
+
if (el2.hidden) return false;
|
|
28
|
+
if (el2.closest("[hidden]")) return false;
|
|
29
|
+
const r = el2.getBoundingClientRect();
|
|
29
30
|
return r.width > 0 || r.height > 0;
|
|
30
31
|
});
|
|
31
32
|
}
|
|
@@ -33,7 +34,7 @@ var _stateCache = null;
|
|
|
33
34
|
function _loadState() {
|
|
34
35
|
if (_stateCache) return _stateCache;
|
|
35
36
|
try {
|
|
36
|
-
const raw = localStorage.getItem(
|
|
37
|
+
const raw = localStorage.getItem(_storageKey);
|
|
37
38
|
_stateCache = raw ? JSON.parse(raw) : {};
|
|
38
39
|
} catch {
|
|
39
40
|
_stateCache = {};
|
|
@@ -43,7 +44,7 @@ function _loadState() {
|
|
|
43
44
|
function _saveState(state) {
|
|
44
45
|
_stateCache = state;
|
|
45
46
|
try {
|
|
46
|
-
localStorage.setItem(
|
|
47
|
+
localStorage.setItem(_storageKey, JSON.stringify(state));
|
|
47
48
|
} catch (err) {
|
|
48
49
|
console.warn("[ManagedWindow] Failed to save state:", err);
|
|
49
50
|
}
|
|
@@ -639,7 +640,7 @@ var ManagedWindow = class {
|
|
|
639
640
|
* x = max(minX, min(x, maxX)) = max(0, min(x, maxX)) ✓
|
|
640
641
|
* y = max(minY, min(y, maxY)) = max(TOP, min(y, maxY)) ✓
|
|
641
642
|
*
|
|
642
|
-
*
|
|
643
|
+
* Embedders' modals depend on that arithmetic; prove the
|
|
643
644
|
* equivalence in review by substitution rather than by testing.
|
|
644
645
|
*/
|
|
645
646
|
_bounds() {
|
|
@@ -1199,6 +1200,23 @@ var ManagedWindow = class {
|
|
|
1199
1200
|
}
|
|
1200
1201
|
}
|
|
1201
1202
|
// ========== Static Methods ==========
|
|
1203
|
+
/**
|
|
1204
|
+
* Choose where window geometry is saved and restored. Call once at boot,
|
|
1205
|
+
* before the first window opens; from then on windows read and write only
|
|
1206
|
+
* `storageKey`. The geometry already read from another key is dropped, so
|
|
1207
|
+
* a window shown afterwards restores what `storageKey` holds.
|
|
1208
|
+
*
|
|
1209
|
+
* @param {object} [opts]
|
|
1210
|
+
* @param {string} [opts.storageKey=DEFAULT_WINDOW_STORAGE_KEY]
|
|
1211
|
+
*/
|
|
1212
|
+
static configure({ storageKey = DEFAULT_WINDOW_STORAGE_KEY } = {}) {
|
|
1213
|
+
_storageKey = storageKey;
|
|
1214
|
+
_stateCache = null;
|
|
1215
|
+
}
|
|
1216
|
+
/** @returns {string} The localStorage key window geometry uses. */
|
|
1217
|
+
static get storageKey() {
|
|
1218
|
+
return _storageKey;
|
|
1219
|
+
}
|
|
1202
1220
|
/**
|
|
1203
1221
|
* Get a window by ID.
|
|
1204
1222
|
*/
|
|
@@ -1231,6 +1249,602 @@ var ManagedWindow = class {
|
|
|
1231
1249
|
}
|
|
1232
1250
|
};
|
|
1233
1251
|
|
|
1252
|
+
// src/ui/components/toggle_field.js
|
|
1253
|
+
var ToggleField = class {
|
|
1254
|
+
/**
|
|
1255
|
+
* @param {object} o
|
|
1256
|
+
* @param {boolean} [o.checked=false]
|
|
1257
|
+
* @param {string?} [o.label] text beside the switch, and its accessible name
|
|
1258
|
+
* @param {string?} [o.ariaLabel] accessible name when there is no visible label
|
|
1259
|
+
* @param {string?} [o.onText] state text shown while on
|
|
1260
|
+
* @param {string?} [o.offText] state text shown while off
|
|
1261
|
+
* @param {boolean} [o.disabled=false]
|
|
1262
|
+
* @param {boolean} [o.compact=false] a smaller track, for dense rows
|
|
1263
|
+
* @param {string?} [o.name] the input's name, for a surrounding form
|
|
1264
|
+
* @param {string?} [o.id] the input's id
|
|
1265
|
+
* @param {Function?}[o.onChange] `(checked: boolean)` after a user toggle
|
|
1266
|
+
*/
|
|
1267
|
+
constructor({
|
|
1268
|
+
checked = false,
|
|
1269
|
+
label = null,
|
|
1270
|
+
ariaLabel = null,
|
|
1271
|
+
onText = null,
|
|
1272
|
+
offText = null,
|
|
1273
|
+
disabled = false,
|
|
1274
|
+
compact = false,
|
|
1275
|
+
name = null,
|
|
1276
|
+
id = null,
|
|
1277
|
+
onChange = null
|
|
1278
|
+
} = {}) {
|
|
1279
|
+
this._initial = !!checked;
|
|
1280
|
+
this._label = label == null ? null : String(label);
|
|
1281
|
+
this._ariaLabel = ariaLabel == null ? null : String(ariaLabel);
|
|
1282
|
+
this._onText = onText == null ? null : String(onText);
|
|
1283
|
+
this._offText = offText == null ? null : String(offText);
|
|
1284
|
+
this._disabled = !!disabled;
|
|
1285
|
+
this._compact = !!compact;
|
|
1286
|
+
this._name = name == null ? null : String(name);
|
|
1287
|
+
this._id = id == null ? null : String(id);
|
|
1288
|
+
this._onChange = typeof onChange === "function" ? onChange : null;
|
|
1289
|
+
this.root = null;
|
|
1290
|
+
this.input = null;
|
|
1291
|
+
this._stateEl = null;
|
|
1292
|
+
this._disposers = [];
|
|
1293
|
+
}
|
|
1294
|
+
/** Build the switch once and hand back its root; later calls return it. */
|
|
1295
|
+
render() {
|
|
1296
|
+
if (this.root) return this.root;
|
|
1297
|
+
const root = document.createElement("label");
|
|
1298
|
+
root.className = "twm-toggle";
|
|
1299
|
+
if (this._compact) root.classList.add("twm-toggle--compact");
|
|
1300
|
+
const control = document.createElement("span");
|
|
1301
|
+
control.className = "twm-toggle__control";
|
|
1302
|
+
const input = document.createElement("input");
|
|
1303
|
+
input.type = "checkbox";
|
|
1304
|
+
input.className = "twm-toggle__input";
|
|
1305
|
+
input.setAttribute("role", "switch");
|
|
1306
|
+
if (this._name) input.name = this._name;
|
|
1307
|
+
if (this._id) input.id = this._id;
|
|
1308
|
+
if (this._ariaLabel && !this._label) input.setAttribute("aria-label", this._ariaLabel);
|
|
1309
|
+
input.checked = this._initial;
|
|
1310
|
+
const track = document.createElement("span");
|
|
1311
|
+
track.className = "twm-toggle__track";
|
|
1312
|
+
track.setAttribute("aria-hidden", "true");
|
|
1313
|
+
const knob = document.createElement("span");
|
|
1314
|
+
knob.className = "twm-toggle__knob";
|
|
1315
|
+
track.appendChild(knob);
|
|
1316
|
+
control.append(input, track);
|
|
1317
|
+
root.appendChild(control);
|
|
1318
|
+
if (this._onText != null || this._offText != null) {
|
|
1319
|
+
this._stateEl = document.createElement("span");
|
|
1320
|
+
this._stateEl.className = "twm-toggle__state";
|
|
1321
|
+
this._stateEl.setAttribute("aria-hidden", "true");
|
|
1322
|
+
root.appendChild(this._stateEl);
|
|
1323
|
+
}
|
|
1324
|
+
if (this._label != null) {
|
|
1325
|
+
const labelEl = document.createElement("span");
|
|
1326
|
+
labelEl.className = "twm-toggle__label";
|
|
1327
|
+
labelEl.textContent = this._label;
|
|
1328
|
+
root.appendChild(labelEl);
|
|
1329
|
+
}
|
|
1330
|
+
this.root = root;
|
|
1331
|
+
this.input = input;
|
|
1332
|
+
this.setDisabled(this._disabled);
|
|
1333
|
+
this._sync();
|
|
1334
|
+
const onKeyDown = (e) => {
|
|
1335
|
+
if (e.key !== " " && e.key !== "Enter") return;
|
|
1336
|
+
e.preventDefault();
|
|
1337
|
+
if (e.repeat) return;
|
|
1338
|
+
input.click();
|
|
1339
|
+
};
|
|
1340
|
+
const onKeyUp = (e) => {
|
|
1341
|
+
if (e.key === " ") e.preventDefault();
|
|
1342
|
+
};
|
|
1343
|
+
const onChange = () => {
|
|
1344
|
+
this._sync();
|
|
1345
|
+
this._onChange?.(input.checked);
|
|
1346
|
+
};
|
|
1347
|
+
input.addEventListener("keydown", onKeyDown);
|
|
1348
|
+
input.addEventListener("keyup", onKeyUp);
|
|
1349
|
+
input.addEventListener("change", onChange);
|
|
1350
|
+
this._disposers.push(
|
|
1351
|
+
() => input.removeEventListener("keydown", onKeyDown),
|
|
1352
|
+
() => input.removeEventListener("keyup", onKeyUp),
|
|
1353
|
+
() => input.removeEventListener("change", onChange)
|
|
1354
|
+
);
|
|
1355
|
+
return root;
|
|
1356
|
+
}
|
|
1357
|
+
/** Whether the switch is on. */
|
|
1358
|
+
get() {
|
|
1359
|
+
return this.input ? this.input.checked : this._initial;
|
|
1360
|
+
}
|
|
1361
|
+
/** Turn it on or off. Does NOT call `onChange`. */
|
|
1362
|
+
set(checked) {
|
|
1363
|
+
if (!this.input) {
|
|
1364
|
+
this._initial = !!checked;
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
this.input.checked = !!checked;
|
|
1368
|
+
this._sync();
|
|
1369
|
+
}
|
|
1370
|
+
/** A disabled switch ignores clicks and keys alike. */
|
|
1371
|
+
setDisabled(disabled) {
|
|
1372
|
+
this._disabled = !!disabled;
|
|
1373
|
+
if (!this.input) return;
|
|
1374
|
+
this.input.disabled = this._disabled;
|
|
1375
|
+
this.root.classList.toggle("twm-toggle--disabled", this._disabled);
|
|
1376
|
+
}
|
|
1377
|
+
dispose() {
|
|
1378
|
+
for (const d of this._disposers) {
|
|
1379
|
+
try {
|
|
1380
|
+
d();
|
|
1381
|
+
} catch {
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
this._disposers = [];
|
|
1385
|
+
this.root?.remove();
|
|
1386
|
+
this.root = null;
|
|
1387
|
+
this.input = null;
|
|
1388
|
+
this._stateEl = null;
|
|
1389
|
+
}
|
|
1390
|
+
_sync() {
|
|
1391
|
+
const on = this.input.checked;
|
|
1392
|
+
this.input.setAttribute("aria-checked", on ? "true" : "false");
|
|
1393
|
+
if (this._stateEl) this._stateEl.textContent = (on ? this._onText : this._offText) ?? "";
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
|
|
1397
|
+
// src/ui/components/color_field.js
|
|
1398
|
+
var HEX_RE = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
1399
|
+
var RGB_RE = /^rgba?\(\s*([^)]*)\)$/i;
|
|
1400
|
+
function isHexColor(value) {
|
|
1401
|
+
return typeof value === "string" && HEX_RE.test(value.trim());
|
|
1402
|
+
}
|
|
1403
|
+
function normalizeHex(value) {
|
|
1404
|
+
if (typeof value !== "string") return null;
|
|
1405
|
+
const s = value.trim();
|
|
1406
|
+
if (HEX_RE.test(s)) {
|
|
1407
|
+
const h = s.slice(1).toLowerCase();
|
|
1408
|
+
return h.length === 3 ? `#${h[0]}${h[0]}${h[1]}${h[1]}${h[2]}${h[2]}` : `#${h}`;
|
|
1409
|
+
}
|
|
1410
|
+
const m = RGB_RE.exec(s);
|
|
1411
|
+
if (!m) return null;
|
|
1412
|
+
const parts = m[1].split(/\s*[,/]\s*|\s+/).filter(Boolean);
|
|
1413
|
+
if (parts.length < 3 || parts.length > 4) return null;
|
|
1414
|
+
const channels = [];
|
|
1415
|
+
for (const p of parts.slice(0, 3)) {
|
|
1416
|
+
const pct = p.endsWith("%");
|
|
1417
|
+
const n = Number(pct ? p.slice(0, -1) : p);
|
|
1418
|
+
if (!Number.isFinite(n)) return null;
|
|
1419
|
+
const v = pct ? n / 100 * 255 : n;
|
|
1420
|
+
if (v < 0 || v > 255) return null;
|
|
1421
|
+
channels.push(Math.round(v));
|
|
1422
|
+
}
|
|
1423
|
+
return `#${channels.map((c) => c.toString(16).padStart(2, "0")).join("")}`;
|
|
1424
|
+
}
|
|
1425
|
+
function displayText(value) {
|
|
1426
|
+
if (value == null) return "";
|
|
1427
|
+
return normalizeHex(String(value)) ?? String(value);
|
|
1428
|
+
}
|
|
1429
|
+
var ColorField = class {
|
|
1430
|
+
/**
|
|
1431
|
+
* @param {Object} [o]
|
|
1432
|
+
* @param {string} [o.value] initial colour (hex or rgb()); '' for none
|
|
1433
|
+
* @param {string[]} [o.presets] preset colours drawn as buttons; ones that
|
|
1434
|
+
* are not colours are left out
|
|
1435
|
+
* @param {string} [o.name] `name` of the hex box, for a host form
|
|
1436
|
+
* @param {string} [o.label] accessible name of the swatch and the box
|
|
1437
|
+
* @param {Function} [o.onChange] `(value, { commit })`, value as `getValue()`
|
|
1438
|
+
*/
|
|
1439
|
+
constructor({ value = "", presets = [], name = null, label = null, onChange = null } = {}) {
|
|
1440
|
+
this.initial = displayText(value);
|
|
1441
|
+
this.presets = (Array.isArray(presets) ? presets : []).map(normalizeHex).filter(Boolean);
|
|
1442
|
+
this.name = name;
|
|
1443
|
+
this.label = label;
|
|
1444
|
+
this.onChange = typeof onChange === "function" ? onChange : null;
|
|
1445
|
+
this.root = null;
|
|
1446
|
+
this.swatch = null;
|
|
1447
|
+
this.hex = null;
|
|
1448
|
+
this._disposers = [];
|
|
1449
|
+
}
|
|
1450
|
+
render() {
|
|
1451
|
+
if (this.root) return this.root;
|
|
1452
|
+
const root = document.createElement("div");
|
|
1453
|
+
root.className = "twm-color-field";
|
|
1454
|
+
const swatch = document.createElement("input");
|
|
1455
|
+
swatch.type = "color";
|
|
1456
|
+
swatch.className = "twm-color-field__swatch";
|
|
1457
|
+
swatch.value = normalizeHex(this.initial) ?? "#000000";
|
|
1458
|
+
if (this.label) swatch.title = this.label;
|
|
1459
|
+
const hex = document.createElement("input");
|
|
1460
|
+
hex.type = "text";
|
|
1461
|
+
hex.className = "twm-color-field__hex";
|
|
1462
|
+
hex.value = this.initial;
|
|
1463
|
+
hex.placeholder = "#rrggbb";
|
|
1464
|
+
hex.spellcheck = false;
|
|
1465
|
+
hex.autocomplete = "off";
|
|
1466
|
+
hex.maxLength = 7;
|
|
1467
|
+
if (this.name) hex.name = this.name;
|
|
1468
|
+
if (this.label) hex.setAttribute("aria-label", this.label);
|
|
1469
|
+
root.append(swatch, hex);
|
|
1470
|
+
this.root = root;
|
|
1471
|
+
this.swatch = swatch;
|
|
1472
|
+
this.hex = hex;
|
|
1473
|
+
if (this.presets.length) {
|
|
1474
|
+
const strip = document.createElement("div");
|
|
1475
|
+
strip.className = "twm-color-field__presets";
|
|
1476
|
+
for (const color of this.presets) {
|
|
1477
|
+
const btn = document.createElement("button");
|
|
1478
|
+
btn.type = "button";
|
|
1479
|
+
btn.className = "twm-color-field__preset";
|
|
1480
|
+
btn.style.backgroundColor = color;
|
|
1481
|
+
btn.title = color;
|
|
1482
|
+
btn.setAttribute("aria-label", color);
|
|
1483
|
+
this.#listen(btn, "click", () => this.#writeBox(color, true));
|
|
1484
|
+
strip.appendChild(btn);
|
|
1485
|
+
}
|
|
1486
|
+
root.appendChild(strip);
|
|
1487
|
+
}
|
|
1488
|
+
this.#listen(swatch, "input", () => this.#writeBox(swatch.value, false));
|
|
1489
|
+
this.#listen(swatch, "change", () => this.#writeBox(swatch.value, true));
|
|
1490
|
+
this.#listen(hex, "input", () => this.#sync(false));
|
|
1491
|
+
this.#listen(hex, "change", () => {
|
|
1492
|
+
const v = this.getValue();
|
|
1493
|
+
if (v) hex.value = v;
|
|
1494
|
+
this.#sync(true);
|
|
1495
|
+
});
|
|
1496
|
+
this.#sync(null);
|
|
1497
|
+
return root;
|
|
1498
|
+
}
|
|
1499
|
+
/** `#rrggbb`, `''` when empty, or `null` when the box holds no hex colour. */
|
|
1500
|
+
getValue() {
|
|
1501
|
+
const text = this.getText().trim();
|
|
1502
|
+
if (text === "") return "";
|
|
1503
|
+
return isHexColor(text) ? normalizeHex(text) : null;
|
|
1504
|
+
}
|
|
1505
|
+
/** The box as it stands. */
|
|
1506
|
+
getText() {
|
|
1507
|
+
return this.hex ? this.hex.value : this.initial;
|
|
1508
|
+
}
|
|
1509
|
+
isValid() {
|
|
1510
|
+
return this.getValue() !== null;
|
|
1511
|
+
}
|
|
1512
|
+
/** Write a colour (hex or rgb()) without firing `onChange`. */
|
|
1513
|
+
setValue(value) {
|
|
1514
|
+
const text = displayText(value);
|
|
1515
|
+
if (!this.hex) {
|
|
1516
|
+
this.initial = text;
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
this.hex.value = text;
|
|
1520
|
+
this.#sync(null);
|
|
1521
|
+
}
|
|
1522
|
+
focus() {
|
|
1523
|
+
this.hex?.focus();
|
|
1524
|
+
}
|
|
1525
|
+
dispose() {
|
|
1526
|
+
for (const d of this._disposers) {
|
|
1527
|
+
try {
|
|
1528
|
+
d();
|
|
1529
|
+
} catch {
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
this._disposers = [];
|
|
1533
|
+
this.root = null;
|
|
1534
|
+
this.swatch = null;
|
|
1535
|
+
this.hex = null;
|
|
1536
|
+
}
|
|
1537
|
+
#listen(el2, type, fn) {
|
|
1538
|
+
el2.addEventListener(type, fn);
|
|
1539
|
+
this._disposers.push(() => el2.removeEventListener(type, fn));
|
|
1540
|
+
}
|
|
1541
|
+
/** Put `text` in the box and fire the box's own events, as typing would. */
|
|
1542
|
+
#writeBox(text, commit) {
|
|
1543
|
+
this.hex.value = text;
|
|
1544
|
+
this.hex.dispatchEvent(new Event("input", { bubbles: true }));
|
|
1545
|
+
if (commit) this.hex.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1546
|
+
}
|
|
1547
|
+
/** Swatch and invalid mark follow the box; `commit === null` is silent. */
|
|
1548
|
+
#sync(commit) {
|
|
1549
|
+
const v = this.getValue();
|
|
1550
|
+
if (v) this.swatch.value = v;
|
|
1551
|
+
this.root.classList.toggle("twm-color-field--invalid", v === null);
|
|
1552
|
+
if (commit !== null) this.onChange?.(v, { commit });
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
|
|
1556
|
+
// src/ui/components/choice_controls.js
|
|
1557
|
+
var shownValue = (v) => v === void 0 ? "" : typeof v === "string" ? v : JSON.stringify(v);
|
|
1558
|
+
function el(tag, className, text) {
|
|
1559
|
+
const n = document.createElement(tag);
|
|
1560
|
+
if (className) n.className = className;
|
|
1561
|
+
if (text !== void 0 && text !== null) n.textContent = String(text);
|
|
1562
|
+
return n;
|
|
1563
|
+
}
|
|
1564
|
+
var isGroup = (o) => o !== null && typeof o === "object" && Array.isArray(o.options) && "group" in o;
|
|
1565
|
+
function choiceOption(o) {
|
|
1566
|
+
if (o === null || typeof o !== "object") {
|
|
1567
|
+
return { value: o, label: shownValue(o), description: null, disabled: false, reason: null };
|
|
1568
|
+
}
|
|
1569
|
+
return {
|
|
1570
|
+
value: o.value,
|
|
1571
|
+
label: o.label != null ? String(o.label) : shownValue(o.value),
|
|
1572
|
+
description: o.description != null ? String(o.description) : null,
|
|
1573
|
+
disabled: Boolean(o.disabled),
|
|
1574
|
+
reason: o.reason != null && o.reason !== "" ? String(o.reason) : null
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
function flatChoices(options) {
|
|
1578
|
+
const out = [];
|
|
1579
|
+
for (const o of options || []) {
|
|
1580
|
+
if (isGroup(o)) for (const inner of o.options) out.push(choiceOption(inner));
|
|
1581
|
+
else out.push(choiceOption(o));
|
|
1582
|
+
}
|
|
1583
|
+
return out;
|
|
1584
|
+
}
|
|
1585
|
+
function groupHeads(options) {
|
|
1586
|
+
const heads = /* @__PURE__ */ new Map();
|
|
1587
|
+
let at = 0;
|
|
1588
|
+
for (const o of options || []) {
|
|
1589
|
+
if (!isGroup(o)) {
|
|
1590
|
+
at += 1;
|
|
1591
|
+
continue;
|
|
1592
|
+
}
|
|
1593
|
+
if (o.options.length) heads.set(at, String(o.group ?? ""));
|
|
1594
|
+
at += o.options.length;
|
|
1595
|
+
}
|
|
1596
|
+
return heads;
|
|
1597
|
+
}
|
|
1598
|
+
var groupHeading = (text) => el("div", "twm-choice__group", text);
|
|
1599
|
+
function sameChoice(v, value, loose = false) {
|
|
1600
|
+
if (v === value) return true;
|
|
1601
|
+
if (!loose || v === void 0 || value === void 0 || v === null || value === null) return false;
|
|
1602
|
+
return String(v) === String(value);
|
|
1603
|
+
}
|
|
1604
|
+
function choiceIndex(list, v, loose = false, from = 0) {
|
|
1605
|
+
for (let i = from; i < list.length; i += 1) if (list[i].value === v) return i;
|
|
1606
|
+
if (!loose) return -1;
|
|
1607
|
+
for (let i = from; i < list.length; i += 1) if (sameChoice(list[i].value, v, true)) return i;
|
|
1608
|
+
return -1;
|
|
1609
|
+
}
|
|
1610
|
+
function findChoice(list, v, loose = false) {
|
|
1611
|
+
const i = choiceIndex(list, v, loose);
|
|
1612
|
+
return i >= 0 ? list[i] : void 0;
|
|
1613
|
+
}
|
|
1614
|
+
var optionText = (o) => o.disabled && o.reason ? `${o.label} \u2014 ${o.reason}` : o.label;
|
|
1615
|
+
function selectBox(options, value, {
|
|
1616
|
+
empty = null,
|
|
1617
|
+
label = "",
|
|
1618
|
+
notFound = (v) => `${v} (not found)`,
|
|
1619
|
+
keepMissing = true,
|
|
1620
|
+
valueAttr = "index",
|
|
1621
|
+
loose = false,
|
|
1622
|
+
className = "twm-flow-input twm-flow-input--select"
|
|
1623
|
+
} = {}) {
|
|
1624
|
+
const box = el("select", className);
|
|
1625
|
+
if (label) box.setAttribute("aria-label", label);
|
|
1626
|
+
let entries = [];
|
|
1627
|
+
const add = (parent, o) => {
|
|
1628
|
+
const attr = valueAttr === "index" ? String(entries.length) : o.value === void 0 ? "" : String(o.value);
|
|
1629
|
+
const opt = el("option", "", optionText(o));
|
|
1630
|
+
opt.value = attr;
|
|
1631
|
+
if (o.disabled) {
|
|
1632
|
+
opt.disabled = true;
|
|
1633
|
+
if (o.reason) opt.title = o.reason;
|
|
1634
|
+
}
|
|
1635
|
+
parent.appendChild(opt);
|
|
1636
|
+
entries.push(o);
|
|
1637
|
+
};
|
|
1638
|
+
const firstEnabled = () => {
|
|
1639
|
+
const i = entries.findIndex((e) => !e.disabled);
|
|
1640
|
+
return i >= 0 ? i : 0;
|
|
1641
|
+
};
|
|
1642
|
+
const select = (v) => {
|
|
1643
|
+
const start = empty !== null ? 1 : 0;
|
|
1644
|
+
const at = choiceIndex(entries, v, loose, start);
|
|
1645
|
+
if (at < 0 || entries[at].disabled || entries[at].stray) return false;
|
|
1646
|
+
box.selectedIndex = at;
|
|
1647
|
+
return true;
|
|
1648
|
+
};
|
|
1649
|
+
const place = (v) => {
|
|
1650
|
+
if (select(v)) return;
|
|
1651
|
+
if (keepMissing && v !== void 0 && v !== null && v !== "") {
|
|
1652
|
+
add(box, {
|
|
1653
|
+
value: v,
|
|
1654
|
+
label: notFound(shownValue(v)),
|
|
1655
|
+
description: null,
|
|
1656
|
+
disabled: false,
|
|
1657
|
+
reason: null,
|
|
1658
|
+
stray: true
|
|
1659
|
+
});
|
|
1660
|
+
box.selectedIndex = entries.length - 1;
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
box.selectedIndex = empty !== null ? 0 : firstEnabled();
|
|
1664
|
+
};
|
|
1665
|
+
const fill = (opts, v) => {
|
|
1666
|
+
box.replaceChildren();
|
|
1667
|
+
entries = [];
|
|
1668
|
+
if (empty !== null) add(box, {
|
|
1669
|
+
value: void 0,
|
|
1670
|
+
label: String(empty),
|
|
1671
|
+
description: null,
|
|
1672
|
+
disabled: false,
|
|
1673
|
+
reason: null
|
|
1674
|
+
});
|
|
1675
|
+
for (const o of opts || []) {
|
|
1676
|
+
if (isGroup(o)) {
|
|
1677
|
+
const g = el("optgroup");
|
|
1678
|
+
g.label = String(o.group ?? "");
|
|
1679
|
+
for (const inner of o.options) add(g, choiceOption(inner));
|
|
1680
|
+
box.appendChild(g);
|
|
1681
|
+
} else {
|
|
1682
|
+
add(box, choiceOption(o));
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
place(v);
|
|
1686
|
+
};
|
|
1687
|
+
const entry = () => box.selectedIndex < 0 ? null : entries[box.selectedIndex] ?? null;
|
|
1688
|
+
const valueOf = () => entry()?.value;
|
|
1689
|
+
fill(options, value);
|
|
1690
|
+
return {
|
|
1691
|
+
box,
|
|
1692
|
+
valueOf,
|
|
1693
|
+
entry,
|
|
1694
|
+
select,
|
|
1695
|
+
setOptions(opts, v = valueOf()) {
|
|
1696
|
+
fill(opts, v);
|
|
1697
|
+
}
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
function toggleChips({
|
|
1701
|
+
options,
|
|
1702
|
+
value,
|
|
1703
|
+
label,
|
|
1704
|
+
readOnly,
|
|
1705
|
+
onChange,
|
|
1706
|
+
notFound = (v) => `${v} (not found)`,
|
|
1707
|
+
keepMissing = true,
|
|
1708
|
+
loose = false
|
|
1709
|
+
}) {
|
|
1710
|
+
const root = el("div", "twm-flow-togglechips");
|
|
1711
|
+
root.setAttribute("role", "group");
|
|
1712
|
+
if (label) root.setAttribute("aria-label", label);
|
|
1713
|
+
let shown = [];
|
|
1714
|
+
let list = [];
|
|
1715
|
+
let chosen = /* @__PURE__ */ new Set();
|
|
1716
|
+
let strays = [];
|
|
1717
|
+
const emit = () => {
|
|
1718
|
+
const out = valueOf();
|
|
1719
|
+
onChange?.(out.length ? out : void 0);
|
|
1720
|
+
};
|
|
1721
|
+
const chipFor = (text, pressed, toggle, { stray = false, reason = null, disabled = false } = {}) => {
|
|
1722
|
+
const b = el("button", `twm-flow-togglechip${stray ? " twm-flow-togglechip--missing" : ""}`, text);
|
|
1723
|
+
b.type = "button";
|
|
1724
|
+
b.setAttribute("aria-pressed", pressed ? "true" : "false");
|
|
1725
|
+
b.disabled = Boolean(readOnly) || disabled;
|
|
1726
|
+
if (reason) {
|
|
1727
|
+
b.title = reason;
|
|
1728
|
+
b.appendChild(el("span", "twm-choice__reason", reason));
|
|
1729
|
+
}
|
|
1730
|
+
b.addEventListener("click", () => {
|
|
1731
|
+
const on = toggle();
|
|
1732
|
+
b.setAttribute("aria-pressed", on ? "true" : "false");
|
|
1733
|
+
emit();
|
|
1734
|
+
});
|
|
1735
|
+
return b;
|
|
1736
|
+
};
|
|
1737
|
+
const draw = (opts, stored) => {
|
|
1738
|
+
shown = opts || [];
|
|
1739
|
+
list = flatChoices(shown);
|
|
1740
|
+
const heads = groupHeads(shown);
|
|
1741
|
+
const wanted = Array.isArray(stored) ? stored : [];
|
|
1742
|
+
const offered = (v) => {
|
|
1743
|
+
const o = findChoice(list, v, loose);
|
|
1744
|
+
return o && !o.disabled ? o : void 0;
|
|
1745
|
+
};
|
|
1746
|
+
chosen = new Set(wanted.map(offered).filter(Boolean).map((o) => o.value));
|
|
1747
|
+
strays = keepMissing ? wanted.filter((v) => !offered(v)) : [];
|
|
1748
|
+
root.replaceChildren();
|
|
1749
|
+
list.forEach((o, i) => {
|
|
1750
|
+
if (heads.has(i)) root.appendChild(groupHeading(heads.get(i)));
|
|
1751
|
+
root.appendChild(chipFor(o.label, chosen.has(o.value), () => {
|
|
1752
|
+
if (o.disabled) return false;
|
|
1753
|
+
if (chosen.has(o.value)) chosen.delete(o.value);
|
|
1754
|
+
else chosen.add(o.value);
|
|
1755
|
+
return chosen.has(o.value);
|
|
1756
|
+
}, { disabled: o.disabled, reason: o.disabled ? o.reason : null }));
|
|
1757
|
+
});
|
|
1758
|
+
for (const v of [...strays]) {
|
|
1759
|
+
root.appendChild(chipFor(notFound(shownValue(v)), true, () => {
|
|
1760
|
+
const i = strays.indexOf(v);
|
|
1761
|
+
if (i >= 0) {
|
|
1762
|
+
strays.splice(i, 1);
|
|
1763
|
+
return false;
|
|
1764
|
+
}
|
|
1765
|
+
strays.push(v);
|
|
1766
|
+
return true;
|
|
1767
|
+
}, { stray: true }));
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1770
|
+
const valueOf = () => [...list.filter((o) => chosen.has(o.value)).map((o) => o.value), ...strays];
|
|
1771
|
+
draw(options, value);
|
|
1772
|
+
return {
|
|
1773
|
+
el: root,
|
|
1774
|
+
valueOf,
|
|
1775
|
+
setValue: (stored) => draw(shown, stored),
|
|
1776
|
+
setOptions: (opts) => draw(opts, valueOf())
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
function choiceList({
|
|
1780
|
+
options,
|
|
1781
|
+
value,
|
|
1782
|
+
name,
|
|
1783
|
+
label,
|
|
1784
|
+
readOnly,
|
|
1785
|
+
onChange,
|
|
1786
|
+
notFound = (v) => `${v} (not found)`,
|
|
1787
|
+
keepMissing = true,
|
|
1788
|
+
loose = false
|
|
1789
|
+
}) {
|
|
1790
|
+
const root = el("div", "twm-flow-choices");
|
|
1791
|
+
root.setAttribute("role", "radiogroup");
|
|
1792
|
+
if (label) root.setAttribute("aria-label", label);
|
|
1793
|
+
let list = [];
|
|
1794
|
+
let radios = [];
|
|
1795
|
+
const draw = (opts, current) => {
|
|
1796
|
+
list = flatChoices(opts);
|
|
1797
|
+
const heads = groupHeads(opts);
|
|
1798
|
+
radios = [];
|
|
1799
|
+
root.replaceChildren();
|
|
1800
|
+
const named = choiceIndex(list, current, loose);
|
|
1801
|
+
const at = named >= 0 && !list[named].disabled ? named : -1;
|
|
1802
|
+
list.forEach((o, i) => {
|
|
1803
|
+
if (heads.has(i)) root.appendChild(groupHeading(heads.get(i)));
|
|
1804
|
+
const row = el("label", `twm-flow-choice${o.disabled ? " twm-choice--disabled" : ""}`);
|
|
1805
|
+
const radio = el("input", "twm-flow-choice__radio");
|
|
1806
|
+
radio.type = "radio";
|
|
1807
|
+
radio.name = name;
|
|
1808
|
+
radio.checked = i === at;
|
|
1809
|
+
radio.disabled = Boolean(readOnly) || o.disabled;
|
|
1810
|
+
radio.addEventListener("change", () => {
|
|
1811
|
+
if (radio.checked) onChange?.(o.value);
|
|
1812
|
+
});
|
|
1813
|
+
radios.push(radio);
|
|
1814
|
+
const words = el("span", "twm-flow-choice__words");
|
|
1815
|
+
words.appendChild(el("span", "twm-flow-choice__label", o.label));
|
|
1816
|
+
if (o.description !== null) words.appendChild(el("span", "twm-flow-choice__sub", o.description));
|
|
1817
|
+
if (o.disabled && o.reason) words.appendChild(el("span", "twm-choice__reason", o.reason));
|
|
1818
|
+
row.append(radio, words);
|
|
1819
|
+
root.appendChild(row);
|
|
1820
|
+
});
|
|
1821
|
+
if (keepMissing && current !== void 0 && named < 0) {
|
|
1822
|
+
root.appendChild(el("p", "twm-flow-field__note", notFound(shownValue(current))));
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
const checkedAt = () => radios.findIndex((r) => r.checked);
|
|
1826
|
+
const entry = () => list[checkedAt()] ?? null;
|
|
1827
|
+
const api = {
|
|
1828
|
+
el: root,
|
|
1829
|
+
focus: () => (radios.find((r) => r.checked && !r.disabled) || radios.find((r) => !r.disabled))?.focus({ preventScroll: true }),
|
|
1830
|
+
entry,
|
|
1831
|
+
valueOf: () => entry()?.value,
|
|
1832
|
+
select(v) {
|
|
1833
|
+
const named = choiceIndex(list, v, loose);
|
|
1834
|
+
const at = named >= 0 && !list[named].disabled ? named : -1;
|
|
1835
|
+
radios.forEach((r, i) => {
|
|
1836
|
+
r.checked = i === at;
|
|
1837
|
+
});
|
|
1838
|
+
return at >= 0;
|
|
1839
|
+
},
|
|
1840
|
+
setOptions(opts) {
|
|
1841
|
+
draw(opts, api.valueOf());
|
|
1842
|
+
}
|
|
1843
|
+
};
|
|
1844
|
+
draw(options, value);
|
|
1845
|
+
return api;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1234
1848
|
// src/ui/components/row_activation.js
|
|
1235
1849
|
var ROW_CONTROL_SELECTOR = [
|
|
1236
1850
|
"button",
|
|
@@ -1268,10 +1882,21 @@ function isRowActivation(ev, gesture = "click", { scope = null } = {}) {
|
|
|
1268
1882
|
}
|
|
1269
1883
|
|
|
1270
1884
|
export {
|
|
1885
|
+
DEFAULT_WINDOW_STORAGE_KEY,
|
|
1271
1886
|
ManagedWindow,
|
|
1887
|
+
ToggleField,
|
|
1888
|
+
isHexColor,
|
|
1889
|
+
normalizeHex,
|
|
1890
|
+
ColorField,
|
|
1891
|
+
shownValue,
|
|
1892
|
+
flatChoices,
|
|
1893
|
+
findChoice,
|
|
1894
|
+
selectBox,
|
|
1895
|
+
toggleChips,
|
|
1896
|
+
choiceList,
|
|
1272
1897
|
ROW_CONTROL_SELECTOR,
|
|
1273
1898
|
isRowControl,
|
|
1274
1899
|
endsTextSelection,
|
|
1275
1900
|
isRowActivation
|
|
1276
1901
|
};
|
|
1277
|
-
//# sourceMappingURL=chunk-
|
|
1902
|
+
//# sourceMappingURL=chunk-CVMCZZX2.js.map
|