@fulate/core 1.0.12 → 1.0.13

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/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { ChangeImpact, NodeProperties, resolveOrigin, TransformProperties } from
8
8
  export type { OriginX, OriginY, PropertyChanges, PropertyUpdates, TransformableOptions } from "./node/properties";
9
9
  export { Element, ElementProperties } from "./node/element";
10
10
  export type { AnyElement, BaseElementOption, ElementJSON, ElementOptionPatch, AnimateOptions, AnimateTarget } from "./node/element";
11
- export { isReparentTransformIntent, resolveAuthoredGeometryFramePatch, resolveReferenceTransform, resolveReferenceTransformTarget } from "./node/reference-transform";
11
+ export { isReparentTransformIntent, resolveAuthoredGeometryFramePatch, resolveReferenceBoundsTranslation, resolveReferenceTransform, resolveReferenceTransformTarget } from "./node/reference-transform";
12
12
  export type { ElementTransformBaseline, ReferenceTransformBaseline, ReferenceTransformFrame, ReferenceTransformResolution, ReferenceTransformTarget, ReparentTransformIntent, TransformIntent } from "./node/reference-transform";
13
13
  export { DEFAULT_CONNECTION_PORT_SCHEMA, getElementConnectionPort, getElementConnectionPortPoint, getElementConnectionPortPoints, projectConnectionPortPoint } from "./utils/connection-port";
14
14
  export type { ConnectionPortId, ConnectionPortConfiguration, ConnectionPortDefinition, ConnectionPortLabelStyle, ConnectionPortDirection, ConnectionPortLimit, ConnectionPortLimits, ConnectionPortRef, DerivedConnectionPort, EdgeConnectionPortPosition, ResolvedConnectionPort, ResolvedConnectionPortSlot } from "./utils/connection-port";
@@ -25,6 +25,7 @@ export { FrameStabilizationError, RootFrameRuntime } from "./root/frame-runtime"
25
25
  export type { RootFrameCompletionWork, RootFrameLayoutOwner, RootFrameParticipant } from "./root/frame-runtime";
26
26
  export { SceneRegistry } from "./root/scene-registry";
27
27
  export type { NodeKeyObserver, NodeRegistrationObserver, SceneChangeObserver } from "./root/scene-registry";
28
+ export { mergeOwnerPropertyChanges } from "./mutation/change-batch";
28
29
  export type { ChangeHistorySink, OwnerPropertyChange, StructureChange } from "./mutation/change-batch";
29
30
  export { Layer, LayerProperties, LayerTransform } from "./layer/index";
30
31
  export type { LayerFrameWork, LayerOption, LayerOptionPatch } from "./layer/index";
package/dist/index.js CHANGED
@@ -3277,6 +3277,11 @@ var Element = class Element extends Node {
3277
3277
  /** @internal 在全部 owner/tree 安装及 lifecycle 后运行 owner hook。 */
3278
3278
  runPropertyCommitHook(commit) {
3279
3279
  if (commit.update.changes.size) this.onPropertiesChanged(this.propertyState, commit.update.changes);
3280
+ if (commit.update.source === "configured" && this.onConfiguredPropertiesChanged) {
3281
+ const keys = [];
3282
+ for (const field of commit.update.fields) if (field.sourceChanged) keys.push(field.key);
3283
+ if (keys.length) this.onConfiguredPropertiesChanged(keys);
3284
+ }
3280
3285
  }
3281
3286
  /** @internal 在 owner hook 后通知依赖实际 Ports commit 的框架消费者。 */
3282
3287
  notifyPortsCommit(commit) {
@@ -3494,22 +3499,13 @@ var Element = class Element extends Node {
3494
3499
  origin: "builtin"
3495
3500
  };
3496
3501
  }
3497
- /** @internal 按给定 whole-value 解析 Port replacement 的最终投影。 */
3498
- resolveConnectionPorts(ports) {
3499
- if (ports === false) return EMPTY_CONNECTION_PORTS;
3500
- if (ports !== true) return resolveConnectionPortSlots(this, ports);
3501
- return (this.getDefaultConnectionPortSchema() ?? DEFAULT_CONNECTION_PORT_SCHEMA).map((port) => ({
3502
- ref: {
3503
- elementKey: this.key,
3504
- portId: port.id
3505
- },
3506
- kind: "endpoint-binding",
3507
- localPosition: port.localPosition(this),
3508
- origin: "builtin"
3509
- }));
3502
+ /** @internal 只解释显式 Port replacement IDs;patch 是同批最终 owner fields。 */
3503
+ resolveConnectionPortIds(ports, patch) {
3504
+ if (ports === false) return [];
3505
+ return (ports === true ? this.getDefaultConnectionPortSchema(patch) ?? DEFAULT_CONNECTION_PORT_SCHEMA : ports).map(({ id }) => id);
3510
3506
  }
3511
3507
  /** 返回元素类型自有的默认 Port;`null` 使用通用四边 Ports。 */
3512
- getDefaultConnectionPortSchema() {
3508
+ getDefaultConnectionPortSchema(_patch) {
3513
3509
  return null;
3514
3510
  }
3515
3511
  /** 返回 custom Ports 的当前 decoration slots。 @internal */
@@ -3552,11 +3548,18 @@ var Element = class Element extends Node {
3552
3548
  edgeLength: edge === "top" || edge === "bottom" ? Math.abs(this.width ?? 0) : Math.abs(this.height ?? 0)
3553
3549
  };
3554
3550
  }
3555
- /** @internal 一次借用 owner 当前 configured source 的指定字段。 */
3551
+ /**
3552
+ * 将当前配置值填入 caller 提供的 value cells,保留结构化值的原引用。
3553
+ * 读取包含默认值的 configured 结果,不读取 runtime 覆盖;保留 null/undefined。
3554
+ * cells 可复用;借用值不得原地修改并期待自动提交,需要独立值时由 caller 复制。
3555
+ */
3556
3556
  static readConfiguredPropertyValues(owner, targets) {
3557
3557
  readConfiguredPropertyValues(owner.propertyState, targets);
3558
3558
  }
3559
- /** @internal 借用 owner 当前 configured source 的单个字段。 */
3559
+ /**
3560
+ * 借用当前字段的 configured/default 值,忽略 runtime 覆盖,保留 null/undefined。
3561
+ * 返回结构化原引用,不表示该字段是否曾被显式配置;需要独立值时由 caller 复制。
3562
+ */
3560
3563
  static getConfiguredPropertyValue(owner, key) {
3561
3564
  return getConfiguredPropertyValue(owner.propertyState, key);
3562
3565
  }
@@ -3804,19 +3807,31 @@ function resolveBakedAuthoredGeometryTransform(baseline, target) {
3804
3807
  function resolveAuthoredGeometryFramePatch(baseline, resolution, authoredBounds) {
3805
3808
  if (isIdentityMatrix(resolution.authoredLocalDelta)) return resolution.framePatch;
3806
3809
  const approximateBounds = transformReferenceBounds(baseline.referenceBounds, resolution.authoredLocalDelta);
3807
- const originX = resolveOrigin(baseline.frame.originX) + .5;
3808
- const originY = resolveOrigin(baseline.frame.originY) + .5;
3809
- const approximateOffsetX = approximateBounds.left + originX * approximateBounds.width;
3810
- const approximateOffsetY = approximateBounds.top + originY * approximateBounds.height;
3811
- const authoredOffsetX = authoredBounds.left + originX * authoredBounds.width;
3812
- const authoredOffsetY = authoredBounds.top + originY * authoredBounds.height;
3813
- const deltaX = authoredOffsetX - approximateOffsetX;
3814
- const deltaY = authoredOffsetY - approximateOffsetY;
3815
- const frameLinear = createFrameLinearMatrix(baseline.frame);
3816
3810
  return {
3817
3811
  ...resolution.framePatch,
3818
- left: (resolution.framePatch.left ?? baseline.frame.left) + -deltaX + frameLinear.a * deltaX + frameLinear.c * deltaY,
3819
- top: (resolution.framePatch.top ?? baseline.frame.top) + -deltaY + frameLinear.b * deltaX + frameLinear.d * deltaY
3812
+ ...resolveReferenceBoundsTranslation({
3813
+ ...baseline.frame,
3814
+ ...resolution.framePatch
3815
+ }, approximateBounds, authoredBounds)
3816
+ };
3817
+ }
3818
+ /** @internal reference bounds 改变时修正 origin 位移,保留给定最终 frame 的仿射。 */
3819
+ function resolveReferenceBoundsTranslation(frame, before, after) {
3820
+ const { left = 0, top = 0, angle = 0, skewX = 0, skewY = 0, scaleX = 1, scaleY = 1, originX = "center", originY = "center" } = frame;
3821
+ const x = resolveOrigin(originX) + .5;
3822
+ const y = resolveOrigin(originY) + .5;
3823
+ const deltaX = after.left + x * after.width - before.left - x * before.width;
3824
+ const deltaY = after.top + y * after.height - before.top - y * before.height;
3825
+ const linear = createFrameLinearMatrix({
3826
+ angle,
3827
+ skewX,
3828
+ skewY,
3829
+ scaleX,
3830
+ scaleY
3831
+ });
3832
+ return {
3833
+ left: left - deltaX + linear.a * deltaX + linear.c * deltaY,
3834
+ top: top - deltaY + linear.b * deltaX + linear.d * deltaY
3820
3835
  };
3821
3836
  }
3822
3837
  /** 判断变换意图是否包含跨父级重挂载所需的目标父级矩阵。 */
@@ -4496,14 +4511,14 @@ var RootInputController = class {
4496
4511
  isPanning = false;
4497
4512
  /** @internal 是否应在连续指针操作期间暂停 hover 重算。 */
4498
4513
  hasLockPoint = false;
4499
- /** @internal 最近一次 DOM 指针的 clientX/clientY,不是 world 坐标。 */
4500
- lastPointerPos = {
4514
+ /** Input 原地更新的唯一 client 坐标。 */
4515
+ pointerPosition = {
4501
4516
  x: 0,
4502
4517
  y: 0
4503
4518
  };
4504
4519
  /** 最近一次记录的指针是否位于 Root 容器内。 */
4505
4520
  pointerInside = false;
4506
- /** 当前允许接收元素级输入的工具子树根节点。 */
4521
+ /** 当前允许接收元素级指针输入的子树根节点。 */
4507
4522
  interactionScopes = /* @__PURE__ */ new Set();
4508
4523
  /** 一次 Root 激活周期内全部 DOM listener 的统一清理器。 */
4509
4524
  abortController = null;
@@ -4517,7 +4532,11 @@ var RootInputController = class {
4517
4532
  constructor(root) {
4518
4533
  this.root = root;
4519
4534
  }
4520
- /** @internal Root 当前是否认为指针位于容器内。 */
4535
+ /** 最近一次 DOM 指针的 clientX/clientY 只读借用;后续输入原地更新同一对象。 */
4536
+ get lastPointerPos() {
4537
+ return this.pointerPosition;
4538
+ }
4539
+ /** Root 当前是否认为指针位于容器内。 */
4521
4540
  get isPointerInside() {
4522
4541
  return this.pointerInside;
4523
4542
  }
@@ -4563,7 +4582,16 @@ var RootInputController = class {
4563
4582
  this.deactivate();
4564
4583
  this.interactionScopes.clear();
4565
4584
  }
4566
- /** @internal 取消全部指针会话,或仅取消目标位于指定节点子树的场景会话。 */
4585
+ /**
4586
+ * 取消当前指针操作,释放指针捕获与 hover 锁定,并清除连续点击记录。
4587
+ *
4588
+ * 省略 node 时取消当前场景或空格平移操作。传入所属 Root 内的节点时,
4589
+ * 仅取消按下目标为该节点或其后代的场景操作;空白处以 Root 为目标的操作、
4590
+ * 空格平移和其他子树的操作不受影响。
4591
+ *
4592
+ * 场景操作按当前交互范围派发一次 pointercancel,不产生 pointerup 或 click;
4593
+ * 平移操作只释放输入状态,保留已经发生的 Viewport 平移。
4594
+ */
4567
4595
  cancelSession(node) {
4568
4596
  if (!node) {
4569
4597
  this.cancelPointerSession();
@@ -4584,7 +4612,17 @@ var RootInputController = class {
4584
4612
  setPointerInside(inside) {
4585
4613
  this.pointerInside = inside;
4586
4614
  }
4587
- /** @internal 注册工具交互范围,只让其子树接收元素级输入,并返回注销函数。 */
4615
+ /**
4616
+ * 允许所属 Root 内的 scope 及其后代接收元素级指针输入,返回注销函数。
4617
+ *
4618
+ * 多个范围取并集;没有范围时恢复普通派发。范围外的命中仍作为事件 target
4619
+ * 派给 Root,但不进入命中元素的指针、点击、悬停或右键处理器。
4620
+ * wheel 仍派给命中元素;范围内事件保留正常冒泡,范围不改变命中查询结果。
4621
+ *
4622
+ * 调用方负责每个 scope 同时只保留一次注册,并在退出交互或停用时注销;
4623
+ * 再次进入时重新注册。注册和注销通过现有帧队列刷新 hover 与 cursor,
4624
+ * 不自动取消进行中的指针操作;需要取消时调用 cancelSession(scope)。
4625
+ */
4588
4626
  registerInteractionScope(scope) {
4589
4627
  this.interactionScopes.add(scope);
4590
4628
  this.root.scheduleHoverRefresh();
@@ -4593,7 +4631,7 @@ var RootInputController = class {
4593
4631
  this.root.scheduleHoverRefresh();
4594
4632
  };
4595
4633
  }
4596
- /** @internal 判断命中元素是否属于当前任一 interaction scope。 */
4634
+ /** 判断元素是否属于当前允许交互的子树;无范围限制时为 true,不执行命中或焦点查询。 */
4597
4635
  isInteractionTarget(element) {
4598
4636
  if (this.interactionScopes.size === 0) return true;
4599
4637
  for (let node = element; node; node = node.parent) if (node instanceof Element && this.interactionScopes.has(node)) return true;
@@ -4613,8 +4651,8 @@ var RootInputController = class {
4613
4651
  }
4614
4652
  /** 保存 DOM client 坐标,供无显式事件的 hover 重算使用。 */
4615
4653
  updatePointer(event) {
4616
- this.lastPointerPos.x = event.clientX;
4617
- this.lastPointerPos.y = event.clientY;
4654
+ this.pointerPosition.x = event.clientX;
4655
+ this.pointerPosition.y = event.clientY;
4618
4656
  }
4619
4657
  /** 将一个 DOM 输入转换为 Fulate world 事件并派给当前场景目标。 */
4620
4658
  dispatchDomEvent(event, eventName, target = this.root.currentElement, point = this.root.viewport.getLogicalPosition(event.clientX, event.clientY)) {
@@ -5565,11 +5603,21 @@ var SceneRegistry = class {
5565
5603
  sceneChangeObservers = /* @__PURE__ */ new Set();
5566
5604
  /** 监听 active registration 的轻量观察器。 */
5567
5605
  nodeRegistrationObservers = /* @__PURE__ */ new Set();
5568
- /** 创建注册表;可注入已有 Map 以共享或测试已经成立的 key 索引。 */
5569
- constructor(keyElements = /* @__PURE__ */ new Map()) {
5570
- this.keyElements = keyElements;
5606
+ /** @internal Root 创建,拥有当前场景唯一 key 索引。 */
5607
+ constructor(nodes = /* @__PURE__ */ new Map()) {
5608
+ this.nodes = nodes;
5571
5609
  }
5572
- /** 订阅场景变化并返回注销函数。 */
5610
+ /**
5611
+ * 当前 active 节点的只读 live 索引;与内部 Map 为同一引用,不创建快照。
5612
+ * 初始枚举后可订阅增量变化,后续注册/注销会直接更新此视图。
5613
+ */
5614
+ get keyElements() {
5615
+ return this.nodes;
5616
+ }
5617
+ /**
5618
+ * 订阅后续场景查询/结构变化,返回退订函数;不补发当前状态。
5619
+ * 此通知不代表完整属性变化或帧已稳定;Root 销毁时清除订阅。
5620
+ */
5573
5621
  observeSceneChanges(observer) {
5574
5622
  this.sceneChangeObservers.add(observer);
5575
5623
  return () => this.sceneChangeObservers.delete(observer);
@@ -5578,7 +5626,11 @@ var SceneRegistry = class {
5578
5626
  get hasSceneChangeObservers() {
5579
5627
  return this.sceneChangeObservers.size > 0;
5580
5628
  }
5581
- /** 订阅节点 active registration 并返回注销函数。 */
5629
+ /**
5630
+ * 订阅后续节点进入/离开 active 生命周期,返回退订函数;不补发已有节点。
5631
+ * 回调时索引与 active 状态已安装;detach/reinsert 分别通知 false/true。
5632
+ * Root 销毁时清除订阅。
5633
+ */
5582
5634
  observeNodeRegistrations(observer) {
5583
5635
  this.nodeRegistrationObservers.add(observer);
5584
5636
  return () => this.nodeRegistrationObservers.delete(observer);
@@ -5621,13 +5673,13 @@ var SceneRegistry = class {
5621
5673
  const key = node.key;
5622
5674
  const existing = this.keyElements.get(key);
5623
5675
  if (existing && existing !== node) console.warn(`Duplicate node key: "${key}"`);
5624
- this.keyElements.set(key, node);
5676
+ this.nodes.set(key, node);
5625
5677
  }
5626
5678
  /** @internal 从索引移除停用节点并通知 key 观察器。 */
5627
5679
  unregisterNodeKey(node) {
5628
5680
  const key = node.key;
5629
5681
  if (this.keyElements.get(key) === node) {
5630
- this.keyElements.delete(key);
5682
+ this.nodes.delete(key);
5631
5683
  this.notifyNodeKeyObservers(key, node, false);
5632
5684
  }
5633
5685
  this.notifyNodeRegistrationObservers(node, false);
@@ -5645,7 +5697,7 @@ var SceneRegistry = class {
5645
5697
  }
5646
5698
  /** @internal 清空 key 索引和全部观察器。 */
5647
5699
  clear() {
5648
- this.keyElements.clear();
5700
+ this.nodes.clear();
5649
5701
  this.nodeKeyObservers.clear();
5650
5702
  this.nodeRegistrationObservers.clear();
5651
5703
  this.sceneChangeObservers.clear();
@@ -5745,15 +5797,8 @@ function syncStructureLifecycles(nodes) {
5745
5797
  }
5746
5798
  //#endregion
5747
5799
  //#region packages/core/src/mutation/change-batch.ts
5748
- /**
5749
- * 同步应用一份 trusted change batch。
5750
- *
5751
- * owner effects 先按对象身份合并最终 patch;所有 fields/raw links 安装完成后才运行
5752
- * History、lifecycle、hooks、dirty 和一次 scene delivery。本函数不提供 rollback、
5753
- * retry、receipt 或 rejected 结果。
5754
- */
5755
- function applyChangeBatch(root, ownerEffects, structureEffects = [], history) {
5756
- if (ownerEffects.length === 0 && structureEffects.length === 0) return;
5800
+ /** @internal 合并 raw owner effects;单个 patch 直接借用,仅合并同 owner 字段时分配。 */
5801
+ function mergeOwnerPropertyChanges(ownerEffects) {
5757
5802
  const slots = /* @__PURE__ */ new Map();
5758
5803
  let mergedOwners = null;
5759
5804
  for (const { owner, patch } of ownerEffects) {
@@ -5772,6 +5817,18 @@ function applyChangeBatch(root, ownerEffects, structureEffects = [], history) {
5772
5817
  }
5773
5818
  for (const key of Object.keys(patch)) finalPatch[key] = patch[key];
5774
5819
  }
5820
+ return slots;
5821
+ }
5822
+ /**
5823
+ * 同步应用一份 trusted change batch。
5824
+ *
5825
+ * owner effects 先按对象身份合并最终 patch;所有 fields/raw links 安装完成后才运行
5826
+ * History、lifecycle、hooks、dirty 和一次 scene delivery。本函数不提供 rollback、
5827
+ * retry、receipt 或 rejected 结果。返回本批次是否实际安装属性或结构变化。
5828
+ */
5829
+ function applyChangeBatch(root, ownerEffects, structureEffects = [], history) {
5830
+ if (ownerEffects.length === 0 && structureEffects.length === 0) return false;
5831
+ const slots = mergeOwnerPropertyChanges(ownerEffects);
5775
5832
  const properties = [];
5776
5833
  for (const [owner, patch] of slots) {
5777
5834
  const commit = owner.preparePropertyCommit(patch);
@@ -5782,7 +5839,7 @@ function applyChangeBatch(root, ownerEffects, structureEffects = [], history) {
5782
5839
  }
5783
5840
  const structureBatch = prepareStructureBatch(structureEffects);
5784
5841
  const structure = structureBatch.changes;
5785
- if (properties.length === 0 && structure.length === 0) return;
5842
+ if (properties.length === 0 && structure.length === 0) return false;
5786
5843
  const placements = history ? preparePlacementChanges(structure) : null;
5787
5844
  for (const { owner, commit } of properties) owner.installPropertyCommit(commit);
5788
5845
  const lifecycleRoots = installStructureLinks(structureBatch);
@@ -5811,6 +5868,7 @@ function applyChangeBatch(root, ownerEffects, structureEffects = [], history) {
5811
5868
  else if (hoverChanged) root.scheduleHoverRefresh();
5812
5869
  if (root.sceneRegistry.hasSceneChangeObservers) root.sceneRegistry.notifySceneChange(void 0, [...properties.map(({ owner }) => owner), ...structure.flatMap(({ owner, changed }) => [owner, ...changed])]);
5813
5870
  for (const { owner, commit } of properties) owner.dispatchPortsChange(commit);
5871
+ return true;
5814
5872
  }
5815
5873
  //#endregion
5816
5874
  //#region packages/core/src/root/index.ts
@@ -5826,9 +5884,9 @@ var Root = class extends Node {
5826
5884
  skinTextCommitObservers;
5827
5885
  /** Root 的平移、缩放、DPR 和坐标换算对象。 */
5828
5886
  viewport;
5829
- /** @internal Root 拥有的 DOM 输入和指针会话控制器。 */
5887
+ /** Root 拥有的输入控制器,提供只读查询、交互范围注册和指针操作取消。 */
5830
5888
  input;
5831
- /** @internal 活动节点 key 索引和场景变化观察器。 */
5889
+ /** 当前活动节点的只读索引及增量场景订阅。 */
5832
5890
  sceneRegistry;
5833
5891
  /** @internal 跨 Layer 帧队列、动画时钟和 nextTick 状态。 */
5834
5892
  frameRuntime;
@@ -6057,7 +6115,7 @@ var Root = class extends Node {
6057
6115
  * 同 owner 只 finalize/install 一次,全部 fields/raw links 安装后统一发布。
6058
6116
  */
6059
6117
  applyChangeBatch(owners, structure = [], history) {
6060
- applyChangeBatch(this, owners, structure, history);
6118
+ return applyChangeBatch(this, owners, structure, history);
6061
6119
  }
6062
6120
  /** 按活动场景中的唯一 key 查询节点;key 来自 `node.key`。 */
6063
6121
  getByKey(key) {
@@ -6940,4 +6998,4 @@ var Layer = class Layer extends Element {
6940
6998
  }
6941
6999
  };
6942
7000
  //#endregion
6943
- export { ChangeImpact, CustomEvent, DEFAULT_CONNECTION_PORT_SCHEMA, EVENT_NAMES, Element, ElementProperties, ElementTransform, EventEmitter, FrameStabilizationError, Layer, LayerProperties, LayerTransform, Node, NodeLifecycleEvent, NodeProperties, Root, RootFrameRuntime, RootInputController, SKIN_DEFAULTS, SceneRegistry, Shape, ShapeProperties, ShapeTransform, Skin, TransformProperties, Viewport, createAuthoredLineSubpath, createGeometryQuery, createGeometrySnapshot, createLineSubpath, createPathLocalId, evaluatePathSegmentPoint, getElementConnectionPort, getElementConnectionPortPoint, getElementConnectionPortPoints, isFormControlTarget, isReparentTransformIntent, projectConnectionPortPoint, resolveAuthoredGeometryFramePatch, resolveAuthoredSubpath, resolveOrigin, resolveReferenceTransform, resolveReferenceTransformTarget, splitPathSegment };
7001
+ export { ChangeImpact, CustomEvent, DEFAULT_CONNECTION_PORT_SCHEMA, EVENT_NAMES, Element, ElementProperties, ElementTransform, EventEmitter, FrameStabilizationError, Layer, LayerProperties, LayerTransform, Node, NodeLifecycleEvent, NodeProperties, Root, RootFrameRuntime, RootInputController, SKIN_DEFAULTS, SceneRegistry, Shape, ShapeProperties, ShapeTransform, Skin, TransformProperties, Viewport, createAuthoredLineSubpath, createGeometryQuery, createGeometrySnapshot, createLineSubpath, createPathLocalId, evaluatePathSegmentPoint, getElementConnectionPort, getElementConnectionPortPoint, getElementConnectionPortPoints, isFormControlTarget, isReparentTransformIntent, mergeOwnerPropertyChanges, projectConnectionPortPoint, resolveAuthoredGeometryFramePatch, resolveAuthoredSubpath, resolveOrigin, resolveReferenceBoundsTranslation, resolveReferenceTransform, resolveReferenceTransformTarget, splitPathSegment };
@@ -18,12 +18,14 @@ export interface ChangeHistorySink {
18
18
  /** 记录一个节点首次触及批次提供的 before placement。 */
19
19
  recordPlacementChange(node: Node, beforeOwner: Node | null, beforeIndex: number): void;
20
20
  }
21
+ /** @internal 合并 raw owner effects;单个 patch 直接借用,仅合并同 owner 字段时分配。 */
22
+ export declare function mergeOwnerPropertyChanges(ownerEffects: readonly OwnerPropertyChange[]): Map<Element<import("..").ElementProperties, import("..").BaseElementOption<any>, Partial<Omit<import("..").BaseElementOption<any>, "key" | "children">>>, Readonly<Record<string, unknown>>>;
21
23
  /**
22
24
  * 同步应用一份 trusted change batch。
23
25
  *
24
26
  * owner effects 先按对象身份合并最终 patch;所有 fields/raw links 安装完成后才运行
25
27
  * History、lifecycle、hooks、dirty 和一次 scene delivery。本函数不提供 rollback、
26
- * retry、receipt 或 rejected 结果。
28
+ * retry、receipt 或 rejected 结果。返回本批次是否实际安装属性或结构变化。
27
29
  */
28
- export declare function applyChangeBatch(root: Root, ownerEffects: readonly OwnerPropertyChange[], structureEffects?: readonly StructureChange[], history?: ChangeHistorySink): void;
30
+ export declare function applyChangeBatch(root: Root, ownerEffects: readonly OwnerPropertyChange[], structureEffects?: readonly StructureChange[], history?: ChangeHistorySink): boolean;
29
31
  export type { StructureChange } from "./structure-change";
@@ -218,6 +218,13 @@ export declare class Element<P extends ElementProperties = ElementProperties, O
218
218
  private syncOptionEvents;
219
219
  /** 属性提交后的派生类扩展点。 */
220
220
  protected onPropertiesChanged(_current: P, _changes: PropertyChanges): void;
221
+ /**
222
+ * 作者配置实际变化后的扩展点,在 effective 属性 hook 之后运行。
223
+ * runtime 遮罩不阻止此通知;runtime-only 更新和相同配置不触发。
224
+ * changedKeys 只包含本次实际改变的 configured 字段;通过 configured reader 读取当前值。
225
+ * direct、batch 和 History replay 使用同一阶段;可在此更新当前数据的 runtime 显示。
226
+ */
227
+ protected onConfiguredPropertiesChanged?(changedKeys: readonly string[]): void;
221
228
  /** 把非 geometry impact 路由到绘制、Layer 顺序和 hover 队列。 */
222
229
  private invalidate;
223
230
  /** 返回在当前元素 local 坐标系中对 children 生效的裁剪区域。 */
@@ -239,10 +246,10 @@ export declare class Element<P extends ElementProperties = ElementProperties, O
239
246
  private resolveCurrentConnectionPortProjection;
240
247
  /** 直接解析一个当前 Port,不 materialize 其余 Ports。 */
241
248
  getConnectionPort(portId: string): ResolvedConnectionPort | undefined;
242
- /** @internal 按给定 whole-value 解析 Port replacement 的最终投影。 */
243
- resolveConnectionPorts(ports: ConnectionPortConfiguration): readonly ResolvedConnectionPort[];
249
+ /** @internal 只解释显式 Port replacement IDs;patch 是同批最终 owner fields。 */
250
+ resolveConnectionPortIds(ports: ConnectionPortConfiguration, patch?: Readonly<Record<string, unknown>>): readonly string[];
244
251
  /** 返回元素类型自有的默认 Port;`null` 使用通用四边 Ports。 */
245
- protected getDefaultConnectionPortSchema(): readonly DerivedConnectionPort[] | null;
252
+ protected getDefaultConnectionPortSchema(_patch?: Readonly<Record<string, unknown>>): readonly DerivedConnectionPort[] | null;
246
253
  /** 返回 custom Ports 的当前 decoration slots。 @internal */
247
254
  getResolvedConnectionPortSlots(): readonly ResolvedConnectionPortSlot[];
248
255
  /**
@@ -253,12 +260,19 @@ export declare class Element<P extends ElementProperties = ElementProperties, O
253
260
  getConnectionPortPosition(edge: Edge, ratio: number): PointView;
254
261
  /** @internal 一次产出 custom Port position、法线与 label edge 长度。 */
255
262
  getConnectionPortGeometry(edge: Edge, ratio: number): ConnectionPortGeometry;
256
- /** @internal 一次借用 owner 当前 configured source 的指定字段。 */
263
+ /**
264
+ * 将当前配置值填入 caller 提供的 value cells,保留结构化值的原引用。
265
+ * 读取包含默认值的 configured 结果,不读取 runtime 覆盖;保留 null/undefined。
266
+ * cells 可复用;借用值不得原地修改并期待自动提交,需要独立值时由 caller 复制。
267
+ */
257
268
  static readConfiguredPropertyValues(owner: Element, targets: ReadonlyMap<string, {
258
269
  value: unknown;
259
270
  }>): void;
260
- /** @internal 借用 owner 当前 configured source 的单个字段。 */
261
- protected static getConfiguredPropertyValue(owner: Element, key: string): any;
271
+ /**
272
+ * 借用当前字段的 configured/default 值,忽略 runtime 覆盖,保留 null/undefined。
273
+ * 返回结构化原引用,不表示该字段是否曾被显式配置;需要独立值时由 caller 复制。
274
+ */
275
+ static getConfiguredPropertyValue(owner: Element, key: string): unknown;
262
276
  /**
263
277
  * 提交需要持久化的配置属性补丁。
264
278
  * @param options 要修改的属性;省略时不修改,字段为 `undefined` 时恢复默认值。
@@ -61,6 +61,8 @@ export interface ReferenceTransformResolution {
61
61
  * 新几何后把真实 bounds 交回这里,保持 frame world matrix 与目标一致。
62
62
  */
63
63
  export declare function resolveAuthoredGeometryFramePatch(baseline: Readonly<Pick<ReferenceTransformBaseline, "referenceBounds" | "frame">>, resolution: Readonly<ReferenceTransformResolution>, authoredBounds: Readonly<Rect>): Readonly<ElementOptionPatch>;
64
+ /** @internal reference bounds 改变时修正 origin 位移,保留给定最终 frame 的仿射。 */
65
+ export declare function resolveReferenceBoundsTranslation(frame: Readonly<ElementOptionPatch>, before: Readonly<Rect>, after: Readonly<Rect>): Readonly<Pick<ElementOptionPatch, "left" | "top">>;
64
66
  /** 判断变换意图是否包含跨父级重挂载所需的目标父级矩阵。 */
65
67
  export declare function isReparentTransformIntent(intent: Readonly<TransformIntent | ReparentTransformIntent>): intent is Readonly<ReparentTransformIntent>;
66
68
  /**
@@ -30,9 +30,9 @@ export declare class Root extends Node<NodeProperties, Layer> {
30
30
  private skinTextCommitObservers?;
31
31
  /** Root 的平移、缩放、DPR 和坐标换算对象。 */
32
32
  readonly viewport: Viewport;
33
- /** @internal Root 拥有的 DOM 输入和指针会话控制器。 */
33
+ /** Root 拥有的输入控制器,提供只读查询、交互范围注册和指针操作取消。 */
34
34
  readonly input: RootInputController;
35
- /** @internal 活动节点 key 索引和场景变化观察器。 */
35
+ /** 当前活动节点的只读索引及增量场景订阅。 */
36
36
  readonly sceneRegistry: SceneRegistry;
37
37
  /** @internal 跨 Layer 帧队列、动画时钟和 nextTick 状态。 */
38
38
  readonly frameRuntime: RootFrameRuntime;
@@ -133,7 +133,7 @@ export declare class Root extends Node<NodeProperties, Layer> {
133
133
  * 同步应用领域已经决定的 owner/structure effects。
134
134
  * 同 owner 只 finalize/install 一次,全部 fields/raw links 安装后统一发布。
135
135
  */
136
- applyChangeBatch(owners: readonly OwnerPropertyChange[], structure?: readonly StructureChange[], history?: ChangeHistorySink): void;
136
+ applyChangeBatch(owners: readonly OwnerPropertyChange[], structure?: readonly StructureChange[], history?: ChangeHistorySink): boolean;
137
137
  /** 按活动场景中的唯一 key 查询节点;key 来自 `node.key`。 */
138
138
  getByKey(key: string): Node | undefined;
139
139
  /**
@@ -1,7 +1,7 @@
1
1
  import { Element } from "../node/element";
2
2
  import type { Node as SceneNode } from "../node/node";
3
3
  import type { Root } from "./index";
4
- import type { MutablePointView } from "@fulate/share";
4
+ import type { PointView } from "@fulate/share";
5
5
  /** 判断键盘事件目标是否应保留浏览器原生空格输入。 */
6
6
  export declare function isFormControlTarget(target: EventTarget | null): boolean;
7
7
  /** Root 拥有的 DOM 输入监听、指针会话和交互范围控制器。 */
@@ -13,11 +13,11 @@ export declare class RootInputController {
13
13
  isPanning: boolean;
14
14
  /** @internal 是否应在连续指针操作期间暂停 hover 重算。 */
15
15
  hasLockPoint: boolean;
16
- /** @internal 最近一次 DOM 指针的 clientX/clientY,不是 world 坐标。 */
17
- lastPointerPos: MutablePointView;
16
+ /** Input 原地更新的唯一 client 坐标。 */
17
+ private readonly pointerPosition;
18
18
  /** 最近一次记录的指针是否位于 Root 容器内。 */
19
19
  private pointerInside;
20
- /** 当前允许接收元素级输入的工具子树根节点。 */
20
+ /** 当前允许接收元素级指针输入的子树根节点。 */
21
21
  private readonly interactionScopes;
22
22
  /** 一次 Root 激活周期内全部 DOM listener 的统一清理器。 */
23
23
  private abortController;
@@ -29,7 +29,9 @@ export declare class RootInputController {
29
29
  private lastClick;
30
30
  /** @internal 由 Root 构造;单独实例化不会接入 Root 生命周期。 */
31
31
  constructor(root: Root);
32
- /** @internal Root 当前是否认为指针位于容器内。 */
32
+ /** 最近一次 DOM 指针的 clientX/clientY 只读借用;后续输入原地更新同一对象。 */
33
+ get lastPointerPos(): PointView;
34
+ /** Root 当前是否认为指针位于容器内。 */
33
35
  get isPointerInside(): boolean;
34
36
  /** @internal 安装当前 Root 的键盘、指针、滚轮和焦点监听。 */
35
37
  activate(): void;
@@ -37,13 +39,32 @@ export declare class RootInputController {
37
39
  deactivate(): void;
38
40
  /** @internal 停用控制器并释放全部 interaction scope。 */
39
41
  dispose(): void;
40
- /** @internal 取消全部指针会话,或仅取消目标位于指定节点子树的场景会话。 */
42
+ /**
43
+ * 取消当前指针操作,释放指针捕获与 hover 锁定,并清除连续点击记录。
44
+ *
45
+ * 省略 node 时取消当前场景或空格平移操作。传入所属 Root 内的节点时,
46
+ * 仅取消按下目标为该节点或其后代的场景操作;空白处以 Root 为目标的操作、
47
+ * 空格平移和其他子树的操作不受影响。
48
+ *
49
+ * 场景操作按当前交互范围派发一次 pointercancel,不产生 pointerup 或 click;
50
+ * 平移操作只释放输入状态,保留已经发生的 Viewport 平移。
51
+ */
41
52
  cancelSession(node?: SceneNode): void;
42
53
  /** @internal 更新容器内外状态。 */
43
54
  setPointerInside(inside: boolean): void;
44
- /** @internal 注册工具交互范围,只让其子树接收元素级输入,并返回注销函数。 */
55
+ /**
56
+ * 允许所属 Root 内的 scope 及其后代接收元素级指针输入,返回注销函数。
57
+ *
58
+ * 多个范围取并集;没有范围时恢复普通派发。范围外的命中仍作为事件 target
59
+ * 派给 Root,但不进入命中元素的指针、点击、悬停或右键处理器。
60
+ * wheel 仍派给命中元素;范围内事件保留正常冒泡,范围不改变命中查询结果。
61
+ *
62
+ * 调用方负责每个 scope 同时只保留一次注册,并在退出交互或停用时注销;
63
+ * 再次进入时重新注册。注册和注销通过现有帧队列刷新 hover 与 cursor,
64
+ * 不自动取消进行中的指针操作;需要取消时调用 cancelSession(scope)。
65
+ */
45
66
  registerInteractionScope(scope: Element): () => void;
46
- /** @internal 判断命中元素是否属于当前任一 interaction scope。 */
67
+ /** 判断元素是否属于当前允许交互的子树;无范围限制时为 true,不执行命中或焦点查询。 */
47
68
  isInteractionTarget(element: Element): boolean;
48
69
  /** Root 容器所属的 Document。 */
49
70
  private get ownerDocument();
@@ -7,23 +7,32 @@ export type NodeRegistrationObserver = (node: Node, registered: boolean) => void
7
7
  export type SceneChangeObserver = (node?: Node, affected?: readonly Node[]) => void;
8
8
  /** 管理活动场景的节点 key 索引和轻量变化观察器。 */
9
9
  export declare class SceneRegistry {
10
- /** 活动节点的 key 索引。 */
11
- readonly keyElements: Map<string, Node<import("..").NodeProperties, Node<any, any>>>;
10
+ private readonly nodes;
12
11
  /** 按 key 保存观察注册和注销的回调。 */
13
12
  private readonly nodeKeyObservers;
14
13
  /** 监听结构、geometry 和命中策略变化的回调。 */
15
14
  private readonly sceneChangeObservers;
16
15
  /** 监听 active registration 的轻量观察器。 */
17
16
  private readonly nodeRegistrationObservers;
18
- /** 创建注册表;可注入已有 Map 以共享或测试已经成立的 key 索引。 */
19
- constructor(
20
- /** 活动节点的 key 索引。 */
21
- keyElements?: Map<string, Node<import("..").NodeProperties, Node<any, any>>>);
22
- /** 订阅场景变化并返回注销函数。 */
17
+ /** @internal Root 创建,拥有当前场景唯一 key 索引。 */
18
+ constructor(nodes?: Map<string, Node<import("..").NodeProperties, Node<any, any>>>);
19
+ /**
20
+ * 当前 active 节点的只读 live 索引;与内部 Map 为同一引用,不创建快照。
21
+ * 初始枚举后可订阅增量变化,后续注册/注销会直接更新此视图。
22
+ */
23
+ get keyElements(): ReadonlyMap<string, Node>;
24
+ /**
25
+ * 订阅后续场景查询/结构变化,返回退订函数;不补发当前状态。
26
+ * 此通知不代表完整属性变化或帧已稳定;Root 销毁时清除订阅。
27
+ */
23
28
  observeSceneChanges(observer: SceneChangeObserver): () => boolean;
24
29
  /** @internal 当前是否存在真实 scene change consumer。 */
25
30
  get hasSceneChangeObservers(): boolean;
26
- /** 订阅节点 active registration 并返回注销函数。 */
31
+ /**
32
+ * 订阅后续节点进入/离开 active 生命周期,返回退订函数;不补发已有节点。
33
+ * 回调时索引与 active 状态已安装;detach/reinsert 分别通知 false/true。
34
+ * Root 销毁时清除订阅。
35
+ */
27
36
  observeNodeRegistrations(observer: NodeRegistrationObserver): () => boolean;
28
37
  /** @internal 通知场景观察器;node 省略时表示整批变化。 */
29
38
  notifySceneChange(node?: Node, affected?: readonly Node[]): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fulate/core",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",