@ai-matrx/canvas 0.3.0 → 0.5.0
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 +35 -0
- package/README.md +66 -1
- package/dist/index.cjs +203 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +203 -21
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +972 -286
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +100 -3
- package/dist/react.d.ts +100 -3
- package/dist/react.js +980 -291
- package/dist/react.js.map +1 -1
- package/dist/styles.css +238 -26
- package/dist/{toggleKind-A9v45oSb.d.cts → toggleKind-BD78LnMB.d.cts} +105 -1
- package/dist/{toggleKind-A9v45oSb.d.ts → toggleKind-BD78LnMB.d.ts} +105 -1
- package/dist/tokens.css +3 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, c as CanvasLayoutNode, d as CanvasPaneId, e as CanvasStoreBinding, f as CanvasState, g as CanvasAction, h as CanvasController, i as CanvasItem, j as CanvasExtraWindow, k as
|
|
2
|
-
export {
|
|
1
|
+
import { C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, c as CanvasLayoutNode, d as CanvasPaneId, e as CanvasStoreBinding, f as CanvasState, g as CanvasAction, h as CanvasController, i as CanvasItem, j as CanvasExtraWindow, k as CanvasHistoryEntry, l as CanvasPane, m as canvasWindowOfItem } from './toggleKind-BD78LnMB.cjs';
|
|
2
|
+
export { n as CANVAS_DEFAULT_KEY, o as CANVAS_DEFAULT_WIDTH, p as CANVAS_DESKTOP_LAYOUT_RULES, q as CANVAS_HISTORY_LIMIT, r as CANVAS_LAUNCHER_KIND, s as CANVAS_MAIN_WINDOW, t as CANVAS_MIN_SPLIT_FRACTION, u as CANVAS_MIN_WIDTH, v as CANVAS_NARROW_WIDTH, w as CANVAS_STORAGE_KEY, x as CANVAS_WEB_LAYOUT_RULES, y as CanvasControllerOptions, z as CanvasErrorReport, A as CanvasErrorSink, B as CanvasKeyValueStore, D as CanvasKindVisibility, E as CanvasLayoutRules, F as CanvasNavigateInput, G as CanvasOpenInput, H as CanvasOpenTarget, I as CanvasOrientation, J as CanvasPersistencePort, K as CanvasPreferredTarget, L as CanvasPresentation, M as CanvasPresentationOrientation, N as CanvasRect, O as CanvasSessionAttachReason, P as CanvasSessionDetachReason, Q as CanvasSessionEvent, R as CanvasSessionHooks, S as CanvasSplitId, T as CanvasWindowCloseMode, U as CanvasWindowFrame, V as CanvasWindowPorts, W as ReduxStoreLike, X as ToggleKindInput, Y as bindCanvasToReduxStore, Z as canvasActions, _ as canvasOrientation, $ as canvasPresentation, a0 as canvasReducer, a1 as canvasWindowFrame, a2 as canvasWindowOfPane, a3 as clampDraggedCanvasWidth, a4 as consoleCanvasErrorSink, a5 as createCanvasController, a6 as createCanvasStore, a7 as createInitialCanvasState, a8 as createKeyValueCanvasPersistence, a9 as createLocalStorageCanvasPersistence, aa as defaultCanvasWidth, ab as fitCanvasWidth, ac as foldCanvasWindows, ad as isCanvasAction, ae as listCanvasWindowIds, af as preferredFlowDirection, ag as resolveCanvasLayoutRules, ah as sanitizeCanvasSnapshot, ai as selectCanvasKindVisibility, aj as shouldStackSplit, ak as toPersistableSnapshot, al as toggleKind } from './toggleKind-BD78LnMB.cjs';
|
|
3
3
|
|
|
4
4
|
declare function canvasItemId(kind: string, key: string): CanvasItemId;
|
|
5
5
|
declare function parseCanvasItemId(id: CanvasItemId): {
|
|
@@ -142,5 +142,9 @@ declare function selectCanvasWindows(s: CanvasState): CanvasState["windows"];
|
|
|
142
142
|
declare const selectCanvasExtraWindow: (s: CanvasState, windowId: CanvasWindowId) => CanvasExtraWindow | undefined;
|
|
143
143
|
/** The window an item is in, or null when it is not on the canvas. */
|
|
144
144
|
declare const selectCanvasWindowOfItem: typeof canvasWindowOfItem;
|
|
145
|
+
/** What a tab showed before, oldest first. Stable per state. */
|
|
146
|
+
declare function selectCanvasItemHistory(s: CanvasState, itemId: CanvasItemId): readonly CanvasHistoryEntry[];
|
|
147
|
+
/** Whether a tab offers Back (it navigated in place). */
|
|
148
|
+
declare const selectCanvasCanGoBack: (s: CanvasState, itemId: CanvasItemId) => boolean;
|
|
145
149
|
|
|
146
|
-
export { CANVAS_SHORTCUTS, CanvasAction, type CanvasCommandId, CanvasController, CanvasExtraWindow, CanvasItem, CanvasItemId, CanvasJson, type CanvasKeyInput, CanvasLayoutNode, CanvasPane, CanvasPaneId, type CanvasShortcut, type CanvasShortcutWhen, CanvasState, CanvasStoreBinding, CanvasWindowId, type RemoteCanvasStore, type RemoteCanvasStoreOptions, canvasItemId, canvasShortcutHint, canvasWindowId, canvasWindowOfItem, createRemoteCanvasStore, findNonJson, isCanvasJson, listPaneIds, matchesCanvasAccelerator, normalizeSizes, parseCanvasItemId, runCanvasCommand, selectCanvasActiveItem, selectCanvasExtraWindow, selectCanvasFocusedPaneId, selectCanvasIsFullscreen, selectCanvasIsHydrated, selectCanvasIsOpen, selectCanvasItem, selectCanvasItemCount, selectCanvasLayout, selectCanvasPane, selectCanvasPaneCount, selectCanvasWidth, selectCanvasWindowItemCount, selectCanvasWindowOfItem, selectCanvasWindows, shareStructure };
|
|
150
|
+
export { CANVAS_SHORTCUTS, CanvasAction, type CanvasCommandId, CanvasController, CanvasExtraWindow, CanvasHistoryEntry, CanvasItem, CanvasItemId, CanvasJson, type CanvasKeyInput, CanvasLayoutNode, CanvasPane, CanvasPaneId, type CanvasShortcut, type CanvasShortcutWhen, CanvasState, CanvasStoreBinding, CanvasWindowId, type RemoteCanvasStore, type RemoteCanvasStoreOptions, canvasItemId, canvasShortcutHint, canvasWindowId, canvasWindowOfItem, createRemoteCanvasStore, findNonJson, isCanvasJson, listPaneIds, matchesCanvasAccelerator, normalizeSizes, parseCanvasItemId, runCanvasCommand, selectCanvasActiveItem, selectCanvasCanGoBack, selectCanvasExtraWindow, selectCanvasFocusedPaneId, selectCanvasIsFullscreen, selectCanvasIsHydrated, selectCanvasIsOpen, selectCanvasItem, selectCanvasItemCount, selectCanvasItemHistory, selectCanvasLayout, selectCanvasPane, selectCanvasPaneCount, selectCanvasWidth, selectCanvasWindowItemCount, selectCanvasWindowOfItem, selectCanvasWindows, shareStructure };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, c as CanvasLayoutNode, d as CanvasPaneId, e as CanvasStoreBinding, f as CanvasState, g as CanvasAction, h as CanvasController, i as CanvasItem, j as CanvasExtraWindow, k as
|
|
2
|
-
export {
|
|
1
|
+
import { C as CanvasItemId, a as CanvasWindowId, b as CanvasJson, c as CanvasLayoutNode, d as CanvasPaneId, e as CanvasStoreBinding, f as CanvasState, g as CanvasAction, h as CanvasController, i as CanvasItem, j as CanvasExtraWindow, k as CanvasHistoryEntry, l as CanvasPane, m as canvasWindowOfItem } from './toggleKind-BD78LnMB.js';
|
|
2
|
+
export { n as CANVAS_DEFAULT_KEY, o as CANVAS_DEFAULT_WIDTH, p as CANVAS_DESKTOP_LAYOUT_RULES, q as CANVAS_HISTORY_LIMIT, r as CANVAS_LAUNCHER_KIND, s as CANVAS_MAIN_WINDOW, t as CANVAS_MIN_SPLIT_FRACTION, u as CANVAS_MIN_WIDTH, v as CANVAS_NARROW_WIDTH, w as CANVAS_STORAGE_KEY, x as CANVAS_WEB_LAYOUT_RULES, y as CanvasControllerOptions, z as CanvasErrorReport, A as CanvasErrorSink, B as CanvasKeyValueStore, D as CanvasKindVisibility, E as CanvasLayoutRules, F as CanvasNavigateInput, G as CanvasOpenInput, H as CanvasOpenTarget, I as CanvasOrientation, J as CanvasPersistencePort, K as CanvasPreferredTarget, L as CanvasPresentation, M as CanvasPresentationOrientation, N as CanvasRect, O as CanvasSessionAttachReason, P as CanvasSessionDetachReason, Q as CanvasSessionEvent, R as CanvasSessionHooks, S as CanvasSplitId, T as CanvasWindowCloseMode, U as CanvasWindowFrame, V as CanvasWindowPorts, W as ReduxStoreLike, X as ToggleKindInput, Y as bindCanvasToReduxStore, Z as canvasActions, _ as canvasOrientation, $ as canvasPresentation, a0 as canvasReducer, a1 as canvasWindowFrame, a2 as canvasWindowOfPane, a3 as clampDraggedCanvasWidth, a4 as consoleCanvasErrorSink, a5 as createCanvasController, a6 as createCanvasStore, a7 as createInitialCanvasState, a8 as createKeyValueCanvasPersistence, a9 as createLocalStorageCanvasPersistence, aa as defaultCanvasWidth, ab as fitCanvasWidth, ac as foldCanvasWindows, ad as isCanvasAction, ae as listCanvasWindowIds, af as preferredFlowDirection, ag as resolveCanvasLayoutRules, ah as sanitizeCanvasSnapshot, ai as selectCanvasKindVisibility, aj as shouldStackSplit, ak as toPersistableSnapshot, al as toggleKind } from './toggleKind-BD78LnMB.js';
|
|
3
3
|
|
|
4
4
|
declare function canvasItemId(kind: string, key: string): CanvasItemId;
|
|
5
5
|
declare function parseCanvasItemId(id: CanvasItemId): {
|
|
@@ -142,5 +142,9 @@ declare function selectCanvasWindows(s: CanvasState): CanvasState["windows"];
|
|
|
142
142
|
declare const selectCanvasExtraWindow: (s: CanvasState, windowId: CanvasWindowId) => CanvasExtraWindow | undefined;
|
|
143
143
|
/** The window an item is in, or null when it is not on the canvas. */
|
|
144
144
|
declare const selectCanvasWindowOfItem: typeof canvasWindowOfItem;
|
|
145
|
+
/** What a tab showed before, oldest first. Stable per state. */
|
|
146
|
+
declare function selectCanvasItemHistory(s: CanvasState, itemId: CanvasItemId): readonly CanvasHistoryEntry[];
|
|
147
|
+
/** Whether a tab offers Back (it navigated in place). */
|
|
148
|
+
declare const selectCanvasCanGoBack: (s: CanvasState, itemId: CanvasItemId) => boolean;
|
|
145
149
|
|
|
146
|
-
export { CANVAS_SHORTCUTS, CanvasAction, type CanvasCommandId, CanvasController, CanvasExtraWindow, CanvasItem, CanvasItemId, CanvasJson, type CanvasKeyInput, CanvasLayoutNode, CanvasPane, CanvasPaneId, type CanvasShortcut, type CanvasShortcutWhen, CanvasState, CanvasStoreBinding, CanvasWindowId, type RemoteCanvasStore, type RemoteCanvasStoreOptions, canvasItemId, canvasShortcutHint, canvasWindowId, canvasWindowOfItem, createRemoteCanvasStore, findNonJson, isCanvasJson, listPaneIds, matchesCanvasAccelerator, normalizeSizes, parseCanvasItemId, runCanvasCommand, selectCanvasActiveItem, selectCanvasExtraWindow, selectCanvasFocusedPaneId, selectCanvasIsFullscreen, selectCanvasIsHydrated, selectCanvasIsOpen, selectCanvasItem, selectCanvasItemCount, selectCanvasLayout, selectCanvasPane, selectCanvasPaneCount, selectCanvasWidth, selectCanvasWindowItemCount, selectCanvasWindowOfItem, selectCanvasWindows, shareStructure };
|
|
150
|
+
export { CANVAS_SHORTCUTS, CanvasAction, type CanvasCommandId, CanvasController, CanvasExtraWindow, CanvasHistoryEntry, CanvasItem, CanvasItemId, CanvasJson, type CanvasKeyInput, CanvasLayoutNode, CanvasPane, CanvasPaneId, type CanvasShortcut, type CanvasShortcutWhen, CanvasState, CanvasStoreBinding, CanvasWindowId, type RemoteCanvasStore, type RemoteCanvasStoreOptions, canvasItemId, canvasShortcutHint, canvasWindowId, canvasWindowOfItem, createRemoteCanvasStore, findNonJson, isCanvasJson, listPaneIds, matchesCanvasAccelerator, normalizeSizes, parseCanvasItemId, runCanvasCommand, selectCanvasActiveItem, selectCanvasCanGoBack, selectCanvasExtraWindow, selectCanvasFocusedPaneId, selectCanvasIsFullscreen, selectCanvasIsHydrated, selectCanvasIsOpen, selectCanvasItem, selectCanvasItemCount, selectCanvasItemHistory, selectCanvasLayout, selectCanvasPane, selectCanvasPaneCount, selectCanvasWidth, selectCanvasWindowItemCount, selectCanvasWindowOfItem, selectCanvasWindows, shareStructure };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/core/types.ts
|
|
2
2
|
var CANVAS_MAIN_WINDOW = "main";
|
|
3
|
+
var CANVAS_LAUNCHER_KIND = "canvas.launcher";
|
|
4
|
+
var CANVAS_HISTORY_LIMIT = 50;
|
|
3
5
|
var CANVAS_MIN_WIDTH = 360;
|
|
4
6
|
var CANVAS_DEFAULT_WIDTH = 640;
|
|
5
7
|
var CANVAS_MIN_SPLIT_FRACTION = 0.12;
|
|
@@ -165,6 +167,10 @@ var canvasActions = {
|
|
|
165
167
|
}),
|
|
166
168
|
/** Gives an item a new identity in place (e.g. a draft that was just saved and now has an id). */
|
|
167
169
|
rekey: (itemId, key) => ({ type: `${P}rekey`, payload: { itemId, key } }),
|
|
170
|
+
/** Replaces a tab's content with another item in place, remembering what it showed (Back returns). */
|
|
171
|
+
navigate: (itemId, to) => ({ type: `${P}navigate`, payload: { itemId, to, now: Date.now() } }),
|
|
172
|
+
/** Returns a tab to what it showed before its last navigate. */
|
|
173
|
+
back: (itemId) => ({ type: `${P}back`, payload: { itemId, now: Date.now() } }),
|
|
168
174
|
closeItem: (itemId) => ({ type: `${P}closeItem`, payload: { itemId } }),
|
|
169
175
|
closeOthers: (itemId) => ({ type: `${P}closeOthers`, payload: { itemId } }),
|
|
170
176
|
activate: (itemId) => ({ type: `${P}activate`, payload: { itemId } }),
|
|
@@ -361,6 +367,63 @@ function sendHome(state, itemId, home, activate) {
|
|
|
361
367
|
next = insertInto(next, homeFrame.focusedPaneId, itemId, activate);
|
|
362
368
|
return activate ? withFrame(next, target, { focusedPaneId: homeFrame.focusedPaneId }) : next;
|
|
363
369
|
}
|
|
370
|
+
function newItem(kind, key, title, data, now, history) {
|
|
371
|
+
const id = canvasItemId(kind, key);
|
|
372
|
+
return {
|
|
373
|
+
id,
|
|
374
|
+
kind,
|
|
375
|
+
key,
|
|
376
|
+
title,
|
|
377
|
+
data,
|
|
378
|
+
openedAt: now,
|
|
379
|
+
updatedAt: now,
|
|
380
|
+
instance: `${now.toString(36)}:${id}`,
|
|
381
|
+
...history && history.length > 0 ? { history: history.slice(-CANVAS_HISTORY_LIMIT) } : {}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function historyEntry(item) {
|
|
385
|
+
return { kind: item.kind, key: item.key, title: item.title, data: item.data };
|
|
386
|
+
}
|
|
387
|
+
function replaceInPlace(state, current, next) {
|
|
388
|
+
const pane = paneOf(state, current.id);
|
|
389
|
+
if (!pane) return state;
|
|
390
|
+
const items = { ...state.items, [next.id]: next };
|
|
391
|
+
delete items[current.id];
|
|
392
|
+
const withItems = { ...state, items };
|
|
393
|
+
const replaced = withPane(withItems, {
|
|
394
|
+
...pane,
|
|
395
|
+
itemIds: pane.itemIds.map((id) => id === current.id ? next.id : id),
|
|
396
|
+
activeItemId: pane.activeItemId === current.id ? next.id : pane.activeItemId
|
|
397
|
+
});
|
|
398
|
+
return focus(replaced, pane.id);
|
|
399
|
+
}
|
|
400
|
+
function focusExisting(state, itemId) {
|
|
401
|
+
const pane = paneOf(state, itemId);
|
|
402
|
+
if (!pane) return state;
|
|
403
|
+
const next = focus(withPane(state, { ...pane, activeItemId: itemId }), pane.id);
|
|
404
|
+
const windowId = canvasWindowOfPane(next, pane.id);
|
|
405
|
+
return windowId ? withFrame(next, windowId, { isOpen: true }) : next;
|
|
406
|
+
}
|
|
407
|
+
function sanitizeHistory(raw) {
|
|
408
|
+
if (!Array.isArray(raw)) return [];
|
|
409
|
+
const out = [];
|
|
410
|
+
for (const entry of raw) {
|
|
411
|
+
if (!entry || typeof entry !== "object") continue;
|
|
412
|
+
const e = entry;
|
|
413
|
+
if (typeof e.kind !== "string" || typeof e.key !== "string") continue;
|
|
414
|
+
out.push({ kind: e.kind, key: e.key, title: typeof e.title === "string" ? e.title : null, data: e.data ?? null });
|
|
415
|
+
}
|
|
416
|
+
return out.slice(-CANVAS_HISTORY_LIMIT);
|
|
417
|
+
}
|
|
418
|
+
function sanitizeItem(item) {
|
|
419
|
+
const history = sanitizeHistory(item.history);
|
|
420
|
+
const { history: _history, instance, ...rest } = item;
|
|
421
|
+
return {
|
|
422
|
+
...rest,
|
|
423
|
+
...typeof instance === "string" && instance ? { instance } : {},
|
|
424
|
+
...history.length > 0 ? { history } : {}
|
|
425
|
+
};
|
|
426
|
+
}
|
|
364
427
|
function clampWidth(width) {
|
|
365
428
|
return Number.isFinite(width) ? Math.max(CANVAS_MIN_WIDTH, Math.round(width)) : null;
|
|
366
429
|
}
|
|
@@ -408,7 +471,7 @@ function sanitizeCanvasSnapshot(raw) {
|
|
|
408
471
|
const items = {};
|
|
409
472
|
for (const [id, item] of Object.entries(s.items)) {
|
|
410
473
|
if (item && typeof item.kind === "string" && typeof item.key === "string" && canvasItemId(item.kind, item.key) === id) {
|
|
411
|
-
items[id] = item;
|
|
474
|
+
items[id] = sanitizeItem(item);
|
|
412
475
|
}
|
|
413
476
|
}
|
|
414
477
|
const placed = /* @__PURE__ */ new Set();
|
|
@@ -482,7 +545,7 @@ function canvasReducer(state = createInitialCanvasState(), action) {
|
|
|
482
545
|
next = insertInto(next, frame2.focusedPaneId, itemId, true);
|
|
483
546
|
}
|
|
484
547
|
} else {
|
|
485
|
-
const item =
|
|
548
|
+
const item = newItem(kind, key, title ?? null, data ?? null, now);
|
|
486
549
|
next = ensureWindow({ ...next, items: { ...next.items, [itemId]: item } }, revealIn);
|
|
487
550
|
const frame2 = canvasWindowFrame(next, revealIn) ?? next;
|
|
488
551
|
let paneId = frame2.focusedPaneId;
|
|
@@ -531,6 +594,35 @@ function canvasReducer(state = createInitialCanvasState(), action) {
|
|
|
531
594
|
}
|
|
532
595
|
return { ...state, items, panes };
|
|
533
596
|
}
|
|
597
|
+
case `${P}navigate`: {
|
|
598
|
+
const { itemId, to, now } = action.payload;
|
|
599
|
+
const current = state.items[itemId];
|
|
600
|
+
if (!current || !paneOf(state, itemId)) return state;
|
|
601
|
+
const targetId = canvasItemId(to.kind, to.key);
|
|
602
|
+
if (targetId === itemId) {
|
|
603
|
+
const refresh = { type: `${P}update`, payload: { itemId, data: to.data, title: to.title, now } };
|
|
604
|
+
return canvasReducer(state, refresh);
|
|
605
|
+
}
|
|
606
|
+
if (state.items[targetId]) {
|
|
607
|
+
const focused = focusExisting(state, targetId);
|
|
608
|
+
return current.kind === CANVAS_LAUNCHER_KIND ? canvasReducer(focused, canvasActions.closeItem(itemId)) : focused;
|
|
609
|
+
}
|
|
610
|
+
const history = [...current.history ?? [], historyEntry(current)];
|
|
611
|
+
return replaceInPlace(state, current, newItem(to.kind, to.key, to.title ?? null, to.data ?? null, now, history));
|
|
612
|
+
}
|
|
613
|
+
case `${P}back`: {
|
|
614
|
+
const { itemId, now } = action.payload;
|
|
615
|
+
const current = state.items[itemId];
|
|
616
|
+
const history = current?.history ?? [];
|
|
617
|
+
const entry = history[history.length - 1];
|
|
618
|
+
if (!current || !entry || !paneOf(state, itemId)) return state;
|
|
619
|
+
const targetId = canvasItemId(entry.kind, entry.key);
|
|
620
|
+
if (targetId === itemId) return state;
|
|
621
|
+
if (state.items[targetId]) {
|
|
622
|
+
return focusExisting(canvasReducer(state, canvasActions.closeItem(itemId)), targetId);
|
|
623
|
+
}
|
|
624
|
+
return replaceInPlace(state, current, newItem(entry.kind, entry.key, entry.title, entry.data, now, history.slice(0, -1)));
|
|
625
|
+
}
|
|
534
626
|
case `${P}closeItem`: {
|
|
535
627
|
const { itemId } = action.payload;
|
|
536
628
|
if (!state.items[itemId]) return state;
|
|
@@ -861,7 +953,8 @@ var CANVAS_WEB_LAYOUT_RULES = {
|
|
|
861
953
|
defaultWidth: CANVAS_DEFAULT_WIDTH,
|
|
862
954
|
minWidth: CANVAS_MIN_WIDTH,
|
|
863
955
|
centreMinWidth: 420,
|
|
864
|
-
|
|
956
|
+
// Split down 70/30 like the desktop: what opens below (notifications, a feed) is the smaller pane.
|
|
957
|
+
stackSplit: 0.7,
|
|
865
958
|
sideSplit: 0.5,
|
|
866
959
|
paneMinWidth: 0
|
|
867
960
|
};
|
|
@@ -994,7 +1087,8 @@ function createCanvasController(options) {
|
|
|
994
1087
|
presentationListeners: /* @__PURE__ */ new Set(),
|
|
995
1088
|
views: /* @__PURE__ */ new Map(),
|
|
996
1089
|
started: /* @__PURE__ */ new Map(),
|
|
997
|
-
sessionStop: null
|
|
1090
|
+
sessionStop: null,
|
|
1091
|
+
launcherSeq: 0
|
|
998
1092
|
};
|
|
999
1093
|
return view(shared, canvasWindowId(options.windowId ?? CANVAS_MAIN_WINDOW));
|
|
1000
1094
|
}
|
|
@@ -1009,6 +1103,36 @@ function view(shared, windowId) {
|
|
|
1009
1103
|
for (const listener of [...shared.presentationListeners]) listener();
|
|
1010
1104
|
};
|
|
1011
1105
|
const shareFor = (orientation) => orientation === "vertical" ? rules.stackSplit : rules.sideSplit;
|
|
1106
|
+
const acceptable = (input) => {
|
|
1107
|
+
if (input.kind !== CANVAS_LAUNCHER_KIND && options.isKnownKind && !options.isKnownKind(input.kind)) {
|
|
1108
|
+
onError({ code: "unknown-kind", message: `No canvas kind "${input.kind}" is registered.`, detail: input });
|
|
1109
|
+
return false;
|
|
1110
|
+
}
|
|
1111
|
+
if (input.data !== void 0) {
|
|
1112
|
+
const bad = findNonJson(input.data);
|
|
1113
|
+
if (bad) {
|
|
1114
|
+
onError({
|
|
1115
|
+
code: "non-json-data",
|
|
1116
|
+
message: `Canvas data for "${input.kind}" must be plain JSON; ${bad} is not.`,
|
|
1117
|
+
detail: { kind: input.kind, key: input.key }
|
|
1118
|
+
});
|
|
1119
|
+
return false;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return true;
|
|
1123
|
+
};
|
|
1124
|
+
const preferredTargetFor = (input) => {
|
|
1125
|
+
const preferred = options.preferredTarget?.(input.kind);
|
|
1126
|
+
if (!preferred || preferred === "focused") return "focused";
|
|
1127
|
+
const state = store.getState();
|
|
1128
|
+
if (canvasItemId(input.kind, input.key) in state.items) return "focused";
|
|
1129
|
+
const frame2 = canvasWindowFrame(state, input.windowId ?? windowId);
|
|
1130
|
+
if (!frame2?.isOpen) return "focused";
|
|
1131
|
+
const panes = listPaneIds(frame2.layout);
|
|
1132
|
+
const holding = panes.find((paneId) => state.panes[paneId]?.itemIds.some((id) => state.items[id]?.kind === input.kind));
|
|
1133
|
+
if (holding) return { paneId: holding };
|
|
1134
|
+
return state.panes[frame2.focusedPaneId]?.activeItemId ? preferred : "focused";
|
|
1135
|
+
};
|
|
1012
1136
|
const controller = {
|
|
1013
1137
|
store,
|
|
1014
1138
|
windowId,
|
|
@@ -1016,24 +1140,11 @@ function view(shared, windowId) {
|
|
|
1016
1140
|
forWindow: (id) => view(shared, canvasWindowId(id)),
|
|
1017
1141
|
getState: () => store.getState(),
|
|
1018
1142
|
open(input) {
|
|
1019
|
-
if (
|
|
1020
|
-
|
|
1021
|
-
return null;
|
|
1022
|
-
}
|
|
1023
|
-
if (input.data !== void 0) {
|
|
1024
|
-
const bad = findNonJson(input.data);
|
|
1025
|
-
if (bad) {
|
|
1026
|
-
onError({
|
|
1027
|
-
code: "non-json-data",
|
|
1028
|
-
message: `Canvas data for "${input.kind}" must be plain JSON; ${bad} is not.`,
|
|
1029
|
-
detail: { kind: input.kind, key: input.key }
|
|
1030
|
-
});
|
|
1031
|
-
return null;
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
const target = input.target ?? "focused";
|
|
1143
|
+
if (!acceptable(input)) return null;
|
|
1144
|
+
const target = input.target ?? preferredTargetFor(input);
|
|
1035
1145
|
const splitShare = target === "split-down" ? rules.stackSplit : target === "split-right" ? rules.sideSplit : void 0;
|
|
1036
|
-
const
|
|
1146
|
+
const withTarget = input.target === target ? input : { ...input, target };
|
|
1147
|
+
const resolved = withTarget.windowId || windowId === CANVAS_MAIN_WINDOW ? withTarget : { ...withTarget, windowId };
|
|
1037
1148
|
dispatch(canvasActions.open(resolved, splitShare === void 0 ? void 0 : { splitShare }));
|
|
1038
1149
|
return canvasItemId(input.kind, input.key);
|
|
1039
1150
|
},
|
|
@@ -1049,6 +1160,34 @@ function view(shared, windowId) {
|
|
|
1049
1160
|
dispatch(canvasActions.update(itemId, patch));
|
|
1050
1161
|
return true;
|
|
1051
1162
|
},
|
|
1163
|
+
navigate(itemId, to) {
|
|
1164
|
+
if (!store.getState().items[itemId] || !acceptable(to)) return null;
|
|
1165
|
+
dispatch(canvasActions.navigate(itemId, to));
|
|
1166
|
+
const shown = canvasItemId(to.kind, to.key);
|
|
1167
|
+
return shown in store.getState().items ? shown : null;
|
|
1168
|
+
},
|
|
1169
|
+
back(itemId) {
|
|
1170
|
+
const history = store.getState().items[itemId]?.history ?? [];
|
|
1171
|
+
const entry = history[history.length - 1];
|
|
1172
|
+
if (!entry) return null;
|
|
1173
|
+
dispatch(canvasActions.back(itemId));
|
|
1174
|
+
return canvasItemId(entry.kind, entry.key);
|
|
1175
|
+
},
|
|
1176
|
+
newTab(paneId) {
|
|
1177
|
+
const state = store.getState();
|
|
1178
|
+
const frame2 = canvasWindowFrame(state, windowId);
|
|
1179
|
+
const target = paneId && state.panes[paneId] ? paneId : frame2?.focusedPaneId ?? state.focusedPaneId;
|
|
1180
|
+
const existing = state.panes[target]?.itemIds.find((id) => state.items[id]?.kind === CANVAS_LAUNCHER_KIND);
|
|
1181
|
+
if (existing) {
|
|
1182
|
+
dispatch(canvasActions.activate(existing));
|
|
1183
|
+
dispatch(canvasActions.setOpen(true, canvasWindowOfItem(store.getState(), existing) ?? windowId));
|
|
1184
|
+
return existing;
|
|
1185
|
+
}
|
|
1186
|
+
shared.launcherSeq += 1;
|
|
1187
|
+
const key = `${Date.now().toString(36)}-${shared.launcherSeq}`;
|
|
1188
|
+
dispatch(canvasActions.open({ kind: CANVAS_LAUNCHER_KIND, key, target: { paneId: target }, ...windowId === CANVAS_MAIN_WINDOW ? {} : { windowId } }));
|
|
1189
|
+
return canvasItemId(CANVAS_LAUNCHER_KIND, key);
|
|
1190
|
+
},
|
|
1052
1191
|
rekey(itemId, key) {
|
|
1053
1192
|
const item = store.getState().items[itemId];
|
|
1054
1193
|
if (!item) return null;
|
|
@@ -1312,6 +1451,41 @@ function selectCanvasWindows(s) {
|
|
|
1312
1451
|
}
|
|
1313
1452
|
var selectCanvasExtraWindow = (s, windowId) => s.windows?.[windowId];
|
|
1314
1453
|
var selectCanvasWindowOfItem = canvasWindowOfItem;
|
|
1454
|
+
var NO_HISTORY = Object.freeze([]);
|
|
1455
|
+
function selectCanvasItemHistory(s, itemId) {
|
|
1456
|
+
return s.items[itemId]?.history ?? NO_HISTORY;
|
|
1457
|
+
}
|
|
1458
|
+
var selectCanvasCanGoBack = (s, itemId) => (s.items[itemId]?.history?.length ?? 0) > 0;
|
|
1459
|
+
|
|
1460
|
+
// src/core/presentation.ts
|
|
1461
|
+
var CANVAS_NARROW_WIDTH = 480;
|
|
1462
|
+
var SQUARE_BAND = 1.2;
|
|
1463
|
+
function canvasOrientation(width, height) {
|
|
1464
|
+
if (!(width > 0) || !(height > 0)) return "square";
|
|
1465
|
+
const ratio = width / height;
|
|
1466
|
+
if (ratio >= SQUARE_BAND) return "landscape";
|
|
1467
|
+
if (ratio <= 1 / SQUARE_BAND) return "portrait";
|
|
1468
|
+
return "square";
|
|
1469
|
+
}
|
|
1470
|
+
function canvasPresentation(input) {
|
|
1471
|
+
const width = Math.max(0, Math.round(input.width));
|
|
1472
|
+
const height = Math.max(0, Math.round(input.height));
|
|
1473
|
+
return {
|
|
1474
|
+
host: "canvas",
|
|
1475
|
+
width,
|
|
1476
|
+
height,
|
|
1477
|
+
orientation: canvasOrientation(width, height),
|
|
1478
|
+
isNarrow: width > 0 && width < CANVAS_NARROW_WIDTH,
|
|
1479
|
+
isFullscreen: input.isFullscreen,
|
|
1480
|
+
paneCount: Math.max(1, input.paneCount)
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
function preferredFlowDirection(presentation) {
|
|
1484
|
+
if (!presentation) return "horizontal";
|
|
1485
|
+
if (presentation.orientation === "portrait") return "vertical";
|
|
1486
|
+
if (presentation.orientation === "landscape") return "horizontal";
|
|
1487
|
+
return presentation.isNarrow ? "vertical" : "horizontal";
|
|
1488
|
+
}
|
|
1315
1489
|
|
|
1316
1490
|
// src/core/toggleKind.ts
|
|
1317
1491
|
var CANVAS_DEFAULT_KEY = "default";
|
|
@@ -1354,15 +1528,20 @@ export {
|
|
|
1354
1528
|
CANVAS_DEFAULT_KEY,
|
|
1355
1529
|
CANVAS_DEFAULT_WIDTH,
|
|
1356
1530
|
CANVAS_DESKTOP_LAYOUT_RULES,
|
|
1531
|
+
CANVAS_HISTORY_LIMIT,
|
|
1532
|
+
CANVAS_LAUNCHER_KIND,
|
|
1357
1533
|
CANVAS_MAIN_WINDOW,
|
|
1358
1534
|
CANVAS_MIN_SPLIT_FRACTION,
|
|
1359
1535
|
CANVAS_MIN_WIDTH,
|
|
1536
|
+
CANVAS_NARROW_WIDTH,
|
|
1360
1537
|
CANVAS_SHORTCUTS,
|
|
1361
1538
|
CANVAS_STORAGE_KEY,
|
|
1362
1539
|
CANVAS_WEB_LAYOUT_RULES,
|
|
1363
1540
|
bindCanvasToReduxStore,
|
|
1364
1541
|
canvasActions,
|
|
1365
1542
|
canvasItemId,
|
|
1543
|
+
canvasOrientation,
|
|
1544
|
+
canvasPresentation,
|
|
1366
1545
|
canvasReducer,
|
|
1367
1546
|
canvasShortcutHint,
|
|
1368
1547
|
canvasWindowFrame,
|
|
@@ -1388,10 +1567,12 @@ export {
|
|
|
1388
1567
|
matchesCanvasAccelerator,
|
|
1389
1568
|
normalizeSizes,
|
|
1390
1569
|
parseCanvasItemId,
|
|
1570
|
+
preferredFlowDirection,
|
|
1391
1571
|
resolveCanvasLayoutRules,
|
|
1392
1572
|
runCanvasCommand,
|
|
1393
1573
|
sanitizeCanvasSnapshot,
|
|
1394
1574
|
selectCanvasActiveItem,
|
|
1575
|
+
selectCanvasCanGoBack,
|
|
1395
1576
|
selectCanvasExtraWindow,
|
|
1396
1577
|
selectCanvasFocusedPaneId,
|
|
1397
1578
|
selectCanvasIsFullscreen,
|
|
@@ -1399,6 +1580,7 @@ export {
|
|
|
1399
1580
|
selectCanvasIsOpen,
|
|
1400
1581
|
selectCanvasItem,
|
|
1401
1582
|
selectCanvasItemCount,
|
|
1583
|
+
selectCanvasItemHistory,
|
|
1402
1584
|
selectCanvasKindVisibility,
|
|
1403
1585
|
selectCanvasLayout,
|
|
1404
1586
|
selectCanvasPane,
|