@woven-canvas/core 1.0.15 → 1.2.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.
package/build/index.d.cts CHANGED
@@ -141,6 +141,7 @@ export { createBlock } from './_tsup-dts-rollup.cjs';
141
141
  export { deselectAll } from './_tsup-dts-rollup.cjs';
142
142
  export { deselectBlock } from './_tsup-dts-rollup.cjs';
143
143
  export { detectEmbedProvider } from './_tsup-dts-rollup.cjs';
144
+ export { filterRoots } from './_tsup-dts-rollup.cjs';
144
145
  export { findFrameAtPoint } from './_tsup-dts-rollup.cjs';
145
146
  export { generateUuidBySeed } from './_tsup-dts-rollup.cjs';
146
147
  export { getBlockDef } from './_tsup-dts-rollup.cjs';
package/build/index.d.ts CHANGED
@@ -141,6 +141,7 @@ export { createBlock } from './_tsup-dts-rollup.js';
141
141
  export { deselectAll } from './_tsup-dts-rollup.js';
142
142
  export { deselectBlock } from './_tsup-dts-rollup.js';
143
143
  export { detectEmbedProvider } from './_tsup-dts-rollup.js';
144
+ export { filterRoots } from './_tsup-dts-rollup.js';
144
145
  export { findFrameAtPoint } from './_tsup-dts-rollup.js';
145
146
  export { generateUuidBySeed } from './_tsup-dts-rollup.js';
146
147
  export { getBlockDef } from './_tsup-dts-rollup.js';
package/build/index.js CHANGED
@@ -483,6 +483,7 @@ var BlockDef = z.object({
483
483
  canScale: z.boolean().default(true),
484
484
  snappable: z.boolean().default(true),
485
485
  interactable: z.boolean().default(true),
486
+ showOperations: z.boolean().default(true),
486
487
  excludeFromRankBounds: z.boolean().default(false),
487
488
  connectors: BlockDefConnectors.default(BlockDefConnectors.parse({}))
488
489
  });
@@ -2694,6 +2695,8 @@ var MouseSchema = {
2694
2695
  * wheel events with ctrlKey set.
2695
2696
  */
2696
2697
  wheelModKey: field30.boolean().default(false),
2698
+ /** Shift key was held during this frame's wheel event */
2699
+ wheelShiftKey: field30.boolean().default(false),
2697
2700
  /** True for 1 frame when mouse enters the editor element */
2698
2701
  enterTrigger: field30.boolean().default(false),
2699
2702
  /** True for 1 frame when mouse leaves the editor element */
@@ -2914,7 +2917,8 @@ function getMouseInput(ctx) {
2914
2917
  worldPosition: worldPos,
2915
2918
  wheelDeltaX: mouse.wheelDeltaX,
2916
2919
  wheelDeltaY: mouse.wheelDeltaY,
2917
- wheelModKey: mouse.wheelModKey
2920
+ wheelModKey: mouse.wheelModKey,
2921
+ wheelShiftKey: mouse.wheelShiftKey
2918
2922
  });
2919
2923
  }
2920
2924
  if (mouse.moveTrigger) {
@@ -2925,7 +2929,8 @@ function getMouseInput(ctx) {
2925
2929
  worldPosition: worldPos,
2926
2930
  wheelDeltaX: 0,
2927
2931
  wheelDeltaY: 0,
2928
- wheelModKey: false
2932
+ wheelModKey: false,
2933
+ wheelShiftKey: false
2929
2934
  });
2930
2935
  }
2931
2936
  return events;
@@ -3165,6 +3170,21 @@ function getDescendants(ctx, parentId) {
3165
3170
  }
3166
3171
  return result;
3167
3172
  }
3173
+ function filterRoots(ctx, entityIds) {
3174
+ const idSet = new Set(entityIds);
3175
+ return entityIds.filter((entityId) => {
3176
+ if (!hasComponent3(ctx, entityId, Block)) return false;
3177
+ let current = Block.read(ctx, entityId).parentId;
3178
+ const visited = /* @__PURE__ */ new Set();
3179
+ while (current !== null && hasComponent3(ctx, current, Block)) {
3180
+ if (idSet.has(current)) return false;
3181
+ if (visited.has(current)) break;
3182
+ visited.add(current);
3183
+ current = Block.read(ctx, current).parentId;
3184
+ }
3185
+ return true;
3186
+ });
3187
+ }
3168
3188
  function cascadeDelete(ctx, entityId) {
3169
3189
  const children = getBackrefs(ctx, entityId, Block, "parentId");
3170
3190
  for (const childId of children) {
@@ -4325,7 +4345,8 @@ function attachMouseListeners(domElement) {
4325
4345
  deltaMode: e.deltaMode,
4326
4346
  // Trackpad pinch gestures arrive as wheel events with ctrlKey set,
4327
4347
  // without any keydown — capture the flags from the event itself.
4328
- modKey: e.ctrlKey || e.metaKey
4348
+ modKey: e.ctrlKey || e.metaKey,
4349
+ shiftKey: e.shiftKey
4329
4350
  });
4330
4351
  },
4331
4352
  onMouseEnter: () => {
@@ -4368,6 +4389,7 @@ var mouseSystem = defineEditorSystem({ phase: "input" }, (ctx) => {
4368
4389
  mouse.wheelDeltaX = 0;
4369
4390
  mouse.wheelDeltaY = 0;
4370
4391
  mouse.wheelModKey = false;
4392
+ mouse.wheelShiftKey = false;
4371
4393
  for (const event of state.eventsBuffer) {
4372
4394
  switch (event.type) {
4373
4395
  case "mousemove":
@@ -4380,6 +4402,7 @@ var mouseSystem = defineEditorSystem({ phase: "input" }, (ctx) => {
4380
4402
  mouse.wheelDeltaY = normalizeWheelDelta(event.deltaY, event.deltaMode);
4381
4403
  mouse.wheelTrigger = true;
4382
4404
  mouse.wheelModKey = event.modKey === true;
4405
+ mouse.wheelShiftKey = event.shiftKey === true;
4383
4406
  break;
4384
4407
  case "mouseenter":
4385
4408
  mouse.enterTrigger = true;
@@ -5799,6 +5822,7 @@ var blockSystem = defineEditorSystem({ phase: "update" }, (ctx) => {
5799
5822
  }
5800
5823
  }
5801
5824
  });
5825
+ on(ctx, DuplicateSelected, duplicateSelected);
5802
5826
  on(ctx, BringForwardSelected, bringForwardSelected);
5803
5827
  on(ctx, SendBackwardSelected, sendBackwardSelected);
5804
5828
  on(ctx, SetCursor, (ctx2, payload) => {
@@ -5824,6 +5848,23 @@ function deselectAllBlocks(ctx) {
5824
5848
  deselectBlock(ctx, entityId);
5825
5849
  }
5826
5850
  }
5851
+ var DUPLICATE_OFFSET = 20;
5852
+ function duplicateSelected(ctx) {
5853
+ const selectedBlocks = [...selectedBlocksQuery4.current(ctx)];
5854
+ if (selectedBlocks.length === 0) return;
5855
+ cloneEntities(ctx, selectedBlocks, [0, 0], crypto.randomUUID());
5856
+ const grid = Grid.read(ctx);
5857
+ const offset = grid.enabled && grid.colWidth > 0 && grid.rowHeight > 0 ? [grid.colWidth, grid.rowHeight] : [DUPLICATE_OFFSET, DUPLICATE_OFFSET];
5858
+ for (const entityId of filterRoots(ctx, selectedBlocks)) {
5859
+ const worldPos = Block.getWorldPosition(ctx, entityId);
5860
+ Vec25.add(worldPos, offset);
5861
+ Block.setWorldPosition(ctx, entityId, worldPos);
5862
+ }
5863
+ const { transformBoxId } = TransformBoxStateSingleton.read(ctx);
5864
+ if (transformBoxId !== null) {
5865
+ UpdateTransformBox.spawn(ctx, { transformBoxId });
5866
+ }
5867
+ }
5827
5868
  function bringForwardSelected(ctx) {
5828
5869
  const selectedBlocks = [...selectedBlocksQuery4.current(ctx)];
5829
5870
  if (selectedBlocks.length === 0) return;
@@ -5861,7 +5902,6 @@ function sendBackwardSelected(ctx) {
5861
5902
  }
5862
5903
  }
5863
5904
  function cloneEntities(ctx, entityIds, offset, seed) {
5864
- const rootSet = new Set(entityIds);
5865
5905
  const allEntityIdsSet = new Set(entityIds);
5866
5906
  for (const entityId of entityIds) {
5867
5907
  for (const descendant of getDescendants(ctx, entityId)) {
@@ -5869,6 +5909,7 @@ function cloneEntities(ctx, entityIds, offset, seed) {
5869
5909
  }
5870
5910
  }
5871
5911
  entityIds = [...allEntityIdsSet];
5912
+ const rootSet = new Set(filterRoots(ctx, entityIds));
5872
5913
  const { componentsById } = getResources13(ctx);
5873
5914
  const documentComponents = new Map([...componentsById].filter(([, def]) => def.sync === "document"));
5874
5915
  const syncedComponentId = Synced7._getComponentId(ctx);
@@ -7283,6 +7324,7 @@ export {
7283
7324
  deselectBlock,
7284
7325
  detectEmbedProvider,
7285
7326
  field37 as field,
7327
+ filterRoots,
7286
7328
  findFrameAtPoint,
7287
7329
  generateUuidBySeed,
7288
7330
  getBackrefs5 as getBackrefs,