@avocadostudio-ai/preview-adapter 0.18.0 → 0.19.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.
@@ -131,9 +131,10 @@ export function attachBridge(config) {
131
131
  const isStructural = msg.op?.op === "add_block" || msg.op?.op === "move_block";
132
132
  state.pendingScrollIntoView = isStructural || state.pendingScrollIntoView;
133
133
  }
134
- if (msg.op?.op === "move_item") {
135
- state.skipParentAnimationOnce = true;
136
- }
134
+ // Assigned, not merely set: a stale `true` from an earlier message would
135
+ // otherwise silence the next real arrival, because the flag is cleared
136
+ // only when a focus poll actually runs.
137
+ state.skipEnterAnimationOnce = msg.animate === false || msg.op?.op === "move_item";
137
138
  state.expectingNewBlocks = msg.op?.op === "add_block";
138
139
  bridge.smoothRefresh();
139
140
  emitPatchAck(msg.txId, true);
@@ -158,6 +159,10 @@ export function attachBridge(config) {
158
159
  // scrolled into view after the refresh (a newly added block is only in
159
160
  // the DOM now). Explicit so the other ~20 draftUpdated callers are unaffected.
160
161
  state.pendingScrollIntoView = msg.payload.scrollIntoView === true;
162
+ // Same contract as applyPatch: the sender says whether this is an
163
+ // arrival worth animating. Typed edits fall back to this path whenever
164
+ // the patch transport is off or its ack was dropped.
165
+ state.skipEnterAnimationOnce = msg.payload.animate === false;
161
166
  state.expectingNewBlocks = true;
162
167
  bridge.clearLiveDraft();
163
168
  clearChildFocus();
@@ -314,7 +314,21 @@ export type BridgeState = {
314
314
  } | null;
315
315
  suppressClickUntil: number;
316
316
  selectionMode: boolean;
317
- skipParentAnimationOnce: boolean;
317
+ /**
318
+ * Suppress the focused block's arrival animation for the next refresh only.
319
+ *
320
+ * `applyBlockFocus(id, enter)` normally greets the block it focuses: a
321
+ * `block-enter` keyframe from `opacity: 0`, a 600 ms border flash and a
322
+ * sparkle sweep. That reads as "here is the thing that changed" and is worth
323
+ * having when a block is added, or when the agent edits one.
324
+ *
325
+ * It is wrong whenever the block was already on screen and only its contents
326
+ * changed in place — moving a list item inside it, or the user typing into
327
+ * one of its fields. Then the animation fades out the very block the user is
328
+ * looking at, once per debounce commit, which is read as a flash. The editor
329
+ * says which case it is with `animate: false` on the message.
330
+ */
331
+ skipEnterAnimationOnce: boolean;
318
332
  deleteConfirmTimer: {
319
333
  current: number | null;
320
334
  };
@@ -783,7 +783,7 @@ export function createBridgeState() {
783
783
  pendingScrollRestore: null,
784
784
  suppressClickUntil: 0,
785
785
  selectionMode: false,
786
- skipParentAnimationOnce: false,
786
+ skipEnterAnimationOnce: false,
787
787
  deleteConfirmTimer: { current: null },
788
788
  pendingListItemMovePath: null,
789
789
  childSelectionLock: null,
@@ -1301,7 +1301,7 @@ export function createBridgeFunctions(state, callbacks, config) {
1301
1301
  const nextPath = `${group.listKey}[${targetIndex}]`;
1302
1302
  state.pendingListItemMovePath = nextPath;
1303
1303
  setChildSelectionLock({ blockId, listKey: group.listKey, index: targetIndex, position: targetPosition });
1304
- state.skipParentAnimationOnce = true;
1304
+ state.skipEnterAnimationOnce = true;
1305
1305
  state.selectedEditablePath = nextPath;
1306
1306
  state.selectedBlockId = blockId;
1307
1307
  setHoveredListItem(null);
@@ -1324,7 +1324,7 @@ export function createBridgeFunctions(state, callbacks, config) {
1324
1324
  const nextPath = `${group.listKey}[${targetIndex}]`;
1325
1325
  state.pendingListItemMovePath = nextPath;
1326
1326
  setChildSelectionLock({ blockId, listKey: group.listKey, index: targetIndex, position: targetPosition });
1327
- state.skipParentAnimationOnce = true;
1327
+ state.skipEnterAnimationOnce = true;
1328
1328
  state.selectedEditablePath = nextPath;
1329
1329
  state.selectedBlockId = blockId;
1330
1330
  setHoveredListItem(null);
@@ -1544,7 +1544,7 @@ export function createBridgeFunctions(state, callbacks, config) {
1544
1544
  return;
1545
1545
  let attempts = 0;
1546
1546
  const timer = window.setInterval(() => {
1547
- const shouldAnimate = !state.skipParentAnimationOnce;
1547
+ const shouldAnimate = !state.skipEnterAnimationOnce;
1548
1548
  const done = applyBlockFocus(targetId, shouldAnimate, undefined, { scrollIntoView: state.pendingScrollIntoView });
1549
1549
  attempts += 1;
1550
1550
  if (done || attempts >= 20) {
@@ -1552,7 +1552,7 @@ export function createBridgeFunctions(state, callbacks, config) {
1552
1552
  state.pendingFocusId = null;
1553
1553
  state.pendingScrollIntoView = false;
1554
1554
  state.pendingScrollAnchorY = null;
1555
- state.skipParentAnimationOnce = false;
1555
+ state.skipEnterAnimationOnce = false;
1556
1556
  }
1557
1557
  }, 45);
1558
1558
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avocadostudio-ai/preview-adapter",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "src/styles.css"
38
38
  ],
39
39
  "dependencies": {
40
- "@avocadostudio-ai/shared": "^0.18.0"
40
+ "@avocadostudio-ai/shared": "^0.19.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "next": ">=15.0.0",