@tutti-os/workbench-surface 0.0.254 → 0.0.256

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { WorkbenchFrame as WorkbenchFrame$1, WorkbenchSnapshotDisplayModeV1, WorkbenchSnapshot, WorkbenchSnapshotNode, WorkbenchSnapshotLayoutBasisV1 } from '@tutti-os/workbench-snapshot';
1
+ import { WorkbenchFrame as WorkbenchFrame$1, WorkbenchSnapshotDisplayModeV1, WorkbenchSnapshotLockedLayoutV1, WorkbenchSnapshotLayoutPresetV1, WorkbenchSnapshot, WorkbenchSnapshotNode, WorkbenchSnapshotLayoutBasisV1 } from '@tutti-os/workbench-snapshot';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import { HTMLAttributes, ReactNode, CSSProperties } from 'react';
4
4
  import { I18nRuntime } from '@tutti-os/ui-i18n-runtime';
@@ -19,13 +19,7 @@ interface WorkbenchSafeArea {
19
19
  type WorkbenchDisplayMode = WorkbenchSnapshotDisplayModeV1;
20
20
  type WorkbenchSnapTarget = "left" | "right" | "top" | "bottom" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | null;
21
21
  type WorkbenchQuickLayoutTarget = "left" | "right" | "top" | "bottom" | "center" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
22
- type WorkbenchLayoutPreset = {
23
- kind: "balanced";
24
- } | {
25
- kind: "row";
26
- } | {
27
- kind: "column";
28
- };
22
+ type WorkbenchLayoutPreset = WorkbenchSnapshotLayoutPresetV1;
29
23
  /**
30
24
  * A layout preset that stays "locked" onto a set of nodes: whenever the surface
31
25
  * is resized the layout is re-applied to these nodes so they keep scaling
@@ -33,16 +27,7 @@ type WorkbenchLayoutPreset = {
33
27
  * locked node moves the shared grid dividers; the lock is only released
34
28
  * explicitly (titlebar button) or by programmatic moves.
35
29
  */
36
- interface WorkbenchLockedLayout {
37
- preset: WorkbenchLayoutPreset;
38
- nodeIDs: string[];
39
- /**
40
- * Custom slot geometry created when the user resizes a locked window,
41
- * normalized (0..1) against the safe layout rect. When present it takes
42
- * precedence over the preset frames; when absent the slots derive from the
43
- * preset.
44
- */
45
- normalizedFrames?: Record<string, WorkbenchFrame>;
30
+ interface WorkbenchLockedLayout extends WorkbenchSnapshotLockedLayoutV1 {
46
31
  }
47
32
  interface WorkbenchNode<TData = unknown> {
48
33
  id: string;
@@ -714,6 +699,11 @@ interface WorkbenchHostNodeBodyContext<TExternalNodeState = unknown, TExternalWo
714
699
  * False while minimized, Genie-hidden, or inside Mission Control.
715
700
  */
716
701
  isVisible: boolean;
702
+ /**
703
+ * True when a non-normal Workbench presentation currently paints this node.
704
+ * Omitted by direct hosts that do not use a Workbench presentation.
705
+ */
706
+ isPresentationVisible?: boolean;
717
707
  /** Current host presentation mode; null for the normal window layout. */
718
708
  presentationMode?: WorkbenchSurfacePresentation["mode"] | null;
719
709
  node: WorkbenchNode<WorkbenchHostNodeData>;
@@ -927,8 +917,8 @@ interface CreateWorkbenchSnapshotFromStateOptions {
927
917
  }
928
918
  declare function createWorkbenchNode<TData = unknown>(input: CreateWorkbenchNodeInput<TData>): WorkbenchNode<TData>;
929
919
  declare function createWorkbenchNodeFromSnapshot<TData = unknown>(snapshotNode: WorkbenchSnapshotNode): WorkbenchNode<TData>;
930
- declare function createWorkbenchStateFromSnapshot<TData = unknown>(snapshot: WorkbenchSnapshot): Pick<WorkbenchState<TData>, "nodeStack" | "nodes">;
931
- declare function createWorkbenchSnapshotFromState<TData = unknown>(state: Pick<WorkbenchState<TData>, "nodeStack" | "nodes"> & Partial<Pick<WorkbenchState<TData>, "layoutConstraints" | "surfaceSize">>, options?: CreateWorkbenchSnapshotFromStateOptions): WorkbenchSnapshot;
920
+ declare function createWorkbenchStateFromSnapshot<TData = unknown>(snapshot: WorkbenchSnapshot): Pick<WorkbenchState<TData>, "lockedLayout" | "nodeStack" | "nodes">;
921
+ declare function createWorkbenchSnapshotFromState<TData = unknown>(state: Pick<WorkbenchState<TData>, "nodeStack" | "nodes"> & Partial<Pick<WorkbenchState<TData>, "layoutConstraints" | "lockedLayout" | "surfaceSize">>, options?: CreateWorkbenchSnapshotFromStateOptions): WorkbenchSnapshot;
932
922
  declare function createWorkbenchSnapshotLayoutBasis(state: Partial<Pick<WorkbenchState, "layoutConstraints" | "surfaceSize">>): WorkbenchSnapshotLayoutBasisV1 | undefined;
933
923
 
934
924
  interface WorkbenchHostNodeIdentityInput {
package/dist/index.js CHANGED
@@ -6773,7 +6773,8 @@ function createWorkbenchStateFromSnapshot(snapshot) {
6773
6773
  );
6774
6774
  return {
6775
6775
  nodes,
6776
- nodeStack: normalized.nodeStack ?? nodes.map((node) => node.id)
6776
+ nodeStack: normalized.nodeStack ?? nodes.map((node) => node.id),
6777
+ lockedLayout: normalized.lockedLayout ?? null
6777
6778
  };
6778
6779
  }
6779
6780
  function createWorkbenchSnapshotFromState(state, options = {}) {
@@ -6795,6 +6796,7 @@ function createWorkbenchSnapshotFromState(state, options = {}) {
6795
6796
  spaces: options.spaces,
6796
6797
  activeSpaceId: options.activeSpaceId,
6797
6798
  layoutBasis: createWorkbenchSnapshotLayoutBasis(state),
6799
+ lockedLayout: state.lockedLayout ?? void 0,
6798
6800
  metadata: options.metadata
6799
6801
  });
6800
6802
  }
@@ -7218,22 +7220,24 @@ function createProjectedNodeID(typeId, instanceId) {
7218
7220
  return createWorkbenchHostProjectedNodeId({ instanceId, typeId });
7219
7221
  }
7220
7222
  function persistedWorkbenchState(state, nodeDefinitionByType) {
7223
+ const nodes = state.nodes.filter((node) => {
7224
+ return nodeDefinitionByType.get(node.data.typeId)?.window?.persists !== false;
7225
+ }).map((node) => ({
7226
+ ...node,
7227
+ data: {
7228
+ dockEntryId: node.data.dockEntryId ?? null,
7229
+ ...node.data.snapshotNodeState === void 0 ? {} : { snapshotNodeState: node.data.snapshotNodeState },
7230
+ instanceId: node.data.instanceId,
7231
+ instanceKey: node.data.instanceKey ?? null,
7232
+ ...node.data.isProjected === true ? { isProjected: true } : {},
7233
+ typeId: node.data.typeId
7234
+ }
7235
+ }));
7221
7236
  return {
7222
7237
  layoutConstraints: state.layoutConstraints,
7238
+ lockedLayout: restrictLockedLayoutToNodes(state.lockedLayout, nodes),
7223
7239
  nodeStack: state.nodeStack,
7224
- nodes: state.nodes.filter((node) => {
7225
- return nodeDefinitionByType.get(node.data.typeId)?.window?.persists !== false;
7226
- }).map((node) => ({
7227
- ...node,
7228
- data: {
7229
- dockEntryId: node.data.dockEntryId ?? null,
7230
- ...node.data.snapshotNodeState === void 0 ? {} : { snapshotNodeState: node.data.snapshotNodeState },
7231
- instanceId: node.data.instanceId,
7232
- instanceKey: node.data.instanceKey ?? null,
7233
- ...node.data.isProjected === true ? { isProjected: true } : {},
7234
- typeId: node.data.typeId
7235
- }
7236
- })),
7240
+ nodes,
7237
7241
  surfaceSize: state.surfaceSize
7238
7242
  };
7239
7243
  }
@@ -7288,7 +7292,7 @@ function stateFromSnapshotOrDefinitions(snapshot, nodeDefinitions, projectedNode
7288
7292
  nodeStack.push(node.id);
7289
7293
  }
7290
7294
  }
7291
- return mergeProjectedNodesIntoState(
7295
+ const restoredState = mergeProjectedNodesIntoState(
7292
7296
  {
7293
7297
  nodeStack,
7294
7298
  nodes
@@ -7299,6 +7303,36 @@ function stateFromSnapshotOrDefinitions(snapshot, nodeDefinitions, projectedNode
7299
7303
  snapshot
7300
7304
  }
7301
7305
  );
7306
+ return {
7307
+ ...restoredState,
7308
+ lockedLayout: restrictLockedLayoutToNodes(
7309
+ snapshotState.lockedLayout,
7310
+ restoredState.nodes ?? []
7311
+ )
7312
+ };
7313
+ }
7314
+ function restrictLockedLayoutToNodes(lockedLayout, nodes) {
7315
+ if (!lockedLayout) {
7316
+ return null;
7317
+ }
7318
+ const knownNodeIDs = new Set(nodes.map((node) => node.id));
7319
+ const nodeIDs = lockedLayout.nodeIDs.filter(
7320
+ (nodeID) => knownNodeIDs.has(nodeID)
7321
+ );
7322
+ if (nodeIDs.length < 2) {
7323
+ return null;
7324
+ }
7325
+ if (!lockedLayout.normalizedFrames) {
7326
+ return { preset: { ...lockedLayout.preset }, nodeIDs };
7327
+ }
7328
+ const normalizedFrames = Object.fromEntries(
7329
+ nodeIDs.map((nodeID) => [nodeID, lockedLayout.normalizedFrames[nodeID]])
7330
+ );
7331
+ return {
7332
+ preset: { ...lockedLayout.preset },
7333
+ nodeIDs,
7334
+ normalizedFrames
7335
+ };
7302
7336
  }
7303
7337
  function restoredSnapshotNodesByID(snapshot, nodeDefinitions) {
7304
7338
  if (!snapshot) {
@@ -7784,6 +7818,7 @@ function sanitizeWorkbenchHostSnapshot(snapshot) {
7784
7818
  spaces: normalized.spaces?.map(sanitizeSpace),
7785
7819
  activeSpaceId: normalized.activeSpaceId,
7786
7820
  layoutBasis: normalized.layoutBasis,
7821
+ lockedLayout: normalized.lockedLayout,
7787
7822
  metadata: sanitizeMetadata(normalized.metadata)
7788
7823
  });
7789
7824
  }
@@ -14592,7 +14627,7 @@ function WorkbenchHostNodeBodyRenderer(input) {
14592
14627
  function areWorkbenchHostNodeBodyRendererPropsEqual(previous, next) {
14593
14628
  const previousContext = previous.context;
14594
14629
  const nextContext = next.context;
14595
- if (previous.definition !== next.definition || previousContext.activation !== nextContext.activation || previousContext.displayMode !== nextContext.displayMode || previousContext.externalNodeState !== nextContext.externalNodeState || previousContext.externalWorkspaceState !== nextContext.externalWorkspaceState || previousContext.host !== nextContext.host || previousContext.instanceId !== nextContext.instanceId || previousContext.instanceKey !== nextContext.instanceKey || previousContext.isDragging !== nextContext.isDragging || previousContext.isFocused !== nextContext.isFocused || previousContext.isResizing !== nextContext.isResizing || previousContext.isVisible !== nextContext.isVisible || previousContext.presentationMode !== nextContext.presentationMode || !areWorkbenchOptionalSizesEqual(
14630
+ if (previous.definition !== next.definition || previousContext.activation !== nextContext.activation || previousContext.displayMode !== nextContext.displayMode || previousContext.externalNodeState !== nextContext.externalNodeState || previousContext.externalWorkspaceState !== nextContext.externalWorkspaceState || previousContext.host !== nextContext.host || previousContext.instanceId !== nextContext.instanceId || previousContext.instanceKey !== nextContext.instanceKey || previousContext.isDragging !== nextContext.isDragging || previousContext.isFocused !== nextContext.isFocused || previousContext.isResizing !== nextContext.isResizing || previousContext.isVisible !== nextContext.isVisible || previousContext.isPresentationVisible !== nextContext.isPresentationVisible || previousContext.presentationMode !== nextContext.presentationMode || !areWorkbenchOptionalSizesEqual(
14596
14631
  previousContext.previewViewport,
14597
14632
  nextContext.previewViewport
14598
14633
  )) {
@@ -14686,6 +14721,7 @@ function createWorkbenchHostNodeBodyContext({
14686
14721
  isFocused: selectFocusedWorkbenchNode(host.getSnapshot())?.id === context.node.id,
14687
14722
  isResizing: context.isResizing,
14688
14723
  isVisible,
14724
+ isPresentationVisible: context.layout.presentation?.mode === "mission-control" && context.layout.presentation.visibleNodeIds.has(context.node.id),
14689
14725
  presentationMode: context.layout.presentation?.mode ?? null,
14690
14726
  node: context.node,
14691
14727
  setNodeRuntimeState(state) {
@@ -14853,10 +14889,26 @@ function useWorkbenchHostSurfaceRenderers(input) {
14853
14889
  ]
14854
14890
  );
14855
14891
  const captureNodePreviewImage = useCallback14(
14856
- async (node) => await captureNodeDefinitionPreviewImage(node) ?? await Promise.resolve(
14857
- input.captureNodePreviewImage?.(node) ?? null
14858
- ).catch(() => null),
14859
- [captureNodeDefinitionPreviewImage, input.captureNodePreviewImage]
14892
+ async (node) => {
14893
+ const definitionPreviewImageUrl = await captureNodeDefinitionPreviewImage(node);
14894
+ if (definitionPreviewImageUrl !== null) {
14895
+ return definitionPreviewImageUrl;
14896
+ }
14897
+ if (input.captureNodePreviewImage) {
14898
+ return await Promise.resolve(input.captureNodePreviewImage(node)).catch(
14899
+ () => null
14900
+ );
14901
+ }
14902
+ const previewImages = await Promise.resolve(
14903
+ input.captureNodePreviewImages?.(node) ?? null
14904
+ ).catch(() => null);
14905
+ return previewImages?.dockPreviewImageUrl ?? null;
14906
+ },
14907
+ [
14908
+ captureNodeDefinitionPreviewImage,
14909
+ input.captureNodePreviewImage,
14910
+ input.captureNodePreviewImages
14911
+ ]
14860
14912
  );
14861
14913
  const captureNodePreviewImages = useCallback14(
14862
14914
  async (node) => {