@archie/devtools 0.0.20 → 0.0.22

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.js CHANGED
@@ -517,16 +517,28 @@ function archieDevTools(options = {}) {
517
517
  },
518
518
  configureServer(server) {
519
519
  server.middlewares.use(LOCAL_INSPECTOR_SERVE_PATH, (_req, res) => {
520
- const standaloneFile = (0, import_node_path.join)(__dirname, "../src/client/inject-inspector/inspector.standalone.js");
521
- try {
522
- const content = (0, import_node_fs.readFileSync)(standaloneFile, "utf-8");
523
- res.setHeader("Content-Type", "application/javascript; charset=utf-8");
524
- res.setHeader("Cache-Control", "no-store");
525
- res.end(content);
526
- } catch {
527
- res.statusCode = 404;
528
- res.end("Not found");
520
+ const candidates = [
521
+ (0, import_node_path.join)(__dirname, "client/inject-inspector/inspector.standalone.js"),
522
+ (0, import_node_path.join)(__dirname, "../src/client/inject-inspector/inspector.standalone.js")
523
+ ];
524
+ for (const candidate of candidates) {
525
+ try {
526
+ const content = (0, import_node_fs.readFileSync)(candidate, "utf-8");
527
+ res.setHeader(
528
+ "Content-Type",
529
+ "application/javascript; charset=utf-8"
530
+ );
531
+ res.setHeader("Cache-Control", "no-store");
532
+ res.end(content);
533
+ return;
534
+ } catch {
535
+ }
529
536
  }
537
+ server.config.logger.warn(
538
+ `[archie-devtools] inspector.standalone.js not found at ${LOCAL_INSPECTOR_SERVE_PATH}. Tried: ${candidates.join(", ")}. Did you build with \`pnpm build:local\`?`
539
+ );
540
+ res.statusCode = 404;
541
+ res.end("Not found");
530
542
  });
531
543
  },
532
544
  async transform(code, id) {
package/dist/index.mjs CHANGED
@@ -489,16 +489,28 @@ function archieDevTools(options = {}) {
489
489
  },
490
490
  configureServer(server) {
491
491
  server.middlewares.use(LOCAL_INSPECTOR_SERVE_PATH, (_req, res) => {
492
- const standaloneFile = join(__dirname, "../src/client/inject-inspector/inspector.standalone.js");
493
- try {
494
- const content = readFileSync(standaloneFile, "utf-8");
495
- res.setHeader("Content-Type", "application/javascript; charset=utf-8");
496
- res.setHeader("Cache-Control", "no-store");
497
- res.end(content);
498
- } catch {
499
- res.statusCode = 404;
500
- res.end("Not found");
492
+ const candidates = [
493
+ join(__dirname, "client/inject-inspector/inspector.standalone.js"),
494
+ join(__dirname, "../src/client/inject-inspector/inspector.standalone.js")
495
+ ];
496
+ for (const candidate of candidates) {
497
+ try {
498
+ const content = readFileSync(candidate, "utf-8");
499
+ res.setHeader(
500
+ "Content-Type",
501
+ "application/javascript; charset=utf-8"
502
+ );
503
+ res.setHeader("Cache-Control", "no-store");
504
+ res.end(content);
505
+ return;
506
+ } catch {
507
+ }
501
508
  }
509
+ server.config.logger.warn(
510
+ `[archie-devtools] inspector.standalone.js not found at ${LOCAL_INSPECTOR_SERVE_PATH}. Tried: ${candidates.join(", ")}. Did you build with \`pnpm build:local\`?`
511
+ );
512
+ res.statusCode = 404;
513
+ res.end("Not found");
502
514
  });
503
515
  },
504
516
  async transform(code, id) {
@@ -400,6 +400,12 @@
400
400
  return normalizedTarget
401
401
  }
402
402
 
403
+ // Palette-inserted elements have no React fiber and no source ref, so
404
+ // the source-signature walk below would skip past them and select the
405
+ // nearest ancestor with a source ref (the original <section>/<main>).
406
+ // We tag them with `data-dnd-force-allow` precisely to claim their
407
+ // own identity for selection/arrange; honor that tag here so a click
408
+ // on an inserted Card / Hero / Table targets the insert itself.
403
409
  var current = normalizedTarget
404
410
  while (
405
411
  current &&
@@ -407,6 +413,9 @@
407
413
  current !== document.documentElement &&
408
414
  !isInspectorElement(current)
409
415
  ) {
416
+ if (current.hasAttribute && current.hasAttribute("data-dnd-force-allow")) {
417
+ return current
418
+ }
410
419
  if (getExactSourceSignatureFromElement(current)) {
411
420
  return current
412
421
  }
@@ -855,7 +864,7 @@
855
864
  postMessageToParent({
856
865
  type: "INSPECTOR_SCRIPT_LOADED",
857
866
  timestamp: Date.now(),
858
- version: "2.0.3",
867
+ version: "2.1.0",
859
868
  protocolVersion: 1,
860
869
  capabilities: {
861
870
  inspect: true,
@@ -865,6 +874,11 @@
865
874
  hostControlledHistory: true,
866
875
  arrangeStructuredHistory: true,
867
876
  arrangeStrongNodeIdentity: true,
877
+ // Unified mode: SET_EDITOR_MODE "inspect" also enables the arrange
878
+ // (design) runtime — selection and drag/resize coexist. Hosts MUST
879
+ // feature-detect on this flag: a frozen 2.0.x inspector disables
880
+ // design mode on "inspect" and needs the legacy "design" mode.
881
+ unifiedInspectArrange: true,
868
882
  },
869
883
  })
870
884
 
@@ -902,6 +916,35 @@
902
916
  var inspectorCleanupMap = new WeakMap()
903
917
  var BADGE_UPDATE_DELAY_MS = 50
904
918
 
919
+ /**
920
+ * Bridge to design-mode store: publish current inspector selection as
921
+ * DND nodeIds so arrange overlay knows when to show resize handles +
922
+ * enable drag (single-select only). If the design-mode bundle hasn't
923
+ * mounted yet, buffer the latest selection for it to drain on mount.
924
+ */
925
+ function publishSelectionToDesignMode() {
926
+ var ids = []
927
+ for (var i = 0; i < selectedElements.length; i += 1) {
928
+ var el = selectedElements[i]
929
+ if (!el || typeof el.getAttribute !== "function") continue
930
+ var nodeId = el.getAttribute("data-dnd-node-id")
931
+ if (nodeId) ids.push(nodeId)
932
+ }
933
+ var bridge = window.__ARCHIE_DESIGN_MODE__
934
+ if (bridge && typeof bridge.setInspectorSelection === "function") {
935
+ try {
936
+ bridge.setInspectorSelection(ids)
937
+ } catch (err) {
938
+ // Defensive: never let a bridge error break inspector selection.
939
+ if (window._inspectorDebug) {
940
+ console.warn("[archie-inspector] design-mode bridge error", err)
941
+ }
942
+ }
943
+ } else {
944
+ window.__ARCHIE_DESIGN_MODE_PENDING__ = ids
945
+ }
946
+ }
947
+
905
948
  if (!window._inspectorSelectedElement) {
906
949
  window._inspectorSelectedElement = null
907
950
  }
@@ -925,7 +968,12 @@
925
968
  element === overlay ||
926
969
  element === selectedElementBadge ||
927
970
  element.id === "inspector-ping-effect" ||
928
- (element.closest && element.closest("[data-inspector-badge]"))
971
+ (element.closest && element.closest("[data-inspector-badge]")) ||
972
+ // Design-mode (arrange) overlay elements: HitArea, resize handles,
973
+ // drop-line, etc. These belong to the unified visual editor and must
974
+ // pass mousedown/click events through to React (dnd-kit) instead of
975
+ // being treated as inspect targets.
976
+ (element.closest && element.closest("[data-design-mode-ui]"))
929
977
  )
930
978
  }
931
979
 
@@ -1366,6 +1414,7 @@
1366
1414
  window._inspectorSelectedElement = null
1367
1415
  lastMultiSelectIntent = false
1368
1416
  isInspecting = true
1417
+ publishSelectionToDesignMode()
1369
1418
 
1370
1419
  const applyCursorStyles = () => {
1371
1420
  if (document.body) {
@@ -1396,6 +1445,7 @@
1396
1445
  window.__ARCHIE_INSPECTOR__.selectedElement = null
1397
1446
  }
1398
1447
  lastMultiSelectIntent = false
1448
+ publishSelectionToDesignMode()
1399
1449
  try {
1400
1450
  safeQuerySelectorAll('[data-inspector-editing="true"]').forEach(
1401
1451
  function (el) {
@@ -1422,6 +1472,12 @@
1422
1472
  )
1423
1473
  }
1424
1474
 
1475
+ // Last mode explicitly commanded by the host via SET_EDITOR_MODE. Used
1476
+ // to (a) make repeated "inspect" commands selection-preserving no-ops
1477
+ // and (b) suppress design-mode runtime echoes that would otherwise be
1478
+ // misread by the host as a stale mode (see runtimeBridgeHandler).
1479
+ var hostCommandedEditorMode = "off"
1480
+
1425
1481
  function setEditorModeFromHost(mode, options) {
1426
1482
  var historyMode =
1427
1483
  options && options.hostControlledHistory ? "host" : "local"
@@ -1439,14 +1495,30 @@
1439
1495
  historyMode: historyMode,
1440
1496
  })
1441
1497
 
1498
+ hostCommandedEditorMode = mode === "inspect" || mode === "design" ? mode : "off"
1499
+
1442
1500
  if (mode === "inspect") {
1443
- dispatchHostCommand({ type: "set-design-mode", enabled: false })
1501
+ // Unified mode: visual editor (inspect) + arrange (design) coexist.
1502
+ // The arrange overlay stays passive until the inspector publishes a
1503
+ // single-element selection (via publishSelectionToDesignMode), at
1504
+ // which point it lights up the resize/drag controls on that element.
1505
+ dispatchHostCommand({ type: "set-design-mode", enabled: true })
1506
+ if (isInspecting) {
1507
+ // Recovery re-send (focus/visibility/online): the session is
1508
+ // already live. Activating again would wipe the user's current
1509
+ // selection and retract the arrange handles mid-session — echo
1510
+ // confirmation only.
1511
+ postMessageToParent({ type: "EDITOR_MODE_CHANGED", mode: "inspect" })
1512
+ return
1513
+ }
1444
1514
  activateInspectionMode()
1445
1515
  postMessageToParent({ type: "EDITOR_MODE_CHANGED", mode: "inspect" })
1446
1516
  return
1447
1517
  }
1448
1518
 
1449
1519
  if (mode === "design") {
1520
+ // Legacy "design-only" mode kept for backwards compatibility with
1521
+ // hosts that haven't migrated to the unified flow.
1450
1522
  deactivateInspectionMode({ notifyParent: false })
1451
1523
  dispatchHostCommand({ type: "set-design-mode", enabled: true })
1452
1524
  postMessageToParent({ type: "EDITOR_MODE_CHANGED", mode: "design" })
@@ -2399,6 +2471,16 @@
2399
2471
  }
2400
2472
 
2401
2473
  if (detail.type === "design-mode-changed") {
2474
+ // In unified inspect the arrange overlay flips its internal
2475
+ // design-mode store as a side effect ("design" on mount, "off" on
2476
+ // teardown). Forwarding those flips while the host commanded
2477
+ // "inspect" makes the host see a stale mode and re-send
2478
+ // SET_EDITOR_MODE, which wipes the in-iframe selection. The host
2479
+ // only needs runtime-originated mode changes in the legacy
2480
+ // design-only flow.
2481
+ if (hostCommandedEditorMode === "inspect") {
2482
+ return
2483
+ }
2402
2484
  postMessageToParent({
2403
2485
  type: "EDITOR_MODE_CHANGED",
2404
2486
  mode: detail.mode || "off",
@@ -3090,6 +3172,7 @@
3090
3172
  }
3091
3173
 
3092
3174
  updateSharedHighlights()
3175
+ publishSelectionToDesignMode()
3093
3176
  postMessageToParent({
3094
3177
  type: "ELEMENT_REMOVED",
3095
3178
  requestId: event.data.requestId,
@@ -3344,6 +3427,20 @@
3344
3427
  const inspectorClickHandler = function (e) {
3345
3428
  if (!isInspecting) return
3346
3429
 
3430
+ // If the event originated on a design-mode (arrange) overlay element —
3431
+ // HitArea, resize handle, drop-line — let it propagate untouched so
3432
+ // dnd-kit can pick it up. Without this early-return, getElementFromPoint
3433
+ // below would resolve to the real element underneath the overlay and
3434
+ // the inspector would swallow the pointerdown via stopImmediatePropagation,
3435
+ // breaking arrange drag/resize on the selected element.
3436
+ if (
3437
+ e.target &&
3438
+ typeof e.target.closest === "function" &&
3439
+ e.target.closest("[data-design-mode-ui]")
3440
+ ) {
3441
+ return
3442
+ }
3443
+
3347
3444
  // Prefer e.target: browser already set it to the element under the pointer (e.g. input).
3348
3445
  // getElementFromPoint is fallback when overlay or stacking returns something else.
3349
3446
  let target = null
@@ -3469,6 +3566,7 @@
3469
3566
  type: "ELEMENT_SELECTED",
3470
3567
  metadata: metadataPayload,
3471
3568
  })
3569
+ publishSelectionToDesignMode()
3472
3570
  // Keep inspector active - don't set isInspecting = false
3473
3571
  // User can continue navigating between elements
3474
3572
  }
@@ -3515,6 +3613,7 @@
3515
3613
  if (window.__ARCHIE_INSPECTOR__)
3516
3614
  window.__ARCHIE_INSPECTOR__.selectedElement = null
3517
3615
  updateSharedHighlights()
3616
+ publishSelectionToDesignMode()
3518
3617
  postMessageToParent({ type: "INSPECTION_CANCELLED" })
3519
3618
  }
3520
3619
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archie/devtools",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "DevTools for Archie generated applications - Route synchronization and editor communication",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,9 +29,8 @@
29
29
  "scripts": {
30
30
  "test": "vitest run",
31
31
  "test:watch": "vitest",
32
- "inspector:local": "node scripts/generate-inspector-local.js",
33
32
  "build": "tsup",
34
- "dev": "tsup --watch",
33
+ "build:local": "ARCHIE_INSPECTOR_INCLUDE_STANDALONE=1 tsup",
35
34
  "typecheck": "tsc --noEmit",
36
35
  "release": "node publish.js"
37
36
  },