flexdesk 0.17.0 → 0.17.2
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 +41 -0
- package/README.md +399 -3
- package/canvas.js +18 -0
- package/charts.js +21 -0
- package/core.js +14 -0
- package/css/base.css +23 -1
- package/css/flexdesk.css +61 -1
- package/dist/charts.js +3 -5
- package/dist/charts.js.map +1 -1
- package/dist/{chunk-Q36EPT2R.js → chunk-LWV23YVE.js} +1614 -138
- package/dist/chunk-LWV23YVE.js.map +7 -0
- package/dist/{chunk-MCIXFNVF.js → chunk-RMTRWWEO.js} +2 -2
- package/dist/flexdesk.css +61 -1
- package/dist/flow.js +2 -2
- package/dist/flow.js.map +2 -2
- package/dist/tiles.js +2 -2
- package/dist/widgets.js +186 -55
- package/dist/widgets.js.map +2 -2
- package/dist/wm.js +90 -10
- package/dist/wm.js.map +2 -2
- package/editor.js +20 -0
- package/flow.js +21 -0
- package/host.js +14 -0
- package/package.json +10 -1
- package/src/flow/canvas_editor/editor.js +1 -1
- package/src/tiling/command_palette.js +46 -7
- package/src/tiling/content_registry.js +3 -0
- package/src/tiling/entity_sources.js +10 -0
- package/src/tiling/wm.js +65 -3
- package/src/ui/components/cell_editor_host.js +100 -18
- package/src/ui/components/cell_editors.js +480 -0
- package/src/ui/components/cell_grid.js +121 -8
- package/src/ui/components/cell_paste.js +243 -0
- package/src/ui/components/data_table.js +96 -10
- package/src/ui/components/settings_view.js +192 -51
- package/src/ui/components/staged_edits.js +19 -1
- package/src/ui/components/tsv.js +74 -0
- package/src/ui/notification_center.js +5 -5
- package/tiles.js +27 -0
- package/widgets.js +69 -0
- package/wm.js +28 -0
- package/dist/chunk-Q36EPT2R.js.map +0 -7
- package/dist/chunk-QWQJUDPD.js +0 -610
- package/dist/chunk-QWQJUDPD.js.map +0 -7
- /package/dist/{chunk-MCIXFNVF.js.map → chunk-RMTRWWEO.js.map} +0 -0
package/dist/wm.js
CHANGED
|
@@ -634,8 +634,7 @@ function createCommandPalette({
|
|
|
634
634
|
return;
|
|
635
635
|
}
|
|
636
636
|
list.innerHTML = filtered.slice(0, MAX_ROWS).map((e, i) => `
|
|
637
|
-
|
|
638
|
-
data-idx="${i}">
|
|
637
|
+
${_itemOpen(e, i === active ? " twm-cmdpal__item--active" : "", `data-idx="${i}"`)}
|
|
639
638
|
<span class="material-symbols-outlined twm-cmdpal__icon">${e.icon || "arrow_right"}</span>
|
|
640
639
|
<span class="twm-cmdpal__label">${_esc2(e.label || e.id)}</span>
|
|
641
640
|
<span class="twm-cmdpal__kind">${e.kind}</span>
|
|
@@ -678,7 +677,7 @@ function createCommandPalette({
|
|
|
678
677
|
if (modes.includes("split")) acts.push(`<span${refused}><kbd>Ctrl Enter</kbd> split</span>`);
|
|
679
678
|
if (modes.includes("window")) acts.push(`<span${refused}><kbd>Shift Enter</kbd> window</span>`);
|
|
680
679
|
const side = r.shortcut ? `<kbd class="twm-cmdpal__shortcut">${_esc2(r.shortcut)}</kbd>` : `<span class="twm-cmdpal__kind">${_esc2(kindLabel(r))}</span>`;
|
|
681
|
-
return
|
|
680
|
+
return `${_itemOpen(r, on, `data-idx="${i}" role="option"`)}
|
|
682
681
|
<span class="material-symbols-outlined twm-cmdpal__icon">${_esc2(r.icon || "arrow_right")}</span>
|
|
683
682
|
<span class="twm-cmdpal__main"><span class="twm-cmdpal__label">${_mark(r.label || r.id, r._hits)}</span>${ctx}</span>
|
|
684
683
|
<span class="twm-cmdpal__side">${side}<span class="twm-cmdpal__acts">${acts.join("")}</span></span>
|
|
@@ -747,6 +746,7 @@ function createCommandPalette({
|
|
|
747
746
|
showAll(picked.more);
|
|
748
747
|
return;
|
|
749
748
|
}
|
|
749
|
+
if (_isDisabled(picked)) return;
|
|
750
750
|
if (mode !== "open" && isSingle(picked)) return;
|
|
751
751
|
const pick = _public(picked);
|
|
752
752
|
const how = { mode, scope: scope?.id ?? null };
|
|
@@ -879,6 +879,7 @@ function createCommandPalette({
|
|
|
879
879
|
return;
|
|
880
880
|
}
|
|
881
881
|
let pool = entities;
|
|
882
|
+
if (!filterSet) pool = pool.filter((e) => !e._scopedOnly);
|
|
882
883
|
if (commandsOnly) pool = pool.filter((e) => e.kind === "command");
|
|
883
884
|
else if (filterSet) pool = pool.filter((e) => filterSet.has(_groupOf(e)) || filterSet.has(e.kind));
|
|
884
885
|
else if (q.length < commandMinChars) pool = pool.filter((e) => e.kind !== "command");
|
|
@@ -938,7 +939,7 @@ function createCommandPalette({
|
|
|
938
939
|
}
|
|
939
940
|
const q = input.value.trim().toLowerCase();
|
|
940
941
|
const filterSet = typeFilter ? new Set(typeFilter) : null;
|
|
941
|
-
const pool = filterSet ? entities.filter((e) => filterSet.has(e.kind)) : entities;
|
|
942
|
+
const pool = filterSet ? entities.filter((e) => filterSet.has(e.kind)) : entities.filter((e) => !e._scopedOnly);
|
|
942
943
|
if (!q) {
|
|
943
944
|
filtered = typeFilter ? pool.slice().sort((a, b) => String(a.label || a.id).localeCompare(b.label || b.id)) : [];
|
|
944
945
|
} else {
|
|
@@ -995,8 +996,10 @@ function createCommandPalette({
|
|
|
995
996
|
}
|
|
996
997
|
return [...staticCommands, ...extra];
|
|
997
998
|
};
|
|
999
|
+
const scopedKinds = new Set((catalog?.sources || []).filter((s) => s?.scopedOnly === true).map((s) => s.navKind));
|
|
1000
|
+
const tagScoped = (rows) => scopedKinds.size ? rows.map((r) => scopedKinds.has(r.kind) ? { ...r, _scopedOnly: true } : r) : rows;
|
|
998
1001
|
const withCommands = (rows) => grouped ? [...rows, ...commandRows()] : [...commandRows(), ...rows];
|
|
999
|
-
entities = _decorateIcons(withCommands(cache && cached ? cached : []), taxonomy);
|
|
1002
|
+
entities = _decorateIcons(withCommands(tagScoped(cache && cached ? cached : [])), taxonomy);
|
|
1000
1003
|
if (grouped) {
|
|
1001
1004
|
refilter();
|
|
1002
1005
|
if (typeof empty === "function") {
|
|
@@ -1015,7 +1018,7 @@ function createCommandPalette({
|
|
|
1015
1018
|
const loaded = await catalog.loadAll(api);
|
|
1016
1019
|
if (cache) cached = loaded;
|
|
1017
1020
|
if (overlay !== mine) return;
|
|
1018
|
-
entities = _decorateIcons(withCommands(loaded), taxonomy);
|
|
1021
|
+
entities = _decorateIcons(withCommands(tagScoped(loaded)), taxonomy);
|
|
1019
1022
|
if (grouped ? !scope && (input.value || typeFilter) : input.value) refilter();
|
|
1020
1023
|
} catch (err) {
|
|
1021
1024
|
console.warn("[cmdpal] entity load failed", err);
|
|
@@ -1114,8 +1117,23 @@ function _searched(r) {
|
|
|
1114
1117
|
function _groupOf(r) {
|
|
1115
1118
|
return r.group || r.kind;
|
|
1116
1119
|
}
|
|
1120
|
+
function _isDisabled(r) {
|
|
1121
|
+
if (!r || typeof r.enabled !== "function") return false;
|
|
1122
|
+
try {
|
|
1123
|
+
return !r.enabled();
|
|
1124
|
+
} catch (err) {
|
|
1125
|
+
console.warn("[cmdpal] enabled() threw", err);
|
|
1126
|
+
return true;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
function _itemOpen(r, extra, attrs) {
|
|
1130
|
+
const off = _isDisabled(r);
|
|
1131
|
+
const cls = "twm-cmdpal__item" + extra + (off ? " twm-cmdpal__item--disabled" : "");
|
|
1132
|
+
const refused = !off ? "" : ' aria-disabled="true"' + (r.disabledReason ? ` title="${_esc2(r.disabledReason)}"` : "");
|
|
1133
|
+
return `<div class="${cls}"${refused} ${attrs}>`;
|
|
1134
|
+
}
|
|
1117
1135
|
function _public(r) {
|
|
1118
|
-
const { _hits, _score, ...rest } = r;
|
|
1136
|
+
const { _hits, _score, _scopedOnly, ...rest } = r;
|
|
1119
1137
|
return rest;
|
|
1120
1138
|
}
|
|
1121
1139
|
function _byScore(a, b) {
|
|
@@ -2322,6 +2340,11 @@ function createEntityCatalog({ sources, aliases = {}, aggregate = null } = {}) {
|
|
|
2322
2340
|
`createEntityCatalog: source '${s?.navKind ?? "?"}' needs navKind + list() + shape()`
|
|
2323
2341
|
);
|
|
2324
2342
|
}
|
|
2343
|
+
if (s.scopedOnly != null && typeof s.scopedOnly !== "boolean") {
|
|
2344
|
+
throw new TypeError(
|
|
2345
|
+
`createEntityCatalog: source '${s.navKind}' \`scopedOnly\` must be a boolean when present`
|
|
2346
|
+
);
|
|
2347
|
+
}
|
|
2325
2348
|
}
|
|
2326
2349
|
if (aggregate != null && typeof aggregate !== "function") {
|
|
2327
2350
|
throw new TypeError("createEntityCatalog: `aggregate` must be a function when present");
|
|
@@ -5357,10 +5380,53 @@ var WindowManager = class _WindowManager {
|
|
|
5357
5380
|
return null;
|
|
5358
5381
|
}
|
|
5359
5382
|
/** Reveal the instance of a single kind that is open: answers whether
|
|
5360
|
-
* there was one. Every open path asks this first.
|
|
5383
|
+
* there was one. Every open path asks this first.
|
|
5384
|
+
*
|
|
5385
|
+
* An open path names props too, and revealing alone would drop them: the
|
|
5386
|
+
* instance keeps showing what it was opened with. So a revealed content
|
|
5387
|
+
* that returned a `navigate(props)` hook from its mount is handed the new
|
|
5388
|
+
* props — once per open, the same props twice are two calls — and they
|
|
5389
|
+
* are recorded on its tab, so a page restore or a reload mounts it with
|
|
5390
|
+
* the latest. A content without the hook is revealed as it is: its tab
|
|
5391
|
+
* keeps its props and nothing is called. So is every content when the
|
|
5392
|
+
* open names no props at all — a top-nav button, `openInPrimary(kind)` —
|
|
5393
|
+
* which asks to SEE the instance, not to empty it. */
|
|
5361
5394
|
revealInstance(kind, props = {}) {
|
|
5362
5395
|
const loc = this.findInstance(kind, props);
|
|
5363
|
-
|
|
5396
|
+
if (!loc || !this._revealAt(loc)) return false;
|
|
5397
|
+
if (props && Object.keys(props).length) this._deliverProps(kind, props);
|
|
5398
|
+
return true;
|
|
5399
|
+
}
|
|
5400
|
+
/** Hand a revealed instance the props it was opened with, and record them
|
|
5401
|
+
* on its tab (and the tile's `content` mirror of it, re-baselining the
|
|
5402
|
+
* tile so the write does not rebuild it). Looks
|
|
5403
|
+
* the instance up again: a reveal from a page archive moved it into the
|
|
5404
|
+
* tile's tabs. A throwing hook is a warning, never a crash. */
|
|
5405
|
+
_deliverProps(kind, props) {
|
|
5406
|
+
const loc = this.findInstance(kind, props);
|
|
5407
|
+
if (!loc || loc.where === "archive") return;
|
|
5408
|
+
const scope = loc.where === "window" ? { windowId: loc.windowId } : { leafId: loc.leafId };
|
|
5409
|
+
const content = this._scopeContent(scope);
|
|
5410
|
+
if (typeof content?.navigate !== "function") return;
|
|
5411
|
+
const next = { ...props || {} };
|
|
5412
|
+
if (loc.where === "window") {
|
|
5413
|
+
const rec = this._windowToLeaf.get(loc.windowId);
|
|
5414
|
+
const tab = Array.isArray(rec.tabs) ? rec.tabs[loc.idx] : null;
|
|
5415
|
+
if (tab) tab.props = { ...next };
|
|
5416
|
+
if (rec.original) rec.original = { ...rec.original, props: { ...next } };
|
|
5417
|
+
} else {
|
|
5418
|
+
const leaf = this._tree().get(loc.leafId);
|
|
5419
|
+
const expected = this.renderer?.leafKey?.(loc.leafId) ?? void 0;
|
|
5420
|
+
leaf.tabs[loc.idx].props = { ...next };
|
|
5421
|
+
if (leaf.content?.kind === kind) leaf.content = { ...leaf.content, props: { ...next } };
|
|
5422
|
+
this.renderer?.rebaselineLeaf?.(loc.leafId, expected);
|
|
5423
|
+
}
|
|
5424
|
+
this._persist();
|
|
5425
|
+
try {
|
|
5426
|
+
content.navigate({ ...next });
|
|
5427
|
+
} catch (err) {
|
|
5428
|
+
console.warn("[wm] content navigate threw", err);
|
|
5429
|
+
}
|
|
5364
5430
|
}
|
|
5365
5431
|
/** A leaf's archived pages that can come back — every `pageTabs` entry
|
|
5366
5432
|
* but the CURRENT page's. `swapToPage` restores an archive without
|
|
@@ -8407,8 +8473,22 @@ var WindowManager = class _WindowManager {
|
|
|
8407
8473
|
*
|
|
8408
8474
|
* The lower-level primitives (`openFromContext`,
|
|
8409
8475
|
* `openInTabFromContext`, `openInTabInPrimary`, `openInPrimary`,
|
|
8410
|
-
* `openInWindow`) stay internal; callers prefer `wm.navigate(...)`.
|
|
8476
|
+
* `openInWindow`) stay internal; callers prefer `wm.navigate(...)`.
|
|
8477
|
+
*
|
|
8478
|
+
* Returns `true` once the navigation is routed. A kind the shell's
|
|
8479
|
+
* content registry has no factory for is refused instead: one
|
|
8480
|
+
* `console.warn` naming it, no tile, tab, window or history touched, and
|
|
8481
|
+
* `false` — never a placeholder tile, never a throw. */
|
|
8411
8482
|
navigate(kind, props = {}, opts = {}) {
|
|
8483
|
+
if (!this.content.has(kind)) {
|
|
8484
|
+
console.warn(`[wm] navigate: no content registered for kind "${String(kind)}"`);
|
|
8485
|
+
return false;
|
|
8486
|
+
}
|
|
8487
|
+
this._route(kind, props, opts);
|
|
8488
|
+
return true;
|
|
8489
|
+
}
|
|
8490
|
+
/** The routing behind `navigate`, for a kind known to be registered. */
|
|
8491
|
+
_route(kind, props, opts) {
|
|
8412
8492
|
const { ctx = null, transient = false } = opts;
|
|
8413
8493
|
const background = !!opts.background;
|
|
8414
8494
|
let { dest = "main", newTab = false } = opts;
|