@almadar/ui 6.28.0 → 6.30.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.
Files changed (54) hide show
  1. package/dist/{EntityBindingContext-C6FgxdfG.d.cts → EntityBindingContext-ChCONv2W.d.cts} +3 -39
  2. package/dist/{EntityBindingContext-C6FgxdfG.d.ts → EntityBindingContext-ChCONv2W.d.ts} +3 -39
  3. package/dist/avl/index.cjs +74 -48
  4. package/dist/avl/index.js +74 -48
  5. package/dist/components/index.cjs +54 -45
  6. package/dist/components/index.d.cts +1 -1
  7. package/dist/components/index.d.ts +1 -1
  8. package/dist/components/index.js +54 -45
  9. package/dist/context/index.cjs +135 -105
  10. package/dist/context/index.d.cts +2 -60
  11. package/dist/context/index.d.ts +2 -60
  12. package/dist/context/index.js +135 -105
  13. package/dist/lib/index.cjs +455 -0
  14. package/dist/lib/index.d.cts +42 -1
  15. package/dist/lib/index.d.ts +42 -1
  16. package/dist/lib/index.js +438 -1
  17. package/dist/marketing/index.cjs +4 -5
  18. package/dist/marketing/index.js +4 -5
  19. package/dist/providers/index.cjs +194 -156
  20. package/dist/providers/index.d.cts +1 -1
  21. package/dist/providers/index.d.ts +1 -1
  22. package/dist/providers/index.js +194 -156
  23. package/dist/runtime/index.cjs +74 -48
  24. package/dist/runtime/index.d.cts +16 -2
  25. package/dist/runtime/index.d.ts +16 -2
  26. package/dist/runtime/index.js +74 -48
  27. package/dist/themeTokens-DVRwufw8.d.cts +112 -0
  28. package/dist/themeTokens-DVRwufw8.d.ts +112 -0
  29. package/package.json +7 -6
  30. package/scripts/audit-tailwind-safelist.ts +4 -0
  31. package/tailwind-preset.cjs +155 -28
  32. package/themes/almadar-website.css +37 -107
  33. package/themes/almadar.css +37 -108
  34. package/themes/atelier.css +145 -240
  35. package/themes/bloomberg-dense.css +145 -252
  36. package/themes/clay.css +39 -137
  37. package/themes/comic.css +39 -145
  38. package/themes/corporate.css +39 -131
  39. package/themes/game-adventure.css +22 -87
  40. package/themes/game-rpg.css +22 -84
  41. package/themes/game-sci-fi.css +22 -88
  42. package/themes/game-ui-pack.css +22 -85
  43. package/themes/gazette.css +43 -135
  44. package/themes/glass.css +39 -148
  45. package/themes/kiosk.css +51 -146
  46. package/themes/linear-clean.css +145 -215
  47. package/themes/minimalist.css +39 -125
  48. package/themes/neon.css +39 -132
  49. package/themes/notion-editorial.css +145 -215
  50. package/themes/prism.css +37 -100
  51. package/themes/retro.css +39 -130
  52. package/themes/terminal.css +61 -152
  53. package/themes/trait-wars.css +121 -285
  54. package/themes/wireframe.css +41 -128
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { ReactNode } from 'react';
3
- import { ResolvedEntity, EventPayload, EntityRow, UserContext, OrbitalSchema, BusEventSource, SExpr, ResolvedTrait, ResolvedTraitBinding, TraitConfig } from '@almadar/core';
3
+ import { ResolvedEntity, EventPayload, EntityRow, UserContext, OrbitalSchema, OrbitalEventResponse, ResolvedTrait, ResolvedTraitBinding, TraitConfig } from '@almadar/core';
4
4
  import { AnyPatternConfig } from '@almadar/core/patterns';
5
5
  import { ServerEffectResult, TransitionResult } from '@almadar/runtime';
6
6
 
@@ -84,44 +84,6 @@ declare function useEntitySchema(): EntitySchemaContextValue;
84
84
  */
85
85
  declare function useEntitySchemaOptional(): EntitySchemaContextValue | null;
86
86
 
87
- /** Wire-format client effect tuple from the server response. */
88
- type ClientEffectTuple = ['render-ui', string, AnyPatternConfig | null, ...SExpr[]] | ['navigate', string, ...SExpr[]] | ['navigate-back'];
89
- interface OrbitalEventResponse {
90
- success: boolean;
91
- transitioned: boolean;
92
- states: Record<string, string>;
93
- /**
94
- * Server-cascade events carried back in the response. Each entry has a
95
- * `source: BusEventSource` stamped by the compiled handler (`emit ...
96
- * { source: __ORBITAL_SOURCE }`) so the client can re-broadcast on the
97
- * qualified `UI:Orbital.Trait.EVENT` bus key (gap #13).
98
- */
99
- emittedEvents?: Array<{
100
- event: string;
101
- payload?: EventPayload;
102
- source?: BusEventSource;
103
- }>;
104
- data?: Record<string, EntityRow[]>;
105
- clientEffects?: ClientEffectTuple[];
106
- /**
107
- * Same effects as `clientEffects`, paired with the trait that produced
108
- * each one. When present, prefer this for trait attribution. Falls back
109
- * to legacy `clientEffects` parsing on older servers.
110
- */
111
- clientEffectsByTrait?: Array<{
112
- traitName: string;
113
- effect: ClientEffectTuple;
114
- }>;
115
- /**
116
- * Results from server-side effects (persist, call-service, set, …) —
117
- * `ServerEffectResult`, JSON-serialized. Carries the
118
- * persist effect's real outcome (action, entity, resulting id, denied)
119
- * so the verification trace can read it instead of inferring success
120
- * from a row-count delta.
121
- */
122
- effectResults?: ServerEffectResult[];
123
- error?: string;
124
- }
125
87
  interface ServerClientEffect {
126
88
  type: 'render-ui' | 'navigate' | 'navigate-back';
127
89
  slot?: string;
@@ -151,6 +113,8 @@ interface ServerResponseMeta {
151
113
  dataEntities: Record<string, number>;
152
114
  /** Raw entity data from server response (for EntityStore advancement) */
153
115
  data?: Record<string, EntityRow[]>;
116
+ /** See `OrbitalEventResponse.entityByTrait`'s doc. */
117
+ entityByTrait?: Record<string, EntityRow>;
154
118
  emittedEvents: string[];
155
119
  /** Server-side effect outcomes — see `OrbitalEventResponse.effectResults`. */
156
120
  effectResults?: ServerEffectResult[];
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { ReactNode } from 'react';
3
- import { ResolvedEntity, EventPayload, EntityRow, UserContext, OrbitalSchema, BusEventSource, SExpr, ResolvedTrait, ResolvedTraitBinding, TraitConfig } from '@almadar/core';
3
+ import { ResolvedEntity, EventPayload, EntityRow, UserContext, OrbitalSchema, OrbitalEventResponse, ResolvedTrait, ResolvedTraitBinding, TraitConfig } from '@almadar/core';
4
4
  import { AnyPatternConfig } from '@almadar/core/patterns';
5
5
  import { ServerEffectResult, TransitionResult } from '@almadar/runtime';
6
6
 
@@ -84,44 +84,6 @@ declare function useEntitySchema(): EntitySchemaContextValue;
84
84
  */
85
85
  declare function useEntitySchemaOptional(): EntitySchemaContextValue | null;
86
86
 
87
- /** Wire-format client effect tuple from the server response. */
88
- type ClientEffectTuple = ['render-ui', string, AnyPatternConfig | null, ...SExpr[]] | ['navigate', string, ...SExpr[]] | ['navigate-back'];
89
- interface OrbitalEventResponse {
90
- success: boolean;
91
- transitioned: boolean;
92
- states: Record<string, string>;
93
- /**
94
- * Server-cascade events carried back in the response. Each entry has a
95
- * `source: BusEventSource` stamped by the compiled handler (`emit ...
96
- * { source: __ORBITAL_SOURCE }`) so the client can re-broadcast on the
97
- * qualified `UI:Orbital.Trait.EVENT` bus key (gap #13).
98
- */
99
- emittedEvents?: Array<{
100
- event: string;
101
- payload?: EventPayload;
102
- source?: BusEventSource;
103
- }>;
104
- data?: Record<string, EntityRow[]>;
105
- clientEffects?: ClientEffectTuple[];
106
- /**
107
- * Same effects as `clientEffects`, paired with the trait that produced
108
- * each one. When present, prefer this for trait attribution. Falls back
109
- * to legacy `clientEffects` parsing on older servers.
110
- */
111
- clientEffectsByTrait?: Array<{
112
- traitName: string;
113
- effect: ClientEffectTuple;
114
- }>;
115
- /**
116
- * Results from server-side effects (persist, call-service, set, …) —
117
- * `ServerEffectResult`, JSON-serialized. Carries the
118
- * persist effect's real outcome (action, entity, resulting id, denied)
119
- * so the verification trace can read it instead of inferring success
120
- * from a row-count delta.
121
- */
122
- effectResults?: ServerEffectResult[];
123
- error?: string;
124
- }
125
87
  interface ServerClientEffect {
126
88
  type: 'render-ui' | 'navigate' | 'navigate-back';
127
89
  slot?: string;
@@ -151,6 +113,8 @@ interface ServerResponseMeta {
151
113
  dataEntities: Record<string, number>;
152
114
  /** Raw entity data from server response (for EntityStore advancement) */
153
115
  data?: Record<string, EntityRow[]>;
116
+ /** See `OrbitalEventResponse.entityByTrait`'s doc. */
117
+ entityByTrait?: Record<string, EntityRow>;
154
118
  emittedEvents: string[];
155
119
  /** Server-side effect outcomes — see `OrbitalEventResponse.effectResults`. */
156
120
  effectResults?: ServerEffectResult[];
@@ -6158,6 +6158,13 @@ var init_slot_types = __esm({
6158
6158
  nextRefId = 1;
6159
6159
  }
6160
6160
  });
6161
+ var SlotContainedContext;
6162
+ var init_slotContained = __esm({
6163
+ "lib/slotContained.ts"() {
6164
+ "use client";
6165
+ SlotContainedContext = React96.createContext(false);
6166
+ }
6167
+ });
6161
6168
  function buildForkPaths(x, y, branches, scale) {
6162
6169
  const inLength = 30 * scale;
6163
6170
  const outLength = 30 * scale;
@@ -17227,11 +17234,10 @@ var init_HeroSection = __esm({
17227
17234
  };
17228
17235
  backgroundStyles = {
17229
17236
  dark: "bg-foreground text-background",
17230
- gradient: [
17231
- "bg-[radial-gradient(ellipse_at_top,var(--color-primary)/0.08,transparent_60%),",
17232
- "radial-gradient(ellipse_at_bottom_right,var(--color-accent)/0.06,transparent_50%)]",
17233
- "bg-background"
17234
- ].join(" "),
17237
+ // A single bracket value: joining this as two array entries put a space
17238
+ // inside the class (Tailwind splits utilities on whitespace), so neither
17239
+ // half was a valid utility and the gradient rendered as nothing.
17240
+ gradient: "bg-[radial-gradient(ellipse_at_top,var(--color-primary)/0.08,transparent_60%),radial-gradient(ellipse_at_bottom_right,var(--color-accent)/0.06,transparent_50%)] bg-background",
17235
17241
  subtle: "bg-muted/30"
17236
17242
  };
17237
17243
  MarketingImage = ({ src, alt, className }) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -38470,7 +38476,6 @@ function TableView({
38470
38476
  columns,
38471
38477
  fields,
38472
38478
  itemActions,
38473
- maxInlineActions,
38474
38479
  itemClickEvent = "",
38475
38480
  selectable = false,
38476
38481
  selectEvent,
@@ -38504,8 +38509,7 @@ function TableView({
38504
38509
  const [localSelected, setLocalSelected] = React96__namespace.default.useState(/* @__PURE__ */ new Set());
38505
38510
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
38506
38511
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
38507
- const inlineActions = maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : [];
38508
- const overflowActions = maxInlineActions != null ? actionDefs.slice(maxInlineActions) : actionDefs;
38512
+ const overflowActions = actionDefs;
38509
38513
  const fireAction = (action, row) => eventBus.emit(`UI:${action.event}`, {
38510
38514
  id: row.id,
38511
38515
  row
@@ -38687,7 +38691,7 @@ function TableView({
38687
38691
  }
38688
38692
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format, relationsData?.[col.field ?? col.key]) }) }, col.key);
38689
38693
  }),
38690
- hasActions && /* @__PURE__ */ jsxRuntime.jsxs(
38694
+ hasActions && /* @__PURE__ */ jsxRuntime.jsx(
38691
38695
  HStack,
38692
38696
  {
38693
38697
  gap: "xs",
@@ -38701,38 +38705,20 @@ function TableView({
38701
38705
  "border-l border-[var(--color-border)]",
38702
38706
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
38703
38707
  ),
38704
- children: [
38705
- inlineActions.map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
38706
- Button,
38707
- {
38708
- variant: action.variant ?? "ghost",
38709
- size: "sm",
38710
- onClick: () => fireAction(action, row),
38711
- "data-testid": `action-${action.event}`,
38712
- "data-row-id": String(row.id),
38713
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
38714
- children: [
38715
- action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
38716
- action.label
38717
- ]
38718
- },
38719
- action.event
38720
- )),
38721
- overflowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
38722
- Menu,
38723
- {
38724
- position: "bottom-end",
38725
- trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
38726
- items: overflowActions.map((action) => ({
38727
- label: action.label,
38728
- icon: action.icon,
38729
- event: action.event,
38730
- variant: action.variant === "danger" ? "danger" : "default",
38731
- onClick: () => fireAction(action, row)
38732
- }))
38733
- }
38734
- )
38735
- ]
38708
+ children: overflowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
38709
+ Menu,
38710
+ {
38711
+ position: "bottom-end",
38712
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
38713
+ items: overflowActions.map((action) => ({
38714
+ label: action.label,
38715
+ icon: action.icon,
38716
+ event: action.event,
38717
+ variant: action.variant === "danger" ? "danger" : "default",
38718
+ onClick: () => fireAction(action, row)
38719
+ }))
38720
+ }
38721
+ )
38736
38722
  }
38737
38723
  )
38738
38724
  ]
@@ -47749,6 +47735,7 @@ var init_DetailPanel = __esm({
47749
47735
  init_EmptyState();
47750
47736
  init_cn();
47751
47737
  init_portalRoot();
47738
+ init_slotContained();
47752
47739
  init_format();
47753
47740
  init_getNestedValue();
47754
47741
  init_relationLabel();
@@ -47780,6 +47767,7 @@ var init_DetailPanel = __esm({
47780
47767
  }) => {
47781
47768
  const eventBus = useEventBus();
47782
47769
  const { t } = hooks.useTranslate();
47770
+ const contained = React96.useContext(SlotContainedContext);
47783
47771
  const [titleDraft, setTitleDraft] = React96__namespace.default.useState(null);
47784
47772
  const isFieldDefArray = (arr) => {
47785
47773
  if (!arr || arr.length === 0) return false;
@@ -48167,8 +48155,9 @@ var init_DetailPanel = __esm({
48167
48155
  if (!slideOver) {
48168
48156
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: content });
48169
48157
  }
48170
- const panel = /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("fixed inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
48171
- return typeof document === "undefined" ? panel : reactDom.createPortal(panel, getOrCreatePortalRoot());
48158
+ const panel = /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn(contained ? "absolute" : "fixed", "inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
48159
+ if (contained || typeof document === "undefined") return panel;
48160
+ return reactDom.createPortal(panel, getOrCreatePortalRoot());
48172
48161
  };
48173
48162
  DetailPanel.displayName = "DetailPanel";
48174
48163
  }
@@ -54665,6 +54654,7 @@ var init_component_registry_generated = __esm({
54665
54654
  // components/core/organisms/UISlotRenderer.tsx
54666
54655
  var UISlotRenderer_exports = {};
54667
54656
  __export(UISlotRenderer_exports, {
54657
+ SlotContainedContext: () => SlotContainedContext,
54668
54658
  SlotContentRenderer: () => SlotContentRenderer,
54669
54659
  SuspenseConfigProvider: () => SuspenseConfigProvider,
54670
54660
  UISlotComponent: () => UISlotComponent,
@@ -54837,6 +54827,25 @@ function renderContainedPortal(t, slot, content, onDismiss) {
54837
54827
  }
54838
54828
  );
54839
54829
  case "drawer":
54830
+ if (content.pattern === "detail-panel" && content.props.slideOver === true) {
54831
+ return /* @__PURE__ */ jsxRuntime.jsx(
54832
+ Box,
54833
+ {
54834
+ id: slotId,
54835
+ className: "absolute inset-0 z-50 overflow-hidden",
54836
+ style: { backgroundColor: "rgba(0, 0, 0, 0.5)" },
54837
+ onClick: onDismiss,
54838
+ children: /* @__PURE__ */ jsxRuntime.jsx(
54839
+ Box,
54840
+ {
54841
+ className: "absolute inset-y-0 right-0 pointer-events-auto",
54842
+ onClick: (e) => e.stopPropagation(),
54843
+ children: slotContent
54844
+ }
54845
+ )
54846
+ }
54847
+ );
54848
+ }
54840
54849
  return /* @__PURE__ */ jsxRuntime.jsx(
54841
54850
  Box,
54842
54851
  {
@@ -55688,7 +55697,7 @@ function UISlotRenderer({
55688
55697
  }
55689
55698
  return wrapped;
55690
55699
  }
55691
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
55700
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
55692
55701
  var init_UISlotRenderer = __esm({
55693
55702
  "components/core/organisms/UISlotRenderer.tsx"() {
55694
55703
  "use client";
@@ -55703,6 +55712,7 @@ var init_UISlotRenderer = __esm({
55703
55712
  init_cn();
55704
55713
  init_format();
55705
55714
  init_portalRoot();
55715
+ init_slotContained();
55706
55716
  init_ErrorBoundary();
55707
55717
  init_Skeleton();
55708
55718
  init_renderer();
@@ -55712,7 +55722,6 @@ var init_UISlotRenderer = __esm({
55712
55722
  scopeWrapLog = logger.createLogger("almadar:ui:scope-wrap");
55713
55723
  TRAIT_BINDING_RE = /^@trait\.([A-Z][A-Za-z0-9]*)$/;
55714
55724
  SuspenseConfigContext = React96.createContext({ enabled: false });
55715
- SlotContainedContext = React96.createContext(false);
55716
55725
  SuspenseConfigProvider.displayName = "SuspenseConfigProvider";
55717
55726
  SLOT_SKELETON_MAP = {
55718
55727
  main: "table",
@@ -60554,6 +60563,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
60554
60563
  const normalizedEvent = normalizeEventKey(eventKey);
60555
60564
  return managerRef.current.canHandleEvent(traitName, normalizedEvent);
60556
60565
  }, []);
60566
+ const commitServerEntity = React96.useCallback((traitName, entity) => {
60567
+ traitFieldStatesRef.current.set(traitName, entity);
60568
+ }, []);
60557
60569
  React96.useEffect(() => {
60558
60570
  const allEvents = /* @__PURE__ */ new Set();
60559
60571
  for (const binding of traitBindings) {
@@ -60717,7 +60729,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
60717
60729
  sendEvent,
60718
60730
  getTraitState,
60719
60731
  canHandleEvent,
60720
- entityBindingSource
60732
+ entityBindingSource,
60733
+ commitServerEntity
60721
60734
  };
60722
60735
  }
60723
60736
 
@@ -60740,7 +60753,7 @@ function normalizeChild(child) {
60740
60753
  function effectResultsToTraces(results) {
60741
60754
  if (!results) return [];
60742
60755
  return results.map((r2) => {
60743
- const resultId = r2.data !== void 0 && r2.data !== null && "id" in r2.data && typeof r2.data.id === "string" ? r2.data.id : void 0;
60756
+ const resultId = typeof r2.data === "object" && r2.data !== null && !Array.isArray(r2.data) && "id" in r2.data && typeof r2.data.id === "string" ? r2.data.id : void 0;
60744
60757
  const outcome = r2.denied ? "denied" : r2.success ? "success" : "failed";
60745
60758
  return {
60746
60759
  type: r2.effect,
@@ -60853,6 +60866,8 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60853
60866
  [serverActiveTraits]
60854
60867
  );
60855
60868
  const uiSlots = context.useUISlots();
60869
+ const commitServerEntityRef = React96.useRef(() => {
60870
+ });
60856
60871
  const onEventProcessed = React96.useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
60857
60872
  if (!bridge.connected || !orbitalNames?.length) return;
60858
60873
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
@@ -60869,12 +60884,18 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60869
60884
  }
60870
60885
  void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait, user ?? void 0).then(({ effects, meta }) => {
60871
60886
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60887
+ if (meta.entityByTrait) {
60888
+ for (const [traitName, entity] of Object.entries(meta.entityByTrait)) {
60889
+ commitServerEntityRef.current(traitName, entity);
60890
+ }
60891
+ }
60872
60892
  applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNamesRef.current, onNavigateBack);
60873
60893
  });
60874
60894
  }
60875
60895
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits, user]);
60876
60896
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, callsiteCaptureChildrenByTrait, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, callsiteCaptureChildrenByTrait, initPayload: routeParams };
60877
- const { sendEvent, entityBindingSource } = useTraitStateMachine(traits2, uiSlots, opts);
60897
+ const { sendEvent, entityBindingSource, commitServerEntity } = useTraitStateMachine(traits2, uiSlots, opts);
60898
+ commitServerEntityRef.current = commitServerEntity;
60878
60899
  const initSentRef = React96.useRef(false);
60879
60900
  const prevTraitsRef = React96.useRef(void 0);
60880
60901
  const paramsKey = JSON.stringify(routeParams ?? {});
@@ -60926,6 +60947,11 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60926
60947
  user ?? void 0
60927
60948
  );
60928
60949
  recordServerResponse(name, "INIT", { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60950
+ if (meta.entityByTrait) {
60951
+ for (const [traitName, entity] of Object.entries(meta.entityByTrait)) {
60952
+ commitServerEntityRef.current(traitName, entity);
60953
+ }
60954
+ }
60929
60955
  const effectTraces = [
60930
60956
  { type: "fetch", args: [], status: "executed" },
60931
60957
  ...effects.map((eff) => ({
package/dist/avl/index.js CHANGED
@@ -6082,6 +6082,13 @@ var init_slot_types = __esm({
6082
6082
  nextRefId = 1;
6083
6083
  }
6084
6084
  });
6085
+ var SlotContainedContext;
6086
+ var init_slotContained = __esm({
6087
+ "lib/slotContained.ts"() {
6088
+ "use client";
6089
+ SlotContainedContext = createContext(false);
6090
+ }
6091
+ });
6085
6092
  function buildForkPaths(x, y, branches, scale) {
6086
6093
  const inLength = 30 * scale;
6087
6094
  const outLength = 30 * scale;
@@ -17151,11 +17158,10 @@ var init_HeroSection = __esm({
17151
17158
  };
17152
17159
  backgroundStyles = {
17153
17160
  dark: "bg-foreground text-background",
17154
- gradient: [
17155
- "bg-[radial-gradient(ellipse_at_top,var(--color-primary)/0.08,transparent_60%),",
17156
- "radial-gradient(ellipse_at_bottom_right,var(--color-accent)/0.06,transparent_50%)]",
17157
- "bg-background"
17158
- ].join(" "),
17161
+ // A single bracket value: joining this as two array entries put a space
17162
+ // inside the class (Tailwind splits utilities on whitespace), so neither
17163
+ // half was a valid utility and the gradient rendered as nothing.
17164
+ gradient: "bg-[radial-gradient(ellipse_at_top,var(--color-primary)/0.08,transparent_60%),radial-gradient(ellipse_at_bottom_right,var(--color-accent)/0.06,transparent_50%)] bg-background",
17159
17165
  subtle: "bg-muted/30"
17160
17166
  };
17161
17167
  MarketingImage = ({ src, alt, className }) => /* @__PURE__ */ jsx(
@@ -38394,7 +38400,6 @@ function TableView({
38394
38400
  columns,
38395
38401
  fields,
38396
38402
  itemActions,
38397
- maxInlineActions,
38398
38403
  itemClickEvent = "",
38399
38404
  selectable = false,
38400
38405
  selectEvent,
@@ -38428,8 +38433,7 @@ function TableView({
38428
38433
  const [localSelected, setLocalSelected] = React96__default.useState(/* @__PURE__ */ new Set());
38429
38434
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
38430
38435
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
38431
- const inlineActions = maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : [];
38432
- const overflowActions = maxInlineActions != null ? actionDefs.slice(maxInlineActions) : actionDefs;
38436
+ const overflowActions = actionDefs;
38433
38437
  const fireAction = (action, row) => eventBus.emit(`UI:${action.event}`, {
38434
38438
  id: row.id,
38435
38439
  row
@@ -38611,7 +38615,7 @@ function TableView({
38611
38615
  }
38612
38616
  return /* @__PURE__ */ jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format, relationsData?.[col.field ?? col.key]) }) }, col.key);
38613
38617
  }),
38614
- hasActions && /* @__PURE__ */ jsxs(
38618
+ hasActions && /* @__PURE__ */ jsx(
38615
38619
  HStack,
38616
38620
  {
38617
38621
  gap: "xs",
@@ -38625,38 +38629,20 @@ function TableView({
38625
38629
  "border-l border-[var(--color-border)]",
38626
38630
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
38627
38631
  ),
38628
- children: [
38629
- inlineActions.map((action) => /* @__PURE__ */ jsxs(
38630
- Button,
38631
- {
38632
- variant: action.variant ?? "ghost",
38633
- size: "sm",
38634
- onClick: () => fireAction(action, row),
38635
- "data-testid": `action-${action.event}`,
38636
- "data-row-id": String(row.id),
38637
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
38638
- children: [
38639
- action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
38640
- action.label
38641
- ]
38642
- },
38643
- action.event
38644
- )),
38645
- overflowActions.length > 0 && /* @__PURE__ */ jsx(
38646
- Menu,
38647
- {
38648
- position: "bottom-end",
38649
- trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
38650
- items: overflowActions.map((action) => ({
38651
- label: action.label,
38652
- icon: action.icon,
38653
- event: action.event,
38654
- variant: action.variant === "danger" ? "danger" : "default",
38655
- onClick: () => fireAction(action, row)
38656
- }))
38657
- }
38658
- )
38659
- ]
38632
+ children: overflowActions.length > 0 && /* @__PURE__ */ jsx(
38633
+ Menu,
38634
+ {
38635
+ position: "bottom-end",
38636
+ trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
38637
+ items: overflowActions.map((action) => ({
38638
+ label: action.label,
38639
+ icon: action.icon,
38640
+ event: action.event,
38641
+ variant: action.variant === "danger" ? "danger" : "default",
38642
+ onClick: () => fireAction(action, row)
38643
+ }))
38644
+ }
38645
+ )
38660
38646
  }
38661
38647
  )
38662
38648
  ]
@@ -47673,6 +47659,7 @@ var init_DetailPanel = __esm({
47673
47659
  init_EmptyState();
47674
47660
  init_cn();
47675
47661
  init_portalRoot();
47662
+ init_slotContained();
47676
47663
  init_format();
47677
47664
  init_getNestedValue();
47678
47665
  init_relationLabel();
@@ -47704,6 +47691,7 @@ var init_DetailPanel = __esm({
47704
47691
  }) => {
47705
47692
  const eventBus = useEventBus();
47706
47693
  const { t } = useTranslate();
47694
+ const contained = useContext(SlotContainedContext);
47707
47695
  const [titleDraft, setTitleDraft] = React96__default.useState(null);
47708
47696
  const isFieldDefArray = (arr) => {
47709
47697
  if (!arr || arr.length === 0) return false;
@@ -48091,8 +48079,9 @@ var init_DetailPanel = __esm({
48091
48079
  if (!slideOver) {
48092
48080
  return /* @__PURE__ */ jsx(Box, { className, children: content });
48093
48081
  }
48094
- const panel = /* @__PURE__ */ jsx(Box, { className: cn("fixed inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
48095
- return typeof document === "undefined" ? panel : createPortal(panel, getOrCreatePortalRoot());
48082
+ const panel = /* @__PURE__ */ jsx(Box, { className: cn(contained ? "absolute" : "fixed", "inset-y-0 right-0 w-full max-w-2xl bg-card shadow-lg z-50 overflow-y-auto p-6", className), children: content });
48083
+ if (contained || typeof document === "undefined") return panel;
48084
+ return createPortal(panel, getOrCreatePortalRoot());
48096
48085
  };
48097
48086
  DetailPanel.displayName = "DetailPanel";
48098
48087
  }
@@ -54589,6 +54578,7 @@ var init_component_registry_generated = __esm({
54589
54578
  // components/core/organisms/UISlotRenderer.tsx
54590
54579
  var UISlotRenderer_exports = {};
54591
54580
  __export(UISlotRenderer_exports, {
54581
+ SlotContainedContext: () => SlotContainedContext,
54592
54582
  SlotContentRenderer: () => SlotContentRenderer,
54593
54583
  SuspenseConfigProvider: () => SuspenseConfigProvider,
54594
54584
  UISlotComponent: () => UISlotComponent,
@@ -54761,6 +54751,25 @@ function renderContainedPortal(t, slot, content, onDismiss) {
54761
54751
  }
54762
54752
  );
54763
54753
  case "drawer":
54754
+ if (content.pattern === "detail-panel" && content.props.slideOver === true) {
54755
+ return /* @__PURE__ */ jsx(
54756
+ Box,
54757
+ {
54758
+ id: slotId,
54759
+ className: "absolute inset-0 z-50 overflow-hidden",
54760
+ style: { backgroundColor: "rgba(0, 0, 0, 0.5)" },
54761
+ onClick: onDismiss,
54762
+ children: /* @__PURE__ */ jsx(
54763
+ Box,
54764
+ {
54765
+ className: "absolute inset-y-0 right-0 pointer-events-auto",
54766
+ onClick: (e) => e.stopPropagation(),
54767
+ children: slotContent
54768
+ }
54769
+ )
54770
+ }
54771
+ );
54772
+ }
54764
54773
  return /* @__PURE__ */ jsx(
54765
54774
  Box,
54766
54775
  {
@@ -55612,7 +55621,7 @@ function UISlotRenderer({
55612
55621
  }
55613
55622
  return wrapped;
55614
55623
  }
55615
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
55624
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
55616
55625
  var init_UISlotRenderer = __esm({
55617
55626
  "components/core/organisms/UISlotRenderer.tsx"() {
55618
55627
  "use client";
@@ -55627,6 +55636,7 @@ var init_UISlotRenderer = __esm({
55627
55636
  init_cn();
55628
55637
  init_format();
55629
55638
  init_portalRoot();
55639
+ init_slotContained();
55630
55640
  init_ErrorBoundary();
55631
55641
  init_Skeleton();
55632
55642
  init_renderer();
@@ -55636,7 +55646,6 @@ var init_UISlotRenderer = __esm({
55636
55646
  scopeWrapLog = createLogger("almadar:ui:scope-wrap");
55637
55647
  TRAIT_BINDING_RE = /^@trait\.([A-Z][A-Za-z0-9]*)$/;
55638
55648
  SuspenseConfigContext = createContext({ enabled: false });
55639
- SlotContainedContext = createContext(false);
55640
55649
  SuspenseConfigProvider.displayName = "SuspenseConfigProvider";
55641
55650
  SLOT_SKELETON_MAP = {
55642
55651
  main: "table",
@@ -60478,6 +60487,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
60478
60487
  const normalizedEvent = normalizeEventKey(eventKey);
60479
60488
  return managerRef.current.canHandleEvent(traitName, normalizedEvent);
60480
60489
  }, []);
60490
+ const commitServerEntity = useCallback((traitName, entity) => {
60491
+ traitFieldStatesRef.current.set(traitName, entity);
60492
+ }, []);
60481
60493
  useEffect(() => {
60482
60494
  const allEvents = /* @__PURE__ */ new Set();
60483
60495
  for (const binding of traitBindings) {
@@ -60641,7 +60653,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
60641
60653
  sendEvent,
60642
60654
  getTraitState,
60643
60655
  canHandleEvent,
60644
- entityBindingSource
60656
+ entityBindingSource,
60657
+ commitServerEntity
60645
60658
  };
60646
60659
  }
60647
60660
 
@@ -60664,7 +60677,7 @@ function normalizeChild(child) {
60664
60677
  function effectResultsToTraces(results) {
60665
60678
  if (!results) return [];
60666
60679
  return results.map((r2) => {
60667
- const resultId = r2.data !== void 0 && r2.data !== null && "id" in r2.data && typeof r2.data.id === "string" ? r2.data.id : void 0;
60680
+ const resultId = typeof r2.data === "object" && r2.data !== null && !Array.isArray(r2.data) && "id" in r2.data && typeof r2.data.id === "string" ? r2.data.id : void 0;
60668
60681
  const outcome = r2.denied ? "denied" : r2.success ? "success" : "failed";
60669
60682
  return {
60670
60683
  type: r2.effect,
@@ -60777,6 +60790,8 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60777
60790
  [serverActiveTraits]
60778
60791
  );
60779
60792
  const uiSlots = useUISlots();
60793
+ const commitServerEntityRef = useRef(() => {
60794
+ });
60780
60795
  const onEventProcessed = useCallback((event, payload, dispatchedOrbitals, tick, sourceTrait, locallyEmitted, results, entityByTrait) => {
60781
60796
  if (!bridge.connected || !orbitalNames?.length) return;
60782
60797
  const targets = dispatchedOrbitals && dispatchedOrbitals.size > 0 ? orbitalNames.filter((n) => dispatchedOrbitals.has(n)) : orbitalNames;
@@ -60793,12 +60808,18 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60793
60808
  }
60794
60809
  void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait, user ?? void 0).then(({ effects, meta }) => {
60795
60810
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60811
+ if (meta.entityByTrait) {
60812
+ for (const [traitName, entity] of Object.entries(meta.entityByTrait)) {
60813
+ commitServerEntityRef.current(traitName, entity);
60814
+ }
60815
+ }
60796
60816
  applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNamesRef.current, onNavigateBack);
60797
60817
  });
60798
60818
  }
60799
60819
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits, user]);
60800
60820
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, navigateBack: onNavigateBack, traitConfigsByName, orbitalsByTrait, embeddedTraits, callsiteCaptureChildrenByTrait, initPayload: routeParams } : { navigate: onNavigate, navigateBack: onNavigateBack, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits, callsiteCaptureChildrenByTrait, initPayload: routeParams };
60801
- const { sendEvent, entityBindingSource } = useTraitStateMachine(traits2, uiSlots, opts);
60821
+ const { sendEvent, entityBindingSource, commitServerEntity } = useTraitStateMachine(traits2, uiSlots, opts);
60822
+ commitServerEntityRef.current = commitServerEntity;
60802
60823
  const initSentRef = useRef(false);
60803
60824
  const prevTraitsRef = useRef(void 0);
60804
60825
  const paramsKey = JSON.stringify(routeParams ?? {});
@@ -60850,6 +60871,11 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60850
60871
  user ?? void 0
60851
60872
  );
60852
60873
  recordServerResponse(name, "INIT", { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60874
+ if (meta.entityByTrait) {
60875
+ for (const [traitName, entity] of Object.entries(meta.entityByTrait)) {
60876
+ commitServerEntityRef.current(traitName, entity);
60877
+ }
60878
+ }
60853
60879
  const effectTraces = [
60854
60880
  { type: "fetch", args: [], status: "executed" },
60855
60881
  ...effects.map((eff) => ({