@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.
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, {
3
3
  var __publicField = (obj, key2, value) => __defNormalProp(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
4
4
 
5
5
  // src/client/dnd/DndProvider.tsx
6
- import { useCallback as useCallback9, useEffect as useEffect13 } from "react";
6
+ import { useCallback as useCallback9, useEffect as useEffect12 } from "react";
7
7
 
8
8
  // node_modules/@dnd-kit/core/dist/core.esm.js
9
9
  import React2, { createContext, useContext, useEffect as useEffect2, useState as useState2, useCallback as useCallback3, useMemo as useMemo2, useRef as useRef2, memo, useReducer, cloneElement, forwardRef } from "react";
@@ -4280,6 +4280,9 @@ function findMetaOwnerElement(el) {
4280
4280
  }
4281
4281
  function resolveHostElementFromFiberChain(el) {
4282
4282
  if (shouldIgnoreAsVirtualRuntime(el)) return null;
4283
+ if (el.hasAttribute("data-dnd-force-allow")) {
4284
+ return el;
4285
+ }
4283
4286
  const directMeta = getDirectEditorMeta(el);
4284
4287
  const ownerMeta = directMeta ?? getEditorMeta(el);
4285
4288
  if (isPassthroughMeta(ownerMeta)) {
@@ -4635,8 +4638,8 @@ function buildEmptyArrangeSessionState() {
4635
4638
  var useDesignModeStore = create((set, get) => ({
4636
4639
  // UI state
4637
4640
  enabled: false,
4638
- hoveredSelector: null,
4639
4641
  selectedSelector: null,
4642
+ inspectorSelectedNodeIds: [],
4640
4643
  historyMode: "local",
4641
4644
  inspectorTheme: DEFAULT_INSPECTOR_THEME,
4642
4645
  canUndo: false,
@@ -4652,16 +4655,23 @@ var useDesignModeStore = create((set, get) => ({
4652
4655
  // UI actions
4653
4656
  toggle: () => set((s) => ({ enabled: !s.enabled, ...buildEmptyArrangeSessionState() })),
4654
4657
  setEnabled: (enabled) => set({ enabled }),
4655
- setHovered: (selector) => set({ hoveredSelector: selector }),
4656
4658
  setSelected: (selector) => set({ selectedSelector: selector }),
4659
+ setInspectorSelection: (nodeIds) => {
4660
+ const next = nodeIds.filter((id) => typeof id === "string" && id.length > 0);
4661
+ const prev = get().inspectorSelectedNodeIds;
4662
+ if (prev.length === next.length && prev.every((id, i) => id === next[i])) {
4663
+ return;
4664
+ }
4665
+ set({ inspectorSelectedNodeIds: next });
4666
+ },
4657
4667
  setHistoryMode: (historyMode) => set({ historyMode }),
4658
4668
  setInspectorTheme: (theme) => set((s) => ({ inspectorTheme: mergeInspectorTheme({ ...s.inspectorTheme, ...theme }) })),
4659
4669
  setHistoryAvailability: (canUndo, canRedo) => set({ canUndo, canRedo }),
4660
4670
  requestUndo: () => set((s) => ({ undoRequestId: s.undoRequestId + 1 })),
4661
4671
  requestRedo: () => set((s) => ({ redoRequestId: s.redoRequestId + 1 })),
4662
4672
  resetAll: () => set({
4663
- hoveredSelector: null,
4664
4673
  selectedSelector: null,
4674
+ inspectorSelectedNodeIds: [],
4665
4675
  canUndo: false,
4666
4676
  canRedo: false
4667
4677
  }),
@@ -4779,9 +4789,13 @@ var useDesignModeStore = create((set, get) => ({
4779
4789
  inspectorRef,
4780
4790
  displayName,
4781
4791
  html,
4792
+ tsxCode,
4793
+ tsxImports,
4782
4794
  containerId,
4783
4795
  containerNodeKey,
4784
- index
4796
+ index,
4797
+ beforeSiblingInspectorRef,
4798
+ beforeSiblingNodeKey
4785
4799
  }) => {
4786
4800
  const now = Date.now();
4787
4801
  const normalizedOperationId = operationId ?? buildFallbackOperationId(now, nodeId);
@@ -4793,9 +4807,13 @@ var useDesignModeStore = create((set, get) => ({
4793
4807
  inspectorRef,
4794
4808
  displayName,
4795
4809
  html,
4810
+ tsxCode: tsxCode ?? null,
4811
+ tsxImports: tsxImports ?? null,
4796
4812
  containerId,
4797
4813
  containerNodeKey,
4798
4814
  index,
4815
+ beforeSiblingInspectorRef: beforeSiblingInspectorRef ?? null,
4816
+ beforeSiblingNodeKey: beforeSiblingNodeKey ?? null,
4799
4817
  at: now
4800
4818
  };
4801
4819
  set((s) => {
@@ -4873,7 +4891,7 @@ var useDesignModeStore = create((set, get) => ({
4873
4891
  }));
4874
4892
 
4875
4893
  // src/client/dnd/design-mode/DesignModeOverlay.tsx
4876
- import { useRef as useRef10, useCallback as useCallback8, useEffect as useEffect12, useLayoutEffect as useLayoutEffect2, useState as useState6, useMemo as useMemo6 } from "react";
4894
+ import { useRef as useRef10, useCallback as useCallback8, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useState as useState6, useMemo as useMemo6 } from "react";
4877
4895
 
4878
4896
  // src/client/dnd/design-mode/useElementScanner.ts
4879
4897
  import { useState as useState4, useEffect as useEffect4, useCallback as useCallback4, useRef as useRef4 } from "react";
@@ -4892,15 +4910,17 @@ function buildNodeSelector(nodeId) {
4892
4910
  var LARGE_NODE_NEST_BLOCK_MIN_WIDTH = 520;
4893
4911
  var LARGE_NODE_NEST_BLOCK_MIN_HEIGHT = 260;
4894
4912
  var LARGE_NODE_NEST_BLOCK_MIN_AREA = 18e4;
4895
- function resolveGrabFeedbackTarget(target, scannedByNodeId) {
4896
- if (!(target instanceof Element)) return null;
4897
- if (target.closest("[data-design-mode-ui]")) return null;
4913
+ function shouldShowGrabFeedback(target, scannedByNodeId) {
4914
+ if (!(target instanceof Element)) return false;
4915
+ if (target.closest("[data-design-mode-ui]")) return false;
4916
+ if (!target.closest("#root")) return false;
4898
4917
  const host = target.closest(`[${DND_NODE_ID_ATTR}]`);
4899
- if (!host) return null;
4918
+ if (!host) {
4919
+ return true;
4920
+ }
4900
4921
  const nodeId = host.getAttribute(DND_NODE_ID_ATTR);
4901
4922
  const scanned = nodeId ? scannedByNodeId.get(nodeId) : null;
4902
- if (!scanned || scanned.draggable !== false) return null;
4903
- return scanned;
4923
+ return !scanned || scanned.draggable === false;
4904
4924
  }
4905
4925
  function isEligibleForDrag(sc) {
4906
4926
  if (sc.draggable === false) return false;
@@ -5400,14 +5420,14 @@ function handlePosition(dir) {
5400
5420
  };
5401
5421
  return positions[dir];
5402
5422
  }
5403
- function getOutlineStyle(rect, isSelected, isHovered, inspectorTheme) {
5423
+ function getOutlineStyle(rect, isSelected, inspectorTheme) {
5404
5424
  return {
5405
5425
  ...OUTLINE_BASE_STYLE,
5406
5426
  left: rect.left,
5407
5427
  top: rect.top,
5408
5428
  width: rect.width,
5409
5429
  height: rect.height,
5410
- border: isSelected ? `2px solid ${inspectorTheme.accent}` : isHovered ? `2px dashed ${inspectorTheme.hover}` : `1px dashed ${inspectorTheme.shared}`,
5430
+ border: isSelected ? `2px solid ${inspectorTheme.accent}` : `1px dashed ${inspectorTheme.shared}`,
5411
5431
  backgroundColor: isSelected ? inspectorTheme.accentSoft : "transparent"
5412
5432
  };
5413
5433
  }
@@ -5437,11 +5457,13 @@ function ElementHighlight({
5437
5457
  elements,
5438
5458
  draggingNodeId,
5439
5459
  activeEl,
5460
+ arrangeSelectedNodeId,
5461
+ externalDragActive,
5440
5462
  onResizeHandlePointerDown
5441
5463
  }) {
5442
- const hoveredSelector = useDesignModeStore((s) => s.hoveredSelector);
5443
- const selectedSelector = useDesignModeStore((s) => s.selectedSelector);
5444
5464
  const inspectorTheme = useDesignModeStore((s) => s.inspectorTheme);
5465
+ const internalDragInProgress = draggingNodeId !== null;
5466
+ const overlayVisible = arrangeSelectedNodeId !== null || internalDragInProgress;
5445
5467
  const containerRef = useRef5(null);
5446
5468
  const rafRef = useRef5(0);
5447
5469
  const syncPositions = useCallback5(() => {
@@ -5465,7 +5487,6 @@ function ElementHighlight({
5465
5487
  }
5466
5488
  }, [elements]);
5467
5489
  useEffect5(() => {
5468
- if (draggingNodeId) return;
5469
5490
  let running = true;
5470
5491
  const loop = () => {
5471
5492
  if (!running) return;
@@ -5477,8 +5498,9 @@ function ElementHighlight({
5477
5498
  running = false;
5478
5499
  cancelAnimationFrame(rafRef.current);
5479
5500
  };
5480
- }, [syncPositions, draggingNodeId]);
5481
- if (draggingNodeId) return null;
5501
+ }, [syncPositions]);
5502
+ if (!overlayVisible) return null;
5503
+ if (externalDragActive) return null;
5482
5504
  return /* @__PURE__ */ jsx2(
5483
5505
  "div",
5484
5506
  {
@@ -5488,10 +5510,10 @@ function ElementHighlight({
5488
5510
  children: elements.map((el) => {
5489
5511
  if (el.nodeId === draggingNodeId) return null;
5490
5512
  if (activeEl && activeEl !== el.element && activeEl.contains(el.element)) return null;
5491
- const isHovered = el.nodeId === hoveredSelector;
5492
- const isSelected = el.nodeId === selectedSelector;
5513
+ const isSelected = el.nodeId === arrangeSelectedNodeId;
5514
+ if (!isSelected && !internalDragInProgress) return null;
5493
5515
  const rect = el.element.getBoundingClientRect();
5494
- const showLabel = isHovered || isSelected;
5516
+ const showLabel = isSelected;
5495
5517
  const labelTop = isSelected ? Math.max(0, rect.top - 20) : rect.top;
5496
5518
  const labelLeft = isSelected ? rect.left + 12 : rect.left;
5497
5519
  return /* @__PURE__ */ jsxs("div", { children: [
@@ -5500,7 +5522,7 @@ function ElementHighlight({
5500
5522
  {
5501
5523
  "data-outline-for": el.nodeId,
5502
5524
  "data-design-mode-ui": true,
5503
- style: getOutlineStyle(rect, isSelected, isHovered, inspectorTheme),
5525
+ style: getOutlineStyle(rect, isSelected, inspectorTheme),
5504
5526
  children: isSelected && HANDLES.map((dir) => {
5505
5527
  const pos = handlePosition(dir);
5506
5528
  return /* @__PURE__ */ jsx2(
@@ -5795,6 +5817,57 @@ function buildRectSlotRect(children, nodeMap, cRect, i, n, rows) {
5795
5817
  };
5796
5818
  }
5797
5819
 
5820
+ // src/client/dnd/design-mode/inserted-descendants.ts
5821
+ var NON_DRAGGABLE_DESCENDANT_TAGS = /* @__PURE__ */ new Set([
5822
+ // SVG internals — the whole <svg> is the unit; its parts must stay together.
5823
+ "svg",
5824
+ "path",
5825
+ "circle",
5826
+ "rect",
5827
+ "line",
5828
+ "polyline",
5829
+ "polygon",
5830
+ "g",
5831
+ "defs",
5832
+ "use",
5833
+ // <select>/<option>: options live inside their <select>, never standalone.
5834
+ "option",
5835
+ "optgroup",
5836
+ // Table internals: only meaningful in their <table> tree.
5837
+ "caption",
5838
+ "thead",
5839
+ "tbody",
5840
+ "tfoot",
5841
+ "tr",
5842
+ "th",
5843
+ "td",
5844
+ "col",
5845
+ "colgroup",
5846
+ // Self-closing inline atoms with no draggable surface.
5847
+ "br",
5848
+ "wbr",
5849
+ "hr",
5850
+ // Non-rendered metadata.
5851
+ "script",
5852
+ "style",
5853
+ "meta",
5854
+ "link",
5855
+ "title",
5856
+ "noscript",
5857
+ // Replaced media controls handled by their parent player.
5858
+ "source",
5859
+ "track"
5860
+ ]);
5861
+ function markInsertedDescendants(root) {
5862
+ const descendants = root.querySelectorAll("*");
5863
+ for (const node of descendants) {
5864
+ const tag = node.tagName.toLowerCase();
5865
+ if (NON_DRAGGABLE_DESCENDANT_TAGS.has(tag)) continue;
5866
+ node.setAttribute("data-dnd-force-allow", "");
5867
+ node.setAttribute("data-dnd-moved", "");
5868
+ }
5869
+ }
5870
+
5798
5871
  // src/client/dnd/design-mode/history.ts
5799
5872
  function applyInsertCommand(command, direction, resolveNodeElement) {
5800
5873
  if (direction === "undo") {
@@ -5817,6 +5890,7 @@ function applyInsertCommand(command, direction, resolveNodeElement) {
5817
5890
  (c) => c instanceof HTMLElement
5818
5891
  );
5819
5892
  container.insertBefore(newEl, kids[command.index] ?? null);
5893
+ markInsertedDescendants(newEl);
5820
5894
  return true;
5821
5895
  }
5822
5896
  var DEFAULT_LIMIT = 300;
@@ -6342,6 +6416,8 @@ function serializeArrangeChange(event, index) {
6342
6416
  containerId: event.kind === "insert" ? event.containerId : void 0,
6343
6417
  containerNodeKey: event.kind === "insert" ? event.containerNodeKey : void 0,
6344
6418
  insertIndex: event.kind === "insert" ? event.index : void 0,
6419
+ beforeSiblingInspectorRef: event.kind === "insert" ? event.beforeSiblingInspectorRef : void 0,
6420
+ beforeSiblingNodeKey: event.kind === "insert" ? event.beforeSiblingNodeKey : void 0,
6345
6421
  summary: summarizeEditorChangeEvent(event),
6346
6422
  at: event.at
6347
6423
  };
@@ -6639,50 +6715,8 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
6639
6715
  }), []);
6640
6716
  }
6641
6717
 
6642
- // src/client/dnd/design-mode/useHoverDetection.ts
6643
- import { useEffect as useEffect8 } from "react";
6644
- function useHoverDetection({
6645
- enabled,
6646
- activeDrag,
6647
- elementsRef,
6648
- setHovered
6649
- }) {
6650
- useEffect8(() => {
6651
- if (!enabled) {
6652
- setHovered(null);
6653
- return;
6654
- }
6655
- let lastNodeId = null;
6656
- const fn = (e) => {
6657
- if (activeDrag) return;
6658
- let best = null;
6659
- let bestArea = Infinity;
6660
- for (const sc of elementsRef.current) {
6661
- const r = sc.rect;
6662
- if (e.clientX >= r.left && e.clientX <= r.right && e.clientY >= r.top && e.clientY <= r.bottom) {
6663
- const a = r.width * r.height;
6664
- if (a < bestArea) {
6665
- bestArea = a;
6666
- best = sc;
6667
- }
6668
- }
6669
- }
6670
- const nodeId = best?.nodeId ?? null;
6671
- if (nodeId !== lastNodeId) {
6672
- lastNodeId = nodeId;
6673
- setHovered(nodeId);
6674
- }
6675
- };
6676
- document.addEventListener("mousemove", fn);
6677
- return () => {
6678
- document.removeEventListener("mousemove", fn);
6679
- setHovered(null);
6680
- };
6681
- }, [enabled, setHovered, activeDrag]);
6682
- }
6683
-
6684
6718
  // src/client/dnd/design-mode/useDragVisualLoop.ts
6685
- import { useEffect as useEffect9 } from "react";
6719
+ import { useEffect as useEffect8 } from "react";
6686
6720
 
6687
6721
  // src/client/dnd/design-mode/quadtree.ts
6688
6722
  function overlaps(a, b) {
@@ -7571,7 +7605,7 @@ function useDragVisualLoop({
7571
7605
  setInsideRect,
7572
7606
  setDropLine
7573
7607
  }) {
7574
- useEffect9(() => {
7608
+ useEffect8(() => {
7575
7609
  const engine = refs.engineRef.current;
7576
7610
  const snapshot = refs.snapshotRef.current;
7577
7611
  if (!activeDrag || !engine || !snapshot) return;
@@ -8193,7 +8227,7 @@ function useDragLifecycle({
8193
8227
  }
8194
8228
 
8195
8229
  // src/client/dnd/design-mode/useResizeSession.ts
8196
- import { useCallback as useCallback7, useEffect as useEffect10 } from "react";
8230
+ import { useCallback as useCallback7, useEffect as useEffect9 } from "react";
8197
8231
  var RESIZE_POINTER_TOLERANCE_PX = 2;
8198
8232
  var RESIZE_DRAG_BLOCK_MS = 180;
8199
8233
  var RESIZE_MIN = 24;
@@ -8365,7 +8399,7 @@ function useResizeSession({
8365
8399
  });
8366
8400
  syncHistoryAvailability();
8367
8401
  }, [applyCommand, recordResizeChange, syncHistoryAvailability]);
8368
- useEffect10(() => {
8402
+ useEffect9(() => {
8369
8403
  if (!enabled) return;
8370
8404
  const handleResizePointerCancel = (e) => {
8371
8405
  const session = refs.resizeSessionRef.current;
@@ -8390,8 +8424,13 @@ function useResizeSession({
8390
8424
  }
8391
8425
 
8392
8426
  // src/client/dnd/design-mode/useExternalDragLoop.ts
8393
- import { useEffect as useEffect11, useRef as useRef9 } from "react";
8427
+ import { useEffect as useEffect10, useRef as useRef9 } from "react";
8394
8428
  var EXTERNAL_DRAG_ACTIVE_ID = "__external-drag-placeholder__";
8429
+ var insertNodeIdCounter = 0;
8430
+ function nextInsertNodeId() {
8431
+ insertNodeIdCounter += 1;
8432
+ return `insert:${Date.now()}:${insertNodeIdCounter}`;
8433
+ }
8395
8434
  function useExternalDragLoop({
8396
8435
  externalDrag,
8397
8436
  refs,
@@ -8401,7 +8440,7 @@ function useExternalDragLoop({
8401
8440
  }) {
8402
8441
  const engineRef = useRef9(null);
8403
8442
  const lastIntentRef = useRef9(null);
8404
- useEffect11(() => {
8443
+ useEffect10(() => {
8405
8444
  if (!externalDrag) {
8406
8445
  engineRef.current = null;
8407
8446
  lastIntentRef.current = null;
@@ -8491,7 +8530,7 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
8491
8530
  setDropLine(null);
8492
8531
  return;
8493
8532
  }
8494
- const nodeId = `insert:${Date.now()}`;
8533
+ const nodeId = nextInsertNodeId();
8495
8534
  newElement.setAttribute(DND_NODE_ID_ATTR, nodeId);
8496
8535
  newElement.setAttribute("data-dnd-force-allow", "");
8497
8536
  newElement.setAttribute("data-dnd-moved", "");
@@ -8500,6 +8539,23 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
8500
8539
  );
8501
8540
  const beforeChild = children[intent.index] ?? null;
8502
8541
  containerEl.insertBefore(newElement, beforeChild);
8542
+ markInsertedDescendants(newElement);
8543
+ const postInsertChildren = Array.from(containerEl.children).filter(
8544
+ (child) => child instanceof HTMLElement
8545
+ );
8546
+ let beforeSiblingEl = null;
8547
+ let beforeSiblingNodeId = null;
8548
+ const startIdx = postInsertChildren.indexOf(newElement) + 1;
8549
+ for (let i = startIdx; i < postInsertChildren.length; i += 1) {
8550
+ const candidate = postInsertChildren[i];
8551
+ const candidateNodeId = candidate.getAttribute(DND_NODE_ID_ATTR);
8552
+ if (!candidateNodeId) continue;
8553
+ const isEarlierInsert = candidateNodeId.startsWith("insert:");
8554
+ if (!isEarlierInsert && !getInspectorRefFromElement(candidate)) continue;
8555
+ beforeSiblingEl = candidate;
8556
+ beforeSiblingNodeId = candidateNodeId;
8557
+ break;
8558
+ }
8503
8559
  const insertCommand = {
8504
8560
  type: "insert",
8505
8561
  nodeId,
@@ -8525,6 +8581,15 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
8525
8581
  inspectorRef: getInspectorRefFromElement(containerEl)
8526
8582
  };
8527
8583
  }
8584
+ let beforeSiblingIdentity = null;
8585
+ if (beforeSiblingEl && beforeSiblingNodeId) {
8586
+ beforeSiblingIdentity = {
8587
+ nodeId: beforeSiblingNodeId,
8588
+ nodeKey: getNodeKeyFromElement(beforeSiblingEl),
8589
+ selector: buildNodeSelector(beforeSiblingNodeId),
8590
+ inspectorRef: getInspectorRefFromElement(beforeSiblingEl)
8591
+ };
8592
+ }
8528
8593
  const operationId = `${insertCommand.at}:${nodeId}`;
8529
8594
  useDesignModeStore.getState().recordInsertChange({
8530
8595
  operationId,
@@ -8533,9 +8598,13 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
8533
8598
  inspectorRef,
8534
8599
  displayName: component.displayName,
8535
8600
  html: component.html,
8601
+ tsxCode: component.tsxCode ?? null,
8602
+ tsxImports: component.tsxImports ?? null,
8536
8603
  containerId: intent.containerId,
8537
8604
  containerNodeKey,
8538
- index: intent.index
8605
+ index: intent.index,
8606
+ beforeSiblingInspectorRef: beforeSiblingIdentity?.inspectorRef ?? null,
8607
+ beforeSiblingNodeKey: beforeSiblingIdentity?.nodeKey ?? null
8539
8608
  });
8540
8609
  dispatchRuntimeEvent({
8541
8610
  type: "element-inserted",
@@ -8544,8 +8613,11 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
8544
8613
  nodeKey,
8545
8614
  displayName: component.displayName,
8546
8615
  html: component.html,
8616
+ tsxCode: component.tsxCode ?? null,
8617
+ tsxImports: component.tsxImports ?? null,
8547
8618
  container: containerIdentity,
8548
- index: intent.index
8619
+ index: intent.index,
8620
+ beforeSibling: beforeSiblingIdentity
8549
8621
  });
8550
8622
  }
8551
8623
  setDropLine(null);
@@ -8596,8 +8668,12 @@ function HitArea({
8596
8668
  selectedNodeId,
8597
8669
  onResizeHandlePointerDown
8598
8670
  }) {
8599
- const { setNodeRef, listeners, attributes, isDragging } = useDraggable({ id: scanned.nodeId });
8600
- useEffect12(() => {
8671
+ const isSelected = scanned.nodeId === selectedNodeId;
8672
+ const { setNodeRef, listeners, attributes, isDragging } = useDraggable({
8673
+ id: scanned.nodeId,
8674
+ disabled: !isSelected
8675
+ });
8676
+ useEffect11(() => {
8601
8677
  setNodeRef(scanned.element);
8602
8678
  return () => setNodeRef(null);
8603
8679
  }, [setNodeRef, scanned.element]);
@@ -8609,7 +8685,7 @@ function HitArea({
8609
8685
  el.style.removeProperty("opacity");
8610
8686
  }
8611
8687
  }, [isDragging, scanned.element]);
8612
- useEffect12(() => () => {
8688
+ useEffect11(() => () => {
8613
8689
  scanned.element.style.removeProperty("opacity");
8614
8690
  scanned.element.style.removeProperty("transform");
8615
8691
  scanned.element.style.removeProperty("transition");
@@ -8617,8 +8693,18 @@ function HitArea({
8617
8693
  }, [scanned.element]);
8618
8694
  const divRef = useRef10(null);
8619
8695
  const [hoverResizeHandle, setHoverResizeHandle] = useState6(null);
8620
- const isSelected = scanned.nodeId === selectedNodeId;
8621
- useEffect12(() => {
8696
+ const justDraggedRef = useRef10(false);
8697
+ useEffect11(() => {
8698
+ if (isDragging) {
8699
+ justDraggedRef.current = true;
8700
+ return;
8701
+ }
8702
+ const id = window.setTimeout(() => {
8703
+ justDraggedRef.current = false;
8704
+ }, 0);
8705
+ return () => window.clearTimeout(id);
8706
+ }, [isDragging]);
8707
+ useEffect11(() => {
8622
8708
  const div = divRef.current;
8623
8709
  if (!div) return;
8624
8710
  const onWheel = (e) => {
@@ -8634,7 +8720,7 @@ function HitArea({
8634
8720
  return () => div.removeEventListener("wheel", onWheel);
8635
8721
  }, []);
8636
8722
  const { left, top, width, height } = scanned.rect;
8637
- const cursor = isDragging ? "grabbing" : isSelected && hoverResizeHandle ? resizeCursorFromHandle(hoverResizeHandle) : "grab";
8723
+ const cursor = isDragging ? "grabbing" : !isSelected ? "default" : hoverResizeHandle ? resizeCursorFromHandle(hoverResizeHandle) : "grab";
8638
8724
  return /* @__PURE__ */ jsx4(
8639
8725
  "div",
8640
8726
  {
@@ -8665,6 +8751,35 @@ function HitArea({
8665
8751
  ...attributes,
8666
8752
  ...listeners,
8667
8753
  onClick: (e) => {
8754
+ if (justDraggedRef.current) {
8755
+ e.preventDefault();
8756
+ e.stopPropagation();
8757
+ return;
8758
+ }
8759
+ const stack = document.elementsFromPoint(e.clientX, e.clientY);
8760
+ for (const candidate of stack) {
8761
+ if (!(candidate instanceof HTMLElement)) continue;
8762
+ if (candidate.hasAttribute("data-design-mode-ui")) continue;
8763
+ if (candidate === scanned.element) break;
8764
+ const candidateNodeId = candidate.getAttribute("data-dnd-node-id");
8765
+ if (candidateNodeId && candidateNodeId !== scanned.nodeId) {
8766
+ e.preventDefault();
8767
+ e.stopPropagation();
8768
+ candidate.dispatchEvent(
8769
+ new MouseEvent("mousedown", {
8770
+ bubbles: true,
8771
+ cancelable: true,
8772
+ clientX: e.clientX,
8773
+ clientY: e.clientY,
8774
+ metaKey: e.metaKey,
8775
+ ctrlKey: e.ctrlKey,
8776
+ shiftKey: e.shiftKey,
8777
+ altKey: e.altKey
8778
+ })
8779
+ );
8780
+ return;
8781
+ }
8782
+ }
8668
8783
  e.preventDefault();
8669
8784
  e.stopPropagation();
8670
8785
  onActivate(scanned.nodeId);
@@ -8675,9 +8790,11 @@ function HitArea({
8675
8790
  function DesignModeOverlay() {
8676
8791
  const enabled = useDesignModeStore((s) => s.enabled);
8677
8792
  const historyMode = useDesignModeStore((s) => s.historyMode);
8678
- const setHovered = useDesignModeStore((s) => s.setHovered);
8679
8793
  const selectElement = useDesignModeStore((s) => s.setSelected);
8680
- const selectedSelector = useDesignModeStore((s) => s.selectedSelector);
8794
+ const inspectorSelectedNodeIds = useDesignModeStore(
8795
+ (s) => s.inspectorSelectedNodeIds
8796
+ );
8797
+ const arrangeSelectedNodeId = inspectorSelectedNodeIds.length === 1 ? inspectorSelectedNodeIds[0] : null;
8681
8798
  const setHistoryAvailability = useDesignModeStore((s) => s.setHistoryAvailability);
8682
8799
  const undoRequestId = useDesignModeStore((s) => s.undoRequestId);
8683
8800
  const redoRequestId = useDesignModeStore((s) => s.redoRequestId);
@@ -8703,29 +8820,37 @@ function DesignModeOverlay() {
8703
8820
  (el) => el.draggable !== false
8704
8821
  );
8705
8822
  }, [elements, nodeMap]);
8823
+ const arrangeHitAreaElement = useMemo6(() => {
8824
+ if (!arrangeSelectedNodeId) return null;
8825
+ if (externalDrag) return null;
8826
+ return draggableElements.find(
8827
+ (candidate) => candidate.nodeId === arrangeSelectedNodeId
8828
+ ) ?? null;
8829
+ }, [arrangeSelectedNodeId, externalDrag, draggableElements]);
8706
8830
  const refs = useOverlayRefs(undoRequestId, redoRequestId);
8707
8831
  refs.elementsRef.current = elements;
8708
8832
  refs.nodeMapRef.current = nodeMap;
8709
- useEffect12(() => {
8833
+ useEffect11(() => {
8710
8834
  const m = /* @__PURE__ */ new Map();
8711
8835
  for (const el of draggableElements) m.set(el.nodeId, el);
8712
8836
  refs.draggableNodeMapRef.current = m;
8713
8837
  }, [draggableElements]);
8714
8838
  const [grabFeedback, setGrabFeedback] = useState6(null);
8715
- useEffect12(() => {
8839
+ useEffect11(() => {
8716
8840
  if (!enabled) return;
8717
8841
  const onPointerDown = (e) => {
8718
- const scanned = resolveGrabFeedbackTarget(
8842
+ if (!shouldShowGrabFeedback(
8719
8843
  e.target,
8720
8844
  refs.nodeMapRef.current
8721
- );
8722
- if (!scanned) return;
8845
+ )) {
8846
+ return;
8847
+ }
8723
8848
  setGrabFeedback({ x: e.clientX, y: e.clientY, at: Date.now() });
8724
8849
  };
8725
8850
  document.addEventListener("pointerdown", onPointerDown, true);
8726
8851
  return () => document.removeEventListener("pointerdown", onPointerDown, true);
8727
8852
  }, [enabled]);
8728
- useEffect12(() => {
8853
+ useEffect11(() => {
8729
8854
  if (!grabFeedback) return;
8730
8855
  const t = setTimeout(() => setGrabFeedback(null), 1400);
8731
8856
  return () => clearTimeout(t);
@@ -8782,7 +8907,7 @@ function DesignModeOverlay() {
8782
8907
  }
8783
8908
  setHistoryAvailability(refs.historyRef.current.canUndo(), refs.historyRef.current.canRedo());
8784
8909
  }, [historyMode, setHistoryAvailability]);
8785
- useEffect12(() => {
8910
+ useEffect11(() => {
8786
8911
  refs.historyRef.current.clear();
8787
8912
  syncHistoryAvailability();
8788
8913
  }, [enabled, syncHistoryAvailability]);
@@ -8796,7 +8921,7 @@ function DesignModeOverlay() {
8796
8921
  );
8797
8922
  const [insideRect, setInsideRect] = useState6(null);
8798
8923
  const [dropLine, setDropLine] = useState6(null);
8799
- useEffect12(() => {
8924
+ useEffect11(() => {
8800
8925
  if (!enabled) return;
8801
8926
  const fn = (e) => {
8802
8927
  refs.mouseRef.current = { x: e.clientX, y: e.clientY };
@@ -8804,7 +8929,7 @@ function DesignModeOverlay() {
8804
8929
  window.addEventListener("pointermove", fn, { capture: true, passive: true });
8805
8930
  return () => window.removeEventListener("pointermove", fn, { capture: true });
8806
8931
  }, [enabled]);
8807
- useEffect12(() => {
8932
+ useEffect11(() => {
8808
8933
  if (!enabled) return;
8809
8934
  if (historyMode !== "local") return;
8810
8935
  const onKeyDown = (e) => {
@@ -8833,7 +8958,7 @@ function DesignModeOverlay() {
8833
8958
  setInsideRect,
8834
8959
  setDropLine
8835
8960
  });
8836
- useEffect12(() => {
8961
+ useEffect11(() => {
8837
8962
  if (!enabled || activeDrag) return;
8838
8963
  if (undoRequestId === refs.processedUndoIdRef.current) return;
8839
8964
  refs.processedUndoIdRef.current = undoRequestId;
@@ -8850,7 +8975,7 @@ function DesignModeOverlay() {
8850
8975
  });
8851
8976
  syncHistoryAvailability();
8852
8977
  }, [undoRequestId, enabled, activeDrag, applyCommand, resume, selectElement, syncHistoryAvailability, undoLastChange]);
8853
- useEffect12(() => {
8978
+ useEffect11(() => {
8854
8979
  if (!enabled || activeDrag || historyMode !== "local") return;
8855
8980
  if (redoRequestId === refs.processedRedoIdRef.current) return;
8856
8981
  refs.processedRedoIdRef.current = redoRequestId;
@@ -8862,18 +8987,18 @@ function DesignModeOverlay() {
8862
8987
  }
8863
8988
  syncHistoryAvailability();
8864
8989
  }, [redoRequestId, enabled, activeDrag, applyCommand, historyMode, resume, selectElement, syncHistoryAvailability, redoLastChange]);
8865
- useEffect12(() => {
8990
+ useEffect11(() => {
8866
8991
  syncHistoryAvailability();
8867
8992
  }, [syncHistoryAvailability]);
8868
- useEffect12(() => {
8993
+ useEffect11(() => {
8869
8994
  dispatchRuntimeEvent({
8870
8995
  type: "design-mode-changed",
8871
8996
  mode: enabled ? "design" : "off"
8872
8997
  });
8873
8998
  }, [enabled]);
8874
- useEffect12(() => {
8999
+ useEffect11(() => {
8875
9000
  const aiOutput = exportChangesForAI();
8876
- const updatedAt = orderedChanges.length > 0 ? orderedChanges[orderedChanges.length - 1]?.at ?? Date.now() : Date.now();
9001
+ const updatedAt = Date.now();
8877
9002
  dispatchRuntimeEvent({
8878
9003
  type: "arrange-session-changed",
8879
9004
  session: buildArrangeSessionSnapshot({
@@ -8884,12 +9009,11 @@ function DesignModeOverlay() {
8884
9009
  })
8885
9010
  });
8886
9011
  }, [enabled, exportChangesForAI, orderedChanges]);
8887
- useEffect12(() => {
9012
+ useEffect11(() => {
8888
9013
  if (!enabled) return;
8889
9014
  document.body.classList.add("design-mode-active");
8890
9015
  return () => document.body.classList.remove("design-mode-active");
8891
9016
  }, [enabled]);
8892
- useHoverDetection({ enabled, activeDrag, elementsRef: refs.elementsRef, setHovered });
8893
9017
  useDesignModeAutoScroll({
8894
9018
  active: !!activeDrag,
8895
9019
  mouseRef: refs.mouseRef,
@@ -8928,19 +9052,21 @@ function DesignModeOverlay() {
8928
9052
  elements,
8929
9053
  draggingNodeId: activeDrag?.nodeId ?? null,
8930
9054
  activeEl: refs.activeElRef.current,
9055
+ arrangeSelectedNodeId,
9056
+ externalDragActive: externalDrag !== null,
8931
9057
  onResizeHandlePointerDown: handleResizeHandlePointerDown
8932
9058
  }
8933
9059
  ),
8934
- draggableElements.map((el) => /* @__PURE__ */ jsx4(
9060
+ arrangeHitAreaElement && /* @__PURE__ */ jsx4(
8935
9061
  HitArea,
8936
9062
  {
8937
- scanned: el,
9063
+ scanned: arrangeHitAreaElement,
8938
9064
  onActivate: selectElement,
8939
- selectedNodeId: selectedSelector,
9065
+ selectedNodeId: arrangeHitAreaElement.nodeId,
8940
9066
  onResizeHandlePointerDown: handleResizeHandlePointerDown
8941
9067
  },
8942
- el.nodeId
8943
- )),
9068
+ arrangeHitAreaElement.nodeId
9069
+ ),
8944
9070
  grabFeedback ? /* @__PURE__ */ jsx4(
8945
9071
  "div",
8946
9072
  {
@@ -9055,7 +9181,7 @@ function DndProvider({ children }) {
9055
9181
  designModeState.resetArrangeSession();
9056
9182
  designModeState.setEnabled(nextEnabled);
9057
9183
  }, []);
9058
- useEffect13(() => {
9184
+ useEffect12(() => {
9059
9185
  const handleKeyDown = (e) => {
9060
9186
  if (e.ctrlKey && e.shiftKey && e.key === "D") {
9061
9187
  e.preventDefault();
@@ -9065,7 +9191,7 @@ function DndProvider({ children }) {
9065
9191
  window.addEventListener("keydown", handleKeyDown);
9066
9192
  return () => window.removeEventListener("keydown", handleKeyDown);
9067
9193
  }, [transitionDesignMode]);
9068
- useEffect13(() => {
9194
+ useEffect12(() => {
9069
9195
  const handleHostCommand = (event) => {
9070
9196
  const detail = event.detail;
9071
9197
  if (!detail || typeof detail !== "object") return;
@@ -9124,6 +9250,25 @@ function DndProvider({ children }) {
9124
9250
  setInspectorTheme,
9125
9251
  requestUndo
9126
9252
  ]);
9253
+ useEffect12(() => {
9254
+ const bridgeWindow = window;
9255
+ const bridge = {
9256
+ setInspectorSelection: (nodeIds) => {
9257
+ useDesignModeStore.getState().setInspectorSelection(nodeIds);
9258
+ }
9259
+ };
9260
+ bridgeWindow.__ARCHIE_DESIGN_MODE__ = bridge;
9261
+ const pending = bridgeWindow.__ARCHIE_DESIGN_MODE_PENDING__;
9262
+ if (Array.isArray(pending)) {
9263
+ bridge.setInspectorSelection(pending);
9264
+ delete bridgeWindow.__ARCHIE_DESIGN_MODE_PENDING__;
9265
+ }
9266
+ return () => {
9267
+ if (bridgeWindow.__ARCHIE_DESIGN_MODE__ === bridge) {
9268
+ delete bridgeWindow.__ARCHIE_DESIGN_MODE__;
9269
+ }
9270
+ };
9271
+ }, []);
9127
9272
  const pointerSensor = useSensor(PointerSensor, { activationConstraint: { distance: 8 } });
9128
9273
  const keyboardSensor = useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates });
9129
9274
  const sensors = useSensors(pointerSensor, keyboardSensor);
@@ -9195,12 +9340,12 @@ function DndProvider({ children }) {
9195
9340
  }
9196
9341
 
9197
9342
  // src/client/useArchieDevToolsRuntime.ts
9198
- import { useEffect as useEffect14, useRef as useRef11 } from "react";
9343
+ import { useEffect as useEffect13, useRef as useRef11 } from "react";
9199
9344
 
9200
9345
  // src/client/archieLocalInspectorEnv.ts
9201
9346
  function readArchieLocalInspectorFlag() {
9202
9347
  try {
9203
- return import.meta.env?.VITE_ARCHIE_LOCAL_INSPECTOR === "true";
9348
+ return false;
9204
9349
  } catch {
9205
9350
  return false;
9206
9351
  }
@@ -9421,7 +9566,7 @@ function useArchieDevToolsRuntime({
9421
9566
  const stableOptionsKey = JSON.stringify(inspectorOptions ?? null);
9422
9567
  const inspectorOptionsRef = useRef11(inspectorOptions);
9423
9568
  inspectorOptionsRef.current = inspectorOptions;
9424
- useEffect14(() => {
9569
+ useEffect13(() => {
9425
9570
  if (process.env.NODE_ENV !== "development") {
9426
9571
  return;
9427
9572
  }