@almadar/ui 5.122.14 → 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.
@@ -1568,6 +1568,7 @@ var init_Button = __esm({
1568
1568
  "button",
1569
1569
  {
1570
1570
  ref,
1571
+ type: "button",
1571
1572
  disabled: disabled || isLoading,
1572
1573
  className: cn(
1573
1574
  "relative inline-flex items-center justify-center gap-2",
@@ -1661,6 +1662,11 @@ var init_Typography = __esm({
1661
1662
  inherit: "text-inherit"
1662
1663
  };
1663
1664
  weightStyles = {
1665
+ // Neutral: an atom default of "none" must not override the variant's baked
1666
+ // weight (C-PATTERN-ENUM-BLOCKS-NEUTRAL-OVERRIDE — `variant={h2}` rendered
1667
+ // tiny because the ui-typography atom's `weight: light`/`size: xs` defaults
1668
+ // clobbered every variant).
1669
+ none: "",
1664
1670
  light: "font-light",
1665
1671
  normal: "font-normal",
1666
1672
  medium: "font-medium",
@@ -1686,6 +1692,7 @@ var init_Typography = __esm({
1686
1692
  label: "span"
1687
1693
  };
1688
1694
  typographySizeStyles = {
1695
+ none: "",
1689
1696
  xs: "text-xs",
1690
1697
  sm: "text-sm",
1691
1698
  md: "text-base",
@@ -22623,6 +22630,13 @@ function DataGrid({
22623
22630
  row: itemData
22624
22631
  };
22625
22632
  eventBus.emit(`UI:${action.event}`, payload);
22633
+ if (action.navigatesTo) {
22634
+ const url = action.navigatesTo.replace(
22635
+ /\{\{row\.(\w+(?:\.\w+)*)\}\}/g,
22636
+ (_, field) => String(itemData[field] ?? "")
22637
+ );
22638
+ eventBus.emit("UI:NAVIGATE", { url });
22639
+ }
22626
22640
  };
22627
22641
  const hasRenderProp = typeof children === "function";
22628
22642
  useEffect(() => {
@@ -22690,13 +22704,49 @@ function DataGrid({
22690
22704
  const wrapDnd = (node) => dnd.isZone ? /* @__PURE__ */ jsx(dnd.SortableItem, { id: dndId, children: node }, dndId) : node;
22691
22705
  if (hasRenderProp) {
22692
22706
  return wrapDnd(
22693
- /* @__PURE__ */ jsx(
22707
+ /* @__PURE__ */ jsxs(
22694
22708
  Box,
22695
22709
  {
22696
22710
  "data-entity-row": true,
22697
22711
  "data-entity-id": id,
22698
22712
  className: cn(isSelected && "ring-2 ring-primary rounded-lg"),
22699
- children: children(itemData, index)
22713
+ children: [
22714
+ children(itemData, index),
22715
+ 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: [
22716
+ (maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : actionDefs).map((action, idx) => /* @__PURE__ */ jsxs(
22717
+ Button,
22718
+ {
22719
+ variant: action.variant === "primary" ? "primary" : "ghost",
22720
+ size: "sm",
22721
+ onClick: handleActionClick(action, itemData),
22722
+ "data-testid": `action-${action.event}`,
22723
+ "data-row-id": String(itemData.id),
22724
+ className: action.variant === "danger" ? "text-error hover:text-error hover:bg-error/10" : void 0,
22725
+ children: [
22726
+ action.icon && renderIconInput(action.icon, { size: "xs", className: "mr-1" }),
22727
+ action.label
22728
+ ]
22729
+ },
22730
+ idx
22731
+ )),
22732
+ maxInlineActions != null && actionDefs.length > maxInlineActions && /* @__PURE__ */ jsx(
22733
+ Menu,
22734
+ {
22735
+ position: "bottom-end",
22736
+ 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" }) }),
22737
+ items: actionDefs.slice(maxInlineActions).map((action) => ({
22738
+ label: action.label,
22739
+ icon: action.icon,
22740
+ event: action.event,
22741
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
22742
+ id: itemData.id,
22743
+ row: itemData
22744
+ })
22745
+ }))
22746
+ }
22747
+ )
22748
+ ] }) })
22749
+ ]
22700
22750
  },
22701
22751
  id
22702
22752
  )
@@ -23656,7 +23706,9 @@ var init_FilterGroup = __esm({
23656
23706
  showIcon = true,
23657
23707
  query,
23658
23708
  isLoading,
23659
- look = "toolbar"
23709
+ look = "toolbar",
23710
+ event,
23711
+ clearEvent
23660
23712
  }) => {
23661
23713
  const { t } = useTranslate();
23662
23714
  const eventBus = useEventBus();
@@ -23693,14 +23745,18 @@ var init_FilterGroup = __esm({
23693
23745
  queryState.setFilter(field, value === "all" ? null : value);
23694
23746
  }
23695
23747
  onFilterChange?.(field, value === "all" ? null : value);
23696
- eventBus.emit("UI:FILTER", {
23748
+ const payload = {
23697
23749
  entity,
23698
23750
  field,
23699
23751
  value: value === "all" || value === null ? "" : value,
23700
23752
  query
23701
- });
23753
+ };
23754
+ if (event && event !== "FILTER") {
23755
+ eventBus.emit(`UI:${event}`, payload);
23756
+ }
23757
+ eventBus.emit("UI:FILTER", payload);
23702
23758
  },
23703
- [onFilterChange, queryState, eventBus, entity, query]
23759
+ [onFilterChange, queryState, eventBus, entity, query, event]
23704
23760
  );
23705
23761
  const handleClearAll = useCallback(() => {
23706
23762
  setSelectedValues({});
@@ -23708,8 +23764,11 @@ var init_FilterGroup = __esm({
23708
23764
  queryState.clearFilters();
23709
23765
  }
23710
23766
  onClearAll?.();
23767
+ if (clearEvent && clearEvent !== "CLEAR_FILTERS") {
23768
+ eventBus.emit(`UI:${clearEvent}`, { entity, query });
23769
+ }
23711
23770
  eventBus.emit("UI:CLEAR_FILTERS", { entity, query });
23712
- }, [onClearAll, queryState, eventBus, entity, query]);
23771
+ }, [onClearAll, queryState, eventBus, entity, query, clearEvent]);
23713
23772
  const activeFilterCount = Object.keys(selectedValues).length;
23714
23773
  if (variant === "pills") {
23715
23774
  return /* @__PURE__ */ jsxs(
@@ -24837,7 +24896,7 @@ var init_SearchInput = __esm({
24837
24896
  queryState.setSearch(newValue);
24838
24897
  }
24839
24898
  onSearch?.(newValue);
24840
- if (event) {
24899
+ if (event && event !== "SEARCH") {
24841
24900
  eventBus.emit(`UI:${event}`, { searchTerm: newValue, entity });
24842
24901
  }
24843
24902
  if (event || entity || query) {
@@ -44253,6 +44312,14 @@ function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
44253
44312
  return writes;
44254
44313
  };
44255
44314
  }
44315
+ function containsConfigForward(value) {
44316
+ if (typeof value === "string") return value.startsWith("@config.");
44317
+ if (Array.isArray(value)) return value.some(containsConfigForward);
44318
+ if (value !== null && typeof value === "object") {
44319
+ return Object.values(value).some(containsConfigForward);
44320
+ }
44321
+ return false;
44322
+ }
44256
44323
  function getBindingConfig(binding) {
44257
44324
  const raw = binding.config;
44258
44325
  const normalized = normalizeCallSiteConfigToValues(raw);
@@ -44605,7 +44672,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44605
44672
  const sharedCallSite = sharedCallSiteRaw ? resolveCallSitePayloadCaptures(
44606
44673
  Object.fromEntries(
44607
44674
  Object.entries(sharedCallSiteRaw).filter(
44608
- ([, v]) => !(typeof v === "string" && v.startsWith("@config."))
44675
+ ([, v]) => !containsConfigForward(v)
44609
44676
  )
44610
44677
  ),
44611
44678
  payload || {}
@@ -44670,7 +44737,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44670
44737
  const callSiteOverrides = callSiteConfig ? resolveCallSitePayloadCaptures(
44671
44738
  Object.fromEntries(
44672
44739
  Object.entries(callSiteConfig).filter(
44673
- ([, v]) => !(typeof v === "string" && v.startsWith("@config."))
44740
+ ([, v]) => !containsConfigForward(v)
44674
44741
  )
44675
44742
  ),
44676
44743
  payload || {}
@@ -44912,7 +44979,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44912
44979
  }
44913
44980
  return () => scheduler.stopAll();
44914
44981
  }, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
44915
- const processEventQueued = useCallback(async (eventKey, payload) => {
44982
+ const processEventQueued = useCallback(async (eventKey, payload, targetTrait) => {
44916
44983
  const normalizedEvent = normalizeEventKey(eventKey);
44917
44984
  const bindings = traitBindingsRef.current;
44918
44985
  const currentManager = managerRef.current;
@@ -44941,7 +45008,9 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
44941
45008
  normalizedEvent,
44942
45009
  payload,
44943
45010
  void 0,
44944
- entityByTrait
45011
+ entityByTrait,
45012
+ void 0,
45013
+ targetTrait
44945
45014
  );
44946
45015
  crossTraitLog.debug("processEvent:results", {
44947
45016
  event: normalizedEvent,
@@ -45034,8 +45103,11 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45034
45103
  const effectTraces = result.effects.map(
45035
45104
  (e) => {
45036
45105
  if (Array.isArray(e)) {
45106
+ const head = String(e[0] ?? "unknown");
45107
+ const entityName = head === "fetch" && typeof e[1] === "string" ? e[1] : head === "persist" && typeof e[2] === "string" ? e[2] : void 0;
45037
45108
  return {
45038
- type: String(e[0] ?? "unknown"),
45109
+ type: head,
45110
+ ...entityName !== void 0 ? { entityName } : {},
45039
45111
  args: e.slice(1),
45040
45112
  status: "executed"
45041
45113
  };
@@ -45088,7 +45160,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45088
45160
  const orbital = orbitalsByTrait?.[traitName];
45089
45161
  if (orbital) dispatchedOrbitals.add(orbital);
45090
45162
  }
45091
- await onEventProcessed(normalizedEvent, payload, dispatchedOrbitals);
45163
+ const relayPayload = targetTrait !== void 0 ? { ...payload ?? {}, _targetTrait: targetTrait } : payload;
45164
+ await onEventProcessed(normalizedEvent, relayPayload, dispatchedOrbitals);
45092
45165
  }
45093
45166
  }, [entities, eventBus, sharedEntityStore]);
45094
45167
  const drainEventQueue = useCallback(async () => {
@@ -45097,14 +45170,14 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45097
45170
  try {
45098
45171
  while (eventQueueRef.current.length > 0) {
45099
45172
  const entry = eventQueueRef.current.shift();
45100
- await processEventQueued(entry.eventKey, entry.payload);
45173
+ await processEventQueued(entry.eventKey, entry.payload, entry.targetTrait);
45101
45174
  }
45102
45175
  } finally {
45103
45176
  processingRef.current = false;
45104
45177
  }
45105
45178
  }, [processEventQueued]);
45106
- const enqueueAndDrain = useCallback((eventKey, payload) => {
45107
- eventQueueRef.current.push({ eventKey, payload });
45179
+ const enqueueAndDrain = useCallback((eventKey, payload, targetTrait) => {
45180
+ eventQueueRef.current.push({ eventKey, payload, targetTrait });
45108
45181
  void drainEventQueue();
45109
45182
  }, [drainEventQueue]);
45110
45183
  useCallback((eventKey, payload) => {
@@ -45201,7 +45274,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
45201
45274
  crossTraitLog.debug("listen:subscribed", { busKey, targetTrait: binding.trait.name, sourceOrbital, sourceTrait, listenEvent: listen.event, triggers: listen.triggers });
45202
45275
  const unsub = eventBus.on(busKey, (event) => {
45203
45276
  crossTraitLog.debug("listen:fired", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
45204
- enqueueAndDrain(listen.triggers, event.payload);
45277
+ enqueueAndDrain(listen.triggers, event.payload, binding.trait.name);
45205
45278
  });
45206
45279
  unsubscribes.push(() => {
45207
45280
  crossTraitLog.debug("listen:unsubscribe", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
@@ -45769,6 +45842,15 @@ function OrbPreview({
45769
45842
  }
45770
45843
  }
45771
45844
  }, [pages]);
45845
+ useEffect(() => {
45846
+ const unsubscribe = eventBus.on("UI:NAVIGATE", (event) => {
45847
+ const url = event.payload?.url;
45848
+ if (typeof url === "string" && url.length > 0) {
45849
+ handleNavigate(url);
45850
+ }
45851
+ });
45852
+ return unsubscribe;
45853
+ }, [eventBus, handleNavigate]);
45772
45854
  if (!parseResult.ok) {
45773
45855
  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: [
45774
45856
  "Parse error: ",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.122.14",
3
+ "version": "5.123.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -117,11 +117,11 @@
117
117
  "access": "public"
118
118
  },
119
119
  "dependencies": {
120
- "@almadar/core": "^10.30.0",
121
- "@almadar/evaluator": "^2.30.0",
120
+ "@almadar/core": "^10.32.0",
121
+ "@almadar/evaluator": "^2.32.0",
122
122
  "@almadar/logger": "^1.9.0",
123
- "@almadar/runtime": "^6.33.0",
124
- "@almadar/std": "^16.140.0",
123
+ "@almadar/runtime": "^6.35.0",
124
+ "@almadar/std": "^16.142.0",
125
125
  "@almadar/syntax": "^1.11.0",
126
126
  "@dnd-kit/core": "^6.3.1",
127
127
  "@dnd-kit/sortable": "^10.0.0",