@almadar/ui 5.122.13 → 5.123.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.
@@ -61,6 +61,7 @@ var langPowershell = require('react-syntax-highlighter/dist/esm/languages/prism/
61
61
  var langMakefile = require('react-syntax-highlighter/dist/esm/languages/prism/makefile.js');
62
62
  var langNginx = require('react-syntax-highlighter/dist/esm/languages/prism/nginx.js');
63
63
  var langIni = require('react-syntax-highlighter/dist/esm/languages/prism/ini.js');
64
+ var langClike = require('react-syntax-highlighter/dist/esm/languages/prism/clike.js');
64
65
  var ReactMarkdown = require('react-markdown');
65
66
  var remarkGfm = require('remark-gfm');
66
67
  var remarkMath = require('remark-math');
@@ -145,6 +146,7 @@ var langPowershell__default = /*#__PURE__*/_interopDefault(langPowershell);
145
146
  var langMakefile__default = /*#__PURE__*/_interopDefault(langMakefile);
146
147
  var langNginx__default = /*#__PURE__*/_interopDefault(langNginx);
147
148
  var langIni__default = /*#__PURE__*/_interopDefault(langIni);
149
+ var langClike__default = /*#__PURE__*/_interopDefault(langClike);
148
150
  var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
149
151
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
150
152
  var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
@@ -3223,6 +3225,11 @@ var init_Typography = __esm({
3223
3225
  inherit: "text-inherit"
3224
3226
  };
3225
3227
  weightStyles = {
3228
+ // Neutral: an atom default of "none" must not override the variant's baked
3229
+ // weight (C-PATTERN-ENUM-BLOCKS-NEUTRAL-OVERRIDE — `variant={h2}` rendered
3230
+ // tiny because the ui-typography atom's `weight: light`/`size: xs` defaults
3231
+ // clobbered every variant).
3232
+ none: "",
3226
3233
  light: "font-light",
3227
3234
  normal: "font-normal",
3228
3235
  medium: "font-medium",
@@ -3248,6 +3255,7 @@ var init_Typography = __esm({
3248
3255
  label: "span"
3249
3256
  };
3250
3257
  typographySizeStyles = {
3258
+ none: "",
3251
3259
  xs: "text-xs",
3252
3260
  sm: "text-sm",
3253
3261
  md: "text-base",
@@ -5109,6 +5117,7 @@ var init_Button = __esm({
5109
5117
  "button",
5110
5118
  {
5111
5119
  ref,
5120
+ type: "button",
5112
5121
  disabled: disabled || isLoading,
5113
5122
  className: cn(
5114
5123
  "relative inline-flex items-center justify-center gap-2",
@@ -16745,7 +16754,7 @@ async function loadPrismLanguage(lang) {
16745
16754
  if (isLanguageRegistered(lang)) return;
16746
16755
  try {
16747
16756
  const grammar = codeLanguageLoader ? await codeLanguageLoader(lang) : null;
16748
- if (grammar) SyntaxHighlighter__default.default.registerLanguage(lang, grammar);
16757
+ SyntaxHighlighter__default.default.registerLanguage(lang, grammar ?? langClike__default.default);
16749
16758
  dynamicallyLoaded.add(lang);
16750
16759
  } catch {
16751
16760
  dynamicallyLoaded.add(lang);
@@ -16914,6 +16923,7 @@ var init_CodeBlock = __esm({
16914
16923
  SyntaxHighlighter__default.default.registerLanguage("make", langMakefile__default.default);
16915
16924
  SyntaxHighlighter__default.default.registerLanguage("nginx", langNginx__default.default);
16916
16925
  SyntaxHighlighter__default.default.registerLanguage("ini", langIni__default.default);
16926
+ SyntaxHighlighter__default.default.registerLanguage("clike", langClike__default.default);
16917
16927
  SyntaxHighlighter__default.default.registerLanguage("orb", syntax.orbLanguage);
16918
16928
  SyntaxHighlighter__default.default.registerLanguage("lolo", syntax.loloLanguage);
16919
16929
  dynamicallyLoaded = /* @__PURE__ */ new Set();
@@ -17463,7 +17473,7 @@ var init_CodeBlock = __esm({
17463
17473
  ] }) });
17464
17474
  }
17465
17475
  const hasHeader = showLanguageBadge || effectiveCopy;
17466
- return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: `relative group ${className || ""}`, style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
17476
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: `relative group not-prose ${className || ""}`, style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
17467
17477
  hasHeader && /* @__PURE__ */ jsxRuntime.jsxs(
17468
17478
  HStack,
17469
17479
  {
@@ -25406,6 +25416,13 @@ function DataGrid({
25406
25416
  row: itemData
25407
25417
  };
25408
25418
  eventBus.emit(`UI:${action.event}`, payload);
25419
+ if (action.navigatesTo) {
25420
+ const url = action.navigatesTo.replace(
25421
+ /\{\{row\.(\w+(?:\.\w+)*)\}\}/g,
25422
+ (_, field) => String(itemData[field] ?? "")
25423
+ );
25424
+ eventBus.emit("UI:NAVIGATE", { url });
25425
+ }
25409
25426
  };
25410
25427
  const hasRenderProp = typeof children === "function";
25411
25428
  React91.useEffect(() => {
@@ -25473,13 +25490,49 @@ function DataGrid({
25473
25490
  const wrapDnd = (node) => dnd.isZone ? /* @__PURE__ */ jsxRuntime.jsx(dnd.SortableItem, { id: dndId, children: node }, dndId) : node;
25474
25491
  if (hasRenderProp) {
25475
25492
  return wrapDnd(
25476
- /* @__PURE__ */ jsxRuntime.jsx(
25493
+ /* @__PURE__ */ jsxRuntime.jsxs(
25477
25494
  Box,
25478
25495
  {
25479
25496
  "data-entity-row": true,
25480
25497
  "data-entity-id": id,
25481
25498
  className: cn(isSelected && "ring-2 ring-primary rounded-lg"),
25482
- children: children(itemData, index)
25499
+ children: [
25500
+ children(itemData, index),
25501
+ actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-3 border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-end", children: [
25502
+ (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
25503
+ Button,
25504
+ {
25505
+ variant: action.variant === "primary" ? "primary" : "ghost",
25506
+ size: "sm",
25507
+ onClick: handleActionClick(action, itemData),
25508
+ "data-testid": `action-${action.event}`,
25509
+ "data-row-id": String(itemData.id),
25510
+ className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
25511
+ children: [
25512
+ action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
25513
+ action.label
25514
+ ]
25515
+ },
25516
+ idx
25517
+ )),
25518
+ maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
25519
+ Menu,
25520
+ {
25521
+ position: "bottom-end",
25522
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
25523
+ items: actionDefs.slice(maxInlineActions).map((action) => ({
25524
+ label: action.label,
25525
+ icon: action.icon,
25526
+ event: action.event,
25527
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
25528
+ id: itemData.id,
25529
+ row: itemData
25530
+ })
25531
+ }))
25532
+ }
25533
+ )
25534
+ ] }) })
25535
+ ]
25483
25536
  },
25484
25537
  id
25485
25538
  )
@@ -26503,7 +26556,9 @@ var init_FilterGroup = __esm({
26503
26556
  showIcon = true,
26504
26557
  query,
26505
26558
  isLoading,
26506
- look = "toolbar"
26559
+ look = "toolbar",
26560
+ event,
26561
+ clearEvent
26507
26562
  }) => {
26508
26563
  const { t } = hooks.useTranslate();
26509
26564
  const eventBus = useEventBus();
@@ -26540,14 +26595,18 @@ var init_FilterGroup = __esm({
26540
26595
  queryState.setFilter(field, value === "all" ? null : value);
26541
26596
  }
26542
26597
  onFilterChange?.(field, value === "all" ? null : value);
26543
- eventBus.emit("UI:FILTER", {
26598
+ const payload = {
26544
26599
  entity,
26545
26600
  field,
26546
26601
  value: value === "all" || value === null ? "" : value,
26547
26602
  query
26548
- });
26603
+ };
26604
+ if (event && event !== "FILTER") {
26605
+ eventBus.emit(`UI:${event}`, payload);
26606
+ }
26607
+ eventBus.emit("UI:FILTER", payload);
26549
26608
  },
26550
- [onFilterChange, queryState, eventBus, entity, query]
26609
+ [onFilterChange, queryState, eventBus, entity, query, event]
26551
26610
  );
26552
26611
  const handleClearAll = React91.useCallback(() => {
26553
26612
  setSelectedValues({});
@@ -26555,8 +26614,11 @@ var init_FilterGroup = __esm({
26555
26614
  queryState.clearFilters();
26556
26615
  }
26557
26616
  onClearAll?.();
26617
+ if (clearEvent && clearEvent !== "CLEAR_FILTERS") {
26618
+ eventBus.emit(`UI:${clearEvent}`, { entity, query });
26619
+ }
26558
26620
  eventBus.emit("UI:CLEAR_FILTERS", { entity, query });
26559
- }, [onClearAll, queryState, eventBus, entity, query]);
26621
+ }, [onClearAll, queryState, eventBus, entity, query, clearEvent]);
26560
26622
  const activeFilterCount = Object.keys(selectedValues).length;
26561
26623
  if (variant === "pills") {
26562
26624
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -27684,7 +27746,7 @@ var init_SearchInput = __esm({
27684
27746
  queryState.setSearch(newValue);
27685
27747
  }
27686
27748
  onSearch?.(newValue);
27687
- if (event) {
27749
+ if (event && event !== "SEARCH") {
27688
27750
  eventBus.emit(`UI:${event}`, { searchTerm: newValue, entity });
27689
27751
  }
27690
27752
  if (event || entity || query) {
@@ -50203,6 +50265,14 @@ function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
50203
50265
  return writes;
50204
50266
  };
50205
50267
  }
50268
+ function containsConfigForward(value) {
50269
+ if (typeof value === "string") return value.startsWith("@config.");
50270
+ if (Array.isArray(value)) return value.some(containsConfigForward);
50271
+ if (value !== null && typeof value === "object") {
50272
+ return Object.values(value).some(containsConfigForward);
50273
+ }
50274
+ return false;
50275
+ }
50206
50276
  function getBindingConfig(binding) {
50207
50277
  const raw = binding.config;
50208
50278
  const normalized = runtime.normalizeCallSiteConfigToValues(raw);
@@ -50555,7 +50625,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50555
50625
  const sharedCallSite = sharedCallSiteRaw ? runtime.resolveCallSitePayloadCaptures(
50556
50626
  Object.fromEntries(
50557
50627
  Object.entries(sharedCallSiteRaw).filter(
50558
- ([, v]) => !(typeof v === "string" && v.startsWith("@config."))
50628
+ ([, v]) => !containsConfigForward(v)
50559
50629
  )
50560
50630
  ),
50561
50631
  payload || {}
@@ -50620,7 +50690,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50620
50690
  const callSiteOverrides = callSiteConfig ? runtime.resolveCallSitePayloadCaptures(
50621
50691
  Object.fromEntries(
50622
50692
  Object.entries(callSiteConfig).filter(
50623
- ([, v]) => !(typeof v === "string" && v.startsWith("@config."))
50693
+ ([, v]) => !containsConfigForward(v)
50624
50694
  )
50625
50695
  ),
50626
50696
  payload || {}
@@ -50862,7 +50932,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50862
50932
  }
50863
50933
  return () => scheduler.stopAll();
50864
50934
  }, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
50865
- const processEventQueued = React91.useCallback(async (eventKey, payload) => {
50935
+ const processEventQueued = React91.useCallback(async (eventKey, payload, targetTrait) => {
50866
50936
  const normalizedEvent = normalizeEventKey(eventKey);
50867
50937
  const bindings = traitBindingsRef.current;
50868
50938
  const currentManager = managerRef.current;
@@ -50891,7 +50961,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50891
50961
  normalizedEvent,
50892
50962
  payload,
50893
50963
  void 0,
50894
- entityByTrait
50964
+ entityByTrait,
50965
+ void 0,
50966
+ targetTrait
50895
50967
  );
50896
50968
  crossTraitLog.debug("processEvent:results", {
50897
50969
  event: normalizedEvent,
@@ -50984,8 +51056,11 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50984
51056
  const effectTraces = result.effects.map(
50985
51057
  (e) => {
50986
51058
  if (Array.isArray(e)) {
51059
+ const head = String(e[0] ?? "unknown");
51060
+ const entityName = head === "fetch" && typeof e[1] === "string" ? e[1] : head === "persist" && typeof e[2] === "string" ? e[2] : void 0;
50987
51061
  return {
50988
- type: String(e[0] ?? "unknown"),
51062
+ type: head,
51063
+ ...entityName !== void 0 ? { entityName } : {},
50989
51064
  args: e.slice(1),
50990
51065
  status: "executed"
50991
51066
  };
@@ -51038,7 +51113,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
51038
51113
  const orbital = orbitalsByTrait?.[traitName];
51039
51114
  if (orbital) dispatchedOrbitals.add(orbital);
51040
51115
  }
51041
- await onEventProcessed(normalizedEvent, payload, dispatchedOrbitals);
51116
+ const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
51117
+ await onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals);
51042
51118
  }
51043
51119
  }, [entities, eventBus, sharedEntityStore]);
51044
51120
  const drainEventQueue = React91.useCallback(async () => {
@@ -51047,14 +51123,14 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
51047
51123
  try {
51048
51124
  while (eventQueueRef.current.length > 0) {
51049
51125
  const entry = eventQueueRef.current.shift();
51050
- await processEventQueued(entry.eventKey, entry.payload);
51126
+ await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait);
51051
51127
  }
51052
51128
  } finally {
51053
51129
  processingRef.current = false;
51054
51130
  }
51055
51131
  }, [processEventQueued]);
51056
- const enqueueAndDrain = React91.useCallback((eventKey, payload) => {
51057
- eventQueueRef.current.push({ eventKey, payload });
51132
+ const enqueueAndDrain = React91.useCallback((eventKey, payload, targetTrait) => {
51133
+ eventQueueRef.current.push({ eventKey, payload, targetTrait });
51058
51134
  void drainEventQueue();
51059
51135
  }, [drainEventQueue]);
51060
51136
  React91.useCallback((eventKey, payload) => {
@@ -51151,7 +51227,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
51151
51227
  crossTraitLog.debug("listen:subscribed", { busKey, targetTrait: binding.trait.name, sourceOrbital, sourceTrait, listenEvent: listen.event, triggers: listen.triggers });
51152
51228
  const unsub = eventBus.on(busKey, (event) => {
51153
51229
  crossTraitLog.debug("listen:fired", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
51154
- enqueueAndDrain(listen.triggers, event.payload);
51230
+ enqueueAndDrain(listen.triggers, event.payload, binding.trait.name);
51155
51231
  });
51156
51232
  unsubscribes.push(() => {
51157
51233
  crossTraitLog.debug("listen:unsubscribe", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
@@ -51618,6 +51694,15 @@ function OrbPreview({
51618
51694
  }
51619
51695
  }
51620
51696
  }, [pages]);
51697
+ React91.useEffect(() => {
51698
+ const unsubscribe = eventBus.on("UI:NAVIGATE", (event) => {
51699
+ const url = event.payload?.url;
51700
+ if (typeof url === "string" && url.length > 0) {
51701
+ handleNavigate(url);
51702
+ }
51703
+ });
51704
+ return unsubscribe;
51705
+ }, [eventBus, handleNavigate]);
51621
51706
  if (!parseResult.ok) {
51622
51707
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, style: { height }, children: /* @__PURE__ */ jsxRuntime.jsxs(Typography, { as: "pre", color: "error", variant: "small", className: "font-mono whitespace-pre-wrap break-all m-0 p-4", children: [
51623
51708
  "Parse error: ",
package/dist/avl/index.js CHANGED
@@ -61,6 +61,7 @@ import langPowershell from 'react-syntax-highlighter/dist/esm/languages/prism/po
61
61
  import langMakefile from 'react-syntax-highlighter/dist/esm/languages/prism/makefile.js';
62
62
  import langNginx from 'react-syntax-highlighter/dist/esm/languages/prism/nginx.js';
63
63
  import langIni from 'react-syntax-highlighter/dist/esm/languages/prism/ini.js';
64
+ import langClike from 'react-syntax-highlighter/dist/esm/languages/prism/clike.js';
64
65
  import ReactMarkdown from 'react-markdown';
65
66
  import remarkGfm from 'remark-gfm';
66
67
  import remarkMath from 'remark-math';
@@ -3148,6 +3149,11 @@ var init_Typography = __esm({
3148
3149
  inherit: "text-inherit"
3149
3150
  };
3150
3151
  weightStyles = {
3152
+ // Neutral: an atom default of "none" must not override the variant's baked
3153
+ // weight (C-PATTERN-ENUM-BLOCKS-NEUTRAL-OVERRIDE — `variant={h2}` rendered
3154
+ // tiny because the ui-typography atom's `weight: light`/`size: xs` defaults
3155
+ // clobbered every variant).
3156
+ none: "",
3151
3157
  light: "font-light",
3152
3158
  normal: "font-normal",
3153
3159
  medium: "font-medium",
@@ -3173,6 +3179,7 @@ var init_Typography = __esm({
3173
3179
  label: "span"
3174
3180
  };
3175
3181
  typographySizeStyles = {
3182
+ none: "",
3176
3183
  xs: "text-xs",
3177
3184
  sm: "text-sm",
3178
3185
  md: "text-base",
@@ -5034,6 +5041,7 @@ var init_Button = __esm({
5034
5041
  "button",
5035
5042
  {
5036
5043
  ref,
5044
+ type: "button",
5037
5045
  disabled: disabled || isLoading,
5038
5046
  className: cn(
5039
5047
  "relative inline-flex items-center justify-center gap-2",
@@ -16670,7 +16678,7 @@ async function loadPrismLanguage(lang) {
16670
16678
  if (isLanguageRegistered(lang)) return;
16671
16679
  try {
16672
16680
  const grammar = codeLanguageLoader ? await codeLanguageLoader(lang) : null;
16673
- if (grammar) SyntaxHighlighter.registerLanguage(lang, grammar);
16681
+ SyntaxHighlighter.registerLanguage(lang, grammar ?? langClike);
16674
16682
  dynamicallyLoaded.add(lang);
16675
16683
  } catch {
16676
16684
  dynamicallyLoaded.add(lang);
@@ -16839,6 +16847,7 @@ var init_CodeBlock = __esm({
16839
16847
  SyntaxHighlighter.registerLanguage("make", langMakefile);
16840
16848
  SyntaxHighlighter.registerLanguage("nginx", langNginx);
16841
16849
  SyntaxHighlighter.registerLanguage("ini", langIni);
16850
+ SyntaxHighlighter.registerLanguage("clike", langClike);
16842
16851
  SyntaxHighlighter.registerLanguage("orb", orbLanguage);
16843
16852
  SyntaxHighlighter.registerLanguage("lolo", loloLanguage);
16844
16853
  dynamicallyLoaded = /* @__PURE__ */ new Set();
@@ -17388,7 +17397,7 @@ var init_CodeBlock = __esm({
17388
17397
  ] }) });
17389
17398
  }
17390
17399
  const hasHeader = showLanguageBadge || effectiveCopy;
17391
- return /* @__PURE__ */ jsxs(Box, { className: `relative group ${className || ""}`, style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
17400
+ return /* @__PURE__ */ jsxs(Box, { className: `relative group not-prose ${className || ""}`, style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
17392
17401
  hasHeader && /* @__PURE__ */ jsxs(
17393
17402
  HStack,
17394
17403
  {
@@ -25331,6 +25340,13 @@ function DataGrid({
25331
25340
  row: itemData
25332
25341
  };
25333
25342
  eventBus.emit(`UI:${action.event}`, payload);
25343
+ if (action.navigatesTo) {
25344
+ const url = action.navigatesTo.replace(
25345
+ /\{\{row\.(\w+(?:\.\w+)*)\}\}/g,
25346
+ (_, field) => String(itemData[field] ?? "")
25347
+ );
25348
+ eventBus.emit("UI:NAVIGATE", { url });
25349
+ }
25334
25350
  };
25335
25351
  const hasRenderProp = typeof children === "function";
25336
25352
  useEffect(() => {
@@ -25398,13 +25414,49 @@ function DataGrid({
25398
25414
  const wrapDnd = (node) => dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: dndId, children: node }, dndId) : node;
25399
25415
  if (hasRenderProp) {
25400
25416
  return wrapDnd(
25401
- /* @__PURE__ */ jsx(
25417
+ /* @__PURE__ */ jsxs(
25402
25418
  Box,
25403
25419
  {
25404
25420
  "data-entity-row": true,
25405
25421
  "data-entity-id": id,
25406
25422
  className: cn(isSelected && "ring-2 ring-primary rounded-lg"),
25407
- children: children(itemData, index)
25423
+ children: [
25424
+ children(itemData, index),
25425
+ actionDefs.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 border-t border-border", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-end", children: [
25426
+ (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxs(
25427
+ Button,
25428
+ {
25429
+ variant: action.variant === "primary" ? "primary" : "ghost",
25430
+ size: "sm",
25431
+ onClick: handleActionClick(action, itemData),
25432
+ "data-testid": `action-${action.event}`,
25433
+ "data-row-id": String(itemData.id),
25434
+ className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
25435
+ children: [
25436
+ action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
25437
+ action.label
25438
+ ]
25439
+ },
25440
+ idx
25441
+ )),
25442
+ maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsx(
25443
+ Menu,
25444
+ {
25445
+ position: "bottom-end",
25446
+ trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
25447
+ items: actionDefs.slice(maxInlineActions).map((action) => ({
25448
+ label: action.label,
25449
+ icon: action.icon,
25450
+ event: action.event,
25451
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
25452
+ id: itemData.id,
25453
+ row: itemData
25454
+ })
25455
+ }))
25456
+ }
25457
+ )
25458
+ ] }) })
25459
+ ]
25408
25460
  },
25409
25461
  id
25410
25462
  )
@@ -26428,7 +26480,9 @@ var init_FilterGroup = __esm({
26428
26480
  showIcon = true,
26429
26481
  query,
26430
26482
  isLoading,
26431
- look = "toolbar"
26483
+ look = "toolbar",
26484
+ event,
26485
+ clearEvent
26432
26486
  }) => {
26433
26487
  const { t } = useTranslate();
26434
26488
  const eventBus = useEventBus();
@@ -26465,14 +26519,18 @@ var init_FilterGroup = __esm({
26465
26519
  queryState.setFilter(field, value === "all" ? null : value);
26466
26520
  }
26467
26521
  onFilterChange?.(field, value === "all" ? null : value);
26468
- eventBus.emit("UI:FILTER", {
26522
+ const payload = {
26469
26523
  entity,
26470
26524
  field,
26471
26525
  value: value === "all" || value === null ? "" : value,
26472
26526
  query
26473
- });
26527
+ };
26528
+ if (event && event !== "FILTER") {
26529
+ eventBus.emit(`UI:${event}`, payload);
26530
+ }
26531
+ eventBus.emit("UI:FILTER", payload);
26474
26532
  },
26475
- [onFilterChange, queryState, eventBus, entity, query]
26533
+ [onFilterChange, queryState, eventBus, entity, query, event]
26476
26534
  );
26477
26535
  const handleClearAll = useCallback(() => {
26478
26536
  setSelectedValues({});
@@ -26480,8 +26538,11 @@ var init_FilterGroup = __esm({
26480
26538
  queryState.clearFilters();
26481
26539
  }
26482
26540
  onClearAll?.();
26541
+ if (clearEvent && clearEvent !== "CLEAR_FILTERS") {
26542
+ eventBus.emit(`UI:${clearEvent}`, { entity, query });
26543
+ }
26483
26544
  eventBus.emit("UI:CLEAR_FILTERS", { entity, query });
26484
- }, [onClearAll, queryState, eventBus, entity, query]);
26545
+ }, [onClearAll, queryState, eventBus, entity, query, clearEvent]);
26485
26546
  const activeFilterCount = Object.keys(selectedValues).length;
26486
26547
  if (variant === "pills") {
26487
26548
  return /* @__PURE__ */ jsxs(
@@ -27609,7 +27670,7 @@ var init_SearchInput = __esm({
27609
27670
  queryState.setSearch(newValue);
27610
27671
  }
27611
27672
  onSearch?.(newValue);
27612
- if (event) {
27673
+ if (event && event !== "SEARCH") {
27613
27674
  eventBus.emit(`UI:${event}`, { searchTerm: newValue, entity });
27614
27675
  }
27615
27676
  if (event || entity || query) {
@@ -50128,6 +50189,14 @@ function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
50128
50189
  return writes;
50129
50190
  };
50130
50191
  }
50192
+ function containsConfigForward(value) {
50193
+ if (typeof value === "string") return value.startsWith("@config.");
50194
+ if (Array.isArray(value)) return value.some(containsConfigForward);
50195
+ if (value !== null && typeof value === "object") {
50196
+ return Object.values(value).some(containsConfigForward);
50197
+ }
50198
+ return false;
50199
+ }
50131
50200
  function getBindingConfig(binding) {
50132
50201
  const raw = binding.config;
50133
50202
  const normalized = normalizeCallSiteConfigToValues(raw);
@@ -50480,7 +50549,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50480
50549
  const sharedCallSite = sharedCallSiteRaw ? resolveCallSitePayloadCaptures(
50481
50550
  Object.fromEntries(
50482
50551
  Object.entries(sharedCallSiteRaw).filter(
50483
- ([, v]) => !(typeof v === "string" && v.startsWith("@config."))
50552
+ ([, v]) => !containsConfigForward(v)
50484
50553
  )
50485
50554
  ),
50486
50555
  payload || {}
@@ -50545,7 +50614,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50545
50614
  const callSiteOverrides = callSiteConfig ? resolveCallSitePayloadCaptures(
50546
50615
  Object.fromEntries(
50547
50616
  Object.entries(callSiteConfig).filter(
50548
- ([, v]) => !(typeof v === "string" && v.startsWith("@config."))
50617
+ ([, v]) => !containsConfigForward(v)
50549
50618
  )
50550
50619
  ),
50551
50620
  payload || {}
@@ -50787,7 +50856,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50787
50856
  }
50788
50857
  return () => scheduler.stopAll();
50789
50858
  }, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
50790
- const processEventQueued = useCallback(async (eventKey, payload) => {
50859
+ const processEventQueued = useCallback(async (eventKey, payload, targetTrait) => {
50791
50860
  const normalizedEvent = normalizeEventKey(eventKey);
50792
50861
  const bindings = traitBindingsRef.current;
50793
50862
  const currentManager = managerRef.current;
@@ -50816,7 +50885,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50816
50885
  normalizedEvent,
50817
50886
  payload,
50818
50887
  void 0,
50819
- entityByTrait
50888
+ entityByTrait,
50889
+ void 0,
50890
+ targetTrait
50820
50891
  );
50821
50892
  crossTraitLog.debug("processEvent:results", {
50822
50893
  event: normalizedEvent,
@@ -50909,8 +50980,11 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50909
50980
  const effectTraces = result.effects.map(
50910
50981
  (e) => {
50911
50982
  if (Array.isArray(e)) {
50983
+ const head = String(e[0] ?? "unknown");
50984
+ const entityName = head === "fetch" && typeof e[1] === "string" ? e[1] : head === "persist" && typeof e[2] === "string" ? e[2] : void 0;
50912
50985
  return {
50913
- type: String(e[0] ?? "unknown"),
50986
+ type: head,
50987
+ ...entityName !== void 0 ? { entityName } : {},
50914
50988
  args: e.slice(1),
50915
50989
  status: "executed"
50916
50990
  };
@@ -50963,7 +51037,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50963
51037
  const orbital = orbitalsByTrait?.[traitName];
50964
51038
  if (orbital) dispatchedOrbitals.add(orbital);
50965
51039
  }
50966
- await onEventProcessed(normalizedEvent, payload, dispatchedOrbitals);
51040
+ const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
51041
+ await onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals);
50967
51042
  }
50968
51043
  }, [entities, eventBus, sharedEntityStore]);
50969
51044
  const drainEventQueue = useCallback(async () => {
@@ -50972,14 +51047,14 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
50972
51047
  try {
50973
51048
  while (eventQueueRef.current.length > 0) {
50974
51049
  const entry = eventQueueRef.current.shift();
50975
- await processEventQueued(entry.eventKey, entry.payload);
51050
+ await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait);
50976
51051
  }
50977
51052
  } finally {
50978
51053
  processingRef.current = false;
50979
51054
  }
50980
51055
  }, [processEventQueued]);
50981
- const enqueueAndDrain = useCallback((eventKey, payload) => {
50982
- eventQueueRef.current.push({ eventKey, payload });
51056
+ const enqueueAndDrain = useCallback((eventKey, payload, targetTrait) => {
51057
+ eventQueueRef.current.push({ eventKey, payload, targetTrait });
50983
51058
  void drainEventQueue();
50984
51059
  }, [drainEventQueue]);
50985
51060
  useCallback((eventKey, payload) => {
@@ -51076,7 +51151,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
51076
51151
  crossTraitLog.debug("listen:subscribed", { busKey, targetTrait: binding.trait.name, sourceOrbital, sourceTrait, listenEvent: listen.event, triggers: listen.triggers });
51077
51152
  const unsub = eventBus.on(busKey, (event) => {
51078
51153
  crossTraitLog.debug("listen:fired", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
51079
- enqueueAndDrain(listen.triggers, event.payload);
51154
+ enqueueAndDrain(listen.triggers, event.payload, binding.trait.name);
51080
51155
  });
51081
51156
  unsubscribes.push(() => {
51082
51157
  crossTraitLog.debug("listen:unsubscribe", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
@@ -51543,6 +51618,15 @@ function OrbPreview({
51543
51618
  }
51544
51619
  }
51545
51620
  }, [pages]);
51621
+ useEffect(() => {
51622
+ const unsubscribe = eventBus.on("UI:NAVIGATE", (event) => {
51623
+ const url = event.payload?.url;
51624
+ if (typeof url === "string" && url.length > 0) {
51625
+ handleNavigate(url);
51626
+ }
51627
+ });
51628
+ return unsubscribe;
51629
+ }, [eventBus, handleNavigate]);
51546
51630
  if (!parseResult.ok) {
51547
51631
  return /* @__PURE__ */ jsx(Box, { className, style: { height }, children: /* @__PURE__ */ jsxs(Typography, { as: "pre", color: "error", variant: "small", className: "font-mono whitespace-pre-wrap break-all m-0 p-4", children: [
51548
51632
  "Parse error: ",