@statelyai/flow-dom 3.2.0 → 3.3.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.
@@ -145,6 +145,10 @@ type EntityRectTarget = {
145
145
  getRect: () => Rect | null;
146
146
  autoSize?: boolean;
147
147
  };
148
+ type EntityBoundsTarget = {
149
+ ids: readonly string[];
150
+ getRect: () => Rect | null;
151
+ };
148
152
  type EntityEdgeTarget = {
149
153
  id: string;
150
154
  getPathData: () => EdgePathData | null;
@@ -155,6 +159,7 @@ type EntityGeometryObserverOptions = FlowEntityChangeNotifierOptions & {
155
159
  };
156
160
  type EntityGeometryObserver = {
157
161
  observeRect(element: HTMLElement, target: EntityRectTarget): () => void;
162
+ observeBounds(element: HTMLElement, target: EntityBoundsTarget): () => void;
158
163
  observeEdge(element: SVGElement, target: EntityEdgeTarget): () => void;
159
164
  /** Flush pending writes synchronously. Primarily useful for deterministic hosts/tests. */
160
165
  flush(): void;
@@ -168,9 +173,9 @@ type EntityGeometryObserver = {
168
173
  declare function createEntityGeometryObserver(store: FlowStore, options?: EntityGeometryObserverOptions): EntityGeometryObserver;
169
174
  //#endregion
170
175
  //#region src/index.d.ts
171
- type ResolvedFlowColorMode = "light" | "dark";
172
- declare function resolveFlowColorMode(colorMode: FlowColorMode, targetWindow?: Pick<Window, "matchMedia"> | undefined): ResolvedFlowColorMode;
173
- declare function applyFlowColorMode(element: HTMLElement, colorMode: FlowColorMode, targetWindow?: Pick<Window, "matchMedia"> | undefined): ResolvedFlowColorMode;
176
+ type ResolvedFlowColorMode = 'light' | 'dark';
177
+ declare function resolveFlowColorMode(colorMode: FlowColorMode, targetWindow?: Pick<Window, 'matchMedia'> | undefined): ResolvedFlowColorMode;
178
+ declare function applyFlowColorMode(element: HTMLElement, colorMode: FlowColorMode, targetWindow?: Pick<Window, 'matchMedia'> | undefined): ResolvedFlowColorMode;
174
179
  type MeasurementTarget = {
175
180
  nodeId: string;
176
181
  } | {
@@ -196,7 +201,9 @@ declare function createMeasurementObserver(store: FlowStore, options?: Measureme
196
201
  declare function getAttachedContainer(store: FlowStore): Element | undefined;
197
202
  declare function clientToCanvas(store: FlowStore, point: Point, container?: Element | null | undefined): Point;
198
203
  declare function canvasToClient(store: FlowStore, point: Point, container?: Element | null | undefined): Point;
199
- declare function attachContainer(store: FlowStore, element: Element): () => void;
204
+ declare function attachContainer(store: FlowStore, element: Element, options?: {
205
+ preserveViewportCenter?: boolean;
206
+ }): () => void;
200
207
  type ViewportTransformOptions = {
201
208
  /** Idle delay (ms) before dropping the GPU-layer hint after interaction stops. */
202
209
  promoteIdleMs?: number;
@@ -213,7 +220,7 @@ type AttachInputOptions = {
213
220
  * Where keyboard events are listened for. Defaults to the flow container so
214
221
  * multiple flow instances do not all react to global Delete/undo/arrow keys.
215
222
  */
216
- keyboardTarget?: "window" | "container" | HTMLElement;
223
+ keyboardTarget?: 'window' | 'container' | HTMLElement;
217
224
  /**
218
225
  * Auto-pan policy, evaluated once per animation frame while a gesture
219
226
  * session holds the pointer near the container edge. Pass
@@ -222,7 +229,7 @@ type AttachInputOptions = {
222
229
  * returns a delta, the binder pans the viewport and re-sends the
223
230
  * stationary pointer so the dragged entity follows the canvas.
224
231
  */
225
- autoPan?: (context: ReturnType<FlowStore["getSnapshot"]>["context"], screenPoint: {
232
+ autoPan?: (context: ReturnType<FlowStore['getSnapshot']>['context'], screenPoint: {
226
233
  x: number;
227
234
  y: number;
228
235
  }) => {
@@ -232,4 +239,4 @@ type AttachInputOptions = {
232
239
  };
233
240
  declare function attachInput(options: AttachInputOptions): () => void;
234
241
  //#endregion
235
- export { AttachInputOptions, type ClipboardTransport, type ComputeRenderableIdsOptions, type EntityEdgeTarget, type EntityGeometryObserver, type EntityGeometryObserverOptions, type EntityRectTarget, FLOW_CONTENT_MIME, type FlowClipboard, type FlowImageExportOptions, type FlowImageExportResult, type FlowView, MeasurementObserver, MeasurementObserverOptions, MeasurementTarget, type NodePositionStyle, type RenderableIds, ResolvedFlowColorMode, type ViewportStyle, ViewportTransformOptions, applyFlowColorMode, attachContainer, attachInput, attachViewportTransform, canvasToClient, clientToCanvas, computeRenderableIds, createEntityGeometryObserver, createFlowClipboard, createFlowView, createMeasurementObserver, exportFlowImage, getAttachedContainer, nodePositionStyle, renderableIdsEqual, resolveFlowColorMode, viewportStyle };
242
+ export { AttachInputOptions, type ClipboardTransport, type ComputeRenderableIdsOptions, type EntityBoundsTarget, type EntityEdgeTarget, type EntityGeometryObserver, type EntityGeometryObserverOptions, type EntityRectTarget, FLOW_CONTENT_MIME, type FlowClipboard, type FlowImageExportOptions, type FlowImageExportResult, type FlowView, MeasurementObserver, MeasurementObserverOptions, MeasurementTarget, type NodePositionStyle, type RenderableIds, ResolvedFlowColorMode, type ViewportStyle, ViewportTransformOptions, applyFlowColorMode, attachContainer, attachInput, attachViewportTransform, canvasToClient, clientToCanvas, computeRenderableIds, createEntityGeometryObserver, createFlowClipboard, createFlowView, createMeasurementObserver, exportFlowImage, getAttachedContainer, nodePositionStyle, renderableIdsEqual, resolveFlowColorMode, viewportStyle };
package/dist/esm/index.js CHANGED
@@ -365,12 +365,15 @@ function createEntityGeometryObserver(store, options = {}) {
365
365
  for (const pendingObservation of current) pendingObservation.write();
366
366
  });
367
367
  };
368
- const observe = (id, write) => {
368
+ const observeIds = (ids, write) => {
369
369
  const observation = {
370
370
  write,
371
371
  unsubscribe: () => {}
372
372
  };
373
- observation.unsubscribe = getNotifier().subscribe(id, () => schedule(observation));
373
+ const unsubscribers = [...new Set(ids)].map((id) => getNotifier().subscribe(id, () => schedule(observation)));
374
+ observation.unsubscribe = () => {
375
+ for (const unsubscribe of unsubscribers) unsubscribe();
376
+ };
374
377
  observations.add(observation);
375
378
  write();
376
379
  return () => {
@@ -379,6 +382,7 @@ function createEntityGeometryObserver(store, options = {}) {
379
382
  pending.delete(observation);
380
383
  };
381
384
  };
385
+ const observe = (id, write) => observeIds([id], write);
382
386
  return {
383
387
  observeRect(element, target) {
384
388
  return observe(target.id, () => {
@@ -397,6 +401,18 @@ function createEntityGeometryObserver(store, options = {}) {
397
401
  else element.style.removeProperty("will-change");
398
402
  });
399
403
  },
404
+ observeBounds(element, target) {
405
+ return observeIds(target.ids, () => {
406
+ const rect = target.getRect();
407
+ if (!rect) return;
408
+ const context = store.getSnapshot().context;
409
+ element.style.transform = `translate(${rect.x}px, ${rect.y}px)`;
410
+ element.style.width = `${rect.width}px`;
411
+ element.style.height = `${rect.height}px`;
412
+ if (context.canvasState === "dragging" || context.canvasState === "resizing" || context.layoutAnimation.status === "running") element.style.willChange = "transform, width, height";
413
+ else element.style.removeProperty("will-change");
414
+ });
415
+ },
400
416
  observeEdge(element, target) {
401
417
  return observe(target.id, () => {
402
418
  const pathData = target.getPathData();
@@ -564,13 +580,14 @@ function canvasToClient(store, point, container = containers.get(store)) {
564
580
  y: point.y * viewport.zoom + viewport.y + (rect?.top ?? 0)
565
581
  };
566
582
  }
567
- function attachContainer(store, element) {
583
+ function attachContainer(store, element, options = {}) {
568
584
  containers.set(store, element);
569
585
  const update = () => {
570
586
  const rect = element.getBoundingClientRect();
571
587
  if (rect.width > 0 && rect.height > 0) store.trigger.updateViewportSize({
572
588
  width: rect.width,
573
- height: rect.height
589
+ height: rect.height,
590
+ preserveCenter: options.preserveViewportCenter
574
591
  });
575
592
  };
576
593
  update();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statelyai/flow-dom",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "DOM-specific helpers for @statelyai/flow with core re-exports.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "license": "MIT",
29
29
  "dependencies": {
30
- "@statelyai/flow": "0.5.0"
30
+ "@statelyai/flow": "0.7.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@vitest/coverage-v8": "^4.1.0",