flexdesk 0.17.1 → 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/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
- <div class="twm-cmdpal__item${i === active ? " twm-cmdpal__item--active" : ""}"
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 `<div class="twm-cmdpal__item${on}" data-idx="${i}" role="option">
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
- return loc ? this._revealAt(loc) : false;
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;