@almadar/ui 4.0.1 → 4.1.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.
@@ -40645,30 +40645,76 @@ function useDeepAgentGeneration() {
40645
40645
 
40646
40646
  // hooks/index.ts
40647
40647
  init_useEventBus();
40648
- var DEFAULT_SLOTS = {
40649
- main: null,
40650
- sidebar: null,
40651
- modal: null,
40652
- drawer: null,
40653
- overlay: null,
40654
- center: null,
40655
- toast: null,
40656
- "hud-top": null,
40657
- "hud-bottom": null,
40658
- "hud-left": null,
40659
- "hud-right": null,
40660
- floating: null
40661
- };
40648
+ var DEFAULT_SOURCE_KEY = "__default__";
40649
+ var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
40650
+ var ALL_SLOTS2 = [
40651
+ "main",
40652
+ "sidebar",
40653
+ "modal",
40654
+ "drawer",
40655
+ "overlay",
40656
+ "center",
40657
+ "toast",
40658
+ "hud-top",
40659
+ "hud-bottom",
40660
+ "hud-left",
40661
+ "hud-right",
40662
+ "floating"
40663
+ ];
40664
+ var DEFAULT_SLOTS = ALL_SLOTS2.reduce(
40665
+ (acc, slot) => {
40666
+ acc[slot] = null;
40667
+ return acc;
40668
+ },
40669
+ {}
40670
+ );
40671
+ var DEFAULT_SOURCES = ALL_SLOTS2.reduce(
40672
+ (acc, slot) => {
40673
+ acc[slot] = {};
40674
+ return acc;
40675
+ },
40676
+ {}
40677
+ );
40662
40678
  var idCounter = 0;
40663
40679
  function generateId() {
40664
40680
  return `slot-content-${++idCounter}-${Date.now()}`;
40665
40681
  }
40682
+ function aggregateSlot(sources) {
40683
+ if (!sources) return null;
40684
+ const entries = Object.entries(sources);
40685
+ if (entries.length === 0) return null;
40686
+ if (entries.length === 1) return entries[0][1];
40687
+ const children = entries.map(([, entry]) => ({
40688
+ type: entry.pattern,
40689
+ ...entry.props
40690
+ }));
40691
+ const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
40692
+ return {
40693
+ id: stackId,
40694
+ pattern: "stack",
40695
+ props: {
40696
+ direction: "vertical",
40697
+ gap: "lg",
40698
+ children
40699
+ },
40700
+ priority: 0,
40701
+ animation: "fade",
40702
+ sourceTrait: MULTI_SOURCE_STACK_TRAIT
40703
+ };
40704
+ }
40666
40705
  function useUISlotManager() {
40667
- const [slots, setSlots] = React110.useState(DEFAULT_SLOTS);
40706
+ const [sources, setSources] = React110.useState(DEFAULT_SOURCES);
40668
40707
  const subscribersRef = React110.useRef(/* @__PURE__ */ new Set());
40669
40708
  const timersRef = React110.useRef(/* @__PURE__ */ new Map());
40670
40709
  const traitIndexRef = React110.useRef(/* @__PURE__ */ new Map());
40671
40710
  const traitSubscribersRef = React110.useRef(/* @__PURE__ */ new Map());
40711
+ const slots = React110.useMemo(() => {
40712
+ const out = { ...DEFAULT_SLOTS };
40713
+ for (const slot of ALL_SLOTS2) {
40714
+ out[slot] = aggregateSlot(sources[slot]);
40715
+ }
40716
+ return out;
40717
+ }, [sources]);
40672
40718
  React110.useEffect(() => {
40673
40719
  return () => {
40674
40720
  timersRef.current.forEach((timer) => clearTimeout(timer));
@@ -40707,103 +40753,160 @@ function useUISlotManager() {
40707
40753
  const unindexTrait = React110.useCallback((traitName) => {
40708
40754
  traitIndexRef.current.delete(traitName);
40709
40755
  }, []);
40710
- const render = React110.useCallback((config) => {
40711
- const id = generateId();
40712
- const content = {
40713
- id,
40714
- pattern: config.pattern,
40715
- props: config.props ?? {},
40716
- priority: config.priority ?? 0,
40717
- animation: config.animation ?? "fade",
40718
- onDismiss: config.onDismiss,
40719
- sourceTrait: config.sourceTrait
40720
- };
40721
- if (config.autoDismissMs && config.autoDismissMs > 0) {
40722
- content.autoDismissAt = Date.now() + config.autoDismissMs;
40723
- const timer = setTimeout(() => {
40724
- setSlots((prev) => {
40725
- if (prev[config.target]?.id === id) {
40726
- content.onDismiss?.();
40727
- notifySubscribers(config.target, null);
40728
- return { ...prev, [config.target]: null };
40729
- }
40756
+ const render = React110.useCallback(
40757
+ (config) => {
40758
+ const id = generateId();
40759
+ const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
40760
+ const content = {
40761
+ id,
40762
+ pattern: config.pattern,
40763
+ props: config.props ?? {},
40764
+ priority: config.priority ?? 0,
40765
+ animation: config.animation ?? "fade",
40766
+ onDismiss: config.onDismiss,
40767
+ sourceTrait: config.sourceTrait
40768
+ };
40769
+ if (config.autoDismissMs && config.autoDismissMs > 0) {
40770
+ content.autoDismissAt = Date.now() + config.autoDismissMs;
40771
+ const timer = setTimeout(() => {
40772
+ setSources((prev) => {
40773
+ const slotSources = prev[config.target];
40774
+ if (slotSources && slotSources[sourceKey]?.id === id) {
40775
+ content.onDismiss?.();
40776
+ const next = { ...slotSources };
40777
+ delete next[sourceKey];
40778
+ const updated = { ...prev, [config.target]: next };
40779
+ notifySubscribers(config.target, aggregateSlot(next));
40780
+ return updated;
40781
+ }
40782
+ return prev;
40783
+ });
40784
+ timersRef.current.delete(id);
40785
+ }, config.autoDismissMs);
40786
+ timersRef.current.set(id, timer);
40787
+ }
40788
+ setSources((prev) => {
40789
+ const slotSources = prev[config.target] ?? {};
40790
+ const existing = slotSources[sourceKey];
40791
+ if (existing && existing.priority > content.priority) {
40792
+ console.warn(
40793
+ `[UISlots] Slot "${config.target}" source "${sourceKey}" already has higher priority content (${existing.priority} > ${content.priority})`
40794
+ );
40730
40795
  return prev;
40731
- });
40732
- timersRef.current.delete(id);
40733
- }, config.autoDismissMs);
40734
- timersRef.current.set(id, timer);
40735
- }
40736
- setSlots((prev) => {
40737
- const existing = prev[config.target];
40738
- if (existing && existing.priority > content.priority) {
40739
- console.warn(
40740
- `[UISlots] Slot "${config.target}" already has higher priority content (${existing.priority} > ${content.priority})`
40741
- );
40742
- return prev;
40743
- }
40744
- if (content.sourceTrait) {
40745
- indexTraitRender(content.sourceTrait, content);
40746
- notifyTraitSubscribers(content.sourceTrait, content);
40747
- }
40748
- notifySubscribers(config.target, content);
40749
- return { ...prev, [config.target]: content };
40750
- });
40751
- return id;
40752
- }, [notifySubscribers, notifyTraitSubscribers, indexTraitRender]);
40753
- const clear = React110.useCallback((slot) => {
40754
- setSlots((prev) => {
40755
- const content = prev[slot];
40756
- if (content) {
40757
- const timer = timersRef.current.get(content.id);
40758
- if (timer) {
40759
- clearTimeout(timer);
40760
- timersRef.current.delete(content.id);
40761
40796
  }
40762
- content.onDismiss?.();
40797
+ const nextSources = {
40798
+ ...slotSources,
40799
+ [sourceKey]: content
40800
+ };
40801
+ const nextAll = { ...prev, [config.target]: nextSources };
40763
40802
  if (content.sourceTrait) {
40764
- unindexTrait(content.sourceTrait);
40765
- notifyTraitSubscribers(content.sourceTrait, null);
40803
+ indexTraitRender(content.sourceTrait, content);
40804
+ notifyTraitSubscribers(content.sourceTrait, content);
40805
+ }
40806
+ notifySubscribers(config.target, aggregateSlot(nextSources));
40807
+ return nextAll;
40808
+ });
40809
+ return id;
40810
+ },
40811
+ [notifySubscribers, notifyTraitSubscribers, indexTraitRender]
40812
+ );
40813
+ const clear = React110.useCallback(
40814
+ (slot) => {
40815
+ setSources((prev) => {
40816
+ const slotSources = prev[slot];
40817
+ if (!slotSources || Object.keys(slotSources).length === 0) {
40818
+ return prev;
40819
+ }
40820
+ for (const content of Object.values(slotSources)) {
40821
+ const timer = timersRef.current.get(content.id);
40822
+ if (timer) {
40823
+ clearTimeout(timer);
40824
+ timersRef.current.delete(content.id);
40825
+ }
40826
+ content.onDismiss?.();
40827
+ if (content.sourceTrait) {
40828
+ unindexTrait(content.sourceTrait);
40829
+ notifyTraitSubscribers(content.sourceTrait, null);
40830
+ }
40766
40831
  }
40767
40832
  notifySubscribers(slot, null);
40768
- }
40769
- return { ...prev, [slot]: null };
40770
- });
40771
- }, [notifySubscribers, notifyTraitSubscribers, unindexTrait]);
40772
- const clearById = React110.useCallback((id) => {
40773
- setSlots((prev) => {
40774
- const entry = Object.entries(prev).find(([, content]) => content?.id === id);
40775
- if (entry) {
40776
- const [slot, content] = entry;
40777
- const timer = timersRef.current.get(id);
40833
+ return { ...prev, [slot]: {} };
40834
+ });
40835
+ },
40836
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40837
+ );
40838
+ const clearBySource = React110.useCallback(
40839
+ (slot, sourceTrait) => {
40840
+ const sourceKey = sourceTrait;
40841
+ setSources((prev) => {
40842
+ const slotSources = prev[slot];
40843
+ if (!slotSources || !(sourceKey in slotSources)) return prev;
40844
+ const content = slotSources[sourceKey];
40845
+ const timer = timersRef.current.get(content.id);
40778
40846
  if (timer) {
40779
40847
  clearTimeout(timer);
40780
- timersRef.current.delete(id);
40848
+ timersRef.current.delete(content.id);
40781
40849
  }
40782
40850
  content.onDismiss?.();
40783
40851
  if (content.sourceTrait) {
40784
40852
  unindexTrait(content.sourceTrait);
40785
40853
  notifyTraitSubscribers(content.sourceTrait, null);
40786
40854
  }
40787
- notifySubscribers(slot, null);
40788
- return { ...prev, [slot]: null };
40789
- }
40790
- return prev;
40791
- });
40792
- }, [notifySubscribers, notifyTraitSubscribers, unindexTrait]);
40855
+ const nextSources = { ...slotSources };
40856
+ delete nextSources[sourceKey];
40857
+ notifySubscribers(slot, aggregateSlot(nextSources));
40858
+ return { ...prev, [slot]: nextSources };
40859
+ });
40860
+ },
40861
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40862
+ );
40863
+ const clearById = React110.useCallback(
40864
+ (id) => {
40865
+ setSources((prev) => {
40866
+ for (const slot of ALL_SLOTS2) {
40867
+ const slotSources = prev[slot];
40868
+ if (!slotSources) continue;
40869
+ const matchKey = Object.keys(slotSources).find(
40870
+ (k) => slotSources[k].id === id
40871
+ );
40872
+ if (!matchKey) continue;
40873
+ const content = slotSources[matchKey];
40874
+ const timer = timersRef.current.get(id);
40875
+ if (timer) {
40876
+ clearTimeout(timer);
40877
+ timersRef.current.delete(id);
40878
+ }
40879
+ content.onDismiss?.();
40880
+ if (content.sourceTrait) {
40881
+ unindexTrait(content.sourceTrait);
40882
+ notifyTraitSubscribers(content.sourceTrait, null);
40883
+ }
40884
+ const nextSources = { ...slotSources };
40885
+ delete nextSources[matchKey];
40886
+ notifySubscribers(slot, aggregateSlot(nextSources));
40887
+ return { ...prev, [slot]: nextSources };
40888
+ }
40889
+ return prev;
40890
+ });
40891
+ },
40892
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40893
+ );
40793
40894
  const clearAll = React110.useCallback(() => {
40794
40895
  timersRef.current.forEach((timer) => clearTimeout(timer));
40795
40896
  timersRef.current.clear();
40796
- setSlots((prev) => {
40797
- Object.entries(prev).forEach(([slot, content]) => {
40798
- if (content) {
40897
+ setSources((prev) => {
40898
+ for (const slot of ALL_SLOTS2) {
40899
+ const slotSources = prev[slot];
40900
+ if (!slotSources) continue;
40901
+ for (const content of Object.values(slotSources)) {
40799
40902
  content.onDismiss?.();
40800
40903
  if (content.sourceTrait) {
40801
40904
  notifyTraitSubscribers(content.sourceTrait, null);
40802
40905
  }
40803
- notifySubscribers(slot, null);
40804
40906
  }
40805
- });
40806
- return DEFAULT_SLOTS;
40907
+ notifySubscribers(slot, null);
40908
+ }
40909
+ return DEFAULT_SOURCES;
40807
40910
  });
40808
40911
  traitIndexRef.current.clear();
40809
40912
  }, [notifySubscribers, notifyTraitSubscribers]);
@@ -40813,16 +40916,16 @@ function useUISlotManager() {
40813
40916
  subscribersRef.current.delete(callback);
40814
40917
  };
40815
40918
  }, []);
40816
- const hasContent = React110.useCallback((slot) => {
40817
- return slots[slot] !== null;
40818
- }, [slots]);
40819
- const getContent = React110.useCallback((slot) => {
40820
- return slots[slot];
40821
- }, [slots]);
40919
+ const hasContent = React110.useCallback(
40920
+ (slot) => slots[slot] !== null,
40921
+ [slots]
40922
+ );
40923
+ const getContent = React110.useCallback(
40924
+ (slot) => slots[slot],
40925
+ [slots]
40926
+ );
40822
40927
  const getTraitContent = React110.useCallback(
40823
- (traitName) => {
40824
- return traitIndexRef.current.get(traitName) ?? null;
40825
- },
40928
+ (traitName) => traitIndexRef.current.get(traitName) ?? null,
40826
40929
  []
40827
40930
  );
40828
40931
  const subscribeTrait = React110.useCallback(
@@ -40848,6 +40951,7 @@ function useUISlotManager() {
40848
40951
  slots,
40849
40952
  render,
40850
40953
  clear,
40954
+ clearBySource,
40851
40955
  clearById,
40852
40956
  clearAll,
40853
40957
  subscribe: subscribe2,