@almadar/ui 4.0.1 → 4.2.1

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.
@@ -17221,6 +17221,16 @@ function statusVariant2(value) {
17221
17221
  if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
17222
17222
  return "default";
17223
17223
  }
17224
+ function resolveBadgeVariant(field, value) {
17225
+ const fromMap = field.colorMap?.[value];
17226
+ if (fromMap) {
17227
+ const normalised = fromMap === "destructive" ? "danger" : fromMap;
17228
+ if (BADGE_VARIANTS.has(normalised)) {
17229
+ return normalised;
17230
+ }
17231
+ }
17232
+ return statusVariant2(value);
17233
+ }
17224
17234
  function formatDate2(value) {
17225
17235
  if (!value) return "";
17226
17236
  const d = new Date(String(value));
@@ -17434,7 +17444,7 @@ function DataGrid({
17434
17444
  if (val === void 0 || val === null) return null;
17435
17445
  return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
17436
17446
  field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
17437
- /* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
17447
+ /* @__PURE__ */ jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: String(val) })
17438
17448
  ] }, field.name);
17439
17449
  }) })
17440
17450
  ] }),
@@ -17527,7 +17537,7 @@ function DataGrid({
17527
17537
  )
17528
17538
  ] });
17529
17539
  }
17530
- var gapStyles6;
17540
+ var BADGE_VARIANTS, gapStyles6;
17531
17541
  var init_DataGrid = __esm({
17532
17542
  "components/molecules/DataGrid.tsx"() {
17533
17543
  "use client";
@@ -17542,6 +17552,17 @@ var init_DataGrid = __esm({
17542
17552
  init_Button();
17543
17553
  init_Icon();
17544
17554
  init_InfiniteScrollSentinel();
17555
+ BADGE_VARIANTS = /* @__PURE__ */ new Set([
17556
+ "default",
17557
+ "primary",
17558
+ "secondary",
17559
+ "success",
17560
+ "warning",
17561
+ "danger",
17562
+ "error",
17563
+ "info",
17564
+ "neutral"
17565
+ ]);
17545
17566
  gapStyles6 = {
17546
17567
  none: "gap-0",
17547
17568
  sm: "gap-2",
@@ -40600,30 +40621,76 @@ function useDeepAgentGeneration() {
40600
40621
 
40601
40622
  // hooks/index.ts
40602
40623
  init_useEventBus();
40603
- var DEFAULT_SLOTS = {
40604
- main: null,
40605
- sidebar: null,
40606
- modal: null,
40607
- drawer: null,
40608
- overlay: null,
40609
- center: null,
40610
- toast: null,
40611
- "hud-top": null,
40612
- "hud-bottom": null,
40613
- "hud-left": null,
40614
- "hud-right": null,
40615
- floating: null
40616
- };
40624
+ var DEFAULT_SOURCE_KEY = "__default__";
40625
+ var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
40626
+ var ALL_SLOTS2 = [
40627
+ "main",
40628
+ "sidebar",
40629
+ "modal",
40630
+ "drawer",
40631
+ "overlay",
40632
+ "center",
40633
+ "toast",
40634
+ "hud-top",
40635
+ "hud-bottom",
40636
+ "hud-left",
40637
+ "hud-right",
40638
+ "floating"
40639
+ ];
40640
+ var DEFAULT_SLOTS = ALL_SLOTS2.reduce(
40641
+ (acc, slot) => {
40642
+ acc[slot] = null;
40643
+ return acc;
40644
+ },
40645
+ {}
40646
+ );
40647
+ var DEFAULT_SOURCES = ALL_SLOTS2.reduce(
40648
+ (acc, slot) => {
40649
+ acc[slot] = {};
40650
+ return acc;
40651
+ },
40652
+ {}
40653
+ );
40617
40654
  var idCounter = 0;
40618
40655
  function generateId() {
40619
40656
  return `slot-content-${++idCounter}-${Date.now()}`;
40620
40657
  }
40658
+ function aggregateSlot(sources) {
40659
+ if (!sources) return null;
40660
+ const entries = Object.entries(sources);
40661
+ if (entries.length === 0) return null;
40662
+ if (entries.length === 1) return entries[0][1];
40663
+ const children = entries.map(([, entry]) => ({
40664
+ type: entry.pattern,
40665
+ ...entry.props
40666
+ }));
40667
+ const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
40668
+ return {
40669
+ id: stackId,
40670
+ pattern: "stack",
40671
+ props: {
40672
+ direction: "vertical",
40673
+ gap: "lg",
40674
+ children
40675
+ },
40676
+ priority: 0,
40677
+ animation: "fade",
40678
+ sourceTrait: MULTI_SOURCE_STACK_TRAIT
40679
+ };
40680
+ }
40621
40681
  function useUISlotManager() {
40622
- const [slots, setSlots] = useState(DEFAULT_SLOTS);
40682
+ const [sources, setSources] = useState(DEFAULT_SOURCES);
40623
40683
  const subscribersRef = useRef(/* @__PURE__ */ new Set());
40624
40684
  const timersRef = useRef(/* @__PURE__ */ new Map());
40625
40685
  const traitIndexRef = useRef(/* @__PURE__ */ new Map());
40626
40686
  const traitSubscribersRef = useRef(/* @__PURE__ */ new Map());
40687
+ const slots = useMemo(() => {
40688
+ const out = { ...DEFAULT_SLOTS };
40689
+ for (const slot of ALL_SLOTS2) {
40690
+ out[slot] = aggregateSlot(sources[slot]);
40691
+ }
40692
+ return out;
40693
+ }, [sources]);
40627
40694
  useEffect(() => {
40628
40695
  return () => {
40629
40696
  timersRef.current.forEach((timer) => clearTimeout(timer));
@@ -40662,103 +40729,160 @@ function useUISlotManager() {
40662
40729
  const unindexTrait = useCallback((traitName) => {
40663
40730
  traitIndexRef.current.delete(traitName);
40664
40731
  }, []);
40665
- const render = useCallback((config) => {
40666
- const id = generateId();
40667
- const content = {
40668
- id,
40669
- pattern: config.pattern,
40670
- props: config.props ?? {},
40671
- priority: config.priority ?? 0,
40672
- animation: config.animation ?? "fade",
40673
- onDismiss: config.onDismiss,
40674
- sourceTrait: config.sourceTrait
40675
- };
40676
- if (config.autoDismissMs && config.autoDismissMs > 0) {
40677
- content.autoDismissAt = Date.now() + config.autoDismissMs;
40678
- const timer = setTimeout(() => {
40679
- setSlots((prev) => {
40680
- if (prev[config.target]?.id === id) {
40681
- content.onDismiss?.();
40682
- notifySubscribers(config.target, null);
40683
- return { ...prev, [config.target]: null };
40684
- }
40732
+ const render = useCallback(
40733
+ (config) => {
40734
+ const id = generateId();
40735
+ const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
40736
+ const content = {
40737
+ id,
40738
+ pattern: config.pattern,
40739
+ props: config.props ?? {},
40740
+ priority: config.priority ?? 0,
40741
+ animation: config.animation ?? "fade",
40742
+ onDismiss: config.onDismiss,
40743
+ sourceTrait: config.sourceTrait
40744
+ };
40745
+ if (config.autoDismissMs && config.autoDismissMs > 0) {
40746
+ content.autoDismissAt = Date.now() + config.autoDismissMs;
40747
+ const timer = setTimeout(() => {
40748
+ setSources((prev) => {
40749
+ const slotSources = prev[config.target];
40750
+ if (slotSources && slotSources[sourceKey]?.id === id) {
40751
+ content.onDismiss?.();
40752
+ const next = { ...slotSources };
40753
+ delete next[sourceKey];
40754
+ const updated = { ...prev, [config.target]: next };
40755
+ notifySubscribers(config.target, aggregateSlot(next));
40756
+ return updated;
40757
+ }
40758
+ return prev;
40759
+ });
40760
+ timersRef.current.delete(id);
40761
+ }, config.autoDismissMs);
40762
+ timersRef.current.set(id, timer);
40763
+ }
40764
+ setSources((prev) => {
40765
+ const slotSources = prev[config.target] ?? {};
40766
+ const existing = slotSources[sourceKey];
40767
+ if (existing && existing.priority > content.priority) {
40768
+ console.warn(
40769
+ `[UISlots] Slot "${config.target}" source "${sourceKey}" already has higher priority content (${existing.priority} > ${content.priority})`
40770
+ );
40685
40771
  return prev;
40686
- });
40687
- timersRef.current.delete(id);
40688
- }, config.autoDismissMs);
40689
- timersRef.current.set(id, timer);
40690
- }
40691
- setSlots((prev) => {
40692
- const existing = prev[config.target];
40693
- if (existing && existing.priority > content.priority) {
40694
- console.warn(
40695
- `[UISlots] Slot "${config.target}" already has higher priority content (${existing.priority} > ${content.priority})`
40696
- );
40697
- return prev;
40698
- }
40699
- if (content.sourceTrait) {
40700
- indexTraitRender(content.sourceTrait, content);
40701
- notifyTraitSubscribers(content.sourceTrait, content);
40702
- }
40703
- notifySubscribers(config.target, content);
40704
- return { ...prev, [config.target]: content };
40705
- });
40706
- return id;
40707
- }, [notifySubscribers, notifyTraitSubscribers, indexTraitRender]);
40708
- const clear = useCallback((slot) => {
40709
- setSlots((prev) => {
40710
- const content = prev[slot];
40711
- if (content) {
40712
- const timer = timersRef.current.get(content.id);
40713
- if (timer) {
40714
- clearTimeout(timer);
40715
- timersRef.current.delete(content.id);
40716
40772
  }
40717
- content.onDismiss?.();
40773
+ const nextSources = {
40774
+ ...slotSources,
40775
+ [sourceKey]: content
40776
+ };
40777
+ const nextAll = { ...prev, [config.target]: nextSources };
40718
40778
  if (content.sourceTrait) {
40719
- unindexTrait(content.sourceTrait);
40720
- notifyTraitSubscribers(content.sourceTrait, null);
40779
+ indexTraitRender(content.sourceTrait, content);
40780
+ notifyTraitSubscribers(content.sourceTrait, content);
40781
+ }
40782
+ notifySubscribers(config.target, aggregateSlot(nextSources));
40783
+ return nextAll;
40784
+ });
40785
+ return id;
40786
+ },
40787
+ [notifySubscribers, notifyTraitSubscribers, indexTraitRender]
40788
+ );
40789
+ const clear = useCallback(
40790
+ (slot) => {
40791
+ setSources((prev) => {
40792
+ const slotSources = prev[slot];
40793
+ if (!slotSources || Object.keys(slotSources).length === 0) {
40794
+ return prev;
40795
+ }
40796
+ for (const content of Object.values(slotSources)) {
40797
+ const timer = timersRef.current.get(content.id);
40798
+ if (timer) {
40799
+ clearTimeout(timer);
40800
+ timersRef.current.delete(content.id);
40801
+ }
40802
+ content.onDismiss?.();
40803
+ if (content.sourceTrait) {
40804
+ unindexTrait(content.sourceTrait);
40805
+ notifyTraitSubscribers(content.sourceTrait, null);
40806
+ }
40721
40807
  }
40722
40808
  notifySubscribers(slot, null);
40723
- }
40724
- return { ...prev, [slot]: null };
40725
- });
40726
- }, [notifySubscribers, notifyTraitSubscribers, unindexTrait]);
40727
- const clearById = useCallback((id) => {
40728
- setSlots((prev) => {
40729
- const entry = Object.entries(prev).find(([, content]) => content?.id === id);
40730
- if (entry) {
40731
- const [slot, content] = entry;
40732
- const timer = timersRef.current.get(id);
40809
+ return { ...prev, [slot]: {} };
40810
+ });
40811
+ },
40812
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40813
+ );
40814
+ const clearBySource = useCallback(
40815
+ (slot, sourceTrait) => {
40816
+ const sourceKey = sourceTrait;
40817
+ setSources((prev) => {
40818
+ const slotSources = prev[slot];
40819
+ if (!slotSources || !(sourceKey in slotSources)) return prev;
40820
+ const content = slotSources[sourceKey];
40821
+ const timer = timersRef.current.get(content.id);
40733
40822
  if (timer) {
40734
40823
  clearTimeout(timer);
40735
- timersRef.current.delete(id);
40824
+ timersRef.current.delete(content.id);
40736
40825
  }
40737
40826
  content.onDismiss?.();
40738
40827
  if (content.sourceTrait) {
40739
40828
  unindexTrait(content.sourceTrait);
40740
40829
  notifyTraitSubscribers(content.sourceTrait, null);
40741
40830
  }
40742
- notifySubscribers(slot, null);
40743
- return { ...prev, [slot]: null };
40744
- }
40745
- return prev;
40746
- });
40747
- }, [notifySubscribers, notifyTraitSubscribers, unindexTrait]);
40831
+ const nextSources = { ...slotSources };
40832
+ delete nextSources[sourceKey];
40833
+ notifySubscribers(slot, aggregateSlot(nextSources));
40834
+ return { ...prev, [slot]: nextSources };
40835
+ });
40836
+ },
40837
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40838
+ );
40839
+ const clearById = useCallback(
40840
+ (id) => {
40841
+ setSources((prev) => {
40842
+ for (const slot of ALL_SLOTS2) {
40843
+ const slotSources = prev[slot];
40844
+ if (!slotSources) continue;
40845
+ const matchKey = Object.keys(slotSources).find(
40846
+ (k) => slotSources[k].id === id
40847
+ );
40848
+ if (!matchKey) continue;
40849
+ const content = slotSources[matchKey];
40850
+ const timer = timersRef.current.get(id);
40851
+ if (timer) {
40852
+ clearTimeout(timer);
40853
+ timersRef.current.delete(id);
40854
+ }
40855
+ content.onDismiss?.();
40856
+ if (content.sourceTrait) {
40857
+ unindexTrait(content.sourceTrait);
40858
+ notifyTraitSubscribers(content.sourceTrait, null);
40859
+ }
40860
+ const nextSources = { ...slotSources };
40861
+ delete nextSources[matchKey];
40862
+ notifySubscribers(slot, aggregateSlot(nextSources));
40863
+ return { ...prev, [slot]: nextSources };
40864
+ }
40865
+ return prev;
40866
+ });
40867
+ },
40868
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40869
+ );
40748
40870
  const clearAll = useCallback(() => {
40749
40871
  timersRef.current.forEach((timer) => clearTimeout(timer));
40750
40872
  timersRef.current.clear();
40751
- setSlots((prev) => {
40752
- Object.entries(prev).forEach(([slot, content]) => {
40753
- if (content) {
40873
+ setSources((prev) => {
40874
+ for (const slot of ALL_SLOTS2) {
40875
+ const slotSources = prev[slot];
40876
+ if (!slotSources) continue;
40877
+ for (const content of Object.values(slotSources)) {
40754
40878
  content.onDismiss?.();
40755
40879
  if (content.sourceTrait) {
40756
40880
  notifyTraitSubscribers(content.sourceTrait, null);
40757
40881
  }
40758
- notifySubscribers(slot, null);
40759
40882
  }
40760
- });
40761
- return DEFAULT_SLOTS;
40883
+ notifySubscribers(slot, null);
40884
+ }
40885
+ return DEFAULT_SOURCES;
40762
40886
  });
40763
40887
  traitIndexRef.current.clear();
40764
40888
  }, [notifySubscribers, notifyTraitSubscribers]);
@@ -40768,16 +40892,16 @@ function useUISlotManager() {
40768
40892
  subscribersRef.current.delete(callback);
40769
40893
  };
40770
40894
  }, []);
40771
- const hasContent = useCallback((slot) => {
40772
- return slots[slot] !== null;
40773
- }, [slots]);
40774
- const getContent = useCallback((slot) => {
40775
- return slots[slot];
40776
- }, [slots]);
40895
+ const hasContent = useCallback(
40896
+ (slot) => slots[slot] !== null,
40897
+ [slots]
40898
+ );
40899
+ const getContent = useCallback(
40900
+ (slot) => slots[slot],
40901
+ [slots]
40902
+ );
40777
40903
  const getTraitContent = useCallback(
40778
- (traitName) => {
40779
- return traitIndexRef.current.get(traitName) ?? null;
40780
- },
40904
+ (traitName) => traitIndexRef.current.get(traitName) ?? null,
40781
40905
  []
40782
40906
  );
40783
40907
  const subscribeTrait = useCallback(
@@ -40803,6 +40927,7 @@ function useUISlotManager() {
40803
40927
  slots,
40804
40928
  render,
40805
40929
  clear,
40930
+ clearBySource,
40806
40931
  clearById,
40807
40932
  clearAll,
40808
40933
  subscribe: subscribe2,
@@ -24,6 +24,16 @@ export interface DataGridField {
24
24
  variant?: 'h3' | 'h4' | 'body' | 'caption' | 'badge' | 'small' | 'progress';
25
25
  /** Optional format function name: 'date', 'currency', 'number', 'boolean' */
26
26
  format?: 'date' | 'currency' | 'number' | 'boolean' | 'percent';
27
+ /**
28
+ * Per-value color mapping for `variant: 'badge'`. Keys are exact field
29
+ * values; values are Badge variant names. Accepts the shadcn-style
30
+ * `destructive` alias and normalises it to `danger` at render time. When
31
+ * present, takes precedence over the built-in `statusVariant` heuristic.
32
+ *
33
+ * Example:
34
+ * colorMap: { active: 'success', pending: 'warning', failed: 'destructive' }
35
+ */
36
+ colorMap?: Record<string, string>;
27
37
  }
28
38
  export interface DataGridItemAction {
29
39
  /** Button label */