flexdesk 0.13.0 → 0.14.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/dist/wm.js CHANGED
@@ -16,6 +16,150 @@ import {
16
16
  import "./chunk-WVFGV5FT.js";
17
17
  import "./chunk-JYWURG5T.js";
18
18
 
19
+ // src/tiling/bottom_panel_tabs.js
20
+ var BADGE_LEVELS = Object.freeze(["info", "warning", "alert"]);
21
+ function createBottomPanelTabs(container, {
22
+ panes = [],
23
+ remember = null,
24
+ store = null,
25
+ eventBus = null,
26
+ onSelect = null,
27
+ initial = null
28
+ } = {}) {
29
+ const doc = container.ownerDocument;
30
+ const root = doc.createElement("div");
31
+ root.className = "twm-bp";
32
+ const strip = doc.createElement("div");
33
+ strip.className = "twm-bp__tabs";
34
+ strip.setAttribute("role", "tablist");
35
+ const body = doc.createElement("div");
36
+ body.className = "twm-bp__body";
37
+ root.append(strip, body);
38
+ container.appendChild(root);
39
+ const byId = new Map(panes.map((pane) => [pane.id, pane]));
40
+ const tabs = /* @__PURE__ */ new Map();
41
+ const mounted = /* @__PURE__ */ new Map();
42
+ let active = null;
43
+ let chosen = false;
44
+ let destroyed = false;
45
+ for (const pane of panes) {
46
+ const tab = doc.createElement("button");
47
+ tab.type = "button";
48
+ tab.className = "twm-bp__tab";
49
+ tab.dataset.pane = pane.id;
50
+ tab.setAttribute("role", "tab");
51
+ tab.setAttribute("aria-selected", "false");
52
+ const label = doc.createElement("span");
53
+ label.className = "twm-bp__label";
54
+ label.textContent = pane.label;
55
+ const badge = doc.createElement("span");
56
+ badge.className = "twm-bp__badge";
57
+ badge.hidden = true;
58
+ tab.append(label, badge);
59
+ tab.addEventListener("click", () => api.select(pane.id));
60
+ strip.appendChild(tab);
61
+ tabs.set(pane.id, tab);
62
+ }
63
+ function mount(id) {
64
+ if (mounted.has(id)) return mounted.get(id);
65
+ const pane = byId.get(id);
66
+ const el = doc.createElement("div");
67
+ el.className = "twm-bp-pane";
68
+ el.dataset.pane = id;
69
+ el.setAttribute("role", "tabpanel");
70
+ el.hidden = id !== active;
71
+ body.appendChild(el);
72
+ const entry = { el, instance: null };
73
+ mounted.set(id, entry);
74
+ try {
75
+ entry.instance = pane.mount?.(el, store ? store(pane) : null, api) ?? null;
76
+ } catch (err) {
77
+ console.error(`[bottom-panel] pane "${id}" failed to mount`, err);
78
+ }
79
+ return entry;
80
+ }
81
+ function show(id) {
82
+ if (destroyed || !byId.has(id)) return false;
83
+ active = id;
84
+ for (const [key, tab] of tabs) {
85
+ const on = key === id;
86
+ tab.classList.toggle("twm-bp__tab--on", on);
87
+ tab.setAttribute("aria-selected", String(on));
88
+ }
89
+ for (const [key, entry] of mounted) entry.el.hidden = key !== id;
90
+ mount(id).instance?.onShow?.();
91
+ onSelect?.(id, byId.get(id));
92
+ return true;
93
+ }
94
+ const api = {
95
+ root,
96
+ /** Bring a tab to the front, and remember it. */
97
+ select(id) {
98
+ if (!show(id)) return;
99
+ chosen = true;
100
+ try {
101
+ remember?.write?.(id);
102
+ } catch {
103
+ }
104
+ },
105
+ /** The tab in front, or null. */
106
+ active: () => active,
107
+ /** `count` on a tab, coloured by `level`; nothing at zero. */
108
+ setBadge(id, count, level = null) {
109
+ const badge = tabs.get(id)?.querySelector(".twm-bp__badge");
110
+ if (!badge) return;
111
+ const n = Number(count) || 0;
112
+ badge.hidden = n <= 0;
113
+ badge.textContent = n > 99 ? "99+" : String(Math.max(n, 0));
114
+ badge.className = "twm-bp__badge" + (BADGE_LEVELS.includes(level) ? ` twm-bp__badge--${level}` : "");
115
+ },
116
+ /** A mounted pane's live instance, or null — how one tab hands work to
117
+ * another. `select` it first, which mounts it. */
118
+ instance: (id) => mounted.get(id)?.instance ?? null,
119
+ /** The panel is on screen again (its tile re-mounted): tell the pane in front. */
120
+ reshow() {
121
+ if (active) mounted.get(active)?.instance?.onShow?.();
122
+ },
123
+ /** Before the panel is torn down: every mounted pane saves. */
124
+ async persist() {
125
+ for (const entry of mounted.values()) await entry.instance?.persist?.();
126
+ },
127
+ /** Gone for good: panes save, then are destroyed; the bus is let go. */
128
+ async destroy() {
129
+ if (destroyed) return;
130
+ await api.persist();
131
+ destroyed = true;
132
+ try {
133
+ subscription?.dispose?.();
134
+ } catch {
135
+ }
136
+ for (const entry of mounted.values()) {
137
+ try {
138
+ entry.instance?.destroy?.();
139
+ } catch (err) {
140
+ console.warn("[bottom-panel] pane destroy failed", err);
141
+ }
142
+ }
143
+ mounted.clear();
144
+ root.remove();
145
+ }
146
+ };
147
+ for (const pane of panes) if (pane.eager) mount(pane.id);
148
+ const subscription = eventBus?.on?.(
149
+ "bottompanel:show",
150
+ (payload) => api.select(payload?.tab ?? panes[0]?.id)
151
+ ) ?? null;
152
+ show(byId.has(initial) ? initial : panes[0]?.id);
153
+ if (remember?.read) {
154
+ Promise.resolve().then(() => remember.read()).then((saved) => {
155
+ if (chosen || destroyed) return;
156
+ if (byId.has(saved)) show(saved);
157
+ }).catch(() => {
158
+ });
159
+ }
160
+ return api;
161
+ }
162
+
19
163
  // src/tiling/command_palette.js
20
164
  var ROOT_ID = "twm-cmdpal";
21
165
  var STATIC_COMMANDS = [
@@ -8732,6 +8876,7 @@ function _tileContextMenu(wm, leafId, x, y) {
8732
8876
  });
8733
8877
  }
8734
8878
  export {
8879
+ BADGE_LEVELS,
8735
8880
  DesktopManager,
8736
8881
  PLACEHOLDER_KIND,
8737
8882
  PanelKeyRouter,
@@ -8751,6 +8896,7 @@ export {
8751
8896
  attachLandingShell,
8752
8897
  attachLandingTableBehavior,
8753
8898
  clampZoom,
8899
+ createBottomPanelTabs,
8754
8900
  createCommandPalette,
8755
8901
  createContentRegistry,
8756
8902
  createEntityCatalog,