@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.
@@ -992,6 +992,7 @@ export declare const FRAME_EDGE_THICKNESS = 12;
992
992
  declare const FrameContainmentState: EditorStateDef< {
993
993
  state: StringFieldBuilder;
994
994
  highlightedFrame: RefFieldBuilder;
995
+ draggedEntity: RefFieldBuilder;
995
996
  }>;
996
997
  export { FrameContainmentState }
997
998
  export { FrameContainmentState as FrameContainmentState_alias_1 }
@@ -1067,7 +1068,9 @@ export { getFrameInput }
1067
1068
  export { getFrameInput as getFrameInput_alias_1 }
1068
1069
  export { getFrameInput as getFrameInput_alias_2 }
1069
1070
 
1070
- declare function getKeyboardInput(ctx: Context, keys: number[]): KeyboardInput[];
1071
+ declare function getKeyboardInput(ctx: Context, keys: number[], options?: {
1072
+ repeat?: boolean;
1073
+ }): KeyboardInput[];
1071
1074
  export { getKeyboardInput }
1072
1075
  export { getKeyboardInput as getKeyboardInput_alias_1 }
1073
1076
  export { getKeyboardInput as getKeyboardInput_alias_2 }
@@ -1417,6 +1420,7 @@ declare class KeyboardDef extends CanvasSingletonDef<typeof KeyboardSchema> {
1417
1420
  constructor();
1418
1421
  isKeyDown(ctx: Context, key: number): boolean;
1419
1422
  isKeyDownTrigger(ctx: Context, key: number): boolean;
1423
+ isKeyRepeatTrigger(ctx: Context, key: number): boolean;
1420
1424
  isKeyUpTrigger(ctx: Context, key: number): boolean;
1421
1425
  reset(ctx: Context): void;
1422
1426
  }
@@ -1438,6 +1442,7 @@ export { KeyboardInputType as KeyboardInputType_alias_2 }
1438
1442
  declare const KeyboardSchema: {
1439
1443
  keysDown: BufferFieldBuilder<"uint8">;
1440
1444
  keysDownTrigger: BufferFieldBuilder<"uint8">;
1445
+ keysRepeatTrigger: BufferFieldBuilder<"uint8">;
1441
1446
  keysUpTrigger: BufferFieldBuilder<"uint8">;
1442
1447
  shiftDown: BooleanFieldBuilder;
1443
1448
  altDown: BooleanFieldBuilder;
@@ -992,6 +992,7 @@ export declare const FRAME_EDGE_THICKNESS = 12;
992
992
  declare const FrameContainmentState: EditorStateDef< {
993
993
  state: StringFieldBuilder;
994
994
  highlightedFrame: RefFieldBuilder;
995
+ draggedEntity: RefFieldBuilder;
995
996
  }>;
996
997
  export { FrameContainmentState }
997
998
  export { FrameContainmentState as FrameContainmentState_alias_1 }
@@ -1067,7 +1068,9 @@ export { getFrameInput }
1067
1068
  export { getFrameInput as getFrameInput_alias_1 }
1068
1069
  export { getFrameInput as getFrameInput_alias_2 }
1069
1070
 
1070
- declare function getKeyboardInput(ctx: Context, keys: number[]): KeyboardInput[];
1071
+ declare function getKeyboardInput(ctx: Context, keys: number[], options?: {
1072
+ repeat?: boolean;
1073
+ }): KeyboardInput[];
1071
1074
  export { getKeyboardInput }
1072
1075
  export { getKeyboardInput as getKeyboardInput_alias_1 }
1073
1076
  export { getKeyboardInput as getKeyboardInput_alias_2 }
@@ -1417,6 +1420,7 @@ declare class KeyboardDef extends CanvasSingletonDef<typeof KeyboardSchema> {
1417
1420
  constructor();
1418
1421
  isKeyDown(ctx: Context, key: number): boolean;
1419
1422
  isKeyDownTrigger(ctx: Context, key: number): boolean;
1423
+ isKeyRepeatTrigger(ctx: Context, key: number): boolean;
1420
1424
  isKeyUpTrigger(ctx: Context, key: number): boolean;
1421
1425
  reset(ctx: Context): void;
1422
1426
  }
@@ -1438,6 +1442,7 @@ export { KeyboardInputType as KeyboardInputType_alias_2 }
1438
1442
  declare const KeyboardSchema: {
1439
1443
  keysDown: BufferFieldBuilder<"uint8">;
1440
1444
  keysDownTrigger: BufferFieldBuilder<"uint8">;
1445
+ keysRepeatTrigger: BufferFieldBuilder<"uint8">;
1441
1446
  keysUpTrigger: BufferFieldBuilder<"uint8">;
1442
1447
  shiftDown: BooleanFieldBuilder;
1443
1448
  altDown: BooleanFieldBuilder;
package/build/index.cjs CHANGED
@@ -1882,26 +1882,38 @@ var CursorKind = /* @__PURE__ */ ((CursorKind2) => {
1882
1882
  })(CursorKind || {});
1883
1883
  var DRAG_SVG = `
1884
1884
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 33.94 33.94">
1885
- <g fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
1886
- <path d="M25.46,14.14l2.83,2.83-2.83,2.83"/>
1887
- <path d="M19.8,16.97h8.49"/>
1888
- <path d="M8.49,19.8l-2.83-2.83,2.83-2.83"/>
1889
- <path d="M5.66,16.97h14.57"/>
1890
- <path d="M14.14,25.46l2.83,2.83,2.83-2.83"/>
1891
- <path d="M16.97,19.8v8.49"/>
1892
- <path d="M19.8,8.49l-2.83-2.83-2.83,2.83"/>
1893
- <path d="M16.97,5.66v15.14"/>
1885
+ <defs>
1886
+ <g id="a">
1887
+ <path d="M25.46,14.14l2.83,2.83-2.83,2.83"/>
1888
+ <path d="M19.8,16.97h8.49"/>
1889
+ <path d="M8.49,19.8l-2.83-2.83,2.83-2.83"/>
1890
+ <path d="M5.66,16.97h14.57"/>
1891
+ <path d="M14.14,25.46l2.83,2.83,2.83-2.83"/>
1892
+ <path d="M16.97,19.8v8.49"/>
1893
+ <path d="M19.8,8.49l-2.83-2.83-2.83,2.83"/>
1894
+ <path d="M16.97,5.66v15.14"/>
1895
+ </g>
1896
+ </defs>
1897
+ <g fill="none" stroke-linecap="round" stroke-linejoin="round">
1898
+ <use href="#a" stroke="#fff" stroke-width="4.5"/>
1899
+ <use href="#a" stroke="#000" stroke-width="2"/>
1894
1900
  </g>
1895
1901
  </svg>`;
1896
1902
  function makeResizeSvg(rotateZ) {
1897
1903
  const degrees = rotateZ * 180 / Math.PI;
1898
1904
  return `
1899
1905
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
1900
- fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1906
+ fill="none" stroke-linecap="round" stroke-linejoin="round">
1907
+ <defs>
1908
+ <g id="a">
1909
+ <path d="M8 7l4 -4l4 4"/>
1910
+ <path d="M8 17l4 4l4 -4"/>
1911
+ <path d="M12 3l0 18"/>
1912
+ </g>
1913
+ </defs>
1901
1914
  <g transform="rotate(${degrees} 12 12)">
1902
- <path d="M8 7l4 -4l4 4"/>
1903
- <path d="M8 17l4 4l4 -4"/>
1904
- <path d="M12 3l0 18"/>
1915
+ <use href="#a" stroke="#fff" stroke-width="4.5"/>
1916
+ <use href="#a" stroke="#000" stroke-width="2"/>
1905
1917
  </g>
1906
1918
  </svg>`;
1907
1919
  }
@@ -1909,11 +1921,17 @@ function makeRotateSvg(rotateZ) {
1909
1921
  const degrees = rotateZ * 180 / Math.PI;
1910
1922
  return `
1911
1923
  <svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="-10 -10 34 34"
1912
- fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
1924
+ fill="none" stroke-linecap="round" stroke-linejoin="round">
1925
+ <defs>
1926
+ <g id="a">
1927
+ <path d="M1,14.76l4,4,4-4"/>
1928
+ <path d="M14.61,1l4,4-4,4"/>
1929
+ <path d="M18.61,5h-6.02c-4.19,0-7.59,3.4-7.59,7.59v6.17"/>
1930
+ </g>
1931
+ </defs>
1913
1932
  <g transform="rotate(${degrees} 8 8)">
1914
- <path d="M1,14.76l4,4,4-4"/>
1915
- <path d="M14.61,1l4,4-4,4"/>
1916
- <path d="M18.61,5h-6.02c-4.19,0-7.59,3.4-7.59,7.59v6.17"/>
1933
+ <use href="#a" stroke="#fff" stroke-width="4.5"/>
1934
+ <use href="#a" stroke="#000" stroke-width="2"/>
1917
1935
  </g>
1918
1936
  </svg>`;
1919
1937
  }
@@ -2178,6 +2196,8 @@ var KeyboardSchema = {
2178
2196
  * Uses field.buffer for zero-allocation subarray views.
2179
2197
  */
2180
2198
  keysDownTrigger: import_core24.field.buffer(import_core24.field.uint8()).size(KEY_BUFFER_SIZE),
2199
+ /** Native key-repeat triggers, available separately from initial presses. */
2200
+ keysRepeatTrigger: import_core24.field.buffer(import_core24.field.uint8()).size(KEY_BUFFER_SIZE),
2181
2201
  /**
2182
2202
  * Buffer for key-up triggers (true for exactly 1 frame when key is released).
2183
2203
  * Uses field.buffer for zero-allocation subarray views.
@@ -2216,6 +2236,10 @@ var KeyboardDef = class extends import_canvas_store30.CanvasSingletonDef {
2216
2236
  isKeyDownTrigger(ctx, key) {
2217
2237
  return getBit(this.read(ctx).keysDownTrigger, key);
2218
2238
  }
2239
+ /** Check whether a native key-repeat event occurred this frame. */
2240
+ isKeyRepeatTrigger(ctx, key) {
2241
+ return getBit(this.read(ctx).keysRepeatTrigger, key);
2242
+ }
2219
2243
  /**
2220
2244
  * Check if a key was just released this frame.
2221
2245
  * @param ctx - Editor context
@@ -2232,6 +2256,7 @@ var KeyboardDef = class extends import_canvas_store30.CanvasSingletonDef {
2232
2256
  const keyboard = this.write(ctx);
2233
2257
  clearBits(keyboard.keysDown);
2234
2258
  clearBits(keyboard.keysDownTrigger);
2259
+ clearBits(keyboard.keysRepeatTrigger);
2235
2260
  clearBits(keyboard.keysUpTrigger);
2236
2261
  keyboard.shiftDown = false;
2237
2262
  keyboard.altDown = false;
@@ -2696,7 +2721,14 @@ var FrameContainmentState = defineEditorState("frameContainmentState", {
2696
2721
  /** Current state machine state */
2697
2722
  state: import_core27.field.string().max(16).default(FrameContainmentStateEnum.Idle),
2698
2723
  /** EntityId of the frame currently highlighted as a drop target, or null */
2699
- highlightedFrame: import_core27.field.ref()
2724
+ highlightedFrame: import_core27.field.ref(),
2725
+ /**
2726
+ * The entity being dragged while Tracking (a block, or the TransformBox for a
2727
+ * multi-select), captured on pointerMove. The selection machine has already
2728
+ * left Dragging by the time our pointerUp runs, so the drop fallback can't
2729
+ * re-read it from SelectionState.
2730
+ */
2731
+ draggedEntity: import_core27.field.ref()
2700
2732
  });
2701
2733
 
2702
2734
  // src/singletons/Grid.ts
@@ -3049,10 +3081,10 @@ function getFrameInput(ctx) {
3049
3081
  }
3050
3082
 
3051
3083
  // src/events/keyboardInputEvents.ts
3052
- function getKeyboardInput(ctx, keys) {
3084
+ function getKeyboardInput(ctx, keys, options = {}) {
3053
3085
  const events = [];
3054
3086
  for (const key of keys) {
3055
- if (Keyboard.isKeyDownTrigger(ctx, key)) {
3087
+ if (Keyboard.isKeyDownTrigger(ctx, key) || options.repeat && Keyboard.isKeyRepeatTrigger(ctx, key)) {
3056
3088
  events.push({ type: "keyDown", key, ctx });
3057
3089
  }
3058
3090
  if (Keyboard.isKeyUpTrigger(ctx, key)) {
@@ -3906,8 +3938,7 @@ function clearPointerTrackingState(ctx) {
3906
3938
 
3907
3939
  // src/systems/capture/captureFrameContainmentSystem.ts
3908
3940
  var selectedQuery2 = (0, import_core51.defineQuery)((q) => q.with(Block, Selected));
3909
- function spawnAssignments(ctx, targetFrame) {
3910
- const draggedEntity = getDraggedEntity(ctx);
3941
+ function spawnAssignments(ctx, draggedEntity, targetFrame) {
3911
3942
  if (draggedEntity === null) return;
3912
3943
  const assignments = [];
3913
3944
  if ((0, import_core51.hasComponent)(ctx, draggedEntity, TransformBox)) {
@@ -3955,25 +3986,44 @@ var frameContainmentMachine = (0, import_xstate2.setup)({
3955
3986
  if (targetFrame !== null) {
3956
3987
  AddFrameHighlight.spawn(ctx, { frameId: targetFrame });
3957
3988
  }
3958
- spawnAssignments(ctx, targetFrame);
3989
+ spawnAssignments(ctx, getDraggedEntity(ctx), targetFrame);
3959
3990
  }
3960
3991
  return targetFrame;
3961
- }
3992
+ },
3993
+ draggedEntity: ({ context, event }) => getDraggedEntity(event.ctx) ?? context.draggedEntity
3962
3994
  }),
3963
3995
  clearHighlight: ({ context, event }) => {
3964
3996
  if (context.highlightedFrame !== null) {
3965
3997
  RemoveFrameHighlight.spawn(event.ctx, { frameId: context.highlightedFrame });
3966
3998
  }
3967
3999
  },
4000
+ // Drop fallback. Tracking resolves the target frame from the CURSOR so the
4001
+ // highlight follows the hand, but a drag can release with the cursor off every
4002
+ // frame (the gutter between two pages, just past an edge) while the dragged
4003
+ // block itself still sits on one. Without this the block goes loose
4004
+ // (`parentId: null`) yet looks untouched — and anything that only renders a
4005
+ // frame's children (page captures / print) silently drops it. On pointerUp
4006
+ // with no cursor target, re-resolve by the dragged block's center — the same
4007
+ // rule paste and PlaceBlockEvent use — and parent it there.
4008
+ dropByCenter: ({ context, event }) => {
4009
+ if (context.highlightedFrame !== null) return;
4010
+ const ctx = event.ctx;
4011
+ const draggedEntity = context.draggedEntity;
4012
+ if (draggedEntity === null || !(0, import_core51.hasComponent)(ctx, draggedEntity, Block)) return;
4013
+ const targetFrame = findFrameAtPoint(ctx, Block.getCenter(ctx, draggedEntity), draggedEntity);
4014
+ if (targetFrame !== null) spawnAssignments(ctx, draggedEntity, targetFrame);
4015
+ },
3968
4016
  resetContext: (0, import_xstate2.assign)({
3969
- highlightedFrame: () => null
4017
+ highlightedFrame: () => null,
4018
+ draggedEntity: () => null
3970
4019
  })
3971
4020
  }
3972
4021
  }).createMachine({
3973
4022
  id: "frameContainment",
3974
4023
  initial: FrameContainmentStateEnum.Idle,
3975
4024
  context: {
3976
- highlightedFrame: null
4025
+ highlightedFrame: null,
4026
+ draggedEntity: null
3977
4027
  },
3978
4028
  states: {
3979
4029
  [FrameContainmentStateEnum.Idle]: {
@@ -3992,7 +4042,7 @@ var frameContainmentMachine = (0, import_xstate2.setup)({
3992
4042
  actions: "updateHighlight"
3993
4043
  },
3994
4044
  pointerUp: {
3995
- actions: "clearHighlight",
4045
+ actions: ["dropByCenter", "clearHighlight"],
3996
4046
  target: FrameContainmentStateEnum.Idle
3997
4047
  },
3998
4048
  cancel: {
@@ -4371,7 +4421,10 @@ function attachKeyboardListeners(domElement) {
4371
4421
  const state = {
4372
4422
  eventsBuffer: [],
4373
4423
  onKeyDown: (e) => {
4374
- if (e.key === "Tab" || e.key === "Alt" || e.key === " ") {
4424
+ if (e.defaultPrevented) return;
4425
+ if (e.target instanceof Element && e.target.closest('input, textarea, select, [contenteditable]:not([contenteditable="false"]), [role="textbox"]'))
4426
+ return;
4427
+ if (e.key === "Tab" || e.key === "Alt" || e.key === " " || e.code.startsWith("Arrow")) {
4375
4428
  e.preventDefault();
4376
4429
  }
4377
4430
  state.eventsBuffer.push(e);
@@ -4406,14 +4459,17 @@ var keyboardSystem = defineEditorSystem({ phase: "input" }, (ctx) => {
4406
4459
  });
4407
4460
  const hasEvents = state.eventsBuffer.length > 0;
4408
4461
  const keyboardRead = Keyboard.read(ctx);
4409
- const triggersNeedClearing = !isZeroed(keyboardRead.keysDownTrigger) || !isZeroed(keyboardRead.keysUpTrigger);
4462
+ const triggersNeedClearing = !isZeroed(keyboardRead.keysDownTrigger) || !isZeroed(keyboardRead.keysUpTrigger) || !isZeroed(keyboardRead.keysRepeatTrigger);
4410
4463
  if (!hasEvents && !triggersNeedClearing) return;
4411
4464
  const keyboard = Keyboard.write(ctx);
4412
4465
  clearBits(keyboard.keysDownTrigger);
4466
+ clearBits(keyboard.keysRepeatTrigger);
4413
4467
  clearBits(keyboard.keysUpTrigger);
4414
4468
  for (const event of state.eventsBuffer) {
4415
4469
  if (event.type === "blur") {
4416
4470
  clearBits(keyboard.keysDown);
4471
+ clearBits(keyboard.keysDownTrigger);
4472
+ clearBits(keyboard.keysRepeatTrigger);
4417
4473
  keyboard.shiftDown = false;
4418
4474
  keyboard.altDown = false;
4419
4475
  keyboard.modDown = false;
@@ -4426,6 +4482,7 @@ var keyboardSystem = defineEditorSystem({ phase: "input" }, (ctx) => {
4426
4482
  if (!wasDown || !event.repeat) {
4427
4483
  setBit(keyboard.keysDownTrigger, keyIndex, true);
4428
4484
  }
4485
+ if (event.repeat) setBit(keyboard.keysRepeatTrigger, keyIndex, true);
4429
4486
  setBit(keyboard.keysDown, keyIndex, true);
4430
4487
  } else if (event.type === "keyup") {
4431
4488
  setBit(keyboard.keysDown, keyIndex, false);