@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.
@@ -2961,7 +2961,7 @@ function EventBusProvider({ children, debug: debug2 = false }) {
2961
2961
  }
2962
2962
  };
2963
2963
  }, [debug2]);
2964
- const contextValue = React124.useMemo(
2964
+ const contextValue2 = React124.useMemo(
2965
2965
  () => ({
2966
2966
  emit,
2967
2967
  on,
@@ -2974,12 +2974,12 @@ function EventBusProvider({ children, debug: debug2 = false }) {
2974
2974
  [emit, on, once, hasListeners, onAny, getSelectedEntity, clearSelectedEntity]
2975
2975
  );
2976
2976
  React124.useEffect(() => {
2977
- setGlobalEventBus(contextValue);
2977
+ setGlobalEventBus(contextValue2);
2978
2978
  return () => {
2979
2979
  setGlobalEventBus(null);
2980
2980
  };
2981
- }, [contextValue]);
2982
- return /* @__PURE__ */ jsxRuntime.jsx(EventBusContext.Provider, { value: contextValue, children });
2981
+ }, [contextValue2]);
2982
+ return /* @__PURE__ */ jsxRuntime.jsx(EventBusContext.Provider, { value: contextValue2, children });
2983
2983
  }
2984
2984
  var EventBusContext;
2985
2985
  var init_EventBusProvider = __esm({
@@ -13276,7 +13276,7 @@ var ThemeProvider = ({
13276
13276
  const newMode = resolvedMode === "dark" ? "light" : "dark";
13277
13277
  setMode(newMode);
13278
13278
  }, [resolvedMode, setMode]);
13279
- const contextValue = React124.useMemo(
13279
+ const contextValue2 = React124.useMemo(
13280
13280
  () => ({
13281
13281
  theme,
13282
13282
  mode,
@@ -13298,7 +13298,7 @@ var ThemeProvider = ({
13298
13298
  appliedTheme
13299
13299
  ]
13300
13300
  );
13301
- return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue, children });
13301
+ return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue2, children });
13302
13302
  };
13303
13303
  function useTheme() {
13304
13304
  const context = React124.useContext(ThemeContext);
@@ -13322,25 +13322,92 @@ function useTheme() {
13322
13322
  var store = /* @__PURE__ */ new Map();
13323
13323
  var storeListeners = /* @__PURE__ */ new Set();
13324
13324
  var watchCallbacks = /* @__PURE__ */ new Map();
13325
- function advance(entityType, data) {
13326
- const prev = store.get(entityType);
13327
- const oldData = prev?.data ?? [];
13328
- store.set(entityType, { data, version: (prev?.version ?? 0) + 1 });
13325
+ function extractId(record) {
13326
+ const r2 = record;
13327
+ return String(r2.id ?? r2._id ?? r2.key ?? "");
13328
+ }
13329
+ function materialize(snap) {
13330
+ return snap.ids.map((id) => snap.entities.get(id));
13331
+ }
13332
+ function notifyListeners(entityType, prev) {
13329
13333
  for (const listener of storeListeners) {
13330
13334
  listener();
13331
13335
  }
13332
13336
  const cbs = watchCallbacks.get(entityType);
13333
13337
  if (cbs) {
13338
+ const oldData = prev ? materialize(prev) : [];
13339
+ const cur = store.get(entityType);
13340
+ const newData = cur ? materialize(cur) : [];
13334
13341
  for (const cb of cbs) {
13335
13342
  try {
13336
- cb(oldData, data);
13343
+ cb(oldData, newData);
13337
13344
  } catch {
13338
13345
  }
13339
13346
  }
13340
13347
  }
13341
13348
  }
13349
+ function setAll(entityType, records) {
13350
+ const entities = /* @__PURE__ */ new Map();
13351
+ const ids = [];
13352
+ for (const r2 of records) {
13353
+ const rec = r2;
13354
+ const id = extractId(rec);
13355
+ if (id) {
13356
+ entities.set(id, rec);
13357
+ ids.push(id);
13358
+ }
13359
+ }
13360
+ const prev = store.get(entityType);
13361
+ store.set(entityType, { entities, ids, version: (prev?.version ?? 0) + 1 });
13362
+ notifyListeners(entityType, prev);
13363
+ }
13364
+ function upsertOne(entityType, record) {
13365
+ const id = extractId(record);
13366
+ if (!id) return;
13367
+ const prev = store.get(entityType);
13368
+ const snapshot = prev ? { entities: new Map(prev.entities), ids: [...prev.ids], version: prev.version } : { entities: /* @__PURE__ */ new Map(), ids: [], version: 0 };
13369
+ snapshot.entities.set(id, record);
13370
+ if (!snapshot.ids.includes(id)) snapshot.ids.push(id);
13371
+ snapshot.version++;
13372
+ store.set(entityType, snapshot);
13373
+ notifyListeners(entityType, prev);
13374
+ }
13375
+ function addOne(entityType, record) {
13376
+ upsertOne(entityType, record);
13377
+ }
13378
+ function updateOne(entityType, id, changes) {
13379
+ const prev = store.get(entityType);
13380
+ if (!prev?.entities.has(id)) return;
13381
+ const snapshot = {
13382
+ entities: new Map(prev.entities),
13383
+ ids: [...prev.ids],
13384
+ version: prev.version
13385
+ };
13386
+ snapshot.entities.set(id, { ...snapshot.entities.get(id), ...changes });
13387
+ snapshot.version++;
13388
+ store.set(entityType, snapshot);
13389
+ notifyListeners(entityType, prev);
13390
+ }
13391
+ function removeOne(entityType, id) {
13392
+ const prev = store.get(entityType);
13393
+ if (!prev) return;
13394
+ const snapshot = {
13395
+ entities: new Map(prev.entities),
13396
+ ids: prev.ids.filter((i) => i !== id),
13397
+ version: prev.version
13398
+ };
13399
+ snapshot.entities.delete(id);
13400
+ snapshot.version++;
13401
+ store.set(entityType, snapshot);
13402
+ notifyListeners(entityType, prev);
13403
+ }
13342
13404
  function getSnapshot(entityType) {
13343
- return store.get(entityType)?.data ?? [];
13405
+ const snap = store.get(entityType);
13406
+ if (!snap) return [];
13407
+ return materialize(snap);
13408
+ }
13409
+ function getById(entityType, id) {
13410
+ return store.get(entityType)?.entities.get(id) ?? null;
13344
13411
  }
13345
13412
  function getVersion(entityType) {
13346
13413
  return store.get(entityType)?.version ?? 0;
@@ -13364,15 +13431,21 @@ function useEntityRef(entityType) {
13364
13431
  }, [entityType]);
13365
13432
  return React124.useSyncExternalStore(subscribeToStore, getSnapshotStable, () => []);
13366
13433
  }
13367
- var EntityStoreContext = React124.createContext({
13368
- advance,
13369
- getSnapshot
13370
- });
13434
+ var contextValue = {
13435
+ setAll,
13436
+ upsertOne,
13437
+ addOne,
13438
+ updateOne,
13439
+ removeOne,
13440
+ getSnapshot,
13441
+ getById
13442
+ };
13443
+ var EntityStoreContext = React124.createContext(contextValue);
13371
13444
  function useEntityStore() {
13372
13445
  return React124.useContext(EntityStoreContext);
13373
13446
  }
13374
13447
  function EntityStoreProvider({ children }) {
13375
- return /* @__PURE__ */ jsxRuntime.jsx(EntityStoreContext.Provider, { value: { advance, getSnapshot }, children });
13448
+ return /* @__PURE__ */ jsxRuntime.jsx(EntityStoreContext.Provider, { value: contextValue, children });
13376
13449
  }
13377
13450
 
13378
13451
  // providers/OrbitalProvider.tsx
@@ -13448,13 +13521,13 @@ function SelectionProvider({
13448
13521
  unsubCancel();
13449
13522
  };
13450
13523
  }, [eventBus, setSelected, clearSelection, debug2]);
13451
- const contextValue = {
13524
+ const contextValue2 = {
13452
13525
  selected,
13453
13526
  setSelected,
13454
13527
  clearSelection,
13455
13528
  isSelected
13456
13529
  };
13457
- return /* @__PURE__ */ jsxRuntime.jsx(SelectionContext.Provider, { value: contextValue, children });
13530
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectionContext.Provider, { value: contextValue2, children });
13458
13531
  }
13459
13532
  var DEFAULT_SLOTS = {
13460
13533
  main: null,
@@ -13603,8 +13676,8 @@ function useUISlotManager() {
13603
13676
  var UISlotContext = React124.createContext(null);
13604
13677
  function UISlotProvider({ children }) {
13605
13678
  const slotManager = useUISlotManager();
13606
- const contextValue = React124.useMemo(() => slotManager, [slotManager]);
13607
- return /* @__PURE__ */ jsxRuntime.jsx(UISlotContext.Provider, { value: contextValue, children });
13679
+ const contextValue2 = React124.useMemo(() => slotManager, [slotManager]);
13680
+ return /* @__PURE__ */ jsxRuntime.jsx(UISlotContext.Provider, { value: contextValue2, children });
13608
13681
  }
13609
13682
  function useUISlots() {
13610
13683
  const context = React124.useContext(UISlotContext);
@@ -20107,13 +20180,13 @@ function getState() {
20107
20180
  }
20108
20181
  return { checks: /* @__PURE__ */ new Map(), transitions: [], bridgeHealth: null, listeners: /* @__PURE__ */ new Set() };
20109
20182
  }
20110
- function notifyListeners() {
20183
+ function notifyListeners2() {
20111
20184
  getState().listeners.forEach((l) => l());
20112
20185
  exposeOnWindow();
20113
20186
  }
20114
20187
  function registerCheck(id, label, status = "pending", details) {
20115
20188
  getState().checks.set(id, { id, label, status, details, updatedAt: Date.now() });
20116
- notifyListeners();
20189
+ notifyListeners2();
20117
20190
  }
20118
20191
  function getAllChecks() {
20119
20192
  return Array.from(getState().checks.values());
@@ -20157,7 +20230,7 @@ function recordTransition(trace) {
20157
20230
  failedEffects.map((e) => `${e.type}: ${e.error}`).join("; ")
20158
20231
  );
20159
20232
  }
20160
- notifyListeners();
20233
+ notifyListeners2();
20161
20234
  }
20162
20235
  function getTransitions2() {
20163
20236
  return [...getState().transitions];
@@ -20190,7 +20263,7 @@ function recordServerResponse(orbitalName, event, response) {
20190
20263
  response.error
20191
20264
  );
20192
20265
  }
20193
- notifyListeners();
20266
+ notifyListeners2();
20194
20267
  }
20195
20268
  function getBridgeHealth() {
20196
20269
  const bh = getState().bridgeHealth;
@@ -21806,6 +21879,42 @@ var orbStyleOverrides = {
21806
21879
  "orb-op-async": { color: syntax.ORB_COLORS.dark.async }
21807
21880
  };
21808
21881
  var orbStyle = { ...dark__default.default, ...orbStyleOverrides };
21882
+ function computeFoldRegions(code) {
21883
+ const lines = code.split("\n");
21884
+ const regions = [];
21885
+ const stack = [];
21886
+ for (let i = 0; i < lines.length; i++) {
21887
+ const line = lines[i];
21888
+ let inString = false;
21889
+ for (let j = 0; j < line.length; j++) {
21890
+ const ch = line[j];
21891
+ if (ch === "\\" && inString) {
21892
+ j++;
21893
+ continue;
21894
+ }
21895
+ if (ch === '"') {
21896
+ inString = !inString;
21897
+ continue;
21898
+ }
21899
+ if (inString) continue;
21900
+ if (ch === "{" || ch === "[") {
21901
+ stack.push({ line: i, bracket: ch });
21902
+ } else if (ch === "}" || ch === "]") {
21903
+ const open = stack.pop();
21904
+ if (open && open.line < i) {
21905
+ regions.push({
21906
+ start: open.line,
21907
+ end: i,
21908
+ closeBracket: ch
21909
+ });
21910
+ }
21911
+ }
21912
+ }
21913
+ }
21914
+ return regions.sort((a, b) => a.start - b.start);
21915
+ }
21916
+ var LINE_PROPS_FN = (n) => ({ "data-line": String(n - 1) });
21917
+ var HIDDEN_LINE_NUMBERS = { display: "none" };
21809
21918
  var CodeBlock = React124__namespace.default.memo(
21810
21919
  ({
21811
21920
  code: rawCode,
@@ -21813,6 +21922,7 @@ var CodeBlock = React124__namespace.default.memo(
21813
21922
  showCopyButton = true,
21814
21923
  showLanguageBadge = true,
21815
21924
  maxHeight = "60vh",
21925
+ foldable: foldableProp,
21816
21926
  className
21817
21927
  }) => {
21818
21928
  const code = typeof rawCode === "string" ? rawCode : String(rawCode ?? "");
@@ -21821,8 +21931,114 @@ var CodeBlock = React124__namespace.default.memo(
21821
21931
  const eventBus = useEventBus();
21822
21932
  const { t: _t } = useTranslate();
21823
21933
  const scrollRef = React124.useRef(null);
21934
+ const codeRef = React124.useRef(null);
21824
21935
  const savedScrollLeftRef = React124.useRef(0);
21825
21936
  const [copied, setCopied] = React124.useState(false);
21937
+ const isFoldable = foldableProp ?? (language === "orb" || language === "json");
21938
+ const [collapsed, setCollapsed] = React124.useState(() => /* @__PURE__ */ new Set());
21939
+ const foldRegions = React124.useMemo(
21940
+ () => isFoldable ? computeFoldRegions(code) : [],
21941
+ [code, isFoldable]
21942
+ );
21943
+ const foldStartMap = React124.useMemo(() => {
21944
+ const m = /* @__PURE__ */ new Map();
21945
+ for (const r2 of foldRegions) m.set(r2.start, r2);
21946
+ return m;
21947
+ }, [foldRegions]);
21948
+ const hiddenLines = React124.useMemo(() => {
21949
+ const h = /* @__PURE__ */ new Set();
21950
+ for (const r2 of foldRegions) {
21951
+ if (!collapsed.has(r2.start)) continue;
21952
+ for (let i = r2.start + 1; i <= r2.end; i++) h.add(i);
21953
+ }
21954
+ return h;
21955
+ }, [foldRegions, collapsed]);
21956
+ const collapsedRef = React124.useRef(collapsed);
21957
+ collapsedRef.current = collapsed;
21958
+ const foldStartMapRef = React124.useRef(foldStartMap);
21959
+ foldStartMapRef.current = foldStartMap;
21960
+ const toggleFold = React124.useCallback((lineNum) => {
21961
+ setCollapsed((prev) => {
21962
+ const next = new Set(prev);
21963
+ if (next.has(lineNum)) next.delete(lineNum);
21964
+ else next.add(lineNum);
21965
+ return next;
21966
+ });
21967
+ }, []);
21968
+ const toggleFoldRef = React124.useRef(toggleFold);
21969
+ toggleFoldRef.current = toggleFold;
21970
+ React124.useEffect(() => {
21971
+ setCollapsed(/* @__PURE__ */ new Set());
21972
+ }, [code]);
21973
+ const highlightedElement = React124.useMemo(
21974
+ () => /* @__PURE__ */ jsxRuntime.jsx(
21975
+ SyntaxHighlighter__default.default,
21976
+ {
21977
+ PreTag: "div",
21978
+ language,
21979
+ style: activeStyle,
21980
+ wrapLines: true,
21981
+ showLineNumbers: true,
21982
+ showInlineLineNumbers: false,
21983
+ lineNumberContainerStyle: HIDDEN_LINE_NUMBERS,
21984
+ lineProps: LINE_PROPS_FN,
21985
+ customStyle: {
21986
+ backgroundColor: "transparent",
21987
+ borderRadius: 0,
21988
+ padding: 0,
21989
+ margin: 0,
21990
+ whiteSpace: "pre",
21991
+ minWidth: "100%"
21992
+ },
21993
+ children: code
21994
+ }
21995
+ ),
21996
+ [code, language, activeStyle]
21997
+ );
21998
+ React124.useLayoutEffect(() => {
21999
+ const container = codeRef.current;
22000
+ if (!container) return;
22001
+ container.querySelectorAll(".fold-toggle, .fold-summary").forEach((el) => el.remove());
22002
+ const lineEls = container.querySelectorAll("[data-line]");
22003
+ if (!isFoldable || foldRegions.length === 0) {
22004
+ lineEls.forEach((el) => {
22005
+ el.style.display = "";
22006
+ el.style.position = "";
22007
+ el.style.paddingLeft = "";
22008
+ });
22009
+ return;
22010
+ }
22011
+ lineEls.forEach((el) => {
22012
+ const num = parseInt(el.getAttribute("data-line") ?? "-1", 10);
22013
+ if (hiddenLines.has(num)) {
22014
+ el.style.display = "none";
22015
+ return;
22016
+ }
22017
+ el.style.display = "";
22018
+ el.style.position = "relative";
22019
+ el.style.paddingLeft = "1.2em";
22020
+ const region = foldStartMap.get(num);
22021
+ if (!region) return;
22022
+ const isCollapsed = collapsed.has(num);
22023
+ const toggle = document.createElement("span");
22024
+ toggle.className = "fold-toggle";
22025
+ toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
22026
+ 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%";
22027
+ toggle.addEventListener("click", (e) => {
22028
+ e.stopPropagation();
22029
+ toggleFoldRef.current(num);
22030
+ });
22031
+ el.insertBefore(toggle, el.firstChild);
22032
+ if (isCollapsed) {
22033
+ const summary = document.createElement("span");
22034
+ summary.className = "fold-summary";
22035
+ summary.style.cssText = "color:#858585;font-style:italic";
22036
+ const count = region.end - region.start - 1;
22037
+ summary.textContent = ` ... ${count} line${count !== 1 ? "s" : ""} ${region.closeBracket}`;
22038
+ el.appendChild(summary);
22039
+ }
22040
+ });
22041
+ }, [collapsed, hiddenLines, foldStartMap, foldRegions, isFoldable]);
21826
22042
  React124.useLayoutEffect(() => {
21827
22043
  const el = scrollRef.current;
21828
22044
  return () => {
@@ -21853,8 +22069,9 @@ var CodeBlock = React124__namespace.default.memo(
21853
22069
  eventBus.emit("UI:COPY_CODE", { language, success: false });
21854
22070
  }
21855
22071
  };
22072
+ const hasHeader = showLanguageBadge || showCopyButton;
21856
22073
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: `relative group ${className || ""}`, children: [
21857
- (showLanguageBadge || showCopyButton) && /* @__PURE__ */ jsxRuntime.jsxs(
22074
+ hasHeader && /* @__PURE__ */ jsxRuntime.jsxs(
21858
22075
  HStack,
21859
22076
  {
21860
22077
  justify: "between",
@@ -21889,31 +22106,14 @@ var CodeBlock = React124__namespace.default.memo(
21889
22106
  touchAction: "pan-x pan-y",
21890
22107
  contain: "paint",
21891
22108
  backgroundColor: "#1e1e1e",
21892
- borderRadius: showLanguageBadge || showCopyButton ? "0 0 0.5rem 0.5rem" : "0.5rem",
21893
- padding: "1rem"
22109
+ borderRadius: hasHeader ? "0 0 0.5rem 0.5rem" : "0.5rem"
21894
22110
  },
21895
- children: /* @__PURE__ */ jsxRuntime.jsx(
21896
- SyntaxHighlighter__default.default,
21897
- {
21898
- PreTag: "div",
21899
- language,
21900
- style: activeStyle,
21901
- customStyle: {
21902
- backgroundColor: "transparent",
21903
- borderRadius: 0,
21904
- padding: 0,
21905
- margin: 0,
21906
- whiteSpace: "pre",
21907
- minWidth: "100%"
21908
- },
21909
- children: code
21910
- }
21911
- )
22111
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: codeRef, style: { padding: "1rem" }, children: highlightedElement })
21912
22112
  }
21913
22113
  )
21914
22114
  ] });
21915
22115
  },
21916
- (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight
22116
+ (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight && prev.foldable === next.foldable
21917
22117
  );
21918
22118
  CodeBlock.displayName = "CodeBlock";
21919
22119
 
@@ -29817,27 +30017,27 @@ function useQuerySingleton(query) {
29817
30017
  store2.listeners.delete(listener);
29818
30018
  };
29819
30019
  }, [store2]);
29820
- const notifyListeners3 = React124.useCallback(() => {
30020
+ const notifyListeners4 = React124.useCallback(() => {
29821
30021
  store2.listeners.forEach((listener) => listener());
29822
30022
  }, [store2]);
29823
30023
  const setSearch = React124.useCallback((value) => {
29824
30024
  store2.search = value;
29825
- notifyListeners3();
29826
- }, [store2, notifyListeners3]);
30025
+ notifyListeners4();
30026
+ }, [store2, notifyListeners4]);
29827
30027
  const setFilter = React124.useCallback((key, value) => {
29828
30028
  store2.filters = { ...store2.filters, [key]: value };
29829
- notifyListeners3();
29830
- }, [store2, notifyListeners3]);
30029
+ notifyListeners4();
30030
+ }, [store2, notifyListeners4]);
29831
30031
  const clearFilters = React124.useCallback(() => {
29832
30032
  store2.filters = {};
29833
30033
  store2.search = "";
29834
- notifyListeners3();
29835
- }, [store2, notifyListeners3]);
30034
+ notifyListeners4();
30035
+ }, [store2, notifyListeners4]);
29836
30036
  const setSort = React124.useCallback((field, direction) => {
29837
30037
  store2.sortField = field;
29838
30038
  store2.sortDirection = direction;
29839
- notifyListeners3();
29840
- }, [store2, notifyListeners3]);
30039
+ notifyListeners4();
30040
+ }, [store2, notifyListeners4]);
29841
30041
  return {
29842
30042
  search: store2.search,
29843
30043
  setSearch,
@@ -40019,24 +40219,24 @@ init_cn();
40019
40219
  // lib/traitRegistry.ts
40020
40220
  var traits = /* @__PURE__ */ new Map();
40021
40221
  var listeners = /* @__PURE__ */ new Set();
40022
- function notifyListeners2() {
40222
+ function notifyListeners3() {
40023
40223
  listeners.forEach((listener) => listener());
40024
40224
  }
40025
40225
  function registerTrait(info) {
40026
40226
  traits.set(info.id, info);
40027
- notifyListeners2();
40227
+ notifyListeners3();
40028
40228
  }
40029
40229
  function updateTraitState(id, newState) {
40030
40230
  const trait = traits.get(id);
40031
40231
  if (trait) {
40032
40232
  trait.currentState = newState;
40033
40233
  trait.transitionCount++;
40034
- notifyListeners2();
40234
+ notifyListeners3();
40035
40235
  }
40036
40236
  }
40037
40237
  function unregisterTrait(id) {
40038
40238
  traits.delete(id);
40039
- notifyListeners2();
40239
+ notifyListeners3();
40040
40240
  }
40041
40241
  function getAllTraits() {
40042
40242
  return Array.from(traits.values());
@@ -41815,7 +42015,7 @@ function SequencerBoard({
41815
42015
  setPlayState("playing");
41816
42016
  setCurrentStep(0);
41817
42017
  let step = 0;
41818
- const advance2 = () => {
42018
+ const advance = () => {
41819
42019
  step++;
41820
42020
  if (step >= entity.maxSlots) {
41821
42021
  const playerSeq = slots.map((s) => s?.id);
@@ -41846,10 +42046,10 @@ function SequencerBoard({
41846
42046
  }
41847
42047
  } else {
41848
42048
  setCurrentStep(step);
41849
- timerRef.current = setTimeout(advance2, stepDurationMs);
42049
+ timerRef.current = setTimeout(advance, stepDurationMs);
41850
42050
  }
41851
42051
  };
41852
- timerRef.current = setTimeout(advance2, stepDurationMs);
42052
+ timerRef.current = setTimeout(advance, stepDurationMs);
41853
42053
  }, [canPlay, slots, entity.maxSlots, entity.solutions, stepDurationMs, playEvent, completeEvent, emit]);
41854
42054
  const machine = {
41855
42055
  name: entity.title,
@@ -45409,13 +45609,14 @@ function getToastPosition(position) {
45409
45609
  return "top-4 right-4";
45410
45610
  }
45411
45611
  }
45412
- function renderPatternChildren(children, onDismiss, parentId = "root") {
45612
+ function renderPatternChildren(children, onDismiss, parentId = "root", parentPath = "root") {
45413
45613
  if (!children || !Array.isArray(children) || children.length === 0) {
45414
45614
  return null;
45415
45615
  }
45416
45616
  return children.map((child, index) => {
45417
45617
  if (!child || typeof child !== "object") return null;
45418
45618
  const childId = `${parentId}-${index}`;
45619
+ const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
45419
45620
  const childContent = {
45420
45621
  id: childId,
45421
45622
  pattern: child.type,
@@ -45427,7 +45628,8 @@ function renderPatternChildren(children, onDismiss, parentId = "root") {
45427
45628
  SlotContentRenderer,
45428
45629
  {
45429
45630
  content: childContent,
45430
- onDismiss
45631
+ onDismiss,
45632
+ patternPath: childPath
45431
45633
  },
45432
45634
  childId
45433
45635
  );
@@ -45459,7 +45661,8 @@ function renderPatternProps(props, onDismiss) {
45459
45661
  }
45460
45662
  function SlotContentRenderer({
45461
45663
  content,
45462
- onDismiss
45664
+ onDismiss,
45665
+ patternPath
45463
45666
  }) {
45464
45667
  const entityProp = content.props.entity;
45465
45668
  const entityType = typeof entityProp === "string" ? entityProp : "";
@@ -45468,7 +45671,8 @@ function SlotContentRenderer({
45468
45671
  if (PatternComponent) {
45469
45672
  const childrenConfig = content.props.children;
45470
45673
  const hasChildren = PATTERNS_WITH_CHILDREN.has(content.pattern) || Array.isArray(childrenConfig) && childrenConfig.length > 0;
45471
- const renderedChildren = hasChildren ? renderPatternChildren(childrenConfig, onDismiss, content.id) : void 0;
45674
+ const myPath = patternPath ?? "root";
45675
+ const renderedChildren = hasChildren ? renderPatternChildren(childrenConfig, onDismiss, content.id, myPath) : void 0;
45472
45676
  const { children: _childrenConfig, ...restProps } = content.props;
45473
45677
  const renderedProps = renderPatternProps(restProps, onDismiss);
45474
45678
  let finalProps;
@@ -45484,6 +45688,7 @@ function SlotContentRenderer({
45484
45688
  } else {
45485
45689
  finalProps = renderedProps;
45486
45690
  }
45691
+ const acceptsChildren = PATTERNS_WITH_CHILDREN.has(content.pattern);
45487
45692
  return /* @__PURE__ */ jsxRuntime.jsx(
45488
45693
  Box,
45489
45694
  {
@@ -45492,6 +45697,9 @@ function SlotContentRenderer({
45492
45697
  "data-id": content.id,
45493
45698
  "data-node-id": content.nodeId,
45494
45699
  "data-source-trait": content.sourceTrait,
45700
+ "data-pattern-path": myPath,
45701
+ "data-pattern-type": content.pattern,
45702
+ "data-accepts-children": acceptsChildren ? "true" : void 0,
45495
45703
  children: /* @__PURE__ */ jsxRuntime.jsx(PatternComponent, { ...finalProps, children: renderedChildren })
45496
45704
  }
45497
45705
  );
@@ -45844,6 +46052,13 @@ React124.createContext(null);
45844
46052
 
45845
46053
  // lib/api-client.ts
45846
46054
  typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "/api";
46055
+
46056
+ // hooks/useDraggable.ts
46057
+ init_useEventBus();
46058
+ var ALMADAR_DND_MIME = "application/x-almadar-dnd";
46059
+
46060
+ // hooks/useDropZone.ts
46061
+ init_useEventBus();
45847
46062
  typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "http://localhost:3000";
45848
46063
 
45849
46064
  // runtime/createClientEffectHandlers.ts
@@ -45891,13 +46106,13 @@ function EntitySchemaProvider({
45891
46106
  }
45892
46107
  return map;
45893
46108
  }, [entities]);
45894
- const contextValue = React124.useMemo(
46109
+ const contextValue2 = React124.useMemo(
45895
46110
  () => ({
45896
46111
  entities: entitiesMap
45897
46112
  }),
45898
46113
  [entitiesMap]
45899
46114
  );
45900
- return /* @__PURE__ */ jsxRuntime.jsx(EntitySchemaContext.Provider, { value: contextValue, children });
46115
+ return /* @__PURE__ */ jsxRuntime.jsx(EntitySchemaContext.Provider, { value: contextValue2, children });
45901
46116
  }
45902
46117
  function useEntitySchema() {
45903
46118
  const context = React124.useContext(EntitySchemaContext);
@@ -46496,7 +46711,7 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
46496
46711
  if (responseData) {
46497
46712
  for (const [entityType, records] of Object.entries(responseData)) {
46498
46713
  if (Array.isArray(records)) {
46499
- entityStore.advance(entityType, records);
46714
+ entityStore.setAll(entityType, records);
46500
46715
  }
46501
46716
  }
46502
46717
  }
@@ -46555,7 +46770,7 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate }) {
46555
46770
  if (initResponseData) {
46556
46771
  for (const [entityType, records] of Object.entries(initResponseData)) {
46557
46772
  if (Array.isArray(records)) {
46558
- entityStore.advance(entityType, records);
46773
+ entityStore.setAll(entityType, records);
46559
46774
  }
46560
46775
  }
46561
46776
  }
@@ -46604,7 +46819,7 @@ function SchemaRunner({ schema, serverUrl, mockData, pageName, onNavigate }) {
46604
46819
  if (!serverUrl && mockData) {
46605
46820
  for (const [entityType, records] of Object.entries(mockData)) {
46606
46821
  if (Array.isArray(records)) {
46607
- entityStore.advance(entityType, records);
46822
+ entityStore.setAll(entityType, records);
46608
46823
  }
46609
46824
  }
46610
46825
  }
@@ -46685,6 +46900,9 @@ function OrbPreview({
46685
46900
  );
46686
46901
  }
46687
46902
  OrbPreview.displayName = "OrbPreview";
46903
+
46904
+ // components/molecules/avl/OrbPreviewNode.tsx
46905
+ init_useEventBus();
46688
46906
  var ScreenSizeContext = React124.createContext("tablet");
46689
46907
  var PatternSelectionContext = React124.createContext({ selected: null, select: () => {
46690
46908
  } });
@@ -46712,12 +46930,12 @@ function eventHandleStyle(source) {
46712
46930
  };
46713
46931
  }
46714
46932
  function buildOrbitalSchema(fullSchema, orbitalName) {
46715
- const orbital = fullSchema.orbitals?.find((o) => o.name === orbitalName);
46933
+ const orbital = (fullSchema.orbitals ?? []).find((o) => o.name === orbitalName);
46716
46934
  if (!orbital) return fullSchema;
46717
46935
  return { ...fullSchema, name: `${fullSchema.name}__${orbitalName}`, orbitals: [orbital] };
46718
46936
  }
46719
46937
  function buildTransitionSchema(fullSchema, orbitalName, traitName, transitionEvent, fromState, toState) {
46720
- const orbital = fullSchema.orbitals?.find((o) => o.name === orbitalName);
46938
+ const orbital = (fullSchema.orbitals ?? []).find((o) => o.name === orbitalName);
46721
46939
  if (!orbital) return fullSchema;
46722
46940
  const clonedOrbital = JSON.parse(JSON.stringify(orbital));
46723
46941
  const traits2 = clonedOrbital.traits ?? [];
@@ -46750,7 +46968,9 @@ function buildTransitionSchema(fullSchema, orbitalName, traitName, transitionEve
46750
46968
  }
46751
46969
  const targetTrait = traits2.find((t) => {
46752
46970
  if (typeof t === "string") return t === traitName;
46753
- return t.name === traitName;
46971
+ if ("name" in t) return t.name === traitName;
46972
+ if ("ref" in t) return t.ref === traitName;
46973
+ return false;
46754
46974
  });
46755
46975
  if (targetTrait) {
46756
46976
  clonedOrbital.traits = [targetTrait];
@@ -46767,6 +46987,21 @@ var SELECTION_STYLES = `
46767
46987
  outline: 2px solid var(--color-primary);
46768
46988
  outline-offset: 1px;
46769
46989
  }
46990
+ .orb-preview-live.drag-active [data-accepts-children="true"] {
46991
+ outline: 2px dashed var(--color-primary);
46992
+ outline-offset: -2px;
46993
+ transition: outline-color 0.15s, background-color 0.15s;
46994
+ }
46995
+ .orb-preview-live.drag-active [data-accepts-children="true"].drag-hover {
46996
+ outline-color: var(--color-primary);
46997
+ background-color: color-mix(in srgb, var(--color-primary) 5%, transparent);
46998
+ }
46999
+ .orb-preview-live .drop-indicator {
47000
+ height: 2px;
47001
+ background: var(--color-primary);
47002
+ border-radius: 1px;
47003
+ pointer-events: none;
47004
+ }
46770
47005
  `;
46771
47006
  var OrbPreviewNodeInner = (props) => {
46772
47007
  const data = props.data;
@@ -46826,6 +47061,87 @@ var OrbPreviewNodeInner = (props) => {
46826
47061
  select(null);
46827
47062
  }
46828
47063
  }, [data, select]);
47064
+ const eventBus = useEventBus();
47065
+ const [dragActive, setDragActive] = React124.useState(false);
47066
+ React124.useEffect(() => {
47067
+ const unsub1 = eventBus.on("UI:DRAG_START", (e) => {
47068
+ const kind = e.payload?.kind;
47069
+ if (kind === "pattern") setDragActive(true);
47070
+ });
47071
+ const unsub2 = eventBus.on("UI:DRAG_END", () => setDragActive(false));
47072
+ return () => {
47073
+ unsub1();
47074
+ unsub2();
47075
+ };
47076
+ }, [eventBus]);
47077
+ const handlePreviewDrop = React124.useCallback((e) => {
47078
+ e.preventDefault();
47079
+ e.stopPropagation();
47080
+ setDragActive(false);
47081
+ contentRef.current?.querySelectorAll(".drag-hover, .drop-indicator").forEach((el2) => {
47082
+ el2.classList.remove("drag-hover");
47083
+ if (el2.classList.contains("drop-indicator")) el2.remove();
47084
+ });
47085
+ const raw = e.dataTransfer.getData(ALMADAR_DND_MIME);
47086
+ if (!raw) return;
47087
+ let payload;
47088
+ try {
47089
+ payload = JSON.parse(raw);
47090
+ } catch {
47091
+ return;
47092
+ }
47093
+ if (payload.kind !== "pattern") return;
47094
+ let el = e.target;
47095
+ while (el && el.dataset.acceptsChildren !== "true") {
47096
+ el = el.parentElement;
47097
+ if (!el || el === contentRef.current) break;
47098
+ }
47099
+ const containerPath = el?.dataset?.patternPath;
47100
+ if (!containerPath) {
47101
+ eventBus.emit("UI:PATTERN_INSERT", {
47102
+ parentPath: "root",
47103
+ patternType: payload.data.type,
47104
+ index: 0
47105
+ });
47106
+ return;
47107
+ }
47108
+ const pathChildren = el.querySelectorAll(":scope > [data-pattern-path]");
47109
+ let insertIndex = pathChildren.length;
47110
+ for (let i = 0; i < pathChildren.length; i++) {
47111
+ const rect = pathChildren[i].getBoundingClientRect();
47112
+ const style = el.firstElementChild ? getComputedStyle(el.firstElementChild) : null;
47113
+ const isVertical = style?.flexDirection !== "row";
47114
+ const mid = isVertical ? rect.top + rect.height / 2 : rect.left + rect.width / 2;
47115
+ const cursor = isVertical ? e.clientY : e.clientX;
47116
+ if (cursor < mid) {
47117
+ insertIndex = i;
47118
+ break;
47119
+ }
47120
+ }
47121
+ eventBus.emit("UI:PATTERN_INSERT", {
47122
+ parentPath: containerPath,
47123
+ patternType: payload.data.type,
47124
+ index: insertIndex
47125
+ });
47126
+ }, [eventBus]);
47127
+ const handlePreviewDragOver = React124.useCallback((e) => {
47128
+ if (!dragActive) return;
47129
+ e.preventDefault();
47130
+ e.stopPropagation();
47131
+ e.dataTransfer.dropEffect = "copy";
47132
+ let el = e.target;
47133
+ while (el && el.dataset.acceptsChildren !== "true") {
47134
+ el = el.parentElement;
47135
+ if (!el || el === contentRef.current) break;
47136
+ }
47137
+ contentRef.current?.querySelectorAll(".drag-hover").forEach((c) => c.classList.remove("drag-hover"));
47138
+ if (el?.dataset?.acceptsChildren === "true") {
47139
+ el.classList.add("drag-hover");
47140
+ }
47141
+ }, [dragActive]);
47142
+ const handlePreviewDragLeave = React124.useCallback((e) => {
47143
+ contentRef.current?.querySelectorAll(".drag-hover").forEach((c) => c.classList.remove("drag-hover"));
47144
+ }, []);
46829
47145
  return /* @__PURE__ */ jsxRuntime.jsxs(
46830
47146
  Box,
46831
47147
  {
@@ -46870,8 +47186,11 @@ var OrbPreviewNodeInner = (props) => {
46870
47186
  Box,
46871
47187
  {
46872
47188
  ref: contentRef,
46873
- className: "orb-preview-live nodrag",
47189
+ className: `orb-preview-live nodrag${dragActive ? " drag-active" : ""}`,
46874
47190
  onClick: handleContentClick,
47191
+ onDrop: handlePreviewDrop,
47192
+ onDragOver: handlePreviewDragOver,
47193
+ onDragLeave: handlePreviewDragLeave,
46875
47194
  children: orbitalSchema ? /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsxRuntime.jsx(
46876
47195
  OrbPreview,
46877
47196
  {
@@ -46990,7 +47309,9 @@ init_Avl3DExprTree();
46990
47309
  // components/organisms/avl/OrbInspector.tsx
46991
47310
  init_Box();
46992
47311
  init_Typography();
47312
+ init_Stack();
46993
47313
  init_types();
47314
+ init_useEventBus();
46994
47315
  function formatExpression(expr) {
46995
47316
  if (!expr) return "";
46996
47317
  if (typeof expr === "string") return expr;
@@ -47025,7 +47346,7 @@ var FIELD_TYPE_MAP = {
47025
47346
  array: "array"
47026
47347
  };
47027
47348
  function findEntity(schema, orbitalName) {
47028
- const orbital = schema.orbitals?.find((o) => o.name === orbitalName);
47349
+ const orbital = (schema.orbitals ?? []).find((o) => o.name === orbitalName);
47029
47350
  if (!orbital || typeof orbital.entity === "string") return null;
47030
47351
  const e = orbital.entity;
47031
47352
  const fields = (e.fields ?? []).map((f3) => ({
@@ -47036,7 +47357,7 @@ function findEntity(schema, orbitalName) {
47036
47357
  return { name: e.name ?? orbitalName, persistence: e.persistence ?? "runtime", fields };
47037
47358
  }
47038
47359
  function findTransition(schema, orbitalName, traitName, event) {
47039
- const orbital = schema.orbitals?.find((o) => o.name === orbitalName);
47360
+ const orbital = (schema.orbitals ?? []).find((o) => o.name === orbitalName);
47040
47361
  if (!orbital) return null;
47041
47362
  const traits2 = orbital.traits ?? [];
47042
47363
  const trait = traits2.find((t) => typeof t !== "string" && t.name === traitName);
@@ -47046,16 +47367,39 @@ function findTransition(schema, orbitalName, traitName, event) {
47046
47367
  return sm.transitions?.find((t) => t.event === event) ?? null;
47047
47368
  }
47048
47369
  function findTraits(schema, orbitalName) {
47049
- const orbital = schema.orbitals?.find((o) => o.name === orbitalName);
47370
+ const orbital = (schema.orbitals ?? []).find((o) => o.name === orbitalName);
47050
47371
  if (!orbital) return [];
47051
47372
  return (orbital.traits ?? []).filter((t) => typeof t !== "string").map((t) => ({
47052
47373
  name: t.name,
47053
47374
  stateCount: t.stateMachine?.states?.length ?? 0
47054
47375
  }));
47055
47376
  }
47377
+ function findPatternInTree(root, path) {
47378
+ if (!path || path === "root") return root;
47379
+ const parts = path.split(".");
47380
+ let current = root;
47381
+ for (const part of parts) {
47382
+ if (current === null || current === void 0 || typeof current !== "object") return null;
47383
+ const record = current;
47384
+ if (part === "children" && Array.isArray(record.children)) {
47385
+ current = record.children;
47386
+ } else if (Array.isArray(current)) {
47387
+ const idx = parseInt(part, 10);
47388
+ if (isNaN(idx) || idx < 0 || idx >= current.length) return null;
47389
+ current = current[idx];
47390
+ } else {
47391
+ current = record[part];
47392
+ }
47393
+ }
47394
+ return typeof current === "object" && current !== null ? current : null;
47395
+ }
47396
+ var FIELD_TYPE_OPTIONS = core.FieldTypeSchema.options.map((v) => ({ value: v, label: v }));
47397
+ var EFFECT_TYPE_OPTIONS = Object.keys(exports.EFFECT_TYPE_TO_CATEGORY).map((v) => ({ value: v, label: v }));
47056
47398
  function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose }) {
47057
47399
  const { selected: selectedPattern } = React124.useContext(PatternSelectionContext);
47058
47400
  const [activeTab, setActiveTab] = React124.useState("inspector");
47401
+ const eventBus = useEventBus();
47402
+ const { t } = useTranslate();
47059
47403
  const orbitalName = node.orbitalName ?? "";
47060
47404
  const traitName = node.traitName ?? "";
47061
47405
  const transitionEvent = node.transitionEvent ?? "";
@@ -47075,25 +47419,56 @@ function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose
47075
47419
  return findTransition(schema, orbitalName, traitName, transitionEvent);
47076
47420
  }, [schema, orbitalName, traitName, transitionEvent]);
47077
47421
  const traits2 = React124.useMemo(() => findTraits(schema, orbitalName), [schema, orbitalName]);
47422
+ const patternConfig = React124.useMemo(() => {
47423
+ if (!selectedPattern || !transition) return null;
47424
+ const patternId = selectedPattern.patternId ?? "root";
47425
+ for (const eff of transition.effects ?? []) {
47426
+ if (Array.isArray(eff) && eff[0] === "render-ui" && eff[2]) {
47427
+ const found = findPatternInTree(eff[2], patternId);
47428
+ if (found) return found;
47429
+ }
47430
+ }
47431
+ return null;
47432
+ }, [selectedPattern, transition]);
47078
47433
  const orbCode = React124.useMemo(() => {
47079
- const orbital = schema.orbitals?.find((o) => o.name === orbitalName);
47434
+ const orbital = (schema.orbitals ?? []).find((o) => o.name === orbitalName);
47080
47435
  if (!orbital) return "{}";
47081
47436
  if (isExpanded && traitName) {
47082
- const traits3 = orbital.traits ?? [];
47083
- const trait = traits3.find((t) => typeof t !== "string" && t.name === traitName);
47437
+ const traitList = orbital.traits ?? [];
47438
+ const trait = traitList.find((tr) => typeof tr !== "string" && tr.name === traitName);
47084
47439
  if (trait && typeof trait !== "string" && trait.stateMachine) {
47085
47440
  if (transitionEvent) {
47086
- const t = trait.stateMachine.transitions?.find((tx) => tx.event === transitionEvent);
47087
- if (t) return JSON.stringify(t, null, 2);
47441
+ const tx = trait.stateMachine.transitions?.find((txn) => txn.event === transitionEvent);
47442
+ if (tx) return JSON.stringify(tx, null, 2);
47088
47443
  }
47089
47444
  return JSON.stringify({ name: trait.name, stateMachine: trait.stateMachine }, null, 2);
47090
47445
  }
47091
47446
  }
47092
47447
  return JSON.stringify(orbital, null, 2);
47093
47448
  }, [schema, orbitalName, traitName, transitionEvent, isExpanded]);
47094
- const handlePropChange = React124.useCallback((prop, value) => {
47095
- if (!editable || !onSchemaChange) return;
47096
- }, [editable, onSchemaChange]);
47449
+ const handlePropChange = React124.useCallback((propName, value) => {
47450
+ if (!editable) return;
47451
+ eventBus.emit("UI:PROP_CHANGE", { propName, value });
47452
+ }, [editable, eventBus]);
47453
+ const handleAddField = React124.useCallback(() => {
47454
+ eventBus.emit("UI:ADD_FIELD", {});
47455
+ }, [eventBus]);
47456
+ const handleUpdateField = React124.useCallback((fieldName, updates) => {
47457
+ eventBus.emit("UI:UPDATE_FIELD", { fieldName, updates });
47458
+ }, [eventBus]);
47459
+ const handleRemoveField = React124.useCallback((fieldName) => {
47460
+ eventBus.emit("UI:REMOVE_FIELD", { fieldName });
47461
+ }, [eventBus]);
47462
+ const handleGuardChange = React124.useCallback((guardExpr) => {
47463
+ if (!editable) return;
47464
+ eventBus.emit("UI:GUARD_CHANGE", { guard: guardExpr || null });
47465
+ }, [editable, eventBus]);
47466
+ const handleAddEffect = React124.useCallback((effectType) => {
47467
+ eventBus.emit("UI:ADD_EFFECT", { effectType });
47468
+ }, [eventBus]);
47469
+ const handleRemoveEffect = React124.useCallback((effectIndex) => {
47470
+ eventBus.emit("UI:REMOVE_EFFECT", { effectIndex });
47471
+ }, [eventBus]);
47097
47472
  const headerTitle = selectedPattern ? selectedPattern.patternType : isExpanded ? transitionEvent || "Transition" : orbitalName;
47098
47473
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col bg-card border-l border-border h-full", style: { width: 340 }, children: [
47099
47474
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "shrink-0 border-b border-border", children: [
@@ -47151,48 +47526,98 @@ function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose
47151
47526
  /* ── Inspector Tab ── */
47152
47527
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
47153
47528
  selectedPattern && patternDef?.propsSchema && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
47154
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: "Props" }),
47155
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1.5", children: Object.entries(patternDef.propsSchema).slice(0, 8).map(([propName, propSchema]) => {
47529
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: t("Props") }),
47530
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1.5", children: Object.entries(patternDef.propsSchema).slice(0, 12).map(([propName, propSchema]) => {
47156
47531
  const ps = propSchema;
47532
+ const currentValue = patternConfig ? patternConfig[propName] : void 0;
47533
+ const displayValue = currentValue !== void 0 ? typeof currentValue === "object" ? JSON.stringify(currentValue) : String(currentValue) : "";
47157
47534
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
47158
47535
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[11px] w-20 shrink-0 font-mono", children: propName }),
47159
47536
  editable ? /* @__PURE__ */ jsxRuntime.jsx(
47160
47537
  Input,
47161
47538
  {
47539
+ defaultValue: displayValue,
47162
47540
  placeholder: ps.types?.join(" | ") ?? "string",
47163
47541
  className: "flex-1 text-[11px] h-6",
47164
- onChange: (e) => handlePropChange(propName, e.target.value)
47542
+ onBlur: (e) => handlePropChange(propName, e.target.value)
47165
47543
  }
47166
47544
  ) : /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "text-[11px] text-muted-foreground", children: [
47167
- ps.types?.join(" | ") ?? "string",
47545
+ displayValue || (ps.types?.join(" | ") ?? "string"),
47168
47546
  ps.required ? " *" : ""
47169
47547
  ] })
47170
47548
  ] }, propName);
47171
47549
  }) })
47172
47550
  ] }),
47173
47551
  (selectedPattern && isEntityPattern || !selectedPattern && !isExpanded) && entity && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
47174
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: "Entity" }),
47552
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: t("Entity") }),
47175
47553
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2 mb-2", children: [
47176
47554
  /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 14, height: 14, children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 7, cy: 7, r: 5, fill: "var(--color-primary)" }) }),
47177
47555
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "font-semibold text-[12px]", children: entity.name }),
47178
47556
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px]", children: entity.persistence })
47179
47557
  ] }),
47180
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1", children: entity.fields.map((f3) => /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
47558
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1", children: entity.fields.map((f3) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
47181
47559
  /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 12, height: 12, children: /* @__PURE__ */ jsxRuntime.jsx(AvlFieldType, { x: 6, y: 6, kind: FIELD_TYPE_MAP[f3.type] ?? "string", size: 4 }) }),
47182
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-[11px] font-mono flex-1", children: f3.name }),
47183
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px]", children: f3.type }),
47184
- f3.required && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-primary text-[9px]", children: "req" })
47185
- ] }, f3.name)) })
47560
+ editable ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
47561
+ /* @__PURE__ */ jsxRuntime.jsx(
47562
+ Input,
47563
+ {
47564
+ defaultValue: f3.name,
47565
+ className: "flex-1 text-[11px] font-mono h-6",
47566
+ onBlur: (e) => {
47567
+ if (e.target.value !== f3.name) {
47568
+ handleUpdateField(f3.name, { name: e.target.value });
47569
+ }
47570
+ }
47571
+ }
47572
+ ),
47573
+ /* @__PURE__ */ jsxRuntime.jsx(
47574
+ Select,
47575
+ {
47576
+ value: f3.type,
47577
+ options: FIELD_TYPE_OPTIONS,
47578
+ onChange: (e) => handleUpdateField(f3.name, { type: e.target.value }),
47579
+ className: "w-20 text-[10px] h-6"
47580
+ }
47581
+ ),
47582
+ /* @__PURE__ */ jsxRuntime.jsx(
47583
+ Button,
47584
+ {
47585
+ variant: "ghost",
47586
+ size: "sm",
47587
+ onClick: () => handleRemoveField(f3.name),
47588
+ className: "shrink-0 p-0.5 h-6 w-6",
47589
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "x", size: "xs" })
47590
+ }
47591
+ )
47592
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
47593
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-[11px] font-mono flex-1", children: f3.name }),
47594
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px]", children: f3.type }),
47595
+ f3.required && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-primary text-[9px]", children: t("req") })
47596
+ ] })
47597
+ ] }, f3.name)) }),
47598
+ editable && /* @__PURE__ */ jsxRuntime.jsxs(
47599
+ Button,
47600
+ {
47601
+ variant: "ghost",
47602
+ size: "sm",
47603
+ onClick: handleAddField,
47604
+ className: "mt-2 text-[11px] w-full",
47605
+ children: [
47606
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", size: "xs", className: "mr-1" }),
47607
+ t("Add Field")
47608
+ ]
47609
+ }
47610
+ )
47186
47611
  ] }),
47187
47612
  !selectedPattern && !isExpanded && traits2.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
47188
47613
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: "Traits" }),
47189
- /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1", children: traits2.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
47190
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-[11px] font-semibold", children: t.name }),
47614
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1", children: traits2.map((t2) => /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
47615
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-[11px] font-semibold", children: t2.name }),
47191
47616
  /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "text-muted-foreground text-[10px]", children: [
47192
- t.stateCount,
47617
+ t2.stateCount,
47193
47618
  " states"
47194
47619
  ] })
47195
- ] }, t.name)) })
47620
+ ] }, t2.name)) })
47196
47621
  ] }),
47197
47622
  isExpanded && fromState && toState && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
47198
47623
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: "Transition" }),
@@ -47211,19 +47636,22 @@ function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose
47211
47636
  /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 16, height: 16, children: /* @__PURE__ */ jsxRuntime.jsx(AvlEvent, { x: 8, y: 8, size: 12 }) }),
47212
47637
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "font-semibold text-[12px]", children: transitionEvent })
47213
47638
  ] }) }),
47214
- (transition?.guard ?? guard) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-2 border-b border-border/40", children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
47639
+ (transition?.guard ?? guard ?? editable) && isExpanded && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-2 border-b border-border/40", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
47215
47640
  /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 16, height: 16, children: /* @__PURE__ */ jsxRuntime.jsx(AvlGuard, { x: 8, y: 8, size: 12 }) }),
47216
47641
  editable ? /* @__PURE__ */ jsxRuntime.jsx(
47217
47642
  Input,
47218
47643
  {
47219
47644
  defaultValue: formatExpression(transition?.guard ?? guard),
47220
- className: "flex-1 text-[11px] font-mono h-6"
47645
+ placeholder: t("Guard expression"),
47646
+ className: "flex-1 text-[11px] font-mono h-6",
47647
+ onBlur: (e) => handleGuardChange(e.target.value)
47221
47648
  }
47222
47649
  ) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "font-mono text-[11px] text-muted-foreground", children: formatExpression(transition?.guard ?? guard) })
47223
47650
  ] }) }),
47224
- effectTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
47651
+ (effectTypes.length > 0 || editable) && isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3 border-b border-border/40", children: [
47225
47652
  /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: [
47226
- "Effects (",
47653
+ t("Effects"),
47654
+ " (",
47227
47655
  effectTypes.length,
47228
47656
  ")"
47229
47657
  ] }),
@@ -47231,15 +47659,26 @@ function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose
47231
47659
  const isKnown = KNOWN_EFFECTS.has(type);
47232
47660
  const category = exports.EFFECT_TYPE_TO_CATEGORY[type];
47233
47661
  const catColor = category ? exports.EFFECT_CATEGORY_COLORS[category] : void 0;
47234
- return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
47662
+ return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
47235
47663
  /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "text-muted-foreground text-[11px] w-4 text-right shrink-0", children: [
47236
47664
  i + 1,
47237
47665
  "."
47238
47666
  ] }),
47239
47667
  isKnown && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 16, height: 16, children: /* @__PURE__ */ jsxRuntime.jsx(AvlEffect, { x: 8, y: 8, effectType: type, size: 6, showBackground: true }) }),
47240
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-[11px]", style: { color: catColor?.color }, children: effectSummary(type) })
47668
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-[11px] flex-1", style: { color: catColor?.color }, children: effectSummary(type) }),
47669
+ editable && /* @__PURE__ */ jsxRuntime.jsx(
47670
+ Button,
47671
+ {
47672
+ variant: "ghost",
47673
+ size: "sm",
47674
+ onClick: () => handleRemoveEffect(i),
47675
+ className: "shrink-0 p-0.5 h-6 w-6",
47676
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "x", size: "xs" })
47677
+ }
47678
+ )
47241
47679
  ] }, i);
47242
- }) })
47680
+ }) }),
47681
+ editable && /* @__PURE__ */ jsxRuntime.jsx(AddEffectButton, { onAdd: handleAddEffect })
47243
47682
  ] }),
47244
47683
  patterns$1.length > 0 && !selectedPattern && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "px-4 py-3", children: [
47245
47684
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: "render-ui" }),
@@ -47255,6 +47694,40 @@ function OrbInspector({ node, schema, editable = false, onSchemaChange, onClose
47255
47694
  ) })
47256
47695
  ] });
47257
47696
  }
47697
+ function AddEffectButton({ onAdd }) {
47698
+ const [open, setOpen] = React124.useState(false);
47699
+ const { t } = useTranslate();
47700
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative mt-2", children: [
47701
+ /* @__PURE__ */ jsxRuntime.jsxs(
47702
+ Button,
47703
+ {
47704
+ variant: "ghost",
47705
+ size: "sm",
47706
+ onClick: () => setOpen((prev) => !prev),
47707
+ className: "text-[11px] w-full",
47708
+ children: [
47709
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", size: "xs", className: "mr-1" }),
47710
+ t("Add Effect")
47711
+ ]
47712
+ }
47713
+ ),
47714
+ open && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute z-20 top-full left-0 right-0 mt-1 bg-card border border-border rounded-md shadow-lg overflow-hidden", children: EFFECT_TYPE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
47715
+ Box,
47716
+ {
47717
+ className: "px-3 py-1.5 text-[11px] cursor-pointer hover:bg-muted/50 flex items-center gap-2",
47718
+ onClick: () => {
47719
+ onAdd(opt.value);
47720
+ setOpen(false);
47721
+ },
47722
+ children: [
47723
+ KNOWN_EFFECTS.has(opt.value) && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 14, height: 14, children: /* @__PURE__ */ jsxRuntime.jsx(AvlEffect, { x: 7, y: 7, effectType: opt.value, size: 5, showBackground: true }) }),
47724
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-[11px]", children: opt.label })
47725
+ ]
47726
+ },
47727
+ opt.value
47728
+ )) })
47729
+ ] });
47730
+ }
47258
47731
  function OrbPatternTree({ config, depth }) {
47259
47732
  if (!config || typeof config !== "object") return null;
47260
47733
  const { type, children, ...props } = config;
@@ -47303,7 +47776,9 @@ function FlowCanvasInner({
47303
47776
  onLevelChange,
47304
47777
  initialOrbital,
47305
47778
  editable,
47306
- onSchemaChange
47779
+ onSchemaChange,
47780
+ onPatternDelete,
47781
+ onEventWire
47307
47782
  }) {
47308
47783
  const parsedSchema = React124.useMemo(() => {
47309
47784
  if (typeof schemaProp === "string") return JSON.parse(schemaProp);
@@ -47382,8 +47857,15 @@ function FlowCanvasInner({
47382
47857
  setExpandedOrbital(void 0);
47383
47858
  onLevelChange?.("overview");
47384
47859
  }
47860
+ } else if (e.key === "Delete" || e.key === "Backspace") {
47861
+ const target = e.target;
47862
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) return;
47863
+ if (selectedPattern && selectedPattern.nodeData) {
47864
+ onPatternDelete?.({ patternId: selectedPattern.patternId ?? "", nodeData: selectedPattern.nodeData });
47865
+ setSelectedPattern(null);
47866
+ }
47385
47867
  }
47386
- }, [level, onLevelChange, selectedNode]);
47868
+ }, [level, onLevelChange, selectedNode, selectedPattern, onPatternDelete]);
47387
47869
  React124.useEffect(() => {
47388
47870
  document.addEventListener("keydown", handleKeyDown);
47389
47871
  return () => document.removeEventListener("keydown", handleKeyDown);
@@ -47398,6 +47880,22 @@ function FlowCanvasInner({
47398
47880
  onLevelChange?.("overview");
47399
47881
  }
47400
47882
  }, [level, onLevelChange, selectedNode]);
47883
+ const handleConnect = React124.useCallback((connection) => {
47884
+ if (!connection.sourceHandle?.startsWith("event-") || !onEventWire) return;
47885
+ const eventName = connection.sourceHandle.replace("event-", "");
47886
+ const sourceNode = nodes.find((n) => n.id === connection.source);
47887
+ const targetNode = nodes.find((n) => n.id === connection.target);
47888
+ if (!sourceNode || !targetNode) return;
47889
+ const srcData = sourceNode.data;
47890
+ const tgtData = targetNode.data;
47891
+ onEventWire({
47892
+ eventName,
47893
+ sourceOrbital: srcData.orbitalName ?? "",
47894
+ targetOrbital: tgtData.orbitalName ?? "",
47895
+ sourceTraitName: srcData.traitName,
47896
+ targetTraitName: tgtData.traitName
47897
+ });
47898
+ }, [nodes, onEventWire]);
47401
47899
  const screenSizeKeys = ["mobile", "tablet", "desktop"];
47402
47900
  return /* @__PURE__ */ jsxRuntime.jsx(ScreenSizeContext.Provider, { value: screenSize, children: /* @__PURE__ */ jsxRuntime.jsx(PatternSelectionContext.Provider, { value: patternSelectionValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
47403
47901
  Box,
@@ -47418,6 +47916,7 @@ function FlowCanvasInner({
47418
47916
  onEdgesChange,
47419
47917
  onNodeDoubleClick: handleNodeDoubleClick,
47420
47918
  onNodeClick: handleNodeClick,
47919
+ onConnect: handleConnect,
47421
47920
  minZoom: 0.1,
47422
47921
  maxZoom: 2,
47423
47922
  fitView: true,