@archie/devtools 0.0.23 → 0.0.24

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.
@@ -274,6 +274,156 @@
274
274
  return null
275
275
  }
276
276
 
277
+ // ── ARCH-883 F2 — usage chain + instance identity ───────────────────
278
+ // Vanilla twins of collectEditorMetaChain (fiber-bridge.ts) and
279
+ // resolveInstanceIdentity (instance-identity.ts). Those files carry the
280
+ // full rationale; keep the three in step.
281
+ var MAX_META_CHAIN = 24
282
+
283
+ // Every __editorMeta on the fiber return chain, innermost first. The host
284
+ // needs the FULL metas (staticProps/propBindings/propOwner), not the
285
+ // narrowed inspectorSource shape: routing a kit-internal node means
286
+ // finding the USAGE above it and reading the prop value AT that usage.
287
+ function collectEditorMetaChain(el) {
288
+ var chain = []
289
+ var fiber = getFiberFromElement(el)
290
+ while (fiber && chain.length < MAX_META_CHAIN) {
291
+ if (fiber.memoizedProps && fiber.memoizedProps.__editorMeta) {
292
+ var meta = resolveEditorMetaValue(fiber.memoizedProps.__editorMeta)
293
+ if (meta) chain.push(meta)
294
+ }
295
+ fiber = fiber["return"]
296
+ }
297
+ return chain
298
+ }
299
+
300
+ var MAX_ROW_ROOT_DEPTH = 12
301
+ var MAX_KEY_WALK = 40
302
+
303
+ // The fiber that OWNS the nearest __editorMeta for `el`. Vanilla twin of
304
+ // getEditorMetaOwnerFiber (fiber-bridge.ts).
305
+ function getEditorMetaOwnerFiberFromElement(el) {
306
+ var fiber = getFiberFromElement(el)
307
+ while (fiber) {
308
+ if (fiber.memoizedProps && fiber.memoizedProps.__editorMeta) {
309
+ return fiber
310
+ }
311
+ fiber = fiber["return"]
312
+ }
313
+ return null
314
+ }
315
+
316
+ // The SINGLE host element `owner` renders, or null when it renders zero
317
+ // or several, or crosses a HostPortal (tag 4). Vanilla twin of
318
+ // getSingleHostElement (fiber-bridge.ts) — conservative by design.
319
+ function getSingleHostElementFromFiber(owner) {
320
+ var hosts = []
321
+ var stack = owner && owner.child ? [owner.child] : []
322
+ while (stack.length > 0) {
323
+ var fiber = stack.pop()
324
+ if (!fiber) continue
325
+ if (fiber.tag === 4) return null
326
+ if (
327
+ typeof fiber.type === "string" &&
328
+ fiber.stateNode &&
329
+ fiber.stateNode.nodeType === 1
330
+ ) {
331
+ hosts.push(fiber.stateNode)
332
+ if (hosts.length > 1) return null
333
+ } else if (fiber.child) {
334
+ stack.push(fiber.child)
335
+ }
336
+ if (fiber.sibling) stack.push(fiber.sibling)
337
+ }
338
+ return hosts.length === 1 ? hosts[0] : null
339
+ }
340
+
341
+ // Vanilla twin of projectUsageMeta (useElementScanner.ts): the usage meta
342
+ // when `el` is the SINGLE host root a component usage renders and that
343
+ // component destructured its props, so the host fiber carries no meta.
344
+ function projectUsageMetaFromElement(el) {
345
+ if (getDirectEditorMetaFromElement(el)) return null
346
+ var owner = getEditorMetaOwnerFiberFromElement(el)
347
+ if (!owner) return null
348
+ if (getSingleHostElementFromFiber(owner) !== el) return null
349
+ return resolveEditorMetaValue(owner.memoizedProps.__editorMeta)
350
+ }
351
+
352
+ // The nodeId this element carries AS ITS OWN — direct fiber meta, or the
353
+ // single-host projection. NEVER an inherited ancestor nodeId: walking the
354
+ // fiber chain here made every UNSTAMPED subtree (any two siblings
355
+ // rendered by a component the plugin never transformed — anything from
356
+ // node_modules, and here SVG internals too, since this twin accepts any
357
+ // element node) look like a repeated collection. Meanwhile a
358
+ // direct-meta-ONLY rule would make every kit component that destructures
359
+ // its props look like a singleton — which is the fail-OPEN mistake, and
360
+ // would write a literal into a mapped usage, changing every row.
361
+ // See instance-identity.ts for the full rationale.
362
+ function ownMetaNodeId(el) {
363
+ if (!el || el.nodeType !== 1) return null
364
+ var direct = getDirectEditorMetaFromElement(el)
365
+ if (direct && direct.nodeId) return direct.nodeId
366
+ var projected = projectUsageMetaFromElement(el)
367
+ return projected && projected.nodeId ? projected.nodeId : null
368
+ }
369
+
370
+ // The repeated-row boundary above `el`, or null. INNERMOST repetition
371
+ // wins (a tag inside a card inside a list is identified by the tag's key).
372
+ function findCollectionWindow(el) {
373
+ var node = el
374
+ for (var depth = 0; depth < MAX_ROW_ROOT_DEPTH; depth++) {
375
+ var parent = node.parentElement
376
+ if (!parent) return null
377
+
378
+ var nodeId = ownMetaNodeId(node)
379
+ if (nodeId !== null) {
380
+ var twins = []
381
+ for (var i = 0; i < parent.children.length; i++) {
382
+ var child = parent.children[i]
383
+ if (ownMetaNodeId(child) === nodeId) twins.push(child)
384
+ }
385
+ if (twins.length >= 2) {
386
+ return {
387
+ rowRoot: node,
388
+ container: parent,
389
+ ordinal: twins.indexOf(node),
390
+ }
391
+ }
392
+ }
393
+
394
+ node = parent
395
+ }
396
+ return null
397
+ }
398
+
399
+ // Nearest React key BETWEEN the row root and the collection container.
400
+ // Stopping at the container is the point: a keyed ancestor above it
401
+ // identifies a page, not a row.
402
+ function keyWithinWindow(rowRoot, container) {
403
+ var fiber = getFiberFromElement(rowRoot)
404
+ for (var steps = 0; fiber && steps < MAX_KEY_WALK; steps++) {
405
+ if (fiber.stateNode === container) return null
406
+ var key = fiber.key
407
+ if (typeof key === "string" && key.length > 0) return key
408
+ if (typeof key === "number") return String(key)
409
+ fiber = fiber["return"]
410
+ }
411
+ return null
412
+ }
413
+
414
+ // WHICH instance of a possibly-repeated node this element is.
415
+ // `scanOrdinal` is telemetry/UI only — the host must REJECT an intent
416
+ // with inCollection && fiberKey === null, never fall back to it.
417
+ function resolveInstanceIdentity(el) {
418
+ var win = findCollectionWindow(el)
419
+ if (!win) return { fiberKey: null, scanOrdinal: 0, inCollection: false }
420
+ return {
421
+ fiberKey: keyWithinWindow(win.rowRoot, win.container),
422
+ scanOrdinal: win.ordinal,
423
+ inCollection: true,
424
+ }
425
+ }
426
+
277
427
  if (window._inspectorSharedTargetObserver) {
278
428
  try {
279
429
  window._inspectorSharedTargetObserver.disconnect()
@@ -2061,6 +2211,35 @@
2061
2211
  // this script's version. The slot string is opaque here; validating it
2062
2212
  // against kit-runtime's `slot-vocabulary` is the host's job.
2063
2213
  editorMeta: editorMeta ? editorMeta.meta : null,
2214
+ // ARCH-883 F2 — the two things the host cannot derive from
2215
+ // `editorMeta` alone (SDD §2.9):
2216
+ //
2217
+ // editorMetaChain: routing a kit-internal node needs the USAGE
2218
+ // (`<Kit.AuthFrame headline="…"/>` in screens/<slug>.jsx), which
2219
+ // is NOT the nearest meta — the nearest meta is the <h1> inside
2220
+ // AuthFrame's own template. The host locates the usage by
2221
+ // matching `propOwner` against a chain entry's componentName and
2222
+ // applies the usage-value law to that entry's staticProps. Both
2223
+ // fields live only on the full meta.
2224
+ //
2225
+ // editorInstance: WHICH row of a repeated node was clicked. The
2226
+ // nodeId is a source position and collides across instances; the
2227
+ // only identity that survives an insert above the edited row is
2228
+ // React's `key`, which exists on the fiber and nowhere else.
2229
+ //
2230
+ // Both are plain data, so an already-published copy of this script
2231
+ // forwards them through structured clone unchanged.
2232
+ //
2233
+ // The chain starts at the element the meta was FOUND on (the same
2234
+ // element `editorMeta` above describes) — a clicked node with no
2235
+ // fiber of its own would otherwise yield an empty chain while
2236
+ // reporting a meta resolved from its parent. The instance walk starts
2237
+ // at the CLICKED element, so an inner collection wins over an outer
2238
+ // one (a tag inside a card inside a list).
2239
+ editorMetaChain: collectEditorMetaChain(
2240
+ editorMeta ? editorMeta.element : element
2241
+ ),
2242
+ editorInstance: resolveInstanceIdentity(element),
2064
2243
  computedStyles: {
2065
2244
  display: computed.display,
2066
2245
  position: computed.position,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archie/devtools",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "description": "DevTools for Archie generated applications - Route synchronization and editor communication",
5
5
  "repository": {
6
6
  "type": "git",