nudge-ui 0.2.2 → 0.2.3
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/README.md +164 -46
- package/dist/client.mjs +252 -61
- package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
- package/dist/css/value-semantics/colorSemantics.js +17 -0
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
- package/dist/hosts/astro/clientTransport.js +38 -32
- package/dist/hosts/astro/integration.js +5 -1
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +5 -1
- package/dist/hosts/static/manifest.js +1 -1
- package/dist/hosts/static/server.js +3 -0
- package/dist/hosts/vite/vite.d.ts +3 -0
- package/dist/hosts/vite/vite.js +24 -4
- package/dist/inspector/agent/McpConnectionDialog.js +13 -19
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +2 -0
- package/dist/inspector/agent/client.js +29 -1
- package/dist/inspector/agent/connectionStatus.js +1 -1
- package/dist/inspector/agent/httpTransport.js +9 -2
- package/dist/inspector/agent/protocol.d.ts +6 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +11 -1
- package/dist/inspector/agent/verification.js +53 -25
- package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
- package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
- package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
- package/dist/inspector/canvas/CanvasCard.js +133 -38
- package/dist/inspector/canvas/CanvasElementOverlay.js +152 -16
- package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
- package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
- package/dist/inspector/canvas/CanvasToolbar.js +8 -4
- package/dist/inspector/canvas/CanvasWorkspace.js +225 -57
- package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
- package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
- package/dist/inspector/canvas/agentPresentation.js +64 -52
- package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
- package/dist/inspector/canvas/canvasGestures.js +1 -1
- package/dist/inspector/canvas/canvasStore.d.ts +46 -82
- package/dist/inspector/canvas/canvasStore.js +251 -284
- package/dist/inspector/canvas/frameContent.d.ts +21 -0
- package/dist/inspector/canvas/frameContent.js +44 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +21 -4
- package/dist/inspector/canvas/frameProtocol.js +3 -3
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +32 -4
- package/dist/inspector/canvas/rendererElementSelector.js +47 -6
- package/dist/inspector/canvas/rendererStylesheet.js +2 -2
- package/dist/inspector/canvas/resizeHandleScale.js +1 -1
- package/dist/inspector/canvas/sessionStore.d.ts +11 -26
- package/dist/inspector/canvas/sessionStore.js +43 -183
- package/dist/inspector/canvas/staleChangeDetector.js +9 -3
- package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
- package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
- package/dist/inspector/canvas/viewStore.d.ts +38 -0
- package/dist/inspector/canvas/viewStore.js +104 -0
- package/dist/inspector/canvas/wheelPan.d.ts +8 -0
- package/dist/inspector/canvas/wheelPan.js +8 -0
- package/dist/inspector/changes/changesLog.d.ts +6 -5
- package/dist/inspector/changes/changesLog.js +40 -32
- package/dist/inspector/changes/draftChanges.d.ts +56 -0
- package/dist/inspector/changes/draftChanges.js +300 -0
- package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
- package/dist/inspector/changes/previewDiagnostics.js +11 -25
- package/dist/inspector/clientManifest.d.ts +1 -1
- package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
- package/dist/inspector/comments/CommentsOverlay.js +250 -0
- package/dist/inspector/comments/element.d.ts +6 -0
- package/dist/inspector/comments/element.js +47 -0
- package/dist/inspector/comments/store.d.ts +29 -0
- package/dist/inspector/comments/store.js +121 -0
- package/dist/inspector/comments/verification.d.ts +5 -0
- package/dist/inspector/comments/verification.js +52 -0
- package/dist/inspector/drafts/model.d.ts +35 -0
- package/dist/inspector/drafts/model.js +45 -0
- package/dist/inspector/drafts/store.d.ts +28 -0
- package/dist/inspector/drafts/store.js +231 -0
- package/dist/inspector/index.js +20 -27
- package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
- package/dist/inspector/iterations/capture.d.ts +2 -0
- package/dist/inspector/iterations/capture.js +173 -0
- package/dist/inspector/iterations/client.d.ts +7 -0
- package/dist/inspector/iterations/client.js +52 -0
- package/dist/inspector/iterations/coordinator.d.ts +15 -0
- package/dist/inspector/iterations/coordinator.js +130 -0
- package/dist/inspector/iterations/prompt.d.ts +3 -0
- package/dist/inspector/iterations/prompt.js +26 -0
- package/dist/inspector/overlay/DomNavigator.js +21 -15
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
- package/dist/inspector/overlay/spacingGestures.js +82 -5
- package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
- package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
- package/dist/inspector/projection/renderedInstance.d.ts +2 -1
- package/dist/inspector/projection/renderedInstance.js +9 -5
- package/dist/inspector/projection/structuralProjection.d.ts +2 -1
- package/dist/inspector/projection/structuralProjection.js +19 -15
- package/dist/inspector/projection/textProjection.d.ts +2 -1
- package/dist/inspector/projection/textProjection.js +8 -4
- package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
- package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
- package/dist/inspector/prompt/clipboardHandoff.js +92 -143
- package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
- package/dist/inspector/prompt/generatePrompt.js +17 -16
- package/dist/inspector/runtime/runtimeConfig.d.ts +9 -0
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/settings/SettingsDialog.js +21 -8
- package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
- package/dist/inspector/shell/AgentStatusButton.js +36 -0
- package/dist/inspector/shell/AppShell.js +4 -2
- package/dist/inspector/shell/ChangesLog.js +46 -26
- package/dist/inspector/shell/CopyPromptButton.js +138 -89
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +13 -21
- package/dist/inspector/shell/PeekOriginalButton.js +24 -23
- package/dist/inspector/shell/originalPreview.js +5 -5
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +11 -0
- package/dist/inspector/sketch/SketchEditor.js +14 -14
- package/dist/inspector/sketch/SketchEntryButton.js +1 -1
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
- package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
- package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
- package/dist/inspector/sketch/SketchOverlay.js +7 -7
- package/dist/inspector/sketch/SketchWorkspace.js +18 -12
- package/dist/inspector/sketch/interaction.d.ts +1 -0
- package/dist/inspector/sketch/interaction.js +8 -4
- package/dist/inspector/sketch/model.d.ts +5 -0
- package/dist/inspector/sketch/model.js +6 -2
- package/dist/inspector/sketch/raster.d.ts +1 -2
- package/dist/inspector/sketch/raster.js +68 -4
- package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
- package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
- package/dist/inspector/styleEditors/BorderEditor.js +49 -78
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
- package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
- package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
- package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
- package/dist/inspector/styleEditors/ColorPicker.js +10 -4
- package/dist/inspector/styleEditors/GapField.js +3 -5
- package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
- package/dist/inspector/styleEditors/GridChildSection.js +18 -9
- package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
- package/dist/inspector/styleEditors/GridPicker.js +8 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/GridValueField.js +19 -14
- package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
- package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
- package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
- package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
- package/dist/inspector/styleEditors/LayoutSection.js +32 -11
- package/dist/inspector/styleEditors/SpacingBox.js +7 -5
- package/dist/inspector/styleEditors/Typography.js +11 -3
- package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
- package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
- package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
- package/dist/inspector/styleEditors/gradientValue.js +114 -0
- package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
- package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
- package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
- package/dist/inspector/styleEditors/layoutValue.js +0 -42
- package/dist/inspector/styleEditors/nudgeValue.d.ts +2 -2
- package/dist/inspector/styleEditors/nudgeValue.js +36 -8
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +29 -21
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- package/dist/inspector/tokens/editActions.d.ts +1 -1
- package/dist/inspector/tokens/editActions.js +1 -1
- package/dist/inspector/ui/AtRuleContext.js +4 -6
- package/dist/inspector/ui/Button.d.ts +6 -2
- package/dist/inspector/ui/Button.js +4 -3
- package/dist/inspector/ui/ControlSurface.d.ts +2 -2
- package/dist/inspector/ui/ControlSurface.js +4 -3
- package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
- package/dist/inspector/ui/InlineStyleWarning.js +13 -0
- package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
- package/dist/inspector/ui/InspectorPopover.js +4 -5
- package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
- package/dist/inspector/ui/PopoverListbox.js +8 -7
- package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
- package/dist/inspector/ui/SegmentedControl.js +2 -2
- package/dist/inspector/ui/Select.d.ts +6 -1
- package/dist/inspector/ui/Select.js +7 -11
- package/dist/inspector/ui/SideValuesField.js +1 -1
- package/dist/inspector/ui/Tooltip.d.ts +26 -0
- package/dist/inspector/ui/Tooltip.js +32 -0
- package/dist/inspector/ui/classNames.d.ts +2 -0
- package/dist/inspector/ui/classNames.js +4 -0
- package/dist/inspector/ui/customCursors.d.ts +23 -0
- package/dist/inspector/ui/customCursors.js +122 -0
- package/dist/inspector/ui/dragCursor.d.ts +0 -2
- package/dist/inspector/ui/dragCursor.js +2 -10
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +29 -21
- package/dist/inspector/workspace/commands.d.ts +9 -0
- package/dist/inspector/workspace/commands.js +82 -0
- package/dist/inspector/workspace/controller.d.ts +4 -0
- package/dist/inspector/workspace/controller.js +66 -0
- package/dist/inspector/workspace/handoff.d.ts +42 -0
- package/dist/inspector/workspace/handoff.js +115 -0
- package/dist/inspector/workspace/timeline.d.ts +30 -0
- package/dist/inspector/workspace/timeline.js +108 -0
- package/dist/internal/agent-protocol.d.ts +19 -2
- package/dist/internal/agent-protocol.js +13 -0
- package/dist/nudge-ui.mjs +558 -311
- package/dist/project/artifacts.d.ts +13 -0
- package/dist/project/artifacts.js +253 -0
- package/dist/transport/artifacts.d.ts +8 -0
- package/dist/transport/artifacts.js +9 -0
- package/dist/transport/editor.js +3 -1
- package/dist/transport/routes.d.ts +2 -0
- package/dist/transport/routes.js +2 -0
- package/package.json +6 -2
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
- package/dist/inspector/changes/workspaceChanges.js +0 -265
|
@@ -9,7 +9,8 @@ import { resolveSelectionTarget, selectionTargetMode } from "../selection/select
|
|
|
9
9
|
import { escapeCssString } from "../projection/cssEscapes.js";
|
|
10
10
|
import { APPLICATION_GESTURE_EVENTS, blockApplicationClick, blockApplicationGesture, isInlineEditorTarget, isUserClick, } from "../overlay/clickPolicy.js";
|
|
11
11
|
import { EMPTY_TEXT_PROJECTION_ATTR } from "../projection/textProjection.js";
|
|
12
|
-
import { getSpacingAffordanceAtPoint, toSpacingDescriptor, } from "../overlay/spacingGestures.js";
|
|
12
|
+
import { getSpacingAffordanceAtPoint, getSpacingHoverAtPoint, toSpacingDescriptor, } from "../overlay/spacingGestures.js";
|
|
13
|
+
import { COMMENT_CURSOR, INTERACTION_CURSOR_PROPERTY, rendererCursorValue } from "../ui/customCursors.js";
|
|
13
14
|
const REACT_FIBER_KEY = /^__reactFiber\$/;
|
|
14
15
|
const REACT_INTERNAL_KEY = /^__reactInternalInstance\$/;
|
|
15
16
|
const HOVER_SCROLL_SETTLE_DELAY = 150;
|
|
@@ -100,8 +101,29 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
100
101
|
const cidIndex = createCidIndex(document);
|
|
101
102
|
const initialCursor = document.documentElement.style.getPropertyValue("cursor");
|
|
102
103
|
const initialCursorPriority = document.documentElement.style.getPropertyPriority("cursor");
|
|
104
|
+
const initialInteractionCursor = document.documentElement.style.getPropertyValue(INTERACTION_CURSOR_PROPERTY);
|
|
105
|
+
const initialInteractionCursorPriority = document.documentElement.style.getPropertyPriority(INTERACTION_CURSOR_PROPERTY);
|
|
106
|
+
let commentMode = false;
|
|
107
|
+
let interactionCursor = "design";
|
|
108
|
+
let commentCursor = COMMENT_CURSOR;
|
|
109
|
+
let appliedInteractionCursor = rendererCursorValue("design");
|
|
103
110
|
let appliedRootCursor = null;
|
|
104
111
|
let spacingCursor = null;
|
|
112
|
+
function setInteractionCursor(cursor) {
|
|
113
|
+
appliedInteractionCursor = rendererCursorValue(cursor, commentCursor);
|
|
114
|
+
document.documentElement.style.setProperty(INTERACTION_CURSOR_PROPERTY, appliedInteractionCursor);
|
|
115
|
+
}
|
|
116
|
+
function restoreInteractionCursor() {
|
|
117
|
+
if (document.documentElement.style.getPropertyValue(INTERACTION_CURSOR_PROPERTY) !== appliedInteractionCursor)
|
|
118
|
+
return;
|
|
119
|
+
if (initialInteractionCursor) {
|
|
120
|
+
document.documentElement.style.setProperty(INTERACTION_CURSOR_PROPERTY, initialInteractionCursor, initialInteractionCursorPriority);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
document.documentElement.style.removeProperty(INTERACTION_CURSOR_PROPERTY);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
setInteractionCursor("design");
|
|
105
127
|
function clearSpacingCursor() {
|
|
106
128
|
const active = spacingCursor;
|
|
107
129
|
spacingCursor = null;
|
|
@@ -140,7 +162,7 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
140
162
|
spacingCursor.appliedValue = cursor;
|
|
141
163
|
}
|
|
142
164
|
element.style.setProperty("cursor", cursor, "important");
|
|
143
|
-
document.documentElement.style.setProperty("cursor", cursor);
|
|
165
|
+
document.documentElement.style.setProperty("cursor", cursor, "important");
|
|
144
166
|
appliedRootCursor = cursor;
|
|
145
167
|
}
|
|
146
168
|
function reportHover(pending) {
|
|
@@ -152,10 +174,16 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
152
174
|
const selector = buildSelector(element);
|
|
153
175
|
const src = element.getAttribute("data-src") ?? "";
|
|
154
176
|
const rect = clear ? null : element.getBoundingClientRect();
|
|
155
|
-
|
|
177
|
+
// The handle hit is the only target that starts a drag, so it is the only
|
|
178
|
+
// one that changes the cursor. The area-wide match is purely visual.
|
|
179
|
+
const rawSpacing = !commentMode && !clear && pending.point
|
|
156
180
|
? getSpacingAffordanceAtPoint(document, pending.point.x, pending.point.y)
|
|
157
181
|
: null;
|
|
158
182
|
const spacing = rawSpacing && rawSpacing.element === element ? rawSpacing : null;
|
|
183
|
+
const rawHoverSpacing = !commentMode && !clear && pending.point
|
|
184
|
+
? getSpacingHoverAtPoint(document, pending.point.x, pending.point.y)
|
|
185
|
+
: null;
|
|
186
|
+
const hoverSpacing = rawHoverSpacing && rawHoverSpacing.element === element ? rawHoverSpacing : null;
|
|
159
187
|
if (spacing) {
|
|
160
188
|
setSpacingCursor(spacing.element, spacing.cursor);
|
|
161
189
|
}
|
|
@@ -182,6 +210,7 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
182
210
|
borders: rect ? readBorderWidths(element) : null,
|
|
183
211
|
point: pending.point,
|
|
184
212
|
spacing: spacing ? toSpacingDescriptor(spacing) : null,
|
|
213
|
+
hoverSpacing: hoverSpacing ? toSpacingDescriptor(hoverSpacing) : null,
|
|
185
214
|
...identity,
|
|
186
215
|
};
|
|
187
216
|
sendToParent(msg);
|
|
@@ -292,8 +321,19 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
292
321
|
updateMeasureState(message.altKey, measurePointerOverPage);
|
|
293
322
|
return;
|
|
294
323
|
}
|
|
324
|
+
if (message.type === "pan-modifier" && typeof message.spaceHeld === "boolean") {
|
|
325
|
+
setInteractionCursor(message.spaceHeld ? "drag" : interactionCursor);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
295
328
|
if (message.type !== "inspector-interaction-state" || typeof message.open !== "boolean")
|
|
296
329
|
return;
|
|
330
|
+
if (typeof message.commentCursor === "string")
|
|
331
|
+
commentCursor = message.commentCursor;
|
|
332
|
+
interactionCursor = message.cursor === "comment" ? "comment" : message.cursor === "drag" ? "drag" : "design";
|
|
333
|
+
commentMode = interactionCursor === "comment";
|
|
334
|
+
cancelActiveDrag();
|
|
335
|
+
clearSpacingCursor();
|
|
336
|
+
setInteractionCursor(interactionCursor);
|
|
297
337
|
const interactionsEnabled = message.interactionsEnabled === undefined
|
|
298
338
|
? message.open
|
|
299
339
|
: message.interactionsEnabled === true;
|
|
@@ -360,7 +400,7 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
360
400
|
trackListener(document, "mousedown", (event) => {
|
|
361
401
|
if (interactionsSuspended)
|
|
362
402
|
return;
|
|
363
|
-
if (event.button !== 0)
|
|
403
|
+
if (event.button !== 0 || commentMode)
|
|
364
404
|
return;
|
|
365
405
|
const element = resolveSelectionTarget(event.target, selectionTargetMode(event));
|
|
366
406
|
if (!element)
|
|
@@ -559,7 +599,7 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
559
599
|
sendToParent(msg);
|
|
560
600
|
return;
|
|
561
601
|
}
|
|
562
|
-
if (!lastSelected)
|
|
602
|
+
if (!lastSelected || commentMode)
|
|
563
603
|
return;
|
|
564
604
|
const identity = getRendererIdentity();
|
|
565
605
|
if (!identity)
|
|
@@ -619,7 +659,7 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
619
659
|
hoverUpdate.schedule({ element: el, clear: true, point: null });
|
|
620
660
|
}, true);
|
|
621
661
|
trackListener(document, "dblclick", (event) => {
|
|
622
|
-
if (interactionsSuspended)
|
|
662
|
+
if (interactionsSuspended || commentMode)
|
|
623
663
|
return;
|
|
624
664
|
const element = resolveSelectionTarget(event.target, selectionTargetMode(event));
|
|
625
665
|
const identity = getRendererIdentity();
|
|
@@ -701,5 +741,6 @@ export function installRendererElementSelector(acceptsClick = isUserClick) {
|
|
|
701
741
|
measureAltKey = false;
|
|
702
742
|
document.documentElement.removeAttribute("data-nudge-ui-panel");
|
|
703
743
|
clearSpacingCursor();
|
|
744
|
+
restoreInteractionCursor();
|
|
704
745
|
};
|
|
705
746
|
}
|
|
@@ -8,7 +8,7 @@ import { applyRenderedInstanceProjection, getRenderedInstanceProjectionReports,
|
|
|
8
8
|
import { applyStructuralProjection, getStructuralProjectionReports, isStructuralChange, subscribeStructuralDiagnostics, } from "../projection/structuralProjection.js";
|
|
9
9
|
import { applyTextContentProjection, getTextProjectionReports, subscribeTextProjectionDiagnostics, } from "../projection/textProjection.js";
|
|
10
10
|
import { isTextContentChangeListValue } from "../changes/types.js";
|
|
11
|
-
import {
|
|
11
|
+
import { applyDraftProjection, } from "../projection/draftProjection.js";
|
|
12
12
|
const SHEET_ID = "nudge-ui-styles";
|
|
13
13
|
function replaceRendererCss(css) {
|
|
14
14
|
let sheet = document.getElementById(SHEET_ID);
|
|
@@ -208,7 +208,7 @@ export function handleReplaceStyles(msg, projectId, workspaceId, cardId) {
|
|
|
208
208
|
return false;
|
|
209
209
|
if (msg.revision <= lastAppliedRevision)
|
|
210
210
|
return false;
|
|
211
|
-
|
|
211
|
+
applyDraftProjection(rendererDocumentProjectionAdapter, projectionFromReplaceStylesMessage(msg));
|
|
212
212
|
lastStructuralReportRevision = msg.revision;
|
|
213
213
|
lastRenderedInstanceReportRevision = msg.revision;
|
|
214
214
|
lastTextProjectionReportRevision = msg.revision;
|
|
@@ -1,46 +1,33 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type
|
|
3
|
-
import { type
|
|
1
|
+
import { type FrameContent } from "./frameContent.js";
|
|
2
|
+
import { type FrameGroup } from "./canvasStore.js";
|
|
3
|
+
import { type CanvasPresentation, type CanvasMode } from "./viewStore.js";
|
|
4
4
|
import { type ClipboardHandoffSnapshot } from "../prompt/clipboardHandoff.js";
|
|
5
|
-
declare const SCHEMA_VERSION =
|
|
5
|
+
declare const SCHEMA_VERSION = 17;
|
|
6
6
|
declare function storageKey(projectId: string): string;
|
|
7
7
|
export interface SerializableCard {
|
|
8
8
|
id: string;
|
|
9
|
-
|
|
9
|
+
content: FrameContent;
|
|
10
10
|
title: string | null;
|
|
11
|
+
groupId?: string;
|
|
11
12
|
x: number;
|
|
12
13
|
y: number;
|
|
13
14
|
width: number;
|
|
14
15
|
height: number;
|
|
15
|
-
comparisonGroupId?: string;
|
|
16
|
-
}
|
|
17
|
-
export interface SerializableComparisonGroup {
|
|
18
|
-
id: string;
|
|
19
|
-
label: string;
|
|
20
|
-
owner: "agent";
|
|
21
|
-
agentId: string;
|
|
22
|
-
cardIds: string[];
|
|
23
|
-
routes: Array<{
|
|
24
|
-
url: string;
|
|
25
|
-
title?: string | null;
|
|
26
|
-
label?: string;
|
|
27
|
-
}>;
|
|
28
16
|
}
|
|
29
17
|
export interface DurableSession {
|
|
30
18
|
schemaVersion: typeof SCHEMA_VERSION;
|
|
31
19
|
projectId: string;
|
|
32
20
|
mode: CanvasMode;
|
|
21
|
+
presentation: CanvasPresentation;
|
|
22
|
+
groups: readonly FrameGroup[];
|
|
33
23
|
inspectUrl: string;
|
|
34
24
|
cards: SerializableCard[];
|
|
35
|
-
comparisonGroups: SerializableComparisonGroup[];
|
|
36
25
|
camera: {
|
|
37
26
|
x: number;
|
|
38
27
|
y: number;
|
|
39
28
|
zoom: number;
|
|
40
29
|
};
|
|
41
30
|
focusedCardId?: string | null;
|
|
42
|
-
changes: SerializableChange[];
|
|
43
|
-
structuralChanges: StructuralChange[];
|
|
44
31
|
clipboardHandoff: ClipboardHandoffSnapshot | null;
|
|
45
32
|
}
|
|
46
33
|
export type { SerializableChange, SerializableComponentChange, SerializableElementChange, SerializableTextContentChange, SerializableTokenChange, SerializableTokenRef, } from "../changes/codecs.js";
|
|
@@ -51,6 +38,8 @@ export interface HydrationResult {
|
|
|
51
38
|
export declare function serializeSession(): DurableSession;
|
|
52
39
|
export declare function persistSession(): boolean;
|
|
53
40
|
export declare function hydrateSession(): HydrationResult;
|
|
41
|
+
/** Clears the active frame's edit draft while preserving canvas geometry and other drafts. */
|
|
42
|
+
export declare function clearSelectedFrameChanges(): void;
|
|
54
43
|
export declare function clearSession(): void;
|
|
55
44
|
export declare function enableAutoSave(): void;
|
|
56
45
|
/**
|
|
@@ -59,12 +48,8 @@ export declare function enableAutoSave(): void;
|
|
|
59
48
|
* refresh or close inside the debounce window still flushes on `beforeunload`.
|
|
60
49
|
*/
|
|
61
50
|
export declare function scheduleAutoSave(): void;
|
|
62
|
-
/**
|
|
63
|
-
* Canvas mode/card/camera changes persist immediately (synchronous) so a
|
|
64
|
-
* refresh always restores the workspace, even inside the edit-autosave
|
|
65
|
-
* debounce window. Edit autosave stays coalesced behind the trailing timer.
|
|
66
|
-
*/
|
|
67
51
|
export declare function scheduleCanvasSave(): void;
|
|
52
|
+
export declare function flushAutoSave(): void;
|
|
68
53
|
export declare function getRestoreCount(): number;
|
|
69
54
|
export declare function setRestoreCount(count: number): void;
|
|
70
55
|
export declare function clearRestoreCount(): void;
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { isFrameContent } from "./frameContent.js";
|
|
2
|
+
import { clearComments } from "../comments/store.js";
|
|
3
|
+
import { documentTarget, targetFromKey } from "../drafts/model.js";
|
|
4
|
+
import { canEditDraft, getActiveDraftChanges, isDraftLocked } from "../changes/draftChanges.js";
|
|
5
|
+
import { getFrameGroups, isFrameGroup, getCanvasCards, getFocusedCardId, getSelectedCardId, hydrateCanvasStore, removeCanvasCard, } from "./canvasStore.js";
|
|
6
|
+
import { getCanvasMode, getCanvasPresentation, getBoardCamera, setBoardCamera, } from "./viewStore.js";
|
|
5
7
|
import { applyRules } from "../projection/managedStylesheet.js";
|
|
6
|
-
import {
|
|
8
|
+
import { clearActiveDraft } from "../changes/changesLog.js";
|
|
7
9
|
import { removeManagedSheet } from "../projection/managedStylesheet.js";
|
|
8
10
|
import { setSelectedElement } from "../selection/selectionStore.js";
|
|
9
11
|
import { canWriteWorkspace } from "./workspaceLease.js";
|
|
10
|
-
import {
|
|
12
|
+
import { resetStructuralDeleteProjection, } from "../projection/structuralProjection.js";
|
|
11
13
|
import { projectToAllReadyCards } from "./projection.js";
|
|
12
14
|
import { getNudgeUiRuntimeConfig } from "../runtime/runtimeConfig.js";
|
|
13
15
|
import { clearClipboardHandoff, getClipboardHandoffSnapshot, hydrateClipboardHandoff, isClipboardHandoffSnapshot, } from "../prompt/clipboardHandoff.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const SCHEMA_VERSION = 12;
|
|
16
|
+
import { activateDraftForCard, clearDrafts, persistDrafts } from "../drafts/store.js";
|
|
17
|
+
const SCHEMA_VERSION = 17;
|
|
17
18
|
const STORAGE_PREFIX = "nudge-ui";
|
|
18
19
|
function projectId() {
|
|
19
20
|
return getNudgeUiRuntimeConfig().projectId;
|
|
@@ -21,9 +22,6 @@ function projectId() {
|
|
|
21
22
|
function isFiniteNumber(value) {
|
|
22
23
|
return typeof value === "number" && Number.isFinite(value);
|
|
23
24
|
}
|
|
24
|
-
function isRecord(value) {
|
|
25
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
26
|
-
}
|
|
27
25
|
function isSameOriginUrl(value) {
|
|
28
26
|
if (typeof value !== "string")
|
|
29
27
|
return false;
|
|
@@ -34,95 +32,32 @@ function isSameOriginUrl(value) {
|
|
|
34
32
|
return false;
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
|
-
function hasOnlyKeys(value, allowed) {
|
|
38
|
-
return Object.keys(value).every((key) => allowed.includes(key));
|
|
39
|
-
}
|
|
40
|
-
function isSerializableComparisonGroup(value) {
|
|
41
|
-
if (!isRecord(value)
|
|
42
|
-
|| !hasOnlyKeys(value, ["id", "label", "owner", "agentId", "cardIds", "routes"])
|
|
43
|
-
|| typeof value.id !== "string"
|
|
44
|
-
|| value.id.length === 0
|
|
45
|
-
|| value.id.length > 256
|
|
46
|
-
|| typeof value.label !== "string"
|
|
47
|
-
|| value.label.length === 0
|
|
48
|
-
|| value.label.length > 160
|
|
49
|
-
|| value.owner !== "agent"
|
|
50
|
-
|| typeof value.agentId !== "string"
|
|
51
|
-
|| value.agentId.length === 0
|
|
52
|
-
|| value.agentId.length > 256
|
|
53
|
-
|| !Array.isArray(value.cardIds)
|
|
54
|
-
|| value.cardIds.length === 0
|
|
55
|
-
|| value.cardIds.length > 64
|
|
56
|
-
|| !Array.isArray(value.routes)
|
|
57
|
-
|| value.routes.length === 0
|
|
58
|
-
|| value.routes.length > 64) {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
if (!value.cardIds.every((cardId) => typeof cardId === "string" && cardId.length > 0 && cardId.length <= 256)) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
return value.routes.every((route) => {
|
|
65
|
-
if (!isRecord(route)
|
|
66
|
-
|| !hasOnlyKeys(route, ["url", "title", "label"])
|
|
67
|
-
|| !isSameOriginUrl(route.url)
|
|
68
|
-
|| (route.title !== undefined && route.title !== null
|
|
69
|
-
&& (typeof route.title !== "string" || route.title.length > 512))
|
|
70
|
-
|| (route.label !== undefined
|
|
71
|
-
&& (typeof route.label !== "string" || route.label.length > 160))) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
return true;
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
35
|
function storageKey(projectId) {
|
|
78
36
|
return `${STORAGE_PREFIX}:${projectId}:v${SCHEMA_VERSION}`;
|
|
79
37
|
}
|
|
80
38
|
function buildSession() {
|
|
81
|
-
const workspace = getWorkspaceChanges();
|
|
82
|
-
const changes = workspace.changes;
|
|
83
|
-
const serializableChanges = [];
|
|
84
|
-
for (const change of changes) {
|
|
85
|
-
const serialized = serializeChange(change);
|
|
86
|
-
// serializeChange already fails closed, but re-validate here so a future
|
|
87
|
-
// serializer skew can never poison the whole durable session.
|
|
88
|
-
if (serialized && isSerializableChange(serialized))
|
|
89
|
-
serializableChanges.push(serialized);
|
|
90
|
-
}
|
|
91
39
|
const cards = getCanvasCards();
|
|
92
|
-
const comparisonGroups = getCanvasComparisonGroups();
|
|
93
40
|
const camera = getBoardCamera();
|
|
94
41
|
const mode = getCanvasMode();
|
|
95
42
|
return {
|
|
96
43
|
schemaVersion: SCHEMA_VERSION,
|
|
97
44
|
projectId: projectId(),
|
|
98
45
|
mode,
|
|
46
|
+
presentation: getCanvasPresentation(),
|
|
47
|
+
groups: getFrameGroups(),
|
|
99
48
|
inspectUrl: window.location.href,
|
|
100
49
|
cards: cards.map((c) => ({
|
|
101
50
|
id: c.id,
|
|
102
|
-
url: c.url,
|
|
51
|
+
content: c.content.kind === "route" ? { kind: "route", url: c.content.url } : { ...c.content },
|
|
103
52
|
title: c.title,
|
|
53
|
+
...(c.groupId ? { groupId: c.groupId } : {}),
|
|
104
54
|
x: c.x,
|
|
105
55
|
y: c.y,
|
|
106
56
|
width: c.width,
|
|
107
57
|
height: c.height,
|
|
108
|
-
...(c.comparisonGroupId ? { comparisonGroupId: c.comparisonGroupId } : {}),
|
|
109
|
-
})),
|
|
110
|
-
comparisonGroups: comparisonGroups.map((group) => ({
|
|
111
|
-
id: group.id,
|
|
112
|
-
label: group.label,
|
|
113
|
-
owner: "agent",
|
|
114
|
-
agentId: group.agentId,
|
|
115
|
-
cardIds: [...group.cardIds],
|
|
116
|
-
routes: group.routes.map((route) => ({
|
|
117
|
-
url: route.url,
|
|
118
|
-
...(route.title === undefined ? {} : { title: route.title }),
|
|
119
|
-
...(route.label === undefined ? {} : { label: route.label }),
|
|
120
|
-
})),
|
|
121
58
|
})),
|
|
122
59
|
camera: { x: camera.x, y: camera.y, zoom: camera.zoom },
|
|
123
60
|
focusedCardId: getFocusedCardId(),
|
|
124
|
-
changes: serializableChanges,
|
|
125
|
-
structuralChanges: workspace.structuralChanges.map((change) => ({ ...change })),
|
|
126
61
|
clipboardHandoff: getClipboardHandoffSnapshot(),
|
|
127
62
|
};
|
|
128
63
|
}
|
|
@@ -142,6 +77,7 @@ function persistSessionUnchecked() {
|
|
|
142
77
|
if (!projectId())
|
|
143
78
|
return false;
|
|
144
79
|
try {
|
|
80
|
+
persistDrafts();
|
|
145
81
|
const session = buildSession();
|
|
146
82
|
localStorage.setItem(storageKey(projectId()), JSON.stringify(session));
|
|
147
83
|
return true;
|
|
@@ -203,7 +139,7 @@ export function hydrateSession() {
|
|
|
203
139
|
const candidate = card;
|
|
204
140
|
if (!card || typeof card !== "object" ||
|
|
205
141
|
typeof candidate.id !== "string" ||
|
|
206
|
-
!
|
|
142
|
+
!isFrameContent(candidate.content, window.location.origin) ||
|
|
207
143
|
!isFiniteNumber(candidate.x) ||
|
|
208
144
|
!isFiniteNumber(candidate.y) ||
|
|
209
145
|
!isFiniteNumber(candidate.width) ||
|
|
@@ -216,70 +152,20 @@ export function hydrateSession() {
|
|
|
216
152
|
const c = card;
|
|
217
153
|
serializableCards.push({
|
|
218
154
|
id: c.id,
|
|
219
|
-
|
|
155
|
+
content: c.content,
|
|
220
156
|
title: typeof c.title === "string" ? c.title : null,
|
|
157
|
+
...(typeof c.groupId === "string" && c.groupId.length <= 256 ? { groupId: c.groupId } : {}),
|
|
221
158
|
x: c.x,
|
|
222
159
|
y: c.y,
|
|
223
160
|
width: c.width,
|
|
224
161
|
height: c.height,
|
|
225
|
-
...(typeof c.comparisonGroupId === "string"
|
|
226
|
-
? { comparisonGroupId: c.comparisonGroupId }
|
|
227
|
-
: {}),
|
|
228
162
|
});
|
|
229
163
|
}
|
|
230
164
|
if (new Set(serializableCards.map((card) => card.id)).size !== serializableCards.length) {
|
|
231
165
|
safeDiscard();
|
|
232
166
|
return { restored: false, changeCount: 0 };
|
|
233
167
|
}
|
|
234
|
-
const comparisonGroupsRaw = s.comparisonGroups;
|
|
235
|
-
if (!Array.isArray(comparisonGroupsRaw) || comparisonGroupsRaw.length > 128) {
|
|
236
|
-
safeDiscard();
|
|
237
|
-
return { restored: false, changeCount: 0 };
|
|
238
|
-
}
|
|
239
|
-
const serializableComparisonGroups = [];
|
|
240
|
-
for (const group of comparisonGroupsRaw) {
|
|
241
|
-
if (!isSerializableComparisonGroup(group)) {
|
|
242
|
-
safeDiscard();
|
|
243
|
-
return { restored: false, changeCount: 0 };
|
|
244
|
-
}
|
|
245
|
-
serializableComparisonGroups.push({
|
|
246
|
-
id: group.id,
|
|
247
|
-
label: group.label,
|
|
248
|
-
owner: "agent",
|
|
249
|
-
agentId: group.agentId,
|
|
250
|
-
cardIds: [...group.cardIds],
|
|
251
|
-
routes: group.routes.map((route) => ({ ...route })),
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
if (new Set(serializableComparisonGroups.map((group) => group.id)).size
|
|
255
|
-
!== serializableComparisonGroups.length) {
|
|
256
|
-
safeDiscard();
|
|
257
|
-
return { restored: false, changeCount: 0 };
|
|
258
|
-
}
|
|
259
168
|
const cardsById = new Map(serializableCards.map((card) => [card.id, card]));
|
|
260
|
-
const groupedCardIds = new Set();
|
|
261
|
-
for (const group of serializableComparisonGroups) {
|
|
262
|
-
if (group.cardIds.length !== group.routes.length) {
|
|
263
|
-
safeDiscard();
|
|
264
|
-
return { restored: false, changeCount: 0 };
|
|
265
|
-
}
|
|
266
|
-
for (const [routeIndex, cardId] of group.cardIds.entries()) {
|
|
267
|
-
const card = cardsById.get(cardId);
|
|
268
|
-
const route = group.routes[routeIndex];
|
|
269
|
-
if (!card || !route || card.comparisonGroupId !== group.id || groupedCardIds.has(cardId)
|
|
270
|
-
|| card.url !== route.url) {
|
|
271
|
-
safeDiscard();
|
|
272
|
-
return { restored: false, changeCount: 0 };
|
|
273
|
-
}
|
|
274
|
-
groupedCardIds.add(cardId);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
for (const card of serializableCards) {
|
|
278
|
-
if (card.comparisonGroupId && !serializableComparisonGroups.some((group) => group.id === card.comparisonGroupId)) {
|
|
279
|
-
safeDiscard();
|
|
280
|
-
return { restored: false, changeCount: 0 };
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
169
|
const cameraRaw = s.camera;
|
|
284
170
|
if (!cameraRaw || typeof cameraRaw !== "object" ||
|
|
285
171
|
!isFiniteNumber(cameraRaw.x) ||
|
|
@@ -288,35 +174,9 @@ export function hydrateSession() {
|
|
|
288
174
|
safeDiscard();
|
|
289
175
|
return { restored: false, changeCount: 0 };
|
|
290
176
|
}
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
return { restored: false, changeCount: 0 };
|
|
295
|
-
}
|
|
296
|
-
const deserializedChanges = [];
|
|
297
|
-
const textChangeIds = new Set();
|
|
298
|
-
for (const c of changesRaw) {
|
|
299
|
-
if (!isSerializableChange(c)) {
|
|
300
|
-
safeDiscard();
|
|
301
|
-
return { restored: false, changeCount: 0 };
|
|
302
|
-
}
|
|
303
|
-
if (c.kind === "text-content") {
|
|
304
|
-
if (textChangeIds.has(c.id)) {
|
|
305
|
-
safeDiscard();
|
|
306
|
-
return { restored: false, changeCount: 0 };
|
|
307
|
-
}
|
|
308
|
-
textChangeIds.add(c.id);
|
|
309
|
-
}
|
|
310
|
-
try {
|
|
311
|
-
deserializedChanges.push(deserializeChange(c));
|
|
312
|
-
}
|
|
313
|
-
catch {
|
|
314
|
-
safeDiscard();
|
|
315
|
-
return { restored: false, changeCount: 0 };
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
const structuralChanges = s.structuralChanges;
|
|
319
|
-
if (!Array.isArray(structuralChanges) || !structuralChanges.every(isStructuralChange)) {
|
|
177
|
+
const presentation = s.presentation ?? "focus";
|
|
178
|
+
const groups = Array.isArray(s.groups) ? s.groups.filter((group) => group?.kind !== "linked") : s.groups ?? [];
|
|
179
|
+
if ((presentation !== "focus" && presentation !== "canvas") || !Array.isArray(groups) || !groups.every(isFrameGroup)) {
|
|
320
180
|
safeDiscard();
|
|
321
181
|
return { restored: false, changeCount: 0 };
|
|
322
182
|
}
|
|
@@ -339,10 +199,7 @@ export function hydrateSession() {
|
|
|
339
199
|
safeDiscard();
|
|
340
200
|
return { restored: false, changeCount: 0 };
|
|
341
201
|
}
|
|
342
|
-
hydrateCanvasStore(s.mode, serializableCards, camera,
|
|
343
|
-
// Structural intent and instance evidence become visible atomically. The
|
|
344
|
-
// projection layer preserves structural-first document application order.
|
|
345
|
-
loadWorkspaceChanges(deserializedChanges, structuralChanges);
|
|
202
|
+
hydrateCanvasStore(s.mode, serializableCards, camera, focusedCardId, presentation, groups);
|
|
346
203
|
hydrateClipboardHandoff(clipboardHandoff);
|
|
347
204
|
// A different URL means the user intentionally navigated while Inspect was
|
|
348
205
|
// active. Keep the durable edits, but adopt the new route instead of
|
|
@@ -350,8 +207,7 @@ export function hydrateSession() {
|
|
|
350
207
|
// match and restoration remains unchanged.
|
|
351
208
|
if (inspectRouteChanged)
|
|
352
209
|
persistSessionUnchecked();
|
|
353
|
-
|
|
354
|
-
return { restored: true, changeCount: deserializedChanges.length + structuralChanges.length };
|
|
210
|
+
return { restored: true, changeCount: 0 };
|
|
355
211
|
}
|
|
356
212
|
function safeDiscard() {
|
|
357
213
|
try {
|
|
@@ -361,7 +217,22 @@ function safeDiscard() {
|
|
|
361
217
|
// ignore
|
|
362
218
|
}
|
|
363
219
|
}
|
|
220
|
+
/** Clears the active frame's edit draft while preserving canvas geometry and other drafts. */
|
|
221
|
+
export function clearSelectedFrameChanges() {
|
|
222
|
+
if (!canEditDraft())
|
|
223
|
+
return;
|
|
224
|
+
const cardId = getSelectedCardId() ?? getFocusedCardId();
|
|
225
|
+
if (cardId)
|
|
226
|
+
activateDraftForCard(cardId);
|
|
227
|
+
clearComments(targetFromKey(getActiveDraftChanges().draftId) ?? documentTarget(window.location.href));
|
|
228
|
+
clearActiveDraft();
|
|
229
|
+
setSelectedElement(null);
|
|
230
|
+
projectToAllReadyCards();
|
|
231
|
+
scheduleAutoSave();
|
|
232
|
+
}
|
|
364
233
|
export function clearSession() {
|
|
234
|
+
if (isDraftLocked())
|
|
235
|
+
return;
|
|
365
236
|
if (!canWriteWorkspace())
|
|
366
237
|
return;
|
|
367
238
|
try {
|
|
@@ -370,8 +241,10 @@ export function clearSession() {
|
|
|
370
241
|
catch {
|
|
371
242
|
// ignore
|
|
372
243
|
}
|
|
373
|
-
|
|
244
|
+
clearComments();
|
|
245
|
+
clearActiveDraft();
|
|
374
246
|
clearClipboardHandoff();
|
|
247
|
+
clearDrafts();
|
|
375
248
|
resetStructuralDeleteProjection();
|
|
376
249
|
removeManagedSheet();
|
|
377
250
|
setSelectedElement(null);
|
|
@@ -415,27 +288,14 @@ export function scheduleAutoSave() {
|
|
|
415
288
|
autoSaveDirty = false;
|
|
416
289
|
}, AUTOSAVE_DEBOUNCE_MS);
|
|
417
290
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
* refresh always restores the workspace, even inside the edit-autosave
|
|
421
|
-
* debounce window. Edit autosave stays coalesced behind the trailing timer.
|
|
422
|
-
*/
|
|
423
|
-
export function scheduleCanvasSave() {
|
|
424
|
-
if (!autoSaveEnabled)
|
|
425
|
-
return;
|
|
426
|
-
if (persistSession())
|
|
427
|
-
autoSaveDirty = false;
|
|
428
|
-
}
|
|
429
|
-
function flushAutoSave() {
|
|
291
|
+
export function scheduleCanvasSave() { scheduleAutoSave(); }
|
|
292
|
+
export function flushAutoSave() {
|
|
430
293
|
if (autosaveTimer !== null) {
|
|
431
294
|
clearTimeout(autosaveTimer);
|
|
432
295
|
autosaveTimer = null;
|
|
433
296
|
}
|
|
434
297
|
if (!autoSaveDirty)
|
|
435
298
|
return;
|
|
436
|
-
// Keep the normal lease gate on the unload path. The controller registers
|
|
437
|
-
// this listener before releaseLease, so a current owner can flush a first
|
|
438
|
-
// write without allowing a stale tab to overwrite the new owner's session.
|
|
439
299
|
if (persistSession())
|
|
440
300
|
autoSaveDirty = false;
|
|
441
301
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { draftIdForCard } from "../drafts/store.js";
|
|
1
2
|
import { isPreviewableChange, isTokenChange, } from "../changes/changesLog.js";
|
|
2
3
|
import { changeKey } from "../changes/model.js";
|
|
3
4
|
import { beginPreviewAttempt, clearPreviewDiagnostics, getHostPreviewDocument, notifyPreviewDiagnostics, publishPreviewDiagnostic, } from "../changes/previewDiagnostics.js";
|
|
4
|
-
import {
|
|
5
|
+
import { getActiveDraftChanges } from "../changes/draftChanges.js";
|
|
5
6
|
import { getCanvasPreviewDocument, getRegisteredFrames } from "./projection.js";
|
|
6
7
|
import { findCanvasFrameBySource, PROJECT_ID, WORKSPACE_ID } from "./projection.js";
|
|
7
|
-
import { getCanvasCards
|
|
8
|
+
import { getCanvasCards } from "./canvasStore.js";
|
|
9
|
+
import { getCanvasMode } from "./viewStore.js";
|
|
8
10
|
import { isRendererMessageFor } from "./frameProtocol.js";
|
|
9
11
|
import { getNudgeUiRuntimeConfig } from "../runtime/runtimeConfig.js";
|
|
10
12
|
const VERIFICATION_TIMEOUT_MS = 5000;
|
|
@@ -82,6 +84,8 @@ function getPreviewDocuments() {
|
|
|
82
84
|
const documents = getCanvasMode() === "canvas" ? [] : [getHostPreviewDocument()];
|
|
83
85
|
const frames = getRegisteredFrames();
|
|
84
86
|
for (const card of getCanvasCards()) {
|
|
87
|
+
if (draftIdForCard(card.id) && draftIdForCard(card.id) !== getActiveDraftChanges().draftId)
|
|
88
|
+
continue;
|
|
85
89
|
if (frames.has(card.id))
|
|
86
90
|
documents.push(getCanvasPreviewDocument(card.id));
|
|
87
91
|
}
|
|
@@ -89,7 +93,7 @@ function getPreviewDocuments() {
|
|
|
89
93
|
}
|
|
90
94
|
function beginPreviewAttempts() {
|
|
91
95
|
const attempts = new Map();
|
|
92
|
-
const revision =
|
|
96
|
+
const revision = getActiveDraftChanges().revision;
|
|
93
97
|
for (const document of getPreviewDocuments()) {
|
|
94
98
|
const attempt = beginPreviewAttempt(document, revision);
|
|
95
99
|
if (attempt)
|
|
@@ -115,6 +119,8 @@ function gatherMatchEvidence(changes) {
|
|
|
115
119
|
const frames = getRegisteredFrames();
|
|
116
120
|
const cards = getCanvasCards();
|
|
117
121
|
for (const card of cards) {
|
|
122
|
+
if (draftIdForCard(card.id) && draftIdForCard(card.id) !== getActiveDraftChanges().draftId)
|
|
123
|
+
continue;
|
|
118
124
|
const frame = frames.get(card.id);
|
|
119
125
|
if (!frame || !frame.contentWindow)
|
|
120
126
|
continue;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
import { type CanvasCard } from "./canvasStore.js";
|
|
3
|
+
import { type CanvasCamera, type CanvasPresentation } from "./viewStore.js";
|
|
4
|
+
/** Animates frame creation and layout changes without delaying direct manipulation. */
|
|
5
|
+
export declare function useCanvasLayoutAnimation(boardRef: RefObject<HTMLDivElement | null>, cards: readonly CanvasCard[], camera: CanvasCamera, presentation: CanvasPresentation): void;
|