@woven-canvas/core 1.3.1 → 1.3.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/build/index.js CHANGED
@@ -1723,26 +1723,38 @@ var CursorKind = /* @__PURE__ */ ((CursorKind2) => {
1723
1723
  })(CursorKind || {});
1724
1724
  var DRAG_SVG = `
1725
1725
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 33.94 33.94">
1726
- <g fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
1727
- <path d="M25.46,14.14l2.83,2.83-2.83,2.83"/>
1728
- <path d="M19.8,16.97h8.49"/>
1729
- <path d="M8.49,19.8l-2.83-2.83,2.83-2.83"/>
1730
- <path d="M5.66,16.97h14.57"/>
1731
- <path d="M14.14,25.46l2.83,2.83,2.83-2.83"/>
1732
- <path d="M16.97,19.8v8.49"/>
1733
- <path d="M19.8,8.49l-2.83-2.83-2.83,2.83"/>
1734
- <path d="M16.97,5.66v15.14"/>
1726
+ <defs>
1727
+ <g id="a">
1728
+ <path d="M25.46,14.14l2.83,2.83-2.83,2.83"/>
1729
+ <path d="M19.8,16.97h8.49"/>
1730
+ <path d="M8.49,19.8l-2.83-2.83,2.83-2.83"/>
1731
+ <path d="M5.66,16.97h14.57"/>
1732
+ <path d="M14.14,25.46l2.83,2.83,2.83-2.83"/>
1733
+ <path d="M16.97,19.8v8.49"/>
1734
+ <path d="M19.8,8.49l-2.83-2.83-2.83,2.83"/>
1735
+ <path d="M16.97,5.66v15.14"/>
1736
+ </g>
1737
+ </defs>
1738
+ <g fill="none" stroke-linecap="round" stroke-linejoin="round">
1739
+ <use href="#a" stroke="#fff" stroke-width="4.5"/>
1740
+ <use href="#a" stroke="#000" stroke-width="2"/>
1735
1741
  </g>
1736
1742
  </svg>`;
1737
1743
  function makeResizeSvg(rotateZ) {
1738
1744
  const degrees = rotateZ * 180 / Math.PI;
1739
1745
  return `
1740
1746
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
1741
- fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1747
+ fill="none" stroke-linecap="round" stroke-linejoin="round">
1748
+ <defs>
1749
+ <g id="a">
1750
+ <path d="M8 7l4 -4l4 4"/>
1751
+ <path d="M8 17l4 4l4 -4"/>
1752
+ <path d="M12 3l0 18"/>
1753
+ </g>
1754
+ </defs>
1742
1755
  <g transform="rotate(${degrees} 12 12)">
1743
- <path d="M8 7l4 -4l4 4"/>
1744
- <path d="M8 17l4 4l4 -4"/>
1745
- <path d="M12 3l0 18"/>
1756
+ <use href="#a" stroke="#fff" stroke-width="4.5"/>
1757
+ <use href="#a" stroke="#000" stroke-width="2"/>
1746
1758
  </g>
1747
1759
  </svg>`;
1748
1760
  }
@@ -1750,11 +1762,17 @@ function makeRotateSvg(rotateZ) {
1750
1762
  const degrees = rotateZ * 180 / Math.PI;
1751
1763
  return `
1752
1764
  <svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="-10 -10 34 34"
1753
- fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
1765
+ fill="none" stroke-linecap="round" stroke-linejoin="round">
1766
+ <defs>
1767
+ <g id="a">
1768
+ <path d="M1,14.76l4,4,4-4"/>
1769
+ <path d="M14.61,1l4,4-4,4"/>
1770
+ <path d="M18.61,5h-6.02c-4.19,0-7.59,3.4-7.59,7.59v6.17"/>
1771
+ </g>
1772
+ </defs>
1754
1773
  <g transform="rotate(${degrees} 8 8)">
1755
- <path d="M1,14.76l4,4,4-4"/>
1756
- <path d="M14.61,1l4,4-4,4"/>
1757
- <path d="M18.61,5h-6.02c-4.19,0-7.59,3.4-7.59,7.59v6.17"/>
1774
+ <use href="#a" stroke="#fff" stroke-width="4.5"/>
1775
+ <use href="#a" stroke="#000" stroke-width="2"/>
1758
1776
  </g>
1759
1777
  </svg>`;
1760
1778
  }
@@ -2019,6 +2037,8 @@ var KeyboardSchema = {
2019
2037
  * Uses field.buffer for zero-allocation subarray views.
2020
2038
  */
2021
2039
  keysDownTrigger: field24.buffer(field24.uint8()).size(KEY_BUFFER_SIZE),
2040
+ /** Native key-repeat triggers, available separately from initial presses. */
2041
+ keysRepeatTrigger: field24.buffer(field24.uint8()).size(KEY_BUFFER_SIZE),
2022
2042
  /**
2023
2043
  * Buffer for key-up triggers (true for exactly 1 frame when key is released).
2024
2044
  * Uses field.buffer for zero-allocation subarray views.
@@ -2057,6 +2077,10 @@ var KeyboardDef = class extends CanvasSingletonDef3 {
2057
2077
  isKeyDownTrigger(ctx, key) {
2058
2078
  return getBit(this.read(ctx).keysDownTrigger, key);
2059
2079
  }
2080
+ /** Check whether a native key-repeat event occurred this frame. */
2081
+ isKeyRepeatTrigger(ctx, key) {
2082
+ return getBit(this.read(ctx).keysRepeatTrigger, key);
2083
+ }
2060
2084
  /**
2061
2085
  * Check if a key was just released this frame.
2062
2086
  * @param ctx - Editor context
@@ -2073,6 +2097,7 @@ var KeyboardDef = class extends CanvasSingletonDef3 {
2073
2097
  const keyboard = this.write(ctx);
2074
2098
  clearBits(keyboard.keysDown);
2075
2099
  clearBits(keyboard.keysDownTrigger);
2100
+ clearBits(keyboard.keysRepeatTrigger);
2076
2101
  clearBits(keyboard.keysUpTrigger);
2077
2102
  keyboard.shiftDown = false;
2078
2103
  keyboard.altDown = false;
@@ -2537,7 +2562,14 @@ var FrameContainmentState = defineEditorState("frameContainmentState", {
2537
2562
  /** Current state machine state */
2538
2563
  state: field27.string().max(16).default(FrameContainmentStateEnum.Idle),
2539
2564
  /** EntityId of the frame currently highlighted as a drop target, or null */
2540
- highlightedFrame: field27.ref()
2565
+ highlightedFrame: field27.ref(),
2566
+ /**
2567
+ * The entity being dragged while Tracking (a block, or the TransformBox for a
2568
+ * multi-select), captured on pointerMove. The selection machine has already
2569
+ * left Dragging by the time our pointerUp runs, so the drop fallback can't
2570
+ * re-read it from SelectionState.
2571
+ */
2572
+ draggedEntity: field27.ref()
2541
2573
  });
2542
2574
 
2543
2575
  // src/singletons/Grid.ts
@@ -2890,10 +2922,10 @@ function getFrameInput(ctx) {
2890
2922
  }
2891
2923
 
2892
2924
  // src/events/keyboardInputEvents.ts
2893
- function getKeyboardInput(ctx, keys) {
2925
+ function getKeyboardInput(ctx, keys, options = {}) {
2894
2926
  const events = [];
2895
2927
  for (const key of keys) {
2896
- if (Keyboard.isKeyDownTrigger(ctx, key)) {
2928
+ if (Keyboard.isKeyDownTrigger(ctx, key) || options.repeat && Keyboard.isKeyRepeatTrigger(ctx, key)) {
2897
2929
  events.push({ type: "keyDown", key, ctx });
2898
2930
  }
2899
2931
  if (Keyboard.isKeyUpTrigger(ctx, key)) {
@@ -3753,8 +3785,7 @@ function clearPointerTrackingState(ctx) {
3753
3785
 
3754
3786
  // src/systems/capture/captureFrameContainmentSystem.ts
3755
3787
  var selectedQuery2 = defineQuery7((q) => q.with(Block, Selected));
3756
- function spawnAssignments(ctx, targetFrame) {
3757
- const draggedEntity = getDraggedEntity(ctx);
3788
+ function spawnAssignments(ctx, draggedEntity, targetFrame) {
3758
3789
  if (draggedEntity === null) return;
3759
3790
  const assignments = [];
3760
3791
  if (hasComponent11(ctx, draggedEntity, TransformBox)) {
@@ -3802,25 +3833,44 @@ var frameContainmentMachine = setup({
3802
3833
  if (targetFrame !== null) {
3803
3834
  AddFrameHighlight.spawn(ctx, { frameId: targetFrame });
3804
3835
  }
3805
- spawnAssignments(ctx, targetFrame);
3836
+ spawnAssignments(ctx, getDraggedEntity(ctx), targetFrame);
3806
3837
  }
3807
3838
  return targetFrame;
3808
- }
3839
+ },
3840
+ draggedEntity: ({ context, event }) => getDraggedEntity(event.ctx) ?? context.draggedEntity
3809
3841
  }),
3810
3842
  clearHighlight: ({ context, event }) => {
3811
3843
  if (context.highlightedFrame !== null) {
3812
3844
  RemoveFrameHighlight.spawn(event.ctx, { frameId: context.highlightedFrame });
3813
3845
  }
3814
3846
  },
3847
+ // Drop fallback. Tracking resolves the target frame from the CURSOR so the
3848
+ // highlight follows the hand, but a drag can release with the cursor off every
3849
+ // frame (the gutter between two pages, just past an edge) while the dragged
3850
+ // block itself still sits on one. Without this the block goes loose
3851
+ // (`parentId: null`) yet looks untouched — and anything that only renders a
3852
+ // frame's children (page captures / print) silently drops it. On pointerUp
3853
+ // with no cursor target, re-resolve by the dragged block's center — the same
3854
+ // rule paste and PlaceBlockEvent use — and parent it there.
3855
+ dropByCenter: ({ context, event }) => {
3856
+ if (context.highlightedFrame !== null) return;
3857
+ const ctx = event.ctx;
3858
+ const draggedEntity = context.draggedEntity;
3859
+ if (draggedEntity === null || !hasComponent11(ctx, draggedEntity, Block)) return;
3860
+ const targetFrame = findFrameAtPoint(ctx, Block.getCenter(ctx, draggedEntity), draggedEntity);
3861
+ if (targetFrame !== null) spawnAssignments(ctx, draggedEntity, targetFrame);
3862
+ },
3815
3863
  resetContext: assign({
3816
- highlightedFrame: () => null
3864
+ highlightedFrame: () => null,
3865
+ draggedEntity: () => null
3817
3866
  })
3818
3867
  }
3819
3868
  }).createMachine({
3820
3869
  id: "frameContainment",
3821
3870
  initial: FrameContainmentStateEnum.Idle,
3822
3871
  context: {
3823
- highlightedFrame: null
3872
+ highlightedFrame: null,
3873
+ draggedEntity: null
3824
3874
  },
3825
3875
  states: {
3826
3876
  [FrameContainmentStateEnum.Idle]: {
@@ -3839,7 +3889,7 @@ var frameContainmentMachine = setup({
3839
3889
  actions: "updateHighlight"
3840
3890
  },
3841
3891
  pointerUp: {
3842
- actions: "clearHighlight",
3892
+ actions: ["dropByCenter", "clearHighlight"],
3843
3893
  target: FrameContainmentStateEnum.Idle
3844
3894
  },
3845
3895
  cancel: {
@@ -4218,7 +4268,10 @@ function attachKeyboardListeners(domElement) {
4218
4268
  const state = {
4219
4269
  eventsBuffer: [],
4220
4270
  onKeyDown: (e) => {
4221
- if (e.key === "Tab" || e.key === "Alt" || e.key === " ") {
4271
+ if (e.defaultPrevented) return;
4272
+ if (e.target instanceof Element && e.target.closest('input, textarea, select, [contenteditable]:not([contenteditable="false"]), [role="textbox"]'))
4273
+ return;
4274
+ if (e.key === "Tab" || e.key === "Alt" || e.key === " " || e.code.startsWith("Arrow")) {
4222
4275
  e.preventDefault();
4223
4276
  }
4224
4277
  state.eventsBuffer.push(e);
@@ -4253,14 +4306,17 @@ var keyboardSystem = defineEditorSystem({ phase: "input" }, (ctx) => {
4253
4306
  });
4254
4307
  const hasEvents = state.eventsBuffer.length > 0;
4255
4308
  const keyboardRead = Keyboard.read(ctx);
4256
- const triggersNeedClearing = !isZeroed(keyboardRead.keysDownTrigger) || !isZeroed(keyboardRead.keysUpTrigger);
4309
+ const triggersNeedClearing = !isZeroed(keyboardRead.keysDownTrigger) || !isZeroed(keyboardRead.keysUpTrigger) || !isZeroed(keyboardRead.keysRepeatTrigger);
4257
4310
  if (!hasEvents && !triggersNeedClearing) return;
4258
4311
  const keyboard = Keyboard.write(ctx);
4259
4312
  clearBits(keyboard.keysDownTrigger);
4313
+ clearBits(keyboard.keysRepeatTrigger);
4260
4314
  clearBits(keyboard.keysUpTrigger);
4261
4315
  for (const event of state.eventsBuffer) {
4262
4316
  if (event.type === "blur") {
4263
4317
  clearBits(keyboard.keysDown);
4318
+ clearBits(keyboard.keysDownTrigger);
4319
+ clearBits(keyboard.keysRepeatTrigger);
4264
4320
  keyboard.shiftDown = false;
4265
4321
  keyboard.altDown = false;
4266
4322
  keyboard.modDown = false;
@@ -4273,6 +4329,7 @@ var keyboardSystem = defineEditorSystem({ phase: "input" }, (ctx) => {
4273
4329
  if (!wasDown || !event.repeat) {
4274
4330
  setBit(keyboard.keysDownTrigger, keyIndex, true);
4275
4331
  }
4332
+ if (event.repeat) setBit(keyboard.keysRepeatTrigger, keyIndex, true);
4276
4333
  setBit(keyboard.keysDown, keyIndex, true);
4277
4334
  } else if (event.type === "keyup") {
4278
4335
  setBit(keyboard.keysDown, keyIndex, false);