@archie/devtools 0.0.30 → 0.0.32
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/{chunk-4VGQJ3PW.mjs → chunk-CO6SWEYJ.mjs} +5 -0
- package/dist/client/client.js +107 -51
- package/dist/client/client.mjs +107 -51
- package/dist/collection-binding.mjs +1 -1
- package/dist/index.d.mts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +5 -0
- package/dist/index.mjs +1 -1
- package/dist/inspector.standalone.js +121 -31
- package/package.json +1 -1
|
@@ -534,6 +534,11 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
534
534
|
parentNodeId ? t.stringLiteral(parentNodeId) : t.nullLiteral()
|
|
535
535
|
)
|
|
536
536
|
]);
|
|
537
|
+
if (isKitOrigin) {
|
|
538
|
+
metaObj.properties.push(
|
|
539
|
+
t.objectProperty(t.identifier("origin"), t.stringLiteral("kit"))
|
|
540
|
+
);
|
|
541
|
+
}
|
|
537
542
|
if (slot !== null) {
|
|
538
543
|
metaObj.properties.push(
|
|
539
544
|
t.objectProperty(t.identifier("slot"), t.stringLiteral(slot))
|
package/dist/client/client.js
CHANGED
|
@@ -4160,6 +4160,7 @@ var FIBER_KEY_PREFIX = "__reactFiber$";
|
|
|
4160
4160
|
var PROPS_KEY_PREFIX = "__reactProps$";
|
|
4161
4161
|
var metaCache = /* @__PURE__ */ new WeakMap();
|
|
4162
4162
|
var directMetaCache = /* @__PURE__ */ new WeakMap();
|
|
4163
|
+
var usageMetaCache = /* @__PURE__ */ new WeakMap();
|
|
4163
4164
|
function readEditorMetaValue(value) {
|
|
4164
4165
|
if (typeof value === "function") {
|
|
4165
4166
|
return value();
|
|
@@ -4324,6 +4325,34 @@ function getSingleHostElement(owner) {
|
|
|
4324
4325
|
}
|
|
4325
4326
|
return hosts.length === 1 ? hosts[0] : null;
|
|
4326
4327
|
}
|
|
4328
|
+
function getUsageMetaOwnerFiber(el) {
|
|
4329
|
+
let fiber = getFiberSelectionFromElement(el).fiber;
|
|
4330
|
+
while (fiber) {
|
|
4331
|
+
const meta = readEditorMetaValue(fiber.memoizedProps?.__editorMeta);
|
|
4332
|
+
if (meta && meta.origin !== "kit") return fiber;
|
|
4333
|
+
fiber = fiber.return;
|
|
4334
|
+
}
|
|
4335
|
+
return null;
|
|
4336
|
+
}
|
|
4337
|
+
function projectFromOwner(owner, el) {
|
|
4338
|
+
if (!owner) return null;
|
|
4339
|
+
if (getSingleHostElement(owner) !== el) return null;
|
|
4340
|
+
return readEditorMetaValue(owner.memoizedProps?.__editorMeta);
|
|
4341
|
+
}
|
|
4342
|
+
function projectUsageMeta(el) {
|
|
4343
|
+
const selection = getFiberSelectionFromElement(el);
|
|
4344
|
+
const cached = readFiberAwareCache(usageMetaCache, el, selection);
|
|
4345
|
+
if (cached !== void 0) return cached;
|
|
4346
|
+
return writeFiberAwareCache(usageMetaCache, el, selection, computeUsageMeta(el));
|
|
4347
|
+
}
|
|
4348
|
+
function computeUsageMeta(el) {
|
|
4349
|
+
const direct = getDirectEditorMeta(el);
|
|
4350
|
+
if (direct && direct.origin !== "kit") return null;
|
|
4351
|
+
const usage = projectFromOwner(getUsageMetaOwnerFiber(el), el);
|
|
4352
|
+
if (usage) return usage;
|
|
4353
|
+
if (direct) return null;
|
|
4354
|
+
return projectFromOwner(getEditorMetaOwnerFiber(el), el);
|
|
4355
|
+
}
|
|
4327
4356
|
function findMetaOwnerElement(el) {
|
|
4328
4357
|
let current = el;
|
|
4329
4358
|
while (current) {
|
|
@@ -4391,10 +4420,13 @@ function getRuntimeKey(el) {
|
|
|
4391
4420
|
_runtimeKeyMap.set(el, key2);
|
|
4392
4421
|
return key2;
|
|
4393
4422
|
}
|
|
4423
|
+
function identityMeta(host) {
|
|
4424
|
+
return projectUsageMeta(host) ?? getEditorMeta(host);
|
|
4425
|
+
}
|
|
4394
4426
|
function getNodeKeyFromElement(el) {
|
|
4395
4427
|
const resolved = resolveDragSurface(el);
|
|
4396
4428
|
const host = resolved.host ?? el;
|
|
4397
|
-
const meta =
|
|
4429
|
+
const meta = identityMeta(host);
|
|
4398
4430
|
if (meta) return meta.nodeId;
|
|
4399
4431
|
const persisted = host.getAttribute("data-dnd-node-id");
|
|
4400
4432
|
if (persisted) return persisted;
|
|
@@ -4403,7 +4435,7 @@ function getNodeKeyFromElement(el) {
|
|
|
4403
4435
|
function getInspectorRefFromElement(el) {
|
|
4404
4436
|
const resolved = resolveDragSurface(el);
|
|
4405
4437
|
const host = resolved.host ?? el;
|
|
4406
|
-
const meta =
|
|
4438
|
+
const meta = identityMeta(host);
|
|
4407
4439
|
if (!meta) return null;
|
|
4408
4440
|
return { relativePath: meta.file, line: meta.line, column: meta.col };
|
|
4409
4441
|
}
|
|
@@ -5081,13 +5113,6 @@ function isInspectorEligible(el) {
|
|
|
5081
5113
|
if (el.hasAttribute("data-dnd-force-allow")) return "force-allow";
|
|
5082
5114
|
return null;
|
|
5083
5115
|
}
|
|
5084
|
-
function projectUsageMeta(el) {
|
|
5085
|
-
if (getDirectEditorMeta(el)) return null;
|
|
5086
|
-
const owner = getEditorMetaOwnerFiber(el);
|
|
5087
|
-
if (!owner) return null;
|
|
5088
|
-
if (getSingleHostElement(owner) !== el) return null;
|
|
5089
|
-
return readEditorMetaValue(owner.memoizedProps?.__editorMeta);
|
|
5090
|
-
}
|
|
5091
5116
|
function isRuntimeVisualInternal(el) {
|
|
5092
5117
|
if (shouldIgnoreAsVirtualRuntime(el)) return true;
|
|
5093
5118
|
const tag = el.tagName.toLowerCase();
|
|
@@ -5117,10 +5142,10 @@ function ensureUniqueNodeId(base, used) {
|
|
|
5117
5142
|
function resolveStableNodeId(el, used) {
|
|
5118
5143
|
const persisted = el.getAttribute(DND_NODE_ID_ATTR);
|
|
5119
5144
|
if (persisted && !used.has(persisted)) return persisted;
|
|
5120
|
-
const metaId = getEditorMetaNodeId(el);
|
|
5121
|
-
if (metaId) return ensureUniqueNodeId(metaId, used);
|
|
5122
5145
|
const projected = projectUsageMeta(el);
|
|
5123
5146
|
if (projected) return ensureUniqueNodeId(projected.nodeId, used);
|
|
5147
|
+
const metaId = getEditorMetaNodeId(el);
|
|
5148
|
+
if (metaId) return ensureUniqueNodeId(metaId, used);
|
|
5124
5149
|
return ensureUniqueNodeId(getRuntimeNodeId(el), used);
|
|
5125
5150
|
}
|
|
5126
5151
|
function getUniqueSelector(el) {
|
|
@@ -5259,13 +5284,15 @@ function scanElements(root, depth = 0, usedNodeIds = /* @__PURE__ */ new Set(),
|
|
|
5259
5284
|
const surfaceMeta = hostEl instanceof HTMLElement ? getDirectEditorMeta(hostEl) ?? void 0 : void 0;
|
|
5260
5285
|
const ownerMeta = dragSurface.metaOwner && dragSurface.metaOwner instanceof HTMLElement ? getEditorMeta(dragSurface.metaOwner) : null;
|
|
5261
5286
|
const resolvedSelector = getUniqueSelector(hostEl);
|
|
5262
|
-
const
|
|
5287
|
+
const usageMeta = hostEl instanceof HTMLElement ? projectUsageMeta(hostEl) : null;
|
|
5288
|
+
const identityMeta2 = usageMeta ?? ownerMeta ?? surfaceMeta;
|
|
5289
|
+
const draggable = inferredEligibility === "force-allow" || !nodeId.startsWith("runtime:") && (identityMeta2?.origin !== "kit" || resolveRowBinding(hostEl) !== null);
|
|
5263
5290
|
results.push({
|
|
5264
5291
|
nodeId,
|
|
5265
5292
|
element: hostEl,
|
|
5266
5293
|
selector: resolvedSelector,
|
|
5267
5294
|
draggable,
|
|
5268
|
-
sourceMetaNodeId:
|
|
5295
|
+
sourceMetaNodeId: identityMeta2?.nodeId ?? null,
|
|
5269
5296
|
resolvedHostNodeId: nodeId,
|
|
5270
5297
|
resolvedHostSelector: resolvedSelector,
|
|
5271
5298
|
resolutionKind: dragSurface.kind,
|
|
@@ -5273,6 +5300,7 @@ function scanElements(root, depth = 0, usedNodeIds = /* @__PURE__ */ new Set(),
|
|
|
5273
5300
|
rect: hostRect,
|
|
5274
5301
|
containerStrategy,
|
|
5275
5302
|
eligibilitySource: inferredEligibility,
|
|
5303
|
+
identityOrigin: identityMeta2?.origin ?? null,
|
|
5276
5304
|
editorMeta: surfaceMeta
|
|
5277
5305
|
});
|
|
5278
5306
|
if (!isSvgRoot) results.push(...scanElements(el, depth + 1, usedNodeIds, seenResolvedHosts));
|
|
@@ -5282,6 +5310,38 @@ function scanElements(root, depth = 0, usedNodeIds = /* @__PURE__ */ new Set(),
|
|
|
5282
5310
|
}
|
|
5283
5311
|
return results;
|
|
5284
5312
|
}
|
|
5313
|
+
function buildMovedElementEntry(el, usedNodeIds) {
|
|
5314
|
+
const rect = el.getBoundingClientRect();
|
|
5315
|
+
if (rect.width === 0 || rect.height === 0) return null;
|
|
5316
|
+
const nodeId = resolveStableNodeId(el, usedNodeIds);
|
|
5317
|
+
el.setAttribute(DND_NODE_ID_ATTR, nodeId);
|
|
5318
|
+
const parentEl = el.parentElement;
|
|
5319
|
+
const surfaceMeta = getDirectEditorMeta(el) ?? void 0;
|
|
5320
|
+
const ownerMeta = getEditorMeta(el);
|
|
5321
|
+
const identityMeta2 = projectUsageMeta(el) ?? ownerMeta ?? surfaceMeta;
|
|
5322
|
+
const selector = getUniqueSelector(el);
|
|
5323
|
+
const eligibility = isInspectorEligible(el);
|
|
5324
|
+
return {
|
|
5325
|
+
nodeId,
|
|
5326
|
+
element: el,
|
|
5327
|
+
selector,
|
|
5328
|
+
// Same draggable rule as the main scan, INCLUDING the force-allow
|
|
5329
|
+
// escape — an element that was draggable when the user moved it must
|
|
5330
|
+
// not silently lose draggability for having landed below MAX_DEPTH.
|
|
5331
|
+
// Same kit-origin bound-row exemption as the main scan (see there).
|
|
5332
|
+
draggable: eligibility === "force-allow" || !nodeId.startsWith("runtime:") && (identityMeta2?.origin !== "kit" || resolveRowBinding(el) !== null),
|
|
5333
|
+
sourceMetaNodeId: identityMeta2?.nodeId ?? null,
|
|
5334
|
+
resolvedHostNodeId: nodeId,
|
|
5335
|
+
resolvedHostSelector: selector,
|
|
5336
|
+
resolutionKind: ownerMeta && ownerMeta.componentName[0] !== ownerMeta.componentName[0].toLowerCase() ? "wrapper-to-host" : "direct-host",
|
|
5337
|
+
label: getLabel(el),
|
|
5338
|
+
rect,
|
|
5339
|
+
containerStrategy: parentEl && isFlexOrGridParent(parentEl) ? resolveContainerStrategy(parentEl) : null,
|
|
5340
|
+
eligibilitySource: eligibility ?? "force-allow",
|
|
5341
|
+
identityOrigin: identityMeta2?.origin ?? null,
|
|
5342
|
+
editorMeta: surfaceMeta
|
|
5343
|
+
};
|
|
5344
|
+
}
|
|
5285
5345
|
function useElementScanner(enabled) {
|
|
5286
5346
|
const [elements, setElements] = (0, import_react6.useState)([]);
|
|
5287
5347
|
const rafRef = (0, import_react6.useRef)(0);
|
|
@@ -5298,30 +5358,10 @@ function useElementScanner(enabled) {
|
|
|
5298
5358
|
const seenEls = new Set(scanned.map((s) => s.element));
|
|
5299
5359
|
for (const el of Array.from(document.querySelectorAll("[data-dnd-moved]"))) {
|
|
5300
5360
|
if (seenEls.has(el)) continue;
|
|
5301
|
-
const
|
|
5302
|
-
if (
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
el.setAttribute(DND_NODE_ID_ATTR, nodeId);
|
|
5306
|
-
const parentEl = el.parentElement;
|
|
5307
|
-
const surfaceMeta = getDirectEditorMeta(el) ?? void 0;
|
|
5308
|
-
const ownerMeta = getEditorMeta(el);
|
|
5309
|
-
const selector = getUniqueSelector(el);
|
|
5310
|
-
scanned.push({
|
|
5311
|
-
nodeId,
|
|
5312
|
-
element: el,
|
|
5313
|
-
selector,
|
|
5314
|
-
draggable: !nodeId.startsWith("runtime:"),
|
|
5315
|
-
sourceMetaNodeId: ownerMeta?.nodeId ?? surfaceMeta?.nodeId ?? null,
|
|
5316
|
-
resolvedHostNodeId: nodeId,
|
|
5317
|
-
resolvedHostSelector: selector,
|
|
5318
|
-
resolutionKind: ownerMeta && ownerMeta.componentName[0] !== ownerMeta.componentName[0].toLowerCase() ? "wrapper-to-host" : "direct-host",
|
|
5319
|
-
label: getLabel(el),
|
|
5320
|
-
rect,
|
|
5321
|
-
containerStrategy: parentEl && isFlexOrGridParent(parentEl) ? resolveContainerStrategy(parentEl) : null,
|
|
5322
|
-
eligibilitySource: isInspectorEligible(el) ?? "force-allow",
|
|
5323
|
-
editorMeta: surfaceMeta
|
|
5324
|
-
});
|
|
5361
|
+
const entry = buildMovedElementEntry(el, usedNodeIds);
|
|
5362
|
+
if (!entry) continue;
|
|
5363
|
+
usedNodeIds.add(entry.nodeId);
|
|
5364
|
+
scanned.push(entry);
|
|
5325
5365
|
}
|
|
5326
5366
|
const seen = /* @__PURE__ */ new Set();
|
|
5327
5367
|
setElements(scanned.filter((el) => {
|
|
@@ -6696,6 +6736,7 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6696
6736
|
const lastIntentRef = (0, import_react11.useRef)(null);
|
|
6697
6737
|
const visualIntentRef = (0, import_react11.useRef)(null);
|
|
6698
6738
|
const sourceContainerIdRef = (0, import_react11.useRef)(null);
|
|
6739
|
+
const rowLockedRef = (0, import_react11.useRef)(false);
|
|
6699
6740
|
const dragSessionAnchorRef = (0, import_react11.useRef)(null);
|
|
6700
6741
|
const lockRef = (0, import_react11.useRef)({ containerId: null, isCrossUnlocked: false, exitSince: null, unlockUntilTs: null });
|
|
6701
6742
|
const targetPlaneRef = (0, import_react11.useRef)("lane");
|
|
@@ -6727,6 +6768,7 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6727
6768
|
lastIntentRef,
|
|
6728
6769
|
visualIntentRef,
|
|
6729
6770
|
sourceContainerIdRef,
|
|
6771
|
+
rowLockedRef,
|
|
6730
6772
|
dragSessionAnchorRef,
|
|
6731
6773
|
lockRef,
|
|
6732
6774
|
targetPlaneRef,
|
|
@@ -7632,6 +7674,12 @@ function buildPreviewLayout({
|
|
|
7632
7674
|
var CONTAINER_SWITCH_HYSTERESIS = 12;
|
|
7633
7675
|
var SMALL_NODE_NEST_DWELL_MS = 100;
|
|
7634
7676
|
var LARGE_NODE_NEST_DWELL_MS = 320;
|
|
7677
|
+
function computeAllowNest(nestPreview, isLargeDraggedNode, rowLocked) {
|
|
7678
|
+
if (rowLocked) return false;
|
|
7679
|
+
if (!nestPreview) return false;
|
|
7680
|
+
const childId = nestPreview.slotId.split("::nest::")[1] ?? "";
|
|
7681
|
+
return !!childId && !isLargeDraggedNode;
|
|
7682
|
+
}
|
|
7635
7683
|
function useDragVisualLoop({
|
|
7636
7684
|
activeDrag,
|
|
7637
7685
|
refs,
|
|
@@ -7681,11 +7729,7 @@ function useDragVisualLoop({
|
|
|
7681
7729
|
const adjustedPy = py + scrollDy;
|
|
7682
7730
|
const nestPreview = engine.peekNestIntent(px, py, window.scrollX, window.scrollY, snapshot.scroll.x, snapshot.scroll.y);
|
|
7683
7731
|
const isLargeDraggedNode = shouldBlockNestForLargeNode(activeDrag.w, activeDrag.h);
|
|
7684
|
-
|
|
7685
|
-
if (nestPreview) {
|
|
7686
|
-
const childId = nestPreview.slotId.split("::nest::")[1] ?? "";
|
|
7687
|
-
allowNest = !!childId && !isLargeDraggedNode;
|
|
7688
|
-
}
|
|
7732
|
+
const allowNest = computeAllowNest(nestPreview, isLargeDraggedNode, !!refs.rowLockedRef.current);
|
|
7689
7733
|
if (!allowNest) {
|
|
7690
7734
|
refs.nestCandidateRef.current = null;
|
|
7691
7735
|
refs.nestTargetRef.current = null;
|
|
@@ -7870,6 +7914,18 @@ function useDragVisualLoop({
|
|
|
7870
7914
|
|
|
7871
7915
|
// src/client/dnd/design-mode/useDragLifecycle.ts
|
|
7872
7916
|
var import_react13 = require("react");
|
|
7917
|
+
function resolveLaneAllowedContainers(anchorElement, srcContainerId) {
|
|
7918
|
+
if (!srcContainerId) return null;
|
|
7919
|
+
if (!resolveRowBinding(anchorElement)) return null;
|
|
7920
|
+
return /* @__PURE__ */ new Set([srcContainerId]);
|
|
7921
|
+
}
|
|
7922
|
+
function buildDragIntentEngineOptions(anchorElement, srcContainerId, blockedContainerIds) {
|
|
7923
|
+
return {
|
|
7924
|
+
laneRootContainerId: srcContainerId,
|
|
7925
|
+
laneAllowedContainers: resolveLaneAllowedContainers(anchorElement, srcContainerId),
|
|
7926
|
+
blockedContainerIds
|
|
7927
|
+
};
|
|
7928
|
+
}
|
|
7873
7929
|
function buildRuntimeIdentityLocal(nodeId, resolveNodeElement, effectiveLaneSnapshot) {
|
|
7874
7930
|
if (!nodeId) return null;
|
|
7875
7931
|
const element = resolveNodeElement(nodeId);
|
|
@@ -8069,6 +8125,7 @@ function useDragLifecycle({
|
|
|
8069
8125
|
refs.lastIntentRef.current = null;
|
|
8070
8126
|
refs.visualIntentRef.current = null;
|
|
8071
8127
|
refs.sourceContainerIdRef.current = null;
|
|
8128
|
+
refs.rowLockedRef.current = false;
|
|
8072
8129
|
refs.dragSessionAnchorRef.current = null;
|
|
8073
8130
|
refs.lockRef.current = { containerId: null, isCrossUnlocked: false, exitSince: null, unlockUntilTs: null };
|
|
8074
8131
|
refs.targetPlaneRef.current = "lane";
|
|
@@ -8124,10 +8181,9 @@ function useDragLifecycle({
|
|
|
8124
8181
|
const startPosition = getCurrentCommitPlacement(anchorNodeId, srcContainerId);
|
|
8125
8182
|
const blockedContainerIds = buildBlockedStructuralContainerIds(proj, refs.nodeMapRef.current, srcContainerId);
|
|
8126
8183
|
refs.blockedContainerIdsRef.current = blockedContainerIds;
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
});
|
|
8184
|
+
const engineOptions = buildDragIntentEngineOptions(anchorScanned.element, srcContainerId, blockedContainerIds);
|
|
8185
|
+
refs.rowLockedRef.current = !!engineOptions.laneAllowedContainers;
|
|
8186
|
+
refs.engineRef.current = createDragIntentEngine(proj, anchorNodeId, engineOptions);
|
|
8131
8187
|
refs.engineRef.current.setTargetPlane("lane");
|
|
8132
8188
|
refs.targetPlaneRef.current = "lane";
|
|
8133
8189
|
refs.sourceContainerIdRef.current = srcContainerId;
|
|
@@ -8510,7 +8566,9 @@ function useExternalDragLoop({
|
|
|
8510
8566
|
externalDrag,
|
|
8511
8567
|
refs,
|
|
8512
8568
|
resolveNodeElement,
|
|
8513
|
-
setDropLine
|
|
8569
|
+
setDropLine,
|
|
8570
|
+
scrollX,
|
|
8571
|
+
scrollY
|
|
8514
8572
|
);
|
|
8515
8573
|
return;
|
|
8516
8574
|
}
|
|
@@ -8543,10 +8601,8 @@ function useExternalDragLoop({
|
|
|
8543
8601
|
return () => cancelAnimationFrame(rafId);
|
|
8544
8602
|
}, [externalDrag, elements, refs, resolveNodeElement, setDropLine]);
|
|
8545
8603
|
}
|
|
8546
|
-
function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, setDropLine) {
|
|
8547
|
-
const
|
|
8548
|
-
const scrollY = window.scrollY;
|
|
8549
|
-
const intent = engine.resolve(x, y, scrollX, scrollY, scrollX, scrollY);
|
|
8604
|
+
function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, setDropLine, startScrollX, startScrollY) {
|
|
8605
|
+
const intent = engine.resolve(x, y, window.scrollX, window.scrollY, startScrollX, startScrollY);
|
|
8550
8606
|
if (!intent || intent.mode !== "reorder") {
|
|
8551
8607
|
useDesignModeStore.getState().cancelExternalDrag();
|
|
8552
8608
|
setDropLine(null);
|
package/dist/client/client.mjs
CHANGED
|
@@ -4125,6 +4125,7 @@ var FIBER_KEY_PREFIX = "__reactFiber$";
|
|
|
4125
4125
|
var PROPS_KEY_PREFIX = "__reactProps$";
|
|
4126
4126
|
var metaCache = /* @__PURE__ */ new WeakMap();
|
|
4127
4127
|
var directMetaCache = /* @__PURE__ */ new WeakMap();
|
|
4128
|
+
var usageMetaCache = /* @__PURE__ */ new WeakMap();
|
|
4128
4129
|
function readEditorMetaValue(value) {
|
|
4129
4130
|
if (typeof value === "function") {
|
|
4130
4131
|
return value();
|
|
@@ -4289,6 +4290,34 @@ function getSingleHostElement(owner) {
|
|
|
4289
4290
|
}
|
|
4290
4291
|
return hosts.length === 1 ? hosts[0] : null;
|
|
4291
4292
|
}
|
|
4293
|
+
function getUsageMetaOwnerFiber(el) {
|
|
4294
|
+
let fiber = getFiberSelectionFromElement(el).fiber;
|
|
4295
|
+
while (fiber) {
|
|
4296
|
+
const meta = readEditorMetaValue(fiber.memoizedProps?.__editorMeta);
|
|
4297
|
+
if (meta && meta.origin !== "kit") return fiber;
|
|
4298
|
+
fiber = fiber.return;
|
|
4299
|
+
}
|
|
4300
|
+
return null;
|
|
4301
|
+
}
|
|
4302
|
+
function projectFromOwner(owner, el) {
|
|
4303
|
+
if (!owner) return null;
|
|
4304
|
+
if (getSingleHostElement(owner) !== el) return null;
|
|
4305
|
+
return readEditorMetaValue(owner.memoizedProps?.__editorMeta);
|
|
4306
|
+
}
|
|
4307
|
+
function projectUsageMeta(el) {
|
|
4308
|
+
const selection = getFiberSelectionFromElement(el);
|
|
4309
|
+
const cached = readFiberAwareCache(usageMetaCache, el, selection);
|
|
4310
|
+
if (cached !== void 0) return cached;
|
|
4311
|
+
return writeFiberAwareCache(usageMetaCache, el, selection, computeUsageMeta(el));
|
|
4312
|
+
}
|
|
4313
|
+
function computeUsageMeta(el) {
|
|
4314
|
+
const direct = getDirectEditorMeta(el);
|
|
4315
|
+
if (direct && direct.origin !== "kit") return null;
|
|
4316
|
+
const usage = projectFromOwner(getUsageMetaOwnerFiber(el), el);
|
|
4317
|
+
if (usage) return usage;
|
|
4318
|
+
if (direct) return null;
|
|
4319
|
+
return projectFromOwner(getEditorMetaOwnerFiber(el), el);
|
|
4320
|
+
}
|
|
4292
4321
|
function findMetaOwnerElement(el) {
|
|
4293
4322
|
let current = el;
|
|
4294
4323
|
while (current) {
|
|
@@ -4356,10 +4385,13 @@ function getRuntimeKey(el) {
|
|
|
4356
4385
|
_runtimeKeyMap.set(el, key2);
|
|
4357
4386
|
return key2;
|
|
4358
4387
|
}
|
|
4388
|
+
function identityMeta(host) {
|
|
4389
|
+
return projectUsageMeta(host) ?? getEditorMeta(host);
|
|
4390
|
+
}
|
|
4359
4391
|
function getNodeKeyFromElement(el) {
|
|
4360
4392
|
const resolved = resolveDragSurface(el);
|
|
4361
4393
|
const host = resolved.host ?? el;
|
|
4362
|
-
const meta =
|
|
4394
|
+
const meta = identityMeta(host);
|
|
4363
4395
|
if (meta) return meta.nodeId;
|
|
4364
4396
|
const persisted = host.getAttribute("data-dnd-node-id");
|
|
4365
4397
|
if (persisted) return persisted;
|
|
@@ -4368,7 +4400,7 @@ function getNodeKeyFromElement(el) {
|
|
|
4368
4400
|
function getInspectorRefFromElement(el) {
|
|
4369
4401
|
const resolved = resolveDragSurface(el);
|
|
4370
4402
|
const host = resolved.host ?? el;
|
|
4371
|
-
const meta =
|
|
4403
|
+
const meta = identityMeta(host);
|
|
4372
4404
|
if (!meta) return null;
|
|
4373
4405
|
return { relativePath: meta.file, line: meta.line, column: meta.col };
|
|
4374
4406
|
}
|
|
@@ -5046,13 +5078,6 @@ function isInspectorEligible(el) {
|
|
|
5046
5078
|
if (el.hasAttribute("data-dnd-force-allow")) return "force-allow";
|
|
5047
5079
|
return null;
|
|
5048
5080
|
}
|
|
5049
|
-
function projectUsageMeta(el) {
|
|
5050
|
-
if (getDirectEditorMeta(el)) return null;
|
|
5051
|
-
const owner = getEditorMetaOwnerFiber(el);
|
|
5052
|
-
if (!owner) return null;
|
|
5053
|
-
if (getSingleHostElement(owner) !== el) return null;
|
|
5054
|
-
return readEditorMetaValue(owner.memoizedProps?.__editorMeta);
|
|
5055
|
-
}
|
|
5056
5081
|
function isRuntimeVisualInternal(el) {
|
|
5057
5082
|
if (shouldIgnoreAsVirtualRuntime(el)) return true;
|
|
5058
5083
|
const tag = el.tagName.toLowerCase();
|
|
@@ -5082,10 +5107,10 @@ function ensureUniqueNodeId(base, used) {
|
|
|
5082
5107
|
function resolveStableNodeId(el, used) {
|
|
5083
5108
|
const persisted = el.getAttribute(DND_NODE_ID_ATTR);
|
|
5084
5109
|
if (persisted && !used.has(persisted)) return persisted;
|
|
5085
|
-
const metaId = getEditorMetaNodeId(el);
|
|
5086
|
-
if (metaId) return ensureUniqueNodeId(metaId, used);
|
|
5087
5110
|
const projected = projectUsageMeta(el);
|
|
5088
5111
|
if (projected) return ensureUniqueNodeId(projected.nodeId, used);
|
|
5112
|
+
const metaId = getEditorMetaNodeId(el);
|
|
5113
|
+
if (metaId) return ensureUniqueNodeId(metaId, used);
|
|
5089
5114
|
return ensureUniqueNodeId(getRuntimeNodeId(el), used);
|
|
5090
5115
|
}
|
|
5091
5116
|
function getUniqueSelector(el) {
|
|
@@ -5224,13 +5249,15 @@ function scanElements(root, depth = 0, usedNodeIds = /* @__PURE__ */ new Set(),
|
|
|
5224
5249
|
const surfaceMeta = hostEl instanceof HTMLElement ? getDirectEditorMeta(hostEl) ?? void 0 : void 0;
|
|
5225
5250
|
const ownerMeta = dragSurface.metaOwner && dragSurface.metaOwner instanceof HTMLElement ? getEditorMeta(dragSurface.metaOwner) : null;
|
|
5226
5251
|
const resolvedSelector = getUniqueSelector(hostEl);
|
|
5227
|
-
const
|
|
5252
|
+
const usageMeta = hostEl instanceof HTMLElement ? projectUsageMeta(hostEl) : null;
|
|
5253
|
+
const identityMeta2 = usageMeta ?? ownerMeta ?? surfaceMeta;
|
|
5254
|
+
const draggable = inferredEligibility === "force-allow" || !nodeId.startsWith("runtime:") && (identityMeta2?.origin !== "kit" || resolveRowBinding(hostEl) !== null);
|
|
5228
5255
|
results.push({
|
|
5229
5256
|
nodeId,
|
|
5230
5257
|
element: hostEl,
|
|
5231
5258
|
selector: resolvedSelector,
|
|
5232
5259
|
draggable,
|
|
5233
|
-
sourceMetaNodeId:
|
|
5260
|
+
sourceMetaNodeId: identityMeta2?.nodeId ?? null,
|
|
5234
5261
|
resolvedHostNodeId: nodeId,
|
|
5235
5262
|
resolvedHostSelector: resolvedSelector,
|
|
5236
5263
|
resolutionKind: dragSurface.kind,
|
|
@@ -5238,6 +5265,7 @@ function scanElements(root, depth = 0, usedNodeIds = /* @__PURE__ */ new Set(),
|
|
|
5238
5265
|
rect: hostRect,
|
|
5239
5266
|
containerStrategy,
|
|
5240
5267
|
eligibilitySource: inferredEligibility,
|
|
5268
|
+
identityOrigin: identityMeta2?.origin ?? null,
|
|
5241
5269
|
editorMeta: surfaceMeta
|
|
5242
5270
|
});
|
|
5243
5271
|
if (!isSvgRoot) results.push(...scanElements(el, depth + 1, usedNodeIds, seenResolvedHosts));
|
|
@@ -5247,6 +5275,38 @@ function scanElements(root, depth = 0, usedNodeIds = /* @__PURE__ */ new Set(),
|
|
|
5247
5275
|
}
|
|
5248
5276
|
return results;
|
|
5249
5277
|
}
|
|
5278
|
+
function buildMovedElementEntry(el, usedNodeIds) {
|
|
5279
|
+
const rect = el.getBoundingClientRect();
|
|
5280
|
+
if (rect.width === 0 || rect.height === 0) return null;
|
|
5281
|
+
const nodeId = resolveStableNodeId(el, usedNodeIds);
|
|
5282
|
+
el.setAttribute(DND_NODE_ID_ATTR, nodeId);
|
|
5283
|
+
const parentEl = el.parentElement;
|
|
5284
|
+
const surfaceMeta = getDirectEditorMeta(el) ?? void 0;
|
|
5285
|
+
const ownerMeta = getEditorMeta(el);
|
|
5286
|
+
const identityMeta2 = projectUsageMeta(el) ?? ownerMeta ?? surfaceMeta;
|
|
5287
|
+
const selector = getUniqueSelector(el);
|
|
5288
|
+
const eligibility = isInspectorEligible(el);
|
|
5289
|
+
return {
|
|
5290
|
+
nodeId,
|
|
5291
|
+
element: el,
|
|
5292
|
+
selector,
|
|
5293
|
+
// Same draggable rule as the main scan, INCLUDING the force-allow
|
|
5294
|
+
// escape — an element that was draggable when the user moved it must
|
|
5295
|
+
// not silently lose draggability for having landed below MAX_DEPTH.
|
|
5296
|
+
// Same kit-origin bound-row exemption as the main scan (see there).
|
|
5297
|
+
draggable: eligibility === "force-allow" || !nodeId.startsWith("runtime:") && (identityMeta2?.origin !== "kit" || resolveRowBinding(el) !== null),
|
|
5298
|
+
sourceMetaNodeId: identityMeta2?.nodeId ?? null,
|
|
5299
|
+
resolvedHostNodeId: nodeId,
|
|
5300
|
+
resolvedHostSelector: selector,
|
|
5301
|
+
resolutionKind: ownerMeta && ownerMeta.componentName[0] !== ownerMeta.componentName[0].toLowerCase() ? "wrapper-to-host" : "direct-host",
|
|
5302
|
+
label: getLabel(el),
|
|
5303
|
+
rect,
|
|
5304
|
+
containerStrategy: parentEl && isFlexOrGridParent(parentEl) ? resolveContainerStrategy(parentEl) : null,
|
|
5305
|
+
eligibilitySource: eligibility ?? "force-allow",
|
|
5306
|
+
identityOrigin: identityMeta2?.origin ?? null,
|
|
5307
|
+
editorMeta: surfaceMeta
|
|
5308
|
+
};
|
|
5309
|
+
}
|
|
5250
5310
|
function useElementScanner(enabled) {
|
|
5251
5311
|
const [elements, setElements] = useState4([]);
|
|
5252
5312
|
const rafRef = useRef4(0);
|
|
@@ -5263,30 +5323,10 @@ function useElementScanner(enabled) {
|
|
|
5263
5323
|
const seenEls = new Set(scanned.map((s) => s.element));
|
|
5264
5324
|
for (const el of Array.from(document.querySelectorAll("[data-dnd-moved]"))) {
|
|
5265
5325
|
if (seenEls.has(el)) continue;
|
|
5266
|
-
const
|
|
5267
|
-
if (
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
el.setAttribute(DND_NODE_ID_ATTR, nodeId);
|
|
5271
|
-
const parentEl = el.parentElement;
|
|
5272
|
-
const surfaceMeta = getDirectEditorMeta(el) ?? void 0;
|
|
5273
|
-
const ownerMeta = getEditorMeta(el);
|
|
5274
|
-
const selector = getUniqueSelector(el);
|
|
5275
|
-
scanned.push({
|
|
5276
|
-
nodeId,
|
|
5277
|
-
element: el,
|
|
5278
|
-
selector,
|
|
5279
|
-
draggable: !nodeId.startsWith("runtime:"),
|
|
5280
|
-
sourceMetaNodeId: ownerMeta?.nodeId ?? surfaceMeta?.nodeId ?? null,
|
|
5281
|
-
resolvedHostNodeId: nodeId,
|
|
5282
|
-
resolvedHostSelector: selector,
|
|
5283
|
-
resolutionKind: ownerMeta && ownerMeta.componentName[0] !== ownerMeta.componentName[0].toLowerCase() ? "wrapper-to-host" : "direct-host",
|
|
5284
|
-
label: getLabel(el),
|
|
5285
|
-
rect,
|
|
5286
|
-
containerStrategy: parentEl && isFlexOrGridParent(parentEl) ? resolveContainerStrategy(parentEl) : null,
|
|
5287
|
-
eligibilitySource: isInspectorEligible(el) ?? "force-allow",
|
|
5288
|
-
editorMeta: surfaceMeta
|
|
5289
|
-
});
|
|
5326
|
+
const entry = buildMovedElementEntry(el, usedNodeIds);
|
|
5327
|
+
if (!entry) continue;
|
|
5328
|
+
usedNodeIds.add(entry.nodeId);
|
|
5329
|
+
scanned.push(entry);
|
|
5290
5330
|
}
|
|
5291
5331
|
const seen = /* @__PURE__ */ new Set();
|
|
5292
5332
|
setElements(scanned.filter((el) => {
|
|
@@ -6661,6 +6701,7 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6661
6701
|
const lastIntentRef = useRef8(null);
|
|
6662
6702
|
const visualIntentRef = useRef8(null);
|
|
6663
6703
|
const sourceContainerIdRef = useRef8(null);
|
|
6704
|
+
const rowLockedRef = useRef8(false);
|
|
6664
6705
|
const dragSessionAnchorRef = useRef8(null);
|
|
6665
6706
|
const lockRef = useRef8({ containerId: null, isCrossUnlocked: false, exitSince: null, unlockUntilTs: null });
|
|
6666
6707
|
const targetPlaneRef = useRef8("lane");
|
|
@@ -6692,6 +6733,7 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6692
6733
|
lastIntentRef,
|
|
6693
6734
|
visualIntentRef,
|
|
6694
6735
|
sourceContainerIdRef,
|
|
6736
|
+
rowLockedRef,
|
|
6695
6737
|
dragSessionAnchorRef,
|
|
6696
6738
|
lockRef,
|
|
6697
6739
|
targetPlaneRef,
|
|
@@ -7597,6 +7639,12 @@ function buildPreviewLayout({
|
|
|
7597
7639
|
var CONTAINER_SWITCH_HYSTERESIS = 12;
|
|
7598
7640
|
var SMALL_NODE_NEST_DWELL_MS = 100;
|
|
7599
7641
|
var LARGE_NODE_NEST_DWELL_MS = 320;
|
|
7642
|
+
function computeAllowNest(nestPreview, isLargeDraggedNode, rowLocked) {
|
|
7643
|
+
if (rowLocked) return false;
|
|
7644
|
+
if (!nestPreview) return false;
|
|
7645
|
+
const childId = nestPreview.slotId.split("::nest::")[1] ?? "";
|
|
7646
|
+
return !!childId && !isLargeDraggedNode;
|
|
7647
|
+
}
|
|
7600
7648
|
function useDragVisualLoop({
|
|
7601
7649
|
activeDrag,
|
|
7602
7650
|
refs,
|
|
@@ -7646,11 +7694,7 @@ function useDragVisualLoop({
|
|
|
7646
7694
|
const adjustedPy = py + scrollDy;
|
|
7647
7695
|
const nestPreview = engine.peekNestIntent(px, py, window.scrollX, window.scrollY, snapshot.scroll.x, snapshot.scroll.y);
|
|
7648
7696
|
const isLargeDraggedNode = shouldBlockNestForLargeNode(activeDrag.w, activeDrag.h);
|
|
7649
|
-
|
|
7650
|
-
if (nestPreview) {
|
|
7651
|
-
const childId = nestPreview.slotId.split("::nest::")[1] ?? "";
|
|
7652
|
-
allowNest = !!childId && !isLargeDraggedNode;
|
|
7653
|
-
}
|
|
7697
|
+
const allowNest = computeAllowNest(nestPreview, isLargeDraggedNode, !!refs.rowLockedRef.current);
|
|
7654
7698
|
if (!allowNest) {
|
|
7655
7699
|
refs.nestCandidateRef.current = null;
|
|
7656
7700
|
refs.nestTargetRef.current = null;
|
|
@@ -7835,6 +7879,18 @@ function useDragVisualLoop({
|
|
|
7835
7879
|
|
|
7836
7880
|
// src/client/dnd/design-mode/useDragLifecycle.ts
|
|
7837
7881
|
import { useState as useState5, useCallback as useCallback6 } from "react";
|
|
7882
|
+
function resolveLaneAllowedContainers(anchorElement, srcContainerId) {
|
|
7883
|
+
if (!srcContainerId) return null;
|
|
7884
|
+
if (!resolveRowBinding(anchorElement)) return null;
|
|
7885
|
+
return /* @__PURE__ */ new Set([srcContainerId]);
|
|
7886
|
+
}
|
|
7887
|
+
function buildDragIntentEngineOptions(anchorElement, srcContainerId, blockedContainerIds) {
|
|
7888
|
+
return {
|
|
7889
|
+
laneRootContainerId: srcContainerId,
|
|
7890
|
+
laneAllowedContainers: resolveLaneAllowedContainers(anchorElement, srcContainerId),
|
|
7891
|
+
blockedContainerIds
|
|
7892
|
+
};
|
|
7893
|
+
}
|
|
7838
7894
|
function buildRuntimeIdentityLocal(nodeId, resolveNodeElement, effectiveLaneSnapshot) {
|
|
7839
7895
|
if (!nodeId) return null;
|
|
7840
7896
|
const element = resolveNodeElement(nodeId);
|
|
@@ -8034,6 +8090,7 @@ function useDragLifecycle({
|
|
|
8034
8090
|
refs.lastIntentRef.current = null;
|
|
8035
8091
|
refs.visualIntentRef.current = null;
|
|
8036
8092
|
refs.sourceContainerIdRef.current = null;
|
|
8093
|
+
refs.rowLockedRef.current = false;
|
|
8037
8094
|
refs.dragSessionAnchorRef.current = null;
|
|
8038
8095
|
refs.lockRef.current = { containerId: null, isCrossUnlocked: false, exitSince: null, unlockUntilTs: null };
|
|
8039
8096
|
refs.targetPlaneRef.current = "lane";
|
|
@@ -8089,10 +8146,9 @@ function useDragLifecycle({
|
|
|
8089
8146
|
const startPosition = getCurrentCommitPlacement(anchorNodeId, srcContainerId);
|
|
8090
8147
|
const blockedContainerIds = buildBlockedStructuralContainerIds(proj, refs.nodeMapRef.current, srcContainerId);
|
|
8091
8148
|
refs.blockedContainerIdsRef.current = blockedContainerIds;
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
});
|
|
8149
|
+
const engineOptions = buildDragIntentEngineOptions(anchorScanned.element, srcContainerId, blockedContainerIds);
|
|
8150
|
+
refs.rowLockedRef.current = !!engineOptions.laneAllowedContainers;
|
|
8151
|
+
refs.engineRef.current = createDragIntentEngine(proj, anchorNodeId, engineOptions);
|
|
8096
8152
|
refs.engineRef.current.setTargetPlane("lane");
|
|
8097
8153
|
refs.targetPlaneRef.current = "lane";
|
|
8098
8154
|
refs.sourceContainerIdRef.current = srcContainerId;
|
|
@@ -8475,7 +8531,9 @@ function useExternalDragLoop({
|
|
|
8475
8531
|
externalDrag,
|
|
8476
8532
|
refs,
|
|
8477
8533
|
resolveNodeElement,
|
|
8478
|
-
setDropLine
|
|
8534
|
+
setDropLine,
|
|
8535
|
+
scrollX,
|
|
8536
|
+
scrollY
|
|
8479
8537
|
);
|
|
8480
8538
|
return;
|
|
8481
8539
|
}
|
|
@@ -8508,10 +8566,8 @@ function useExternalDragLoop({
|
|
|
8508
8566
|
return () => cancelAnimationFrame(rafId);
|
|
8509
8567
|
}, [externalDrag, elements, refs, resolveNodeElement, setDropLine]);
|
|
8510
8568
|
}
|
|
8511
|
-
function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, setDropLine) {
|
|
8512
|
-
const
|
|
8513
|
-
const scrollY = window.scrollY;
|
|
8514
|
-
const intent = engine.resolve(x, y, scrollX, scrollY, scrollX, scrollY);
|
|
8569
|
+
function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, setDropLine, startScrollX, startScrollY) {
|
|
8570
|
+
const intent = engine.resolve(x, y, window.scrollX, window.scrollY, startScrollX, startScrollY);
|
|
8515
8571
|
if (!intent || intent.mode !== "reorder") {
|
|
8516
8572
|
useDesignModeStore.getState().cancelExternalDrag();
|
|
8517
8573
|
setDropLine(null);
|
package/dist/index.d.mts
CHANGED
|
@@ -11,6 +11,7 @@ import { types, PluginObj } from '@babel/core';
|
|
|
11
11
|
* The injected prop contains:
|
|
12
12
|
* nodeId, file, line, col, componentName, staticProps, movable, parentNodeId
|
|
13
13
|
* + (ARCH-883 F1) slot, propBindings, propOwner
|
|
14
|
+
* + (ARCH-883-KOI) origin
|
|
14
15
|
*
|
|
15
16
|
* At runtime the Fiber bridge reads `memoizedProps.__editorMeta` to resolve
|
|
16
17
|
* element identity without any DOM attributes.
|
|
@@ -30,6 +31,10 @@ import { types, PluginObj } from '@babel/core';
|
|
|
30
31
|
* 3. `movable: false` for kit-origin nodes — reordering inside a kit template
|
|
31
32
|
* affects N usages, a permanent non-objective (PRD §1.3).
|
|
32
33
|
*
|
|
34
|
+
* ARCH-883-KOI (kit-origin-identity, CREW round) adds a FOURTH: `origin: 'kit'`
|
|
35
|
+
* on every kit-origin node (see `types/editor-meta.ts`'s docstring on that
|
|
36
|
+
* field for why it exists separately from `movable`).
|
|
37
|
+
*
|
|
33
38
|
* `parentNodeId` stays INTRA-FILE by construction (it only ever walks JSX
|
|
34
39
|
* ancestors within the file being transformed), so it never links a kit template
|
|
35
40
|
* node to a screen usage; per SDD §2.3 it must not be used across that seam.
|
|
@@ -174,6 +179,52 @@ interface EditorMeta {
|
|
|
174
179
|
* DOM. The root node of a kit template emits `null` here.
|
|
175
180
|
*/
|
|
176
181
|
parentNodeId: string | null;
|
|
182
|
+
/**
|
|
183
|
+
* `'kit'` when the node comes from a kit template — emitted with
|
|
184
|
+
* `origin: 'kit'`, or carrying a slot (which makes it kit-origin by
|
|
185
|
+
* definition). Absent means screen-origin.
|
|
186
|
+
*
|
|
187
|
+
* WHY THIS EXISTS SEPARATELY FROM `movable`. Both are `false`/`'kit'` for a
|
|
188
|
+
* kit node, so it looks redundant, and it is not: `movable` is ALSO `false`
|
|
189
|
+
* for map-callback roots, fragment children and expression-container siblings
|
|
190
|
+
* in ordinary SCREENS (RFC E2.4 §2.7). A consumer that wants "may this node
|
|
191
|
+
* be reordered at all, by any write path" must not read `movable` — it would
|
|
192
|
+
* over-block exactly the list instances that reorder through their backing
|
|
193
|
+
* data. `origin` answers the narrower, structural question: this node is one
|
|
194
|
+
* template behind N usages, so no write path can ever reorder it (PRD §1.3).
|
|
195
|
+
*
|
|
196
|
+
* ABSENCE IS AMBIGUOUS, NOT SAFE, on today's fleet — this is NOT the same
|
|
197
|
+
* claim as "reads the same as screen-origin, the pre-existing meaning of
|
|
198
|
+
* every meta" (an earlier version of this doc said exactly that, and it is
|
|
199
|
+
* false for the current deployed fleet; kept here as the record of the
|
|
200
|
+
* CREW correction, ARCH-883-KOI F4). Two axes move independently:
|
|
201
|
+
*
|
|
202
|
+
* 1. Whether kit COMPONENTS render instrumented (kit-runtime's late-
|
|
203
|
+
* binding fix — a separate repo/change from this one).
|
|
204
|
+
* 2. Whether the `@archie/devtools` version that built a given bundle
|
|
205
|
+
* emits `origin` at all (this field).
|
|
206
|
+
*
|
|
207
|
+
* A page can be on axis-1-yes / axis-2-no TODAY: kit-runtime already
|
|
208
|
+
* instruments kit components on pages whose screen (or kit) build used a
|
|
209
|
+
* pre-`origin` `@archie/devtools`. On such a page a kit-internal host's
|
|
210
|
+
* template meta is present (per the P0-1 thunk) but carries no `origin`
|
|
211
|
+
* key — indistinguishable from a genuine screen-origin meta by this field
|
|
212
|
+
* alone. A consumer that trusts absence-means-screen-origin on that page
|
|
213
|
+
* reproduces the exact F1 bug this change fixes, silently.
|
|
214
|
+
*
|
|
215
|
+
* There is no per-node way to close this gap (a missing field cannot prove
|
|
216
|
+
* its own absence is meaningful). The mitigation is PAGE-LEVEL: the
|
|
217
|
+
* standalone inspector script's `INSPECTOR_SCRIPT_LOADED` handshake reports
|
|
218
|
+
* a `kitOriginIdentity` capability bit (see `inspector.standalone.js`) that
|
|
219
|
+
* tells the host "this SCRIPT understands `origin` and projects across the
|
|
220
|
+
* kit boundary" — it does NOT and cannot tell the host whether the PAGE's
|
|
221
|
+
* own plugin build emitted the field, which is the acg/kitgen build's
|
|
222
|
+
* `@archie/devtools` version, an axis this package has no visibility into.
|
|
223
|
+
* Hosts that need a hard guarantee must track that build version
|
|
224
|
+
* themselves; this capability bit only rules out "the runtime code is too
|
|
225
|
+
* old to know what `origin` means" as a failure mode.
|
|
226
|
+
*/
|
|
227
|
+
origin?: 'kit';
|
|
177
228
|
/**
|
|
178
229
|
* Curated kit slot label, e.g. `"AuthFrame/aside/headline"` (SDD §2.6).
|
|
179
230
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { types, PluginObj } from '@babel/core';
|
|
|
11
11
|
* The injected prop contains:
|
|
12
12
|
* nodeId, file, line, col, componentName, staticProps, movable, parentNodeId
|
|
13
13
|
* + (ARCH-883 F1) slot, propBindings, propOwner
|
|
14
|
+
* + (ARCH-883-KOI) origin
|
|
14
15
|
*
|
|
15
16
|
* At runtime the Fiber bridge reads `memoizedProps.__editorMeta` to resolve
|
|
16
17
|
* element identity without any DOM attributes.
|
|
@@ -30,6 +31,10 @@ import { types, PluginObj } from '@babel/core';
|
|
|
30
31
|
* 3. `movable: false` for kit-origin nodes — reordering inside a kit template
|
|
31
32
|
* affects N usages, a permanent non-objective (PRD §1.3).
|
|
32
33
|
*
|
|
34
|
+
* ARCH-883-KOI (kit-origin-identity, CREW round) adds a FOURTH: `origin: 'kit'`
|
|
35
|
+
* on every kit-origin node (see `types/editor-meta.ts`'s docstring on that
|
|
36
|
+
* field for why it exists separately from `movable`).
|
|
37
|
+
*
|
|
33
38
|
* `parentNodeId` stays INTRA-FILE by construction (it only ever walks JSX
|
|
34
39
|
* ancestors within the file being transformed), so it never links a kit template
|
|
35
40
|
* node to a screen usage; per SDD §2.3 it must not be used across that seam.
|
|
@@ -174,6 +179,52 @@ interface EditorMeta {
|
|
|
174
179
|
* DOM. The root node of a kit template emits `null` here.
|
|
175
180
|
*/
|
|
176
181
|
parentNodeId: string | null;
|
|
182
|
+
/**
|
|
183
|
+
* `'kit'` when the node comes from a kit template — emitted with
|
|
184
|
+
* `origin: 'kit'`, or carrying a slot (which makes it kit-origin by
|
|
185
|
+
* definition). Absent means screen-origin.
|
|
186
|
+
*
|
|
187
|
+
* WHY THIS EXISTS SEPARATELY FROM `movable`. Both are `false`/`'kit'` for a
|
|
188
|
+
* kit node, so it looks redundant, and it is not: `movable` is ALSO `false`
|
|
189
|
+
* for map-callback roots, fragment children and expression-container siblings
|
|
190
|
+
* in ordinary SCREENS (RFC E2.4 §2.7). A consumer that wants "may this node
|
|
191
|
+
* be reordered at all, by any write path" must not read `movable` — it would
|
|
192
|
+
* over-block exactly the list instances that reorder through their backing
|
|
193
|
+
* data. `origin` answers the narrower, structural question: this node is one
|
|
194
|
+
* template behind N usages, so no write path can ever reorder it (PRD §1.3).
|
|
195
|
+
*
|
|
196
|
+
* ABSENCE IS AMBIGUOUS, NOT SAFE, on today's fleet — this is NOT the same
|
|
197
|
+
* claim as "reads the same as screen-origin, the pre-existing meaning of
|
|
198
|
+
* every meta" (an earlier version of this doc said exactly that, and it is
|
|
199
|
+
* false for the current deployed fleet; kept here as the record of the
|
|
200
|
+
* CREW correction, ARCH-883-KOI F4). Two axes move independently:
|
|
201
|
+
*
|
|
202
|
+
* 1. Whether kit COMPONENTS render instrumented (kit-runtime's late-
|
|
203
|
+
* binding fix — a separate repo/change from this one).
|
|
204
|
+
* 2. Whether the `@archie/devtools` version that built a given bundle
|
|
205
|
+
* emits `origin` at all (this field).
|
|
206
|
+
*
|
|
207
|
+
* A page can be on axis-1-yes / axis-2-no TODAY: kit-runtime already
|
|
208
|
+
* instruments kit components on pages whose screen (or kit) build used a
|
|
209
|
+
* pre-`origin` `@archie/devtools`. On such a page a kit-internal host's
|
|
210
|
+
* template meta is present (per the P0-1 thunk) but carries no `origin`
|
|
211
|
+
* key — indistinguishable from a genuine screen-origin meta by this field
|
|
212
|
+
* alone. A consumer that trusts absence-means-screen-origin on that page
|
|
213
|
+
* reproduces the exact F1 bug this change fixes, silently.
|
|
214
|
+
*
|
|
215
|
+
* There is no per-node way to close this gap (a missing field cannot prove
|
|
216
|
+
* its own absence is meaningful). The mitigation is PAGE-LEVEL: the
|
|
217
|
+
* standalone inspector script's `INSPECTOR_SCRIPT_LOADED` handshake reports
|
|
218
|
+
* a `kitOriginIdentity` capability bit (see `inspector.standalone.js`) that
|
|
219
|
+
* tells the host "this SCRIPT understands `origin` and projects across the
|
|
220
|
+
* kit boundary" — it does NOT and cannot tell the host whether the PAGE's
|
|
221
|
+
* own plugin build emitted the field, which is the acg/kitgen build's
|
|
222
|
+
* `@archie/devtools` version, an axis this package has no visibility into.
|
|
223
|
+
* Hosts that need a hard guarantee must track that build version
|
|
224
|
+
* themselves; this capability bit only rules out "the runtime code is too
|
|
225
|
+
* old to know what `origin` means" as a failure mode.
|
|
226
|
+
*/
|
|
227
|
+
origin?: 'kit';
|
|
177
228
|
/**
|
|
178
229
|
* Curated kit slot label, e.g. `"AuthFrame/aside/headline"` (SDD §2.6).
|
|
179
230
|
*
|
package/dist/index.js
CHANGED
|
@@ -733,6 +733,11 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
733
733
|
parentNodeId ? t.stringLiteral(parentNodeId) : t.nullLiteral()
|
|
734
734
|
)
|
|
735
735
|
]);
|
|
736
|
+
if (isKitOrigin) {
|
|
737
|
+
metaObj.properties.push(
|
|
738
|
+
t.objectProperty(t.identifier("origin"), t.stringLiteral("kit"))
|
|
739
|
+
);
|
|
740
|
+
}
|
|
736
741
|
if (slot !== null) {
|
|
737
742
|
metaObj.properties.push(
|
|
738
743
|
t.objectProperty(t.identifier("slot"), t.stringLiteral(slot))
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Archie Inspector - Standalone script for CDN injection.
|
|
3
|
-
* Set before loading: window.__ARCHIE_INSPECTOR_TARGET_ORIGIN__, window.__ARCHIE_INSPECTOR_ALLOWED_ORIGINS__
|
|
4
|
-
* Then load: <script src="https://your-cdn/inspector.standalone.js"></script>
|
|
5
|
-
* Auto-runs if configured; or call window.__ARCHIE_INSPECTOR_RUN__().
|
|
6
|
-
* Security: No eval(), no "*" origins; style values sanitized.
|
|
7
|
-
*/
|
|
1
|
+
/** Archie Inspector standalone: safe DOM inspector for CDN use. */
|
|
8
2
|
;(function () {
|
|
9
3
|
"use strict"
|
|
10
4
|
// Capture originals at module load time so the patch below is never recursive
|
|
@@ -95,19 +89,10 @@
|
|
|
95
89
|
var FIBER_KEY_PREFIX = "__reactFiber$"
|
|
96
90
|
var PROPS_KEY_PREFIX = "__reactProps$"
|
|
97
91
|
|
|
98
|
-
//
|
|
99
|
-
// emits __editorMeta as a zero-arg function, not the object literal
|
|
100
|
-
// directly, so React never writes it into the DOM. Every extraction
|
|
101
|
-
// site below must invoke the value when it is a function. Mirrors
|
|
102
|
-
// readEditorMetaValue in fiber-bridge.ts — if this changes, update
|
|
103
|
-
// that copy to maintain parity.
|
|
92
|
+
// __editorMeta is emitted as a thunk; invoke it (parity with fiber-bridge).
|
|
104
93
|
function resolveEditorMetaValue(value) {
|
|
105
94
|
if (typeof value === "function") {
|
|
106
|
-
//
|
|
107
|
-
// closure and returns a FRESH object literal — never rely on
|
|
108
|
-
// meta object identity (`===`) across two separate reads, even
|
|
109
|
-
// within the same render (mirrors readEditorMetaValue in
|
|
110
|
-
// fiber-bridge.ts).
|
|
95
|
+
// Invoke thunk and return a fresh meta object (do not rely on identity).
|
|
111
96
|
return value()
|
|
112
97
|
}
|
|
113
98
|
// Twin parity with fiber-bridge.ts's readEditorMetaValue: only
|
|
@@ -338,19 +323,56 @@
|
|
|
338
323
|
return hosts.length === 1 ? hosts[0] : null
|
|
339
324
|
}
|
|
340
325
|
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
326
|
+
// The fiber owning the nearest NON-kit __editorMeta for `el` — the usage
|
|
327
|
+
// written in a screen, reached across however many kit template frames
|
|
328
|
+
// sit in between. Vanilla twin of getUsageMetaOwnerFiber
|
|
329
|
+
// (fiber-bridge.ts); see that docstring for why the nearest meta is the
|
|
330
|
+
// wrong one once the kit itself is instrumented.
|
|
331
|
+
function getUsageMetaOwnerFiberFromElement(el) {
|
|
332
|
+
var fiber = getFiberFromElement(el)
|
|
333
|
+
while (fiber) {
|
|
334
|
+
if (fiber.memoizedProps && fiber.memoizedProps.__editorMeta) {
|
|
335
|
+
var meta = resolveEditorMetaValue(fiber.memoizedProps.__editorMeta)
|
|
336
|
+
if (meta && meta.origin !== "kit") return fiber
|
|
337
|
+
}
|
|
338
|
+
fiber = fiber["return"]
|
|
339
|
+
}
|
|
340
|
+
return null
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// The meta `owner` carries, but only if `el` is the single host it renders.
|
|
344
|
+
function projectFromOwnerFiber(owner, el) {
|
|
347
345
|
if (!owner) return null
|
|
348
346
|
if (getSingleHostElementFromFiber(owner) !== el) return null
|
|
349
347
|
return resolveEditorMetaValue(owner.memoizedProps.__editorMeta)
|
|
350
348
|
}
|
|
351
349
|
|
|
352
|
-
//
|
|
353
|
-
//
|
|
350
|
+
// Vanilla twin of projectUsageMeta (fiber-bridge.ts): the usage meta when
|
|
351
|
+
// `el` is the SINGLE host root a component usage renders and that usage's
|
|
352
|
+
// meta never reached the host fiber — because the component destructured
|
|
353
|
+
// its props, or because the plugin sanitized it out of the spread (which
|
|
354
|
+
// is every kit component, once the kit is instrumented).
|
|
355
|
+
function projectUsageMetaFromElement(el) {
|
|
356
|
+
var direct = getDirectEditorMetaFromElement(el)
|
|
357
|
+
if (direct && direct.origin !== "kit") return null
|
|
358
|
+
|
|
359
|
+
var usage = projectFromOwnerFiber(
|
|
360
|
+
getUsageMetaOwnerFiberFromElement(el),
|
|
361
|
+
el
|
|
362
|
+
)
|
|
363
|
+
if (usage) return usage
|
|
364
|
+
|
|
365
|
+
// A kit-internal host already has its own identity; nothing to project.
|
|
366
|
+
if (direct) return null
|
|
367
|
+
|
|
368
|
+
return projectFromOwnerFiber(
|
|
369
|
+
getEditorMetaOwnerFiberFromElement(el),
|
|
370
|
+
el
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// The nodeId this element carries AS ITS OWN — the single-host projection,
|
|
375
|
+
// then direct fiber meta. NEVER an inherited ancestor nodeId: walking the
|
|
354
376
|
// fiber chain here made every UNSTAMPED subtree (any two siblings
|
|
355
377
|
// rendered by a component the plugin never transformed — anything from
|
|
356
378
|
// node_modules, and here SVG internals too, since this twin accepts any
|
|
@@ -358,13 +380,39 @@
|
|
|
358
380
|
// direct-meta-ONLY rule would make every kit component that destructures
|
|
359
381
|
// its props look like a singleton — which is the fail-OPEN mistake, and
|
|
360
382
|
// would write a literal into a mapped usage, changing every row.
|
|
361
|
-
//
|
|
383
|
+
// The projection is checked FIRST because an instrumented kit gives every
|
|
384
|
+
// <Card/> host the same template nodeId; two unrelated Cards under one
|
|
385
|
+
// parent would otherwise read as one repeated source position.
|
|
386
|
+
//
|
|
387
|
+
// ARCH-883-KOI F1 (CREW round): a direct KIT meta is the TEMPLATE's
|
|
388
|
+
// position, shared by every usage. When a screen USAGE exists above (the
|
|
389
|
+
// projection bailed only because `el` is a template-internal node BELOW
|
|
390
|
+
// the usage's single host root — a <Card/>'s inner <span>, not the outer
|
|
391
|
+
// <div> the projection already caught) the id CANNOT be the bare usage
|
|
392
|
+
// nodeId: every other template-internal node under that SAME usage (the
|
|
393
|
+
// sibling <p>) would walk to the identical usage fiber and report the
|
|
394
|
+
// identical id, collapsing two distinct template positions into one and
|
|
395
|
+
// making `findCollectionWindow` read them as a false repeated collection
|
|
396
|
+
// with no real key — refusing a legitimate kit-internal edit. The id is
|
|
397
|
+
// instead a COMPOSITE of the usage's nodeId and this node's OWN template
|
|
398
|
+
// position: stable across N repeats of the SAME position (the
|
|
399
|
+
// DataTable-row case — same usage, same template row id, correctly still
|
|
400
|
+
// a collection) while distinct across different positions under one
|
|
401
|
+
// usage (span vs p). Mirrors ownNodeId in instance-identity.ts — if this
|
|
402
|
+
// changes, update that copy to maintain parity.
|
|
362
403
|
function ownMetaNodeId(el) {
|
|
363
404
|
if (!el || el.nodeType !== 1) return null
|
|
364
|
-
var direct = getDirectEditorMetaFromElement(el)
|
|
365
|
-
if (direct && direct.nodeId) return direct.nodeId
|
|
366
405
|
var projected = projectUsageMetaFromElement(el)
|
|
367
|
-
|
|
406
|
+
if (projected && projected.nodeId) return projected.nodeId
|
|
407
|
+
var direct = getDirectEditorMetaFromElement(el)
|
|
408
|
+
if (direct && direct.origin === "kit") {
|
|
409
|
+
var usageOwner = getUsageMetaOwnerFiberFromElement(el)
|
|
410
|
+
var usage =
|
|
411
|
+
usageOwner &&
|
|
412
|
+
resolveEditorMetaValue(usageOwner.memoizedProps.__editorMeta)
|
|
413
|
+
if (usage && usage.nodeId) return usage.nodeId + " " + direct.nodeId
|
|
414
|
+
}
|
|
415
|
+
return direct && direct.nodeId ? direct.nodeId : null
|
|
368
416
|
}
|
|
369
417
|
|
|
370
418
|
// The repeated-row boundary above `el`, or a search outcome explaining
|
|
@@ -786,6 +834,17 @@
|
|
|
786
834
|
function getExactSourceSignatureFromElement(element) {
|
|
787
835
|
if (!element) return ""
|
|
788
836
|
|
|
837
|
+
// The projected USAGE outranks the element's own meta. On an
|
|
838
|
+
// instrumented kit the host of a `<Card/>` carries the kit TEMPLATE's
|
|
839
|
+
// meta, so reading the direct one first signs the selection as
|
|
840
|
+
// `card.jsx` — a file the per-screen save path cannot write, which
|
|
841
|
+
// surfaces to the user as "no editable source for these changes".
|
|
842
|
+
var usageMeta = projectUsageMetaFromElement(element)
|
|
843
|
+
var usageSignature = usageMeta
|
|
844
|
+
? getSharedSignatureFromMeta(usageMeta)
|
|
845
|
+
: ""
|
|
846
|
+
if (usageSignature) return usageSignature
|
|
847
|
+
|
|
789
848
|
var directMeta = getDirectEditorMetaFromElement(element)
|
|
790
849
|
var directSignature = directMeta
|
|
791
850
|
? getSharedSignatureFromMeta(directMeta)
|
|
@@ -1099,6 +1158,15 @@
|
|
|
1099
1158
|
function getInspectorInfoFromElement(element) {
|
|
1100
1159
|
if (!element) return null
|
|
1101
1160
|
|
|
1161
|
+
// Same precedence as getExactSourceSignatureFromElement: the usage the
|
|
1162
|
+
// screen wrote outranks the kit template that rendered the host. This
|
|
1163
|
+
// is the value that becomes `inspectorSource` in ELEMENT_SELECTED, so
|
|
1164
|
+
// getting it wrong is what makes the host app refuse the save.
|
|
1165
|
+
var usageMeta = projectUsageMetaFromElement(element)
|
|
1166
|
+
if (usageMeta) {
|
|
1167
|
+
return buildInspectorInfoFromMeta(usageMeta)
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1102
1170
|
var directMeta = getDirectEditorMetaFromElement(element)
|
|
1103
1171
|
if (directMeta) {
|
|
1104
1172
|
return buildInspectorInfoFromMeta(directMeta)
|
|
@@ -1350,7 +1418,11 @@
|
|
|
1350
1418
|
// 2.3.0 (ARCH-1065 A17-support): additive only — `QUERY_COLLECTION_ORDER`
|
|
1351
1419
|
// in the message protocol and `capabilities.collectionOrderQuery`
|
|
1352
1420
|
// below. No existing field changed shape, so `protocolVersion` stays 1.
|
|
1353
|
-
|
|
1421
|
+
// 2.4.0 (ARCH-883-KOI, CREW round): additive only — `origin` on
|
|
1422
|
+
// `EditorMeta`, the usage-projected `ownMetaNodeId`/`inspectorSource`/
|
|
1423
|
+
// `editorInstance` resolution, and `capabilities.kitOriginIdentity`
|
|
1424
|
+
// below. No existing field changed shape, so `protocolVersion` stays 1.
|
|
1425
|
+
version: "2.4.0",
|
|
1354
1426
|
protocolVersion: 1,
|
|
1355
1427
|
capabilities: {
|
|
1356
1428
|
// 2.1.1: function-valued __editorMeta props are invoked before any
|
|
@@ -1391,6 +1463,24 @@
|
|
|
1391
1463
|
// concept, singular mechanism — are treated as opaque strings
|
|
1392
1464
|
// elsewhere in this file).
|
|
1393
1465
|
bindingContract: readBindingContractMeta(),
|
|
1466
|
+
// ARCH-883-KOI F4 (v2.4.0) — this SCRIPT resolves `EditorMeta.origin`
|
|
1467
|
+
// and projects identity across an instrumented kit boundary
|
|
1468
|
+
// (`ownMetaNodeId`, `projectUsageMetaFromElement`,
|
|
1469
|
+
// `getInspectorInfoFromElement`, `resolveInstanceIdentity`). Hosts
|
|
1470
|
+
// MUST feature-detect on this flag before trusting `origin`
|
|
1471
|
+
// (absent or `editorMeta.origin === 'kit'`) as meaningful: a frozen
|
|
1472
|
+
// pre-2.4.0 inspector never reads the field at all, so its
|
|
1473
|
+
// `inspectorSource`/`editorInstance` on an instrumented-kit page
|
|
1474
|
+
// reproduce the exact F1 bug this version fixes.
|
|
1475
|
+
//
|
|
1476
|
+
// What this bit CANNOT tell the host: whether the PAGE's own build
|
|
1477
|
+
// emitted `origin` on its metas in the first place — that is the
|
|
1478
|
+
// `@archie/devtools` version the acg/kitgen esbuild path had
|
|
1479
|
+
// installed when the screen (or the kit) was built, a completely
|
|
1480
|
+
// separate axis from this CDN script's version (see the `origin`
|
|
1481
|
+
// field's docstring in `types/editor-meta.ts` for the full
|
|
1482
|
+
// reasoning, and why NO per-node signal can close that gap).
|
|
1483
|
+
kitOriginIdentity: true,
|
|
1394
1484
|
},
|
|
1395
1485
|
})
|
|
1396
1486
|
|