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
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import {
|
|
2
|
+
revealInStrip,
|
|
3
|
+
wheelStripSideways
|
|
4
|
+
} from "./chunk-N7HC3ADV.js";
|
|
5
|
+
import {
|
|
6
|
+
DragReorder
|
|
7
|
+
} from "./chunk-WVFGV5FT.js";
|
|
8
|
+
|
|
9
|
+
// src/ui/components/tabs.js
|
|
10
|
+
var TAB_LEVELS = Object.freeze(["info", "warning", "alert"]);
|
|
11
|
+
var stripCount = 0;
|
|
12
|
+
function createTabs(container, {
|
|
13
|
+
items = [],
|
|
14
|
+
active = null,
|
|
15
|
+
onSelect = null,
|
|
16
|
+
onReselect = null,
|
|
17
|
+
onClose = null,
|
|
18
|
+
onReorder = null,
|
|
19
|
+
onContextMenu = null,
|
|
20
|
+
mountPane = null,
|
|
21
|
+
eventBus = null,
|
|
22
|
+
selectEvent = null,
|
|
23
|
+
selectFrom = (payload) => payload?.id,
|
|
24
|
+
compact = false,
|
|
25
|
+
label = null,
|
|
26
|
+
block = "twm-tabs",
|
|
27
|
+
dataKey = "tab-id"
|
|
28
|
+
} = {}) {
|
|
29
|
+
const doc = container.ownerDocument;
|
|
30
|
+
const uid = `${block}-${++stripCount}`;
|
|
31
|
+
const datasetKey = dataKey.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
32
|
+
const cls = (part) => `${block}__${part}`;
|
|
33
|
+
const root = doc.createElement("div");
|
|
34
|
+
root.className = compact ? `${block} ${block}--compact` : block;
|
|
35
|
+
const strip = doc.createElement("div");
|
|
36
|
+
strip.className = cls("tabs");
|
|
37
|
+
strip.setAttribute("role", "tablist");
|
|
38
|
+
strip.setAttribute("aria-orientation", "horizontal");
|
|
39
|
+
if (label) strip.setAttribute("aria-label", label);
|
|
40
|
+
root.appendChild(strip);
|
|
41
|
+
let body = null;
|
|
42
|
+
if (mountPane) {
|
|
43
|
+
body = doc.createElement("div");
|
|
44
|
+
body.className = cls("body");
|
|
45
|
+
root.appendChild(body);
|
|
46
|
+
}
|
|
47
|
+
container.appendChild(root);
|
|
48
|
+
let order = [];
|
|
49
|
+
const byId = /* @__PURE__ */ new Map();
|
|
50
|
+
const tabs = /* @__PURE__ */ new Map();
|
|
51
|
+
const idByEl = /* @__PURE__ */ new WeakMap();
|
|
52
|
+
const panes = /* @__PURE__ */ new Map();
|
|
53
|
+
let current = null;
|
|
54
|
+
let serial = 0;
|
|
55
|
+
let destroyed = false;
|
|
56
|
+
let subscription = null;
|
|
57
|
+
function tabFor(id) {
|
|
58
|
+
let entry = tabs.get(id);
|
|
59
|
+
if (entry) return entry;
|
|
60
|
+
const el = doc.createElement("button");
|
|
61
|
+
el.type = "button";
|
|
62
|
+
el.className = cls("tab");
|
|
63
|
+
el.dataset[datasetKey] = id;
|
|
64
|
+
el.id = `${uid}-tab-${++serial}`;
|
|
65
|
+
el.setAttribute("role", "tab");
|
|
66
|
+
el.setAttribute("aria-selected", "false");
|
|
67
|
+
el.tabIndex = -1;
|
|
68
|
+
idByEl.set(el, id);
|
|
69
|
+
entry = { el };
|
|
70
|
+
tabs.set(id, entry);
|
|
71
|
+
return entry;
|
|
72
|
+
}
|
|
73
|
+
function badgeOf(item) {
|
|
74
|
+
const b = item.badge;
|
|
75
|
+
if (b && typeof b === "object") return { count: Number(b.count) || 0, level: b.level ?? null };
|
|
76
|
+
return { count: Number(b) || 0, level: null };
|
|
77
|
+
}
|
|
78
|
+
function drawBadge(span, { count, level }) {
|
|
79
|
+
span.hidden = count <= 0;
|
|
80
|
+
span.textContent = count > 99 ? "99+" : String(Math.max(count, 0));
|
|
81
|
+
span.className = cls("badge") + (TAB_LEVELS.includes(level) ? ` ${cls("badge")}--${level}` : "");
|
|
82
|
+
}
|
|
83
|
+
function drawIndicator(span, value) {
|
|
84
|
+
span.hidden = !value;
|
|
85
|
+
span.className = cls("indicator") + (TAB_LEVELS.includes(value) ? ` ${cls("indicator")}--${value}` : "");
|
|
86
|
+
}
|
|
87
|
+
function draw(id) {
|
|
88
|
+
const item = byId.get(id);
|
|
89
|
+
const { el } = tabFor(id);
|
|
90
|
+
const closable = !!(item.closable && onClose);
|
|
91
|
+
el.classList.toggle(`${cls("tab")}--dirty`, !!item.dirty);
|
|
92
|
+
el.classList.toggle(`${cls("tab")}--closable`, closable);
|
|
93
|
+
if (item.title) el.title = item.title;
|
|
94
|
+
else el.removeAttribute("title");
|
|
95
|
+
const parts = [];
|
|
96
|
+
if (item.icon) {
|
|
97
|
+
const icon = doc.createElement("span");
|
|
98
|
+
icon.className = `material-symbols-outlined ${cls("icon")}`;
|
|
99
|
+
icon.setAttribute("aria-hidden", "true");
|
|
100
|
+
icon.textContent = item.icon;
|
|
101
|
+
parts.push(icon);
|
|
102
|
+
}
|
|
103
|
+
const text = doc.createElement("span");
|
|
104
|
+
text.className = cls("label");
|
|
105
|
+
text.textContent = item.label ?? String(id);
|
|
106
|
+
parts.push(text);
|
|
107
|
+
const badge = doc.createElement("span");
|
|
108
|
+
drawBadge(badge, badgeOf(item));
|
|
109
|
+
parts.push(badge);
|
|
110
|
+
const dot = doc.createElement("span");
|
|
111
|
+
dot.setAttribute("aria-hidden", "true");
|
|
112
|
+
drawIndicator(dot, item.indicator);
|
|
113
|
+
parts.push(dot);
|
|
114
|
+
if (item.dirty) {
|
|
115
|
+
const dirty = doc.createElement("span");
|
|
116
|
+
dirty.className = cls("dirty");
|
|
117
|
+
dirty.setAttribute("aria-label", "unsaved");
|
|
118
|
+
dirty.textContent = "\u25CF";
|
|
119
|
+
parts.push(dirty);
|
|
120
|
+
}
|
|
121
|
+
if (closable) {
|
|
122
|
+
const close = doc.createElement("span");
|
|
123
|
+
close.className = cls("close");
|
|
124
|
+
close.setAttribute("aria-hidden", "true");
|
|
125
|
+
close.title = "Close";
|
|
126
|
+
close.textContent = "\xD7";
|
|
127
|
+
parts.push(close);
|
|
128
|
+
}
|
|
129
|
+
el.replaceChildren(...parts);
|
|
130
|
+
}
|
|
131
|
+
function mount(id) {
|
|
132
|
+
if (destroyed || !mountPane || panes.has(id)) return panes.get(id) ?? null;
|
|
133
|
+
const el = doc.createElement("div");
|
|
134
|
+
el.className = `${block}-pane`;
|
|
135
|
+
el.dataset[datasetKey] = id;
|
|
136
|
+
el.id = `${tabFor(id).el.id}-pane`;
|
|
137
|
+
el.setAttribute("role", "tabpanel");
|
|
138
|
+
el.setAttribute("aria-labelledby", tabFor(id).el.id);
|
|
139
|
+
el.hidden = id !== current;
|
|
140
|
+
body.appendChild(el);
|
|
141
|
+
tabFor(id).el.setAttribute("aria-controls", el.id);
|
|
142
|
+
const entry = { el, instance: null };
|
|
143
|
+
panes.set(id, entry);
|
|
144
|
+
let instance = null;
|
|
145
|
+
try {
|
|
146
|
+
instance = mountPane(byId.get(id), el, api) ?? null;
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.error(`[tabs] pane "${id}" failed to mount`, err);
|
|
149
|
+
}
|
|
150
|
+
if (panes.get(id) !== entry) {
|
|
151
|
+
try {
|
|
152
|
+
instance?.destroy?.();
|
|
153
|
+
} catch (err) {
|
|
154
|
+
console.warn(`[tabs] pane "${id}" destroy failed`, err);
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
entry.instance = instance;
|
|
159
|
+
return entry;
|
|
160
|
+
}
|
|
161
|
+
function mountEager() {
|
|
162
|
+
for (const id of order) if (byId.get(id).eager && !panes.has(id)) mount(id);
|
|
163
|
+
}
|
|
164
|
+
function unmount(id) {
|
|
165
|
+
const entry = panes.get(id);
|
|
166
|
+
if (!entry) return;
|
|
167
|
+
panes.delete(id);
|
|
168
|
+
try {
|
|
169
|
+
entry.instance?.destroy?.();
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.warn(`[tabs] pane "${id}" destroy failed`, err);
|
|
172
|
+
}
|
|
173
|
+
entry.el.remove();
|
|
174
|
+
}
|
|
175
|
+
function paint() {
|
|
176
|
+
for (const [key, { el }] of tabs) {
|
|
177
|
+
const on = key === current;
|
|
178
|
+
el.classList.toggle(`${cls("tab")}--on`, on);
|
|
179
|
+
el.setAttribute("aria-selected", String(on));
|
|
180
|
+
el.tabIndex = on ? 0 : -1;
|
|
181
|
+
}
|
|
182
|
+
for (const [key, entry] of panes) entry.el.hidden = key !== current;
|
|
183
|
+
}
|
|
184
|
+
function show(id, notify) {
|
|
185
|
+
current = id;
|
|
186
|
+
paint();
|
|
187
|
+
if (id != null) {
|
|
188
|
+
mount(id)?.instance?.onShow?.();
|
|
189
|
+
if (destroyed) return;
|
|
190
|
+
if (tabs.has(id)) revealInStrip(strip, tabs.get(id).el);
|
|
191
|
+
}
|
|
192
|
+
if (notify) onSelect?.(id, id == null ? null : byId.get(id));
|
|
193
|
+
}
|
|
194
|
+
function select(id, { focus = false } = {}) {
|
|
195
|
+
if (destroyed || !byId.has(id)) return false;
|
|
196
|
+
if (id !== current) show(id, true);
|
|
197
|
+
if (focus && !destroyed) tabs.get(id)?.el.focus();
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
function setItems(next) {
|
|
201
|
+
const seen = /* @__PURE__ */ new Set();
|
|
202
|
+
order = [];
|
|
203
|
+
byId.clear();
|
|
204
|
+
for (const item of next) {
|
|
205
|
+
if (item?.id == null || seen.has(item.id)) continue;
|
|
206
|
+
seen.add(item.id);
|
|
207
|
+
order.push(item.id);
|
|
208
|
+
byId.set(item.id, { ...item });
|
|
209
|
+
}
|
|
210
|
+
for (const id of [...tabs.keys()]) {
|
|
211
|
+
if (byId.has(id)) continue;
|
|
212
|
+
tabs.get(id).el.remove();
|
|
213
|
+
tabs.delete(id);
|
|
214
|
+
unmount(id);
|
|
215
|
+
}
|
|
216
|
+
for (const id of order) {
|
|
217
|
+
draw(id);
|
|
218
|
+
strip.appendChild(tabs.get(id).el);
|
|
219
|
+
}
|
|
220
|
+
dragReorder?.attach();
|
|
221
|
+
}
|
|
222
|
+
const idOf = (target) => {
|
|
223
|
+
const el = target?.closest?.(`.${cls("tab")}`);
|
|
224
|
+
return el && strip.contains(el) && idByEl.has(el) ? idByEl.get(el) : null;
|
|
225
|
+
};
|
|
226
|
+
function onClick(e) {
|
|
227
|
+
const id = idOf(e.target);
|
|
228
|
+
if (id == null) return;
|
|
229
|
+
if (e.target.closest(`.${cls("close")}`)) {
|
|
230
|
+
onClose?.(id, byId.get(id));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (id === current && !destroyed) {
|
|
234
|
+
onReselect?.(id, byId.get(id));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
select(id);
|
|
238
|
+
}
|
|
239
|
+
function onAuxClick(e) {
|
|
240
|
+
const id = idOf(e.target);
|
|
241
|
+
if (e.button !== 1 || id == null || !byId.get(id)?.closable || !onClose) return;
|
|
242
|
+
e.preventDefault();
|
|
243
|
+
onClose(id, byId.get(id));
|
|
244
|
+
}
|
|
245
|
+
function onKeyDown(e) {
|
|
246
|
+
const id = idOf(e.target);
|
|
247
|
+
if (id == null || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
248
|
+
const at = order.indexOf(id);
|
|
249
|
+
let to = null;
|
|
250
|
+
if (e.key === "ArrowRight") to = order[(at + 1) % order.length];
|
|
251
|
+
else if (e.key === "ArrowLeft") to = order[(at - 1 + order.length) % order.length];
|
|
252
|
+
else if (e.key === "Home") to = order[0];
|
|
253
|
+
else if (e.key === "End") to = order[order.length - 1];
|
|
254
|
+
else if (e.key === "Delete" && byId.get(id)?.closable && onClose) {
|
|
255
|
+
e.preventDefault();
|
|
256
|
+
onClose(id, byId.get(id));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (to == null) return;
|
|
260
|
+
e.preventDefault();
|
|
261
|
+
select(to, { focus: true });
|
|
262
|
+
}
|
|
263
|
+
function onMenu(e) {
|
|
264
|
+
const id = idOf(e.target);
|
|
265
|
+
if (id == null || !onContextMenu) return;
|
|
266
|
+
e.preventDefault();
|
|
267
|
+
onContextMenu(id, e, byId.get(id));
|
|
268
|
+
}
|
|
269
|
+
const onWheel = (e) => wheelStripSideways(strip, e);
|
|
270
|
+
strip.addEventListener("click", onClick);
|
|
271
|
+
strip.addEventListener("auxclick", onAuxClick);
|
|
272
|
+
strip.addEventListener("keydown", onKeyDown);
|
|
273
|
+
strip.addEventListener("contextmenu", onMenu);
|
|
274
|
+
strip.addEventListener("wheel", onWheel, { passive: false });
|
|
275
|
+
const dragReorder = onReorder ? new DragReorder({
|
|
276
|
+
container: strip,
|
|
277
|
+
itemSelector: `.${cls("tab")}`,
|
|
278
|
+
keyAttr: datasetKey,
|
|
279
|
+
axis: "x",
|
|
280
|
+
draggableGuard: (e) => !e.target.closest?.(`.${cls("close")}`),
|
|
281
|
+
// DragReorder answers the `data-*` strings; the buttons, now in their
|
|
282
|
+
// new order, give the caller's ids back unchanged.
|
|
283
|
+
onReorder: () => {
|
|
284
|
+
order = [...strip.querySelectorAll(`.${cls("tab")}`)].filter((el) => idByEl.has(el)).map((el) => idByEl.get(el)).filter((id) => byId.has(id));
|
|
285
|
+
onReorder(order.slice());
|
|
286
|
+
}
|
|
287
|
+
}) : null;
|
|
288
|
+
const api = {
|
|
289
|
+
root,
|
|
290
|
+
/** Bring a tab to the front. False for an id it does not have. */
|
|
291
|
+
select: (id) => select(id),
|
|
292
|
+
/** The tab in front, or null. */
|
|
293
|
+
active: () => current,
|
|
294
|
+
/** Whether a tab with this id is in the strip. */
|
|
295
|
+
has: (id) => byId.has(id),
|
|
296
|
+
/** The ids, in strip order. */
|
|
297
|
+
ids: () => order.slice(),
|
|
298
|
+
/**
|
|
299
|
+
* Replace the items. The tab in front is `activeId` when given and
|
|
300
|
+
* present, else the one in front now if it is still there, else the
|
|
301
|
+
* first. Panes of items that went are destroyed; eager items that
|
|
302
|
+
* came are mounted, in order, before the tab in front is settled.
|
|
303
|
+
* No items left: nothing is in front, heard as `onSelect(null, null)`.
|
|
304
|
+
* Focus on a tab that went moves to the tab in front, unless the
|
|
305
|
+
* update put it somewhere else (a pane that focuses itself on show).
|
|
306
|
+
*/
|
|
307
|
+
update(next = [], activeId = void 0) {
|
|
308
|
+
if (destroyed) return;
|
|
309
|
+
const focused = doc.activeElement;
|
|
310
|
+
const focusedTab = idByEl.has(focused) && strip.contains(focused);
|
|
311
|
+
setItems(next);
|
|
312
|
+
mountEager();
|
|
313
|
+
if (destroyed) return;
|
|
314
|
+
const want = activeId !== void 0 && byId.has(activeId) ? activeId : byId.has(current) ? current : order[0] ?? null;
|
|
315
|
+
if (want !== current) show(want, true);
|
|
316
|
+
else paint();
|
|
317
|
+
if (destroyed) return;
|
|
318
|
+
const fell = doc.activeElement == null || doc.activeElement === doc.body;
|
|
319
|
+
if (focusedTab && !strip.contains(focused) && fell && current != null) {
|
|
320
|
+
tabs.get(current).el.focus();
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
/** `count` on a tab, coloured by `level`; nothing at zero. */
|
|
324
|
+
setBadge(id, count, level = null) {
|
|
325
|
+
const item = byId.get(id);
|
|
326
|
+
if (!item) return;
|
|
327
|
+
item.badge = { count: Number(count) || 0, level };
|
|
328
|
+
const span = tabs.get(id).el.querySelector(`.${cls("badge")}`);
|
|
329
|
+
if (span) drawBadge(span, badgeOf(item));
|
|
330
|
+
},
|
|
331
|
+
/** The dot on a tab: a level, `true` for the neutral one, falsy for none. */
|
|
332
|
+
setIndicator(id, value) {
|
|
333
|
+
const item = byId.get(id);
|
|
334
|
+
if (!item) return;
|
|
335
|
+
item.indicator = value;
|
|
336
|
+
const span = tabs.get(id).el.querySelector(`.${cls("indicator")}`);
|
|
337
|
+
if (span) drawIndicator(span, value);
|
|
338
|
+
},
|
|
339
|
+
/** A mounted pane's instance, or null. */
|
|
340
|
+
instance: (id) => panes.get(id)?.instance ?? null,
|
|
341
|
+
/** Every mounted pane's instance, in mount order. */
|
|
342
|
+
instances: () => [...panes.values()].map((p) => p.instance).filter(Boolean),
|
|
343
|
+
/** Gone for good: panes are destroyed, the bus is let go, the markup removed. */
|
|
344
|
+
destroy() {
|
|
345
|
+
if (destroyed) return;
|
|
346
|
+
destroyed = true;
|
|
347
|
+
try {
|
|
348
|
+
subscription?.dispose?.();
|
|
349
|
+
} catch {
|
|
350
|
+
}
|
|
351
|
+
strip.removeEventListener("click", onClick);
|
|
352
|
+
strip.removeEventListener("auxclick", onAuxClick);
|
|
353
|
+
strip.removeEventListener("keydown", onKeyDown);
|
|
354
|
+
strip.removeEventListener("contextmenu", onMenu);
|
|
355
|
+
strip.removeEventListener("wheel", onWheel);
|
|
356
|
+
dragReorder?.destroy();
|
|
357
|
+
for (const id of [...panes.keys()]) unmount(id);
|
|
358
|
+
root.remove();
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
setItems(items);
|
|
362
|
+
current = byId.has(active) ? active : order[0] ?? null;
|
|
363
|
+
mountEager();
|
|
364
|
+
show(current, false);
|
|
365
|
+
if (eventBus && selectEvent && !destroyed) {
|
|
366
|
+
subscription = eventBus.on?.(selectEvent, (payload) => select(selectFrom(payload))) ?? null;
|
|
367
|
+
}
|
|
368
|
+
return api;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export {
|
|
372
|
+
TAB_LEVELS,
|
|
373
|
+
createTabs
|
|
374
|
+
};
|
|
375
|
+
//# sourceMappingURL=chunk-HYJYYEPK.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/ui/components/tabs.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * \u2550\u2550 ONE TAB STRIP, WITH AN OPTIONAL PANE HOST \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * Three strips grew apart: the window manager's (`../../tiling/tab_strip.js`,\n * internal, over `NotebookTabBar`), the editor's (`NotebookTabBar`, keyed by\n * FILE PATH) and the bottom panel's (`createBottomPanelTabs`, tied to its bus\n * event). This one is keyed by whatever id the caller gives, knows no event\n * name and no file, and the bottom panel is built on it (FlexDesk STORY-0048).\n *\n * const tabs = createTabs(el, {\n * items: [{ id: 'a', label: 'Inputs', icon: 'tune' }, { id: 'b', label: 'Results', badge: 3 }],\n * active: 'a',\n * onSelect: (id, item) => \u2026,\n * mountPane: (item, el, tabs) => ({ onShow() {\u2026}, destroy() {\u2026} }), // omit: strip only\n * });\n * tabs.update(nextItems, 'b');\n * tabs.setBadge('b', 7, 'warning');\n *\n * AN ITEM is `{ id, label, icon?, title?, badge?, indicator?, closable?, dirty?, eager? }`:\n * badge a count (`n`, or `{ count, level }`); none at zero, `99+` above 99\n * indicator a dot: `true`, or a level (`info` | `warning` | `alert`)\n * closable draws a close mark (and `{block}__tab--closable`) and lets Delete\n * close \u2014 both call `onClose(id)`; without an `onClose` there is\n * nothing to close and none is drawn\n * dirty the unsaved dot\n * eager mount this item's pane at once instead of on first selection \u2014\n * at creation, or when an `update` brings the item in\n *\n * PANES are optional. Without `mountPane` this is a strip and nothing else.\n * With it, an item's pane is mounted the FIRST time it is selected \u2014 the tab in\n * front at creation counts \u2014 and never again; `eager` items mount at once, in\n * order, before it, and an eager item that an `update` adds mounts in that\n * `update`, before the tab in front is settled. `mountPane(item, el, tabs)`\n * answers an instance or nothing; the strip calls its `onShow()` each time its\n * tab comes to the front and its `destroy()` when the item goes (an `update`\n * without it, or `destroy`). Panes mount INSIDE `createTabs` before it has\n * answered, so a pane reaches the strip through its third argument, not the\n * variable being assigned.\n *\n * `onSelect(id, item)` hears every change of the tab in front AFTER creation \u2014\n * a click, a key, `select`, the bus, an `update` that had to move it \u2014 but not\n * the tab chosen at creation, which the caller already knows. An `update` that\n * leaves no items empties the front, and that is a change too: it is heard as\n * `onSelect(null, null)`. A click on the\n * tab ALREADY in front changes nothing, so it is not a select; a caller that\n * acts on it anyway (the bottom panel re-shows its pane) passes\n * `onReselect(id, item)`, which hears exactly that click.\n *\n * THE BUS IS OPT-IN. Pass `eventBus` AND `selectEvent` (a name) and that event\n * selects a tab: the id is `selectFrom(payload)`, by default `payload.id`. No\n * event name, no subscription \u2014 whatever bus is passed.\n *\n * KEYS are the ARIA tabs pattern with automatic activation: ArrowLeft/Right move\n * the selection (wrapping), Home and End go to the ends, Delete closes a\n * closable tab. One tab is in the tab order \u2014 the one in front. When an\n * `update` removes the tab that has focus (Delete, then the caller drops the\n * item), focus moves to the tab now in front, so the keyboard keeps its place;\n * focus that the update put somewhere else (a pane focusing itself) stays.\n *\n * OVERFLOW scrolls, never wraps: a vertical wheel moves the strip sideways and a\n * tab that comes to the front is scrolled into it (`../utils/strip_scroll.js`).\n *\n * CLASSES are BEM under `block` (default `twm-tabs`): `{block}` root,\n * `{block}--compact`, `{block}__tabs`, `{block}__tab`, `{block}__tab--on`,\n * `{block}__tab--dirty`, `{block}__tab--closable`, `{block}__icon`, `{block}__label`, `{block}__badge`\n * (`--{level}`), `{block}__indicator` (`--{level}`), `{block}__dirty`,\n * `{block}__close`, `{block}__body`, `{block}-pane`. The bottom panel passes\n * `twm-bp` and gets its existing markup. Tabs and panes carry the item id in\n * `data-{dataKey}` (default `tab-id`), as a string; the strip never reads it\n * back, so every callback and `ids()` hand out the id as given (`1` stays `1`).\n *\n * The strip is never rebuilt: a select toggles classes on the same buttons and\n * an `update` keeps the button of every id it keeps, so a click that lands\n * while a tab is being selected keeps its target.\n */\n\nimport { DragReorder } from './drag_reorder.js';\nimport { revealInStrip, wheelStripSideways } from '../utils/strip_scroll.js';\n\n/** Badge and indicator levels, worst last. Any other value draws the neutral one. */\nexport const TAB_LEVELS = Object.freeze(['info', 'warning', 'alert']);\n\nlet stripCount = 0;\n\n/**\n * @param {HTMLElement} container\n * @param {object} opts\n * @param {Array} opts.items see AN ITEM above\n * @param {string} [opts.active] the tab in front at creation; the first by default\n * @param {Function} [opts.onSelect] `(id, item)`; `(null, null)` when an `update` empties the strip\n * @param {Function} [opts.onReselect] `(id, item)` on a click on the tab already in front\n * @param {Function} [opts.onClose] `(id, item)` \u2014 the caller removes it with `update`\n * @param {Function} [opts.onReorder] `(ids)` after a drag; omit and tabs do not drag\n * @param {Function} [opts.onContextMenu] `(id, event, item)` on right-click\n * @param {Function} [opts.mountPane] `(item, el, tabs)`; omit for a strip only\n * @param {object} [opts.eventBus]\n * @param {string} [opts.selectEvent] the bus event that selects a tab\n * @param {Function} [opts.selectFrom] `(payload) => id`; `payload.id` by default\n * @param {boolean} [opts.compact] the dense variant\n * @param {string} [opts.label] the tablist's accessible name\n * @param {string} [opts.block] the BEM block\n * @param {string} [opts.dataKey] the `data-*` key carrying an item's id\n */\nexport function createTabs(container, {\n items = [], active = null, onSelect = null, onReselect = null, onClose = null, onReorder = null,\n onContextMenu = null, mountPane = null, eventBus = null, selectEvent = null,\n selectFrom = (payload) => payload?.id, compact = false, label = null,\n block = 'twm-tabs', dataKey = 'tab-id',\n} = {}) {\n const doc = container.ownerDocument;\n const uid = `${block}-${++stripCount}`;\n const datasetKey = dataKey.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n const cls = (part) => `${block}__${part}`;\n\n const root = doc.createElement('div');\n root.className = compact ? `${block} ${block}--compact` : block;\n const strip = doc.createElement('div');\n strip.className = cls('tabs');\n strip.setAttribute('role', 'tablist');\n strip.setAttribute('aria-orientation', 'horizontal');\n if (label) strip.setAttribute('aria-label', label);\n root.appendChild(strip);\n let body = null;\n if (mountPane) {\n body = doc.createElement('div');\n body.className = cls('body');\n root.appendChild(body);\n }\n container.appendChild(root);\n\n /** id \u2192 the caller's item, as last given (setBadge/setIndicator write here). */\n let order = [];\n const byId = new Map();\n /** id \u2192 { el } for every tab drawn. */\n const tabs = new Map();\n /** A tab's button \u2192 its id, unchanged: `data-*` holds only a string. */\n const idByEl = new WeakMap();\n /** id \u2192 { el, instance } for every pane mounted. */\n const panes = new Map();\n let current = null;\n let serial = 0;\n let destroyed = false;\n /** The bus subscription, made last; a pane may destroy the strip first. */\n let subscription = null;\n\n // \u2500\u2500 a tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function tabFor(id) {\n let entry = tabs.get(id);\n if (entry) return entry;\n const el = doc.createElement('button');\n el.type = 'button';\n el.className = cls('tab');\n el.dataset[datasetKey] = id;\n el.id = `${uid}-tab-${++serial}`;\n el.setAttribute('role', 'tab');\n el.setAttribute('aria-selected', 'false');\n el.tabIndex = -1;\n idByEl.set(el, id);\n entry = { el };\n tabs.set(id, entry);\n return entry;\n }\n\n function badgeOf(item) {\n const b = item.badge;\n if (b && typeof b === 'object') return { count: Number(b.count) || 0, level: b.level ?? null };\n return { count: Number(b) || 0, level: null };\n }\n\n function drawBadge(span, { count, level }) {\n span.hidden = count <= 0;\n span.textContent = count > 99 ? '99+' : String(Math.max(count, 0));\n span.className = cls('badge') + (TAB_LEVELS.includes(level) ? ` ${cls('badge')}--${level}` : '');\n }\n\n function drawIndicator(span, value) {\n span.hidden = !value;\n span.className = cls('indicator')\n + (TAB_LEVELS.includes(value) ? ` ${cls('indicator')}--${value}` : '');\n }\n\n function draw(id) {\n const item = byId.get(id);\n const { el } = tabFor(id);\n const closable = !!(item.closable && onClose);\n el.classList.toggle(`${cls('tab')}--dirty`, !!item.dirty);\n el.classList.toggle(`${cls('tab')}--closable`, closable);\n if (item.title) el.title = item.title; else el.removeAttribute('title');\n const parts = [];\n if (item.icon) {\n const icon = doc.createElement('span');\n icon.className = `material-symbols-outlined ${cls('icon')}`;\n icon.setAttribute('aria-hidden', 'true');\n icon.textContent = item.icon;\n parts.push(icon);\n }\n const text = doc.createElement('span');\n text.className = cls('label');\n text.textContent = item.label ?? String(id);\n parts.push(text);\n const badge = doc.createElement('span');\n drawBadge(badge, badgeOf(item));\n parts.push(badge);\n const dot = doc.createElement('span');\n dot.setAttribute('aria-hidden', 'true');\n drawIndicator(dot, item.indicator);\n parts.push(dot);\n if (item.dirty) {\n const dirty = doc.createElement('span');\n dirty.className = cls('dirty');\n dirty.setAttribute('aria-label', 'unsaved');\n dirty.textContent = '\u25CF';\n parts.push(dirty);\n }\n if (closable) {\n // A mark, not a button: a button inside the tab's button is not\n // HTML. The keyboard closes with Delete.\n const close = doc.createElement('span');\n close.className = cls('close');\n close.setAttribute('aria-hidden', 'true');\n close.title = 'Close';\n close.textContent = '\u00D7';\n parts.push(close);\n }\n el.replaceChildren(...parts);\n }\n\n // \u2500\u2500 panes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function mount(id) {\n if (destroyed || !mountPane || panes.has(id)) return panes.get(id) ?? null;\n const el = doc.createElement('div');\n el.className = `${block}-pane`;\n el.dataset[datasetKey] = id;\n el.id = `${tabFor(id).el.id}-pane`;\n el.setAttribute('role', 'tabpanel');\n el.setAttribute('aria-labelledby', tabFor(id).el.id);\n el.hidden = id !== current;\n body.appendChild(el);\n tabFor(id).el.setAttribute('aria-controls', el.id);\n const entry = { el, instance: null };\n panes.set(id, entry);\n // ONE PANE THAT THROWS IS ONE EMPTY TAB, not a dead strip: the strip\n // and every other pane go on working.\n let instance = null;\n try {\n instance = mountPane(byId.get(id), el, api) ?? null;\n } catch (err) {\n console.error(`[tabs] pane \"${id}\" failed to mount`, err);\n }\n // The pane let go of its own entry while it mounted (it destroyed the\n // strip, or an update dropped its item): it was never anyone's, so it\n // is destroyed now and never shown.\n if (panes.get(id) !== entry) {\n try { instance?.destroy?.(); } catch (err) {\n console.warn(`[tabs] pane \"${id}\" destroy failed`, err);\n }\n return null;\n }\n entry.instance = instance;\n return entry;\n }\n\n /** Every eager item not mounted yet, in strip order. */\n function mountEager() {\n for (const id of order) if (byId.get(id).eager && !panes.has(id)) mount(id);\n }\n\n function unmount(id) {\n const entry = panes.get(id);\n if (!entry) return;\n panes.delete(id);\n try { entry.instance?.destroy?.(); } catch (err) {\n console.warn(`[tabs] pane \"${id}\" destroy failed`, err);\n }\n entry.el.remove();\n }\n\n // \u2500\u2500 the tab in front \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** Classes, ARIA and pane visibility, for the tab in front. */\n function paint() {\n for (const [key, { el }] of tabs) {\n const on = key === current;\n el.classList.toggle(`${cls('tab')}--on`, on);\n el.setAttribute('aria-selected', String(on));\n el.tabIndex = on ? 0 : -1;\n }\n for (const [key, entry] of panes) entry.el.hidden = key !== current;\n }\n\n /** Make `id` the tab in front. `notify` is false only at creation. */\n function show(id, notify) {\n current = id;\n paint();\n if (id != null) {\n mount(id)?.instance?.onShow?.();\n if (destroyed) return; // a pane destroyed the strip as it mounted\n if (tabs.has(id)) revealInStrip(strip, tabs.get(id).el);\n }\n if (notify) onSelect?.(id, id == null ? null : byId.get(id));\n }\n\n function select(id, { focus = false } = {}) {\n if (destroyed || !byId.has(id)) return false;\n if (id !== current) show(id, true);\n if (focus && !destroyed) tabs.get(id)?.el.focus();\n return true;\n }\n\n // \u2500\u2500 items \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function setItems(next) {\n const seen = new Set();\n order = [];\n byId.clear();\n for (const item of next) {\n if (item?.id == null || seen.has(item.id)) continue;\n seen.add(item.id);\n order.push(item.id);\n byId.set(item.id, { ...item });\n }\n for (const id of [...tabs.keys()]) {\n if (byId.has(id)) continue;\n tabs.get(id).el.remove();\n tabs.delete(id);\n unmount(id);\n }\n for (const id of order) {\n draw(id);\n strip.appendChild(tabs.get(id).el); // moves a kept one into its place\n }\n dragReorder?.attach();\n }\n\n // \u2500\u2500 events \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const idOf = (target) => {\n const el = target?.closest?.(`.${cls('tab')}`);\n return el && strip.contains(el) && idByEl.has(el) ? idByEl.get(el) : null;\n };\n\n function onClick(e) {\n const id = idOf(e.target);\n if (id == null) return;\n if (e.target.closest(`.${cls('close')}`)) { onClose?.(id, byId.get(id)); return; }\n if (id === current && !destroyed) { onReselect?.(id, byId.get(id)); return; }\n select(id);\n }\n\n function onAuxClick(e) {\n const id = idOf(e.target);\n if (e.button !== 1 || id == null || !byId.get(id)?.closable || !onClose) return;\n e.preventDefault();\n onClose(id, byId.get(id));\n }\n\n function onKeyDown(e) {\n const id = idOf(e.target);\n if (id == null || e.altKey || e.ctrlKey || e.metaKey) return;\n const at = order.indexOf(id);\n let to = null;\n if (e.key === 'ArrowRight') to = order[(at + 1) % order.length];\n else if (e.key === 'ArrowLeft') to = order[(at - 1 + order.length) % order.length];\n else if (e.key === 'Home') to = order[0];\n else if (e.key === 'End') to = order[order.length - 1];\n else if (e.key === 'Delete' && byId.get(id)?.closable && onClose) {\n e.preventDefault();\n onClose(id, byId.get(id));\n return;\n }\n if (to == null) return;\n e.preventDefault();\n select(to, { focus: true });\n }\n\n function onMenu(e) {\n const id = idOf(e.target);\n if (id == null || !onContextMenu) return;\n e.preventDefault();\n onContextMenu(id, e, byId.get(id));\n }\n\n const onWheel = (e) => wheelStripSideways(strip, e);\n\n strip.addEventListener('click', onClick);\n strip.addEventListener('auxclick', onAuxClick);\n strip.addEventListener('keydown', onKeyDown);\n strip.addEventListener('contextmenu', onMenu);\n strip.addEventListener('wheel', onWheel, { passive: false });\n\n const dragReorder = onReorder ? new DragReorder({\n container: strip,\n itemSelector: `.${cls('tab')}`,\n keyAttr: datasetKey,\n axis: 'x',\n draggableGuard: (e) => !e.target.closest?.(`.${cls('close')}`),\n // DragReorder answers the `data-*` strings; the buttons, now in their\n // new order, give the caller's ids back unchanged.\n onReorder: () => {\n order = [...strip.querySelectorAll(`.${cls('tab')}`)]\n .filter((el) => idByEl.has(el)).map((el) => idByEl.get(el))\n .filter((id) => byId.has(id));\n onReorder(order.slice());\n },\n }) : null;\n\n // \u2500\u2500 the api \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const api = {\n root,\n /** Bring a tab to the front. False for an id it does not have. */\n select: (id) => select(id),\n /** The tab in front, or null. */\n active: () => current,\n /** Whether a tab with this id is in the strip. */\n has: (id) => byId.has(id),\n /** The ids, in strip order. */\n ids: () => order.slice(),\n /**\n * Replace the items. The tab in front is `activeId` when given and\n * present, else the one in front now if it is still there, else the\n * first. Panes of items that went are destroyed; eager items that\n * came are mounted, in order, before the tab in front is settled.\n * No items left: nothing is in front, heard as `onSelect(null, null)`.\n * Focus on a tab that went moves to the tab in front, unless the\n * update put it somewhere else (a pane that focuses itself on show).\n */\n update(next = [], activeId = undefined) {\n if (destroyed) return;\n const focused = doc.activeElement;\n const focusedTab = idByEl.has(focused) && strip.contains(focused);\n setItems(next);\n mountEager();\n if (destroyed) return;\n const want = activeId !== undefined && byId.has(activeId) ? activeId\n : byId.has(current) ? current\n : order[0] ?? null;\n if (want !== current) show(want, true);\n else paint(); // a new button is drawn off; the kept ones keep their state\n if (destroyed) return;\n // The focused tab went with its item and focus fell to <body>:\n // it goes to the tab in front. Focus that landed anywhere else stays.\n const fell = doc.activeElement == null || doc.activeElement === doc.body;\n if (focusedTab && !strip.contains(focused) && fell && current != null) {\n tabs.get(current).el.focus();\n }\n },\n /** `count` on a tab, coloured by `level`; nothing at zero. */\n setBadge(id, count, level = null) {\n const item = byId.get(id);\n if (!item) return;\n item.badge = { count: Number(count) || 0, level };\n const span = tabs.get(id).el.querySelector(`.${cls('badge')}`);\n if (span) drawBadge(span, badgeOf(item));\n },\n /** The dot on a tab: a level, `true` for the neutral one, falsy for none. */\n setIndicator(id, value) {\n const item = byId.get(id);\n if (!item) return;\n item.indicator = value;\n const span = tabs.get(id).el.querySelector(`.${cls('indicator')}`);\n if (span) drawIndicator(span, value);\n },\n /** A mounted pane's instance, or null. */\n instance: (id) => panes.get(id)?.instance ?? null,\n /** Every mounted pane's instance, in mount order. */\n instances: () => [...panes.values()].map((p) => p.instance).filter(Boolean),\n /** Gone for good: panes are destroyed, the bus is let go, the markup removed. */\n destroy() {\n if (destroyed) return;\n destroyed = true;\n try { subscription?.dispose?.(); } catch { /* bus gone */ }\n strip.removeEventListener('click', onClick);\n strip.removeEventListener('auxclick', onAuxClick);\n strip.removeEventListener('keydown', onKeyDown);\n strip.removeEventListener('contextmenu', onMenu);\n strip.removeEventListener('wheel', onWheel);\n dragReorder?.destroy();\n for (const id of [...panes.keys()]) unmount(id);\n root.remove();\n },\n };\n\n setItems(items);\n current = byId.has(active) ? active : order[0] ?? null;\n mountEager();\n show(current, false);\n\n // A pane that destroyed the strip while it mounted leaves nothing to subscribe.\n if (eventBus && selectEvent && !destroyed) {\n subscription = eventBus.on?.(selectEvent, (payload) => select(selectFrom(payload))) ?? null;\n }\n\n return api;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|