@almadar/ui 2.41.0 → 2.43.0

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.
@@ -1,5 +1,5 @@
1
1
  import * as React90 from 'react';
2
- import React90__default, { useCallback, createContext, useState, useRef, useEffect, useLayoutEffect, lazy, useContext, useMemo, useId, Suspense, useSyncExternalStore } from 'react';
2
+ import React90__default, { useCallback, createContext, useState, useRef, useEffect, useMemo, useLayoutEffect, lazy, useContext, useId, Suspense, useSyncExternalStore } from 'react';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import * as LucideIcons from 'lucide-react';
@@ -5835,27 +5835,27 @@ function useQuerySingleton(query) {
5835
5835
  store2.listeners.delete(listener);
5836
5836
  };
5837
5837
  }, [store2]);
5838
- const notifyListeners = useCallback(() => {
5838
+ const notifyListeners2 = useCallback(() => {
5839
5839
  store2.listeners.forEach((listener) => listener());
5840
5840
  }, [store2]);
5841
5841
  const setSearch = useCallback((value) => {
5842
5842
  store2.search = value;
5843
- notifyListeners();
5844
- }, [store2, notifyListeners]);
5843
+ notifyListeners2();
5844
+ }, [store2, notifyListeners2]);
5845
5845
  const setFilter = useCallback((key, value) => {
5846
5846
  store2.filters = { ...store2.filters, [key]: value };
5847
- notifyListeners();
5848
- }, [store2, notifyListeners]);
5847
+ notifyListeners2();
5848
+ }, [store2, notifyListeners2]);
5849
5849
  const clearFilters = useCallback(() => {
5850
5850
  store2.filters = {};
5851
5851
  store2.search = "";
5852
- notifyListeners();
5853
- }, [store2, notifyListeners]);
5852
+ notifyListeners2();
5853
+ }, [store2, notifyListeners2]);
5854
5854
  const setSort = useCallback((field, direction) => {
5855
5855
  store2.sortField = field;
5856
5856
  store2.sortDirection = direction;
5857
- notifyListeners();
5858
- }, [store2, notifyListeners]);
5857
+ notifyListeners2();
5858
+ }, [store2, notifyListeners2]);
5859
5859
  return {
5860
5860
  search: store2.search,
5861
5861
  setSearch,
@@ -8693,6 +8693,42 @@ var orbStyleOverrides = {
8693
8693
  "orb-op-async": { color: ORB_COLORS.dark.async }
8694
8694
  };
8695
8695
  var orbStyle = { ...dark, ...orbStyleOverrides };
8696
+ function computeFoldRegions(code) {
8697
+ const lines = code.split("\n");
8698
+ const regions = [];
8699
+ const stack = [];
8700
+ for (let i = 0; i < lines.length; i++) {
8701
+ const line = lines[i];
8702
+ let inString = false;
8703
+ for (let j = 0; j < line.length; j++) {
8704
+ const ch = line[j];
8705
+ if (ch === "\\" && inString) {
8706
+ j++;
8707
+ continue;
8708
+ }
8709
+ if (ch === '"') {
8710
+ inString = !inString;
8711
+ continue;
8712
+ }
8713
+ if (inString) continue;
8714
+ if (ch === "{" || ch === "[") {
8715
+ stack.push({ line: i, bracket: ch });
8716
+ } else if (ch === "}" || ch === "]") {
8717
+ const open = stack.pop();
8718
+ if (open && open.line < i) {
8719
+ regions.push({
8720
+ start: open.line,
8721
+ end: i,
8722
+ closeBracket: ch
8723
+ });
8724
+ }
8725
+ }
8726
+ }
8727
+ }
8728
+ return regions.sort((a, b) => a.start - b.start);
8729
+ }
8730
+ var LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
8731
+ var HIDDEN_LINE_NUMBERS = { display: "none" };
8696
8732
  var CodeBlock = React90__default.memo(
8697
8733
  ({
8698
8734
  code: rawCode,
@@ -8700,6 +8736,7 @@ var CodeBlock = React90__default.memo(
8700
8736
  showCopyButton = true,
8701
8737
  showLanguageBadge = true,
8702
8738
  maxHeight = "60vh",
8739
+ foldable: foldableProp,
8703
8740
  className
8704
8741
  }) => {
8705
8742
  const code = typeof rawCode === "string" ? rawCode : String(rawCode ?? "");
@@ -8708,8 +8745,114 @@ var CodeBlock = React90__default.memo(
8708
8745
  const eventBus = useEventBus();
8709
8746
  const { t: _t } = useTranslate();
8710
8747
  const scrollRef = useRef(null);
8748
+ const codeRef = useRef(null);
8711
8749
  const savedScrollLeftRef = useRef(0);
8712
8750
  const [copied, setCopied] = useState(false);
8751
+ const isFoldable = foldableProp ?? (language === "orb" || language === "json");
8752
+ const [collapsed, setCollapsed] = useState(() => /* @__PURE__ */ new Set());
8753
+ const foldRegions = useMemo(
8754
+ () => isFoldable ? computeFoldRegions(code) : [],
8755
+ [code, isFoldable]
8756
+ );
8757
+ const foldStartMap = useMemo(() => {
8758
+ const m = /* @__PURE__ */ new Map();
8759
+ for (const r of foldRegions) m.set(r.start, r);
8760
+ return m;
8761
+ }, [foldRegions]);
8762
+ const hiddenLines = useMemo(() => {
8763
+ const h = /* @__PURE__ */ new Set();
8764
+ for (const r of foldRegions) {
8765
+ if (!collapsed.has(r.start)) continue;
8766
+ for (let i = r.start + 1; i <= r.end; i++) h.add(i);
8767
+ }
8768
+ return h;
8769
+ }, [foldRegions, collapsed]);
8770
+ const collapsedRef = useRef(collapsed);
8771
+ collapsedRef.current = collapsed;
8772
+ const foldStartMapRef = useRef(foldStartMap);
8773
+ foldStartMapRef.current = foldStartMap;
8774
+ const toggleFold = useCallback((lineNum) => {
8775
+ setCollapsed((prev) => {
8776
+ const next = new Set(prev);
8777
+ if (next.has(lineNum)) next.delete(lineNum);
8778
+ else next.add(lineNum);
8779
+ return next;
8780
+ });
8781
+ }, []);
8782
+ const toggleFoldRef = useRef(toggleFold);
8783
+ toggleFoldRef.current = toggleFold;
8784
+ useEffect(() => {
8785
+ setCollapsed(/* @__PURE__ */ new Set());
8786
+ }, [code]);
8787
+ const highlightedElement = useMemo(
8788
+ () => /* @__PURE__ */ jsx(
8789
+ SyntaxHighlighter,
8790
+ {
8791
+ PreTag: "div",
8792
+ language,
8793
+ style: activeStyle,
8794
+ wrapLines: true,
8795
+ showLineNumbers: true,
8796
+ showInlineLineNumbers: false,
8797
+ lineNumberContainerStyle: HIDDEN_LINE_NUMBERS,
8798
+ lineProps: LINE_PROPS_FN,
8799
+ customStyle: {
8800
+ backgroundColor: "transparent",
8801
+ borderRadius: 0,
8802
+ padding: 0,
8803
+ margin: 0,
8804
+ whiteSpace: "pre",
8805
+ minWidth: "100%"
8806
+ },
8807
+ children: code
8808
+ }
8809
+ ),
8810
+ [code, language, activeStyle]
8811
+ );
8812
+ useLayoutEffect(() => {
8813
+ const container = codeRef.current;
8814
+ if (!container) return;
8815
+ container.querySelectorAll(".fold-toggle, .fold-summary").forEach((el) => el.remove());
8816
+ const lineEls = container.querySelectorAll("[data-line]");
8817
+ if (!isFoldable || foldRegions.length === 0) {
8818
+ lineEls.forEach((el) => {
8819
+ el.style.display = "";
8820
+ el.style.position = "";
8821
+ el.style.paddingLeft = "";
8822
+ });
8823
+ return;
8824
+ }
8825
+ lineEls.forEach((el) => {
8826
+ const num = parseInt(el.getAttribute("data-line") ?? "-1", 10);
8827
+ if (hiddenLines.has(num)) {
8828
+ el.style.display = "none";
8829
+ return;
8830
+ }
8831
+ el.style.display = "";
8832
+ el.style.position = "relative";
8833
+ el.style.paddingLeft = "1.2em";
8834
+ const region = foldStartMap.get(num);
8835
+ if (!region) return;
8836
+ const isCollapsed = collapsed.has(num);
8837
+ const toggle = document.createElement("span");
8838
+ toggle.className = "fold-toggle";
8839
+ toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
8840
+ toggle.style.cssText = "position:absolute;left:0;top:0;width:1.2em;text-align:center;cursor:pointer;color:#858585;font-size:10px;user-select:none;line-height:inherit;height:100%";
8841
+ toggle.addEventListener("click", (e) => {
8842
+ e.stopPropagation();
8843
+ toggleFoldRef.current(num);
8844
+ });
8845
+ el.insertBefore(toggle, el.firstChild);
8846
+ if (isCollapsed) {
8847
+ const summary = document.createElement("span");
8848
+ summary.className = "fold-summary";
8849
+ summary.style.cssText = "color:#858585;font-style:italic";
8850
+ const count = region.end - region.start - 1;
8851
+ summary.textContent = ` ... ${count} line${count !== 1 ? "s" : ""} ${region.closeBracket}`;
8852
+ el.appendChild(summary);
8853
+ }
8854
+ });
8855
+ }, [collapsed, hiddenLines, foldStartMap, foldRegions, isFoldable]);
8713
8856
  useLayoutEffect(() => {
8714
8857
  const el = scrollRef.current;
8715
8858
  return () => {
@@ -8740,8 +8883,9 @@ var CodeBlock = React90__default.memo(
8740
8883
  eventBus.emit("UI:COPY_CODE", { language, success: false });
8741
8884
  }
8742
8885
  };
8886
+ const hasHeader = showLanguageBadge || showCopyButton;
8743
8887
  return /* @__PURE__ */ jsxs(Box, { className: `relative group ${className || ""}`, children: [
8744
- (showLanguageBadge || showCopyButton) && /* @__PURE__ */ jsxs(
8888
+ hasHeader && /* @__PURE__ */ jsxs(
8745
8889
  HStack,
8746
8890
  {
8747
8891
  justify: "between",
@@ -8776,31 +8920,14 @@ var CodeBlock = React90__default.memo(
8776
8920
  touchAction: "pan-x pan-y",
8777
8921
  contain: "paint",
8778
8922
  backgroundColor: "#1e1e1e",
8779
- borderRadius: showLanguageBadge || showCopyButton ? "0 0 0.5rem 0.5rem" : "0.5rem",
8780
- padding: "1rem"
8923
+ borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem"
8781
8924
  },
8782
- children: /* @__PURE__ */ jsx(
8783
- SyntaxHighlighter,
8784
- {
8785
- PreTag: "div",
8786
- language,
8787
- style: activeStyle,
8788
- customStyle: {
8789
- backgroundColor: "transparent",
8790
- borderRadius: 0,
8791
- padding: 0,
8792
- margin: 0,
8793
- whiteSpace: "pre",
8794
- minWidth: "100%"
8795
- },
8796
- children: code
8797
- }
8798
- )
8925
+ children: /* @__PURE__ */ jsx("div", { ref: codeRef, style: { padding: "1rem" }, children: highlightedElement })
8799
8926
  }
8800
8927
  )
8801
8928
  ] });
8802
8929
  },
8803
- (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight
8930
+ (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight && prev.foldable === next.foldable
8804
8931
  );
8805
8932
  CodeBlock.displayName = "CodeBlock";
8806
8933
  var QuizBlock = ({
@@ -26834,7 +26961,7 @@ function SequencerBoard({
26834
26961
  setPlayState("playing");
26835
26962
  setCurrentStep(0);
26836
26963
  let step = 0;
26837
- const advance2 = () => {
26964
+ const advance = () => {
26838
26965
  step++;
26839
26966
  if (step >= entity.maxSlots) {
26840
26967
  const playerSeq = slots.map((s) => s?.id);
@@ -26865,10 +26992,10 @@ function SequencerBoard({
26865
26992
  }
26866
26993
  } else {
26867
26994
  setCurrentStep(step);
26868
- timerRef.current = setTimeout(advance2, stepDurationMs);
26995
+ timerRef.current = setTimeout(advance, stepDurationMs);
26869
26996
  }
26870
26997
  };
26871
- timerRef.current = setTimeout(advance2, stepDurationMs);
26998
+ timerRef.current = setTimeout(advance, stepDurationMs);
26872
26999
  }, [canPlay, slots, entity.maxSlots, entity.solutions, stepDurationMs, playEvent, completeEvent, emit]);
26873
27000
  const machine = {
26874
27001
  name: entity.title,
@@ -28980,25 +29107,92 @@ function generateCombatMessage(event) {
28980
29107
  var store = /* @__PURE__ */ new Map();
28981
29108
  var storeListeners = /* @__PURE__ */ new Set();
28982
29109
  var watchCallbacks = /* @__PURE__ */ new Map();
28983
- function advance(entityType, data) {
28984
- const prev = store.get(entityType);
28985
- const oldData = prev?.data ?? [];
28986
- store.set(entityType, { data, version: (prev?.version ?? 0) + 1 });
29110
+ function extractId(record) {
29111
+ const r = record;
29112
+ return String(r.id ?? r._id ?? r.key ?? "");
29113
+ }
29114
+ function materialize(snap) {
29115
+ return snap.ids.map((id) => snap.entities.get(id));
29116
+ }
29117
+ function notifyListeners(entityType, prev) {
28987
29118
  for (const listener of storeListeners) {
28988
29119
  listener();
28989
29120
  }
28990
29121
  const cbs = watchCallbacks.get(entityType);
28991
29122
  if (cbs) {
29123
+ const oldData = prev ? materialize(prev) : [];
29124
+ const cur = store.get(entityType);
29125
+ const newData = cur ? materialize(cur) : [];
28992
29126
  for (const cb of cbs) {
28993
29127
  try {
28994
- cb(oldData, data);
29128
+ cb(oldData, newData);
28995
29129
  } catch {
28996
29130
  }
28997
29131
  }
28998
29132
  }
28999
29133
  }
29134
+ function setAll(entityType, records) {
29135
+ const entities2 = /* @__PURE__ */ new Map();
29136
+ const ids = [];
29137
+ for (const r of records) {
29138
+ const rec = r;
29139
+ const id = extractId(rec);
29140
+ if (id) {
29141
+ entities2.set(id, rec);
29142
+ ids.push(id);
29143
+ }
29144
+ }
29145
+ const prev = store.get(entityType);
29146
+ store.set(entityType, { entities: entities2, ids, version: (prev?.version ?? 0) + 1 });
29147
+ notifyListeners(entityType, prev);
29148
+ }
29149
+ function upsertOne(entityType, record) {
29150
+ const id = extractId(record);
29151
+ if (!id) return;
29152
+ const prev = store.get(entityType);
29153
+ const snapshot = prev ? { entities: new Map(prev.entities), ids: [...prev.ids], version: prev.version } : { entities: /* @__PURE__ */ new Map(), ids: [], version: 0 };
29154
+ snapshot.entities.set(id, record);
29155
+ if (!snapshot.ids.includes(id)) snapshot.ids.push(id);
29156
+ snapshot.version++;
29157
+ store.set(entityType, snapshot);
29158
+ notifyListeners(entityType, prev);
29159
+ }
29160
+ function addOne(entityType, record) {
29161
+ upsertOne(entityType, record);
29162
+ }
29163
+ function updateOne(entityType, id, changes) {
29164
+ const prev = store.get(entityType);
29165
+ if (!prev?.entities.has(id)) return;
29166
+ const snapshot = {
29167
+ entities: new Map(prev.entities),
29168
+ ids: [...prev.ids],
29169
+ version: prev.version
29170
+ };
29171
+ snapshot.entities.set(id, { ...snapshot.entities.get(id), ...changes });
29172
+ snapshot.version++;
29173
+ store.set(entityType, snapshot);
29174
+ notifyListeners(entityType, prev);
29175
+ }
29176
+ function removeOne(entityType, id) {
29177
+ const prev = store.get(entityType);
29178
+ if (!prev) return;
29179
+ const snapshot = {
29180
+ entities: new Map(prev.entities),
29181
+ ids: prev.ids.filter((i) => i !== id),
29182
+ version: prev.version
29183
+ };
29184
+ snapshot.entities.delete(id);
29185
+ snapshot.version++;
29186
+ store.set(entityType, snapshot);
29187
+ notifyListeners(entityType, prev);
29188
+ }
29000
29189
  function getSnapshot2(entityType) {
29001
- return store.get(entityType)?.data ?? [];
29190
+ const snap = store.get(entityType);
29191
+ if (!snap) return [];
29192
+ return materialize(snap);
29193
+ }
29194
+ function getById(entityType, id) {
29195
+ return store.get(entityType)?.entities.get(id) ?? null;
29002
29196
  }
29003
29197
  function getVersion(entityType) {
29004
29198
  return store.get(entityType)?.version ?? 0;
@@ -29022,10 +29216,16 @@ function useEntityRef(entityType) {
29022
29216
  }, [entityType]);
29023
29217
  return useSyncExternalStore(subscribeToStore, getSnapshotStable, () => []);
29024
29218
  }
29025
- createContext({
29026
- advance,
29027
- getSnapshot: getSnapshot2
29028
- });
29219
+ var contextValue = {
29220
+ setAll,
29221
+ upsertOne,
29222
+ addOne,
29223
+ updateOne,
29224
+ removeOne,
29225
+ getSnapshot: getSnapshot2,
29226
+ getById
29227
+ };
29228
+ createContext(contextValue);
29029
29229
  var ClientEffectConfigContext = createContext(null);
29030
29230
  ClientEffectConfigContext.Provider;
29031
29231
 
@@ -34417,13 +34617,14 @@ function getToastPosition(position) {
34417
34617
  return "top-4 right-4";
34418
34618
  }
34419
34619
  }
34420
- function renderPatternChildren(children, onDismiss, parentId = "root") {
34620
+ function renderPatternChildren(children, onDismiss, parentId = "root", parentPath = "root") {
34421
34621
  if (!children || !Array.isArray(children) || children.length === 0) {
34422
34622
  return null;
34423
34623
  }
34424
34624
  return children.map((child, index) => {
34425
34625
  if (!child || typeof child !== "object") return null;
34426
34626
  const childId = `${parentId}-${index}`;
34627
+ const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
34427
34628
  const childContent = {
34428
34629
  id: childId,
34429
34630
  pattern: child.type,
@@ -34435,7 +34636,8 @@ function renderPatternChildren(children, onDismiss, parentId = "root") {
34435
34636
  SlotContentRenderer,
34436
34637
  {
34437
34638
  content: childContent,
34438
- onDismiss
34639
+ onDismiss,
34640
+ patternPath: childPath
34439
34641
  },
34440
34642
  childId
34441
34643
  );
@@ -34467,7 +34669,8 @@ function renderPatternProps(props, onDismiss) {
34467
34669
  }
34468
34670
  function SlotContentRenderer({
34469
34671
  content,
34470
- onDismiss
34672
+ onDismiss,
34673
+ patternPath
34471
34674
  }) {
34472
34675
  const entityProp = content.props.entity;
34473
34676
  const entityType = typeof entityProp === "string" ? entityProp : "";
@@ -34476,7 +34679,8 @@ function SlotContentRenderer({
34476
34679
  if (PatternComponent) {
34477
34680
  const childrenConfig = content.props.children;
34478
34681
  const hasChildren = PATTERNS_WITH_CHILDREN.has(content.pattern) || Array.isArray(childrenConfig) && childrenConfig.length > 0;
34479
- const renderedChildren = hasChildren ? renderPatternChildren(childrenConfig, onDismiss, content.id) : void 0;
34682
+ const myPath = patternPath ?? "root";
34683
+ const renderedChildren = hasChildren ? renderPatternChildren(childrenConfig, onDismiss, content.id, myPath) : void 0;
34480
34684
  const { children: _childrenConfig, ...restProps } = content.props;
34481
34685
  const renderedProps = renderPatternProps(restProps, onDismiss);
34482
34686
  let finalProps;
@@ -34492,6 +34696,7 @@ function SlotContentRenderer({
34492
34696
  } else {
34493
34697
  finalProps = renderedProps;
34494
34698
  }
34699
+ const acceptsChildren = PATTERNS_WITH_CHILDREN.has(content.pattern);
34495
34700
  return /* @__PURE__ */ jsx(
34496
34701
  Box,
34497
34702
  {
@@ -34500,6 +34705,9 @@ function SlotContentRenderer({
34500
34705
  "data-id": content.id,
34501
34706
  "data-node-id": content.nodeId,
34502
34707
  "data-source-trait": content.sourceTrait,
34708
+ "data-pattern-path": myPath,
34709
+ "data-pattern-type": content.pattern,
34710
+ "data-accepts-children": acceptsChildren ? "true" : void 0,
34503
34711
  children: /* @__PURE__ */ jsx(PatternComponent, { ...finalProps, children: renderedChildren })
34504
34712
  }
34505
34713
  );
@@ -37174,6 +37382,98 @@ function usePinchZoom(options = {}) {
37174
37382
  resetZoom
37175
37383
  };
37176
37384
  }
37385
+ var ALMADAR_DND_MIME = "application/x-almadar-dnd";
37386
+ function useDraggable({ payload, disabled = false }) {
37387
+ const [isDragging, setIsDragging] = useState(false);
37388
+ const eventBus = useEventBus();
37389
+ const handleDragStart = useCallback(
37390
+ (e) => {
37391
+ if (disabled) {
37392
+ e.preventDefault();
37393
+ return;
37394
+ }
37395
+ e.dataTransfer.setData(ALMADAR_DND_MIME, JSON.stringify(payload));
37396
+ e.dataTransfer.effectAllowed = "copy";
37397
+ setIsDragging(true);
37398
+ eventBus.emit("UI:DRAG_START", { kind: payload.kind, data: payload.data });
37399
+ },
37400
+ [disabled, payload, eventBus]
37401
+ );
37402
+ const handleDragEnd = useCallback(
37403
+ (e) => {
37404
+ setIsDragging(false);
37405
+ eventBus.emit("UI:DRAG_END", { kind: payload.kind, data: payload.data });
37406
+ },
37407
+ [payload, eventBus]
37408
+ );
37409
+ const dragProps = useMemo(
37410
+ () => ({
37411
+ draggable: !disabled,
37412
+ onDragStart: handleDragStart,
37413
+ onDragEnd: handleDragEnd,
37414
+ "aria-grabbed": isDragging
37415
+ }),
37416
+ [disabled, handleDragStart, handleDragEnd, isDragging]
37417
+ );
37418
+ return { dragProps, isDragging };
37419
+ }
37420
+ function parsePayload(e) {
37421
+ try {
37422
+ const raw = e.dataTransfer.getData(ALMADAR_DND_MIME);
37423
+ if (!raw) return null;
37424
+ const parsed = JSON.parse(raw);
37425
+ if (typeof parsed.kind !== "string" || !parsed.data) return null;
37426
+ return parsed;
37427
+ } catch {
37428
+ return null;
37429
+ }
37430
+ }
37431
+ function hasAlmadarPayload(e) {
37432
+ return e.dataTransfer.types.includes(ALMADAR_DND_MIME);
37433
+ }
37434
+ function useDropZone({ accepts, onDrop, disabled = false }) {
37435
+ const [isOver, setIsOver] = useState(false);
37436
+ const eventBus = useEventBus();
37437
+ const handleDragOver = useCallback(
37438
+ (e) => {
37439
+ if (disabled) return;
37440
+ if (!hasAlmadarPayload(e)) return;
37441
+ e.preventDefault();
37442
+ e.dataTransfer.dropEffect = "copy";
37443
+ setIsOver(true);
37444
+ },
37445
+ [disabled]
37446
+ );
37447
+ const handleDragLeave = useCallback(
37448
+ (e) => {
37449
+ setIsOver(false);
37450
+ },
37451
+ []
37452
+ );
37453
+ const handleDrop = useCallback(
37454
+ (e) => {
37455
+ e.preventDefault();
37456
+ setIsOver(false);
37457
+ if (disabled) return;
37458
+ const payload = parsePayload(e);
37459
+ if (!payload) return;
37460
+ if (!accepts.includes(payload.kind)) return;
37461
+ const position = { x: e.clientX, y: e.clientY };
37462
+ onDrop(payload, position);
37463
+ eventBus.emit("UI:DROP", { kind: payload.kind, data: payload.data, ...position });
37464
+ },
37465
+ [disabled, accepts, onDrop, eventBus]
37466
+ );
37467
+ const dropProps = useMemo(
37468
+ () => ({
37469
+ onDragOver: handleDragOver,
37470
+ onDragLeave: handleDragLeave,
37471
+ onDrop: handleDrop
37472
+ }),
37473
+ [handleDragOver, handleDragLeave, handleDrop]
37474
+ );
37475
+ return { dropProps, isOver };
37476
+ }
37177
37477
  var API_BASE = typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "http://localhost:3000";
37178
37478
  function getUserId() {
37179
37479
  return localStorage.getItem("userId") || "anonymous";
@@ -37250,4 +37550,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
37250
37550
  });
37251
37551
  }
37252
37552
 
37253
- export { ALL_PRESETS, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, ClassifierBoard, CodeBlock, CodeExample, CodeView, CodeViewer, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_SLOTS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, DialogueBox, DialogueBubble, Divider, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ENTITY_EVENTS, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDataProvider, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GraphCanvas, GraphView, Grid, HStack, Header, Heading, HealthBar, HealthPanel, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LineChart, List, LoadingState, MapView, MarkdownContent, MarketingStatCard, MasterDetail, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, Navigation, NegotiatorBoard, NotifyListener, NumberStepper, ObjectRulePanel, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerCanvas, Popover, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PullToRefresh, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ResourceBar, ResourceCounter, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, Table, Tabs, TagCloud, TeamCard, TeamOrganism, TerrainPalette, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, ViolationAlert, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, clearEntities, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createTranslate, createUnitAnimationState, drawSprite, entityDataKeys, generateCombatMessage, getAllEntities, getByType, getCurrentFrame, getEntity, getSingleton, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseQueryBinding, pendulum, projectileMotion, removeEntity, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, spawnEntity, springOscillator, tickAnimationState, transitionAnimation, updateEntity, updateSingleton, useAgentChat, useAuthContext, useBattleState, useCamera, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useDragReorder, useEmitEvent, useEntities, useEntitiesByType, useEntity, useEntity2 as useEntityById, useEntityDataAdapter, useEntityDetail, useEntityList, useEntityListSuspense, useEntityMutations, useEntitySuspense, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, useOrbitalMutations, usePhysics, usePhysics2D, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useSpriteAnimations, useSwipeGesture, useTranslate, useUIEvents, useUISlotManager, useUpdateEntity, useValidation };
37553
+ export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, ClassifierBoard, CodeBlock, CodeExample, CodeView, CodeViewer, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_SLOTS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, DialogueBox, DialogueBubble, Divider, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ENTITY_EVENTS, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDataProvider, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GraphCanvas, GraphView, Grid, HStack, Header, Heading, HealthBar, HealthPanel, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LineChart, List, LoadingState, MapView, MarkdownContent, MarketingStatCard, MasterDetail, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, Navigation, NegotiatorBoard, NotifyListener, NumberStepper, ObjectRulePanel, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerCanvas, Popover, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PullToRefresh, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ResourceBar, ResourceCounter, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, Table, Tabs, TagCloud, TeamCard, TeamOrganism, TerrainPalette, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, ViolationAlert, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, clearEntities, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createTranslate, createUnitAnimationState, drawSprite, entityDataKeys, generateCombatMessage, getAllEntities, getByType, getCurrentFrame, getEntity, getSingleton, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseQueryBinding, pendulum, projectileMotion, removeEntity, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, spawnEntity, springOscillator, tickAnimationState, transitionAnimation, updateEntity, updateSingleton, useAgentChat, useAuthContext, useBattleState, useCamera, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEntities, useEntitiesByType, useEntity, useEntity2 as useEntityById, useEntityDataAdapter, useEntityDetail, useEntityList, useEntityListSuspense, useEntityMutations, useEntitySuspense, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, useOrbitalMutations, usePhysics, usePhysics2D, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useSpriteAnimations, useSwipeGesture, useTranslate, useUIEvents, useUISlotManager, useUpdateEntity, useValidation };
@@ -19,6 +19,8 @@ export interface CodeBlockProps {
19
19
  showLanguageBadge?: boolean;
20
20
  /** Maximum height before scrolling */
21
21
  maxHeight?: string;
22
+ /** Enable JSON-style code folding (default: true for json/orb) */
23
+ foldable?: boolean;
22
24
  /** Additional CSS classes */
23
25
  className?: string;
24
26
  }
@@ -59,6 +59,8 @@ interface SlotContentRendererProps {
59
59
  isLoading?: boolean;
60
60
  error?: Error | null;
61
61
  entity?: string;
62
+ /** Schema-compatible path for WYSIWYG drop targeting (e.g., "root.children.0"). */
63
+ patternPath?: string;
62
64
  }
63
65
  /**
64
66
  * Renders the actual content of a slot.
@@ -67,7 +69,7 @@ interface SlotContentRendererProps {
67
69
  * For layout patterns with `hasChildren`, recursively renders nested patterns.
68
70
  * For all patterns, named props containing pattern configs are also rendered.
69
71
  */
70
- declare function SlotContentRenderer({ content, onDismiss, }: SlotContentRendererProps): React.ReactElement;
72
+ declare function SlotContentRenderer({ content, onDismiss, patternPath, }: SlotContentRendererProps): React.ReactElement;
71
73
  export interface UISlotRendererProps {
72
74
  /** Include HUD slots */
73
75
  includeHud?: boolean;
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import React from 'react';
15
15
  import type { OrbitalSchema } from '@almadar/core';
16
- import type { ViewLevel } from '../../molecules/avl/avl-preview-types';
16
+ import type { ViewLevel, PreviewNodeData } from '../../molecules/avl/avl-preview-types';
17
17
  export interface FlowCanvasProps {
18
18
  schema: OrbitalSchema | string;
19
19
  mockData?: Record<string, unknown[]>;
@@ -32,6 +32,19 @@ export interface FlowCanvasProps {
32
32
  editable?: boolean;
33
33
  /** Called when the user edits the schema via the inspector. */
34
34
  onSchemaChange?: (schema: OrbitalSchema) => void;
35
+ /** Called when the user presses Delete/Backspace with a pattern selected. */
36
+ onPatternDelete?: (context: {
37
+ patternId: string;
38
+ nodeData: PreviewNodeData;
39
+ }) => void;
40
+ /** Called when the user drags from a source handle to a target handle (event wiring). */
41
+ onEventWire?: (wire: {
42
+ eventName: string;
43
+ sourceOrbital: string;
44
+ targetOrbital: string;
45
+ sourceTraitName?: string;
46
+ targetTraitName?: string;
47
+ }) => void;
35
48
  /** @deprecated Use onNodeClick instead. Kept for AvlCosmicZoom compat. */
36
49
  onZoomChange?: (level: string, context: Record<string, string | undefined>) => void;
37
50
  /** @deprecated Not used in V3. */