@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.
@@ -40600,30 +40600,76 @@ function useDeepAgentGeneration() {
40600
40600
 
40601
40601
  // hooks/index.ts
40602
40602
  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
- };
40603
+ var DEFAULT_SOURCE_KEY = "__default__";
40604
+ var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
40605
+ var ALL_SLOTS2 = [
40606
+ "main",
40607
+ "sidebar",
40608
+ "modal",
40609
+ "drawer",
40610
+ "overlay",
40611
+ "center",
40612
+ "toast",
40613
+ "hud-top",
40614
+ "hud-bottom",
40615
+ "hud-left",
40616
+ "hud-right",
40617
+ "floating"
40618
+ ];
40619
+ var DEFAULT_SLOTS = ALL_SLOTS2.reduce(
40620
+ (acc, slot) => {
40621
+ acc[slot] = null;
40622
+ return acc;
40623
+ },
40624
+ {}
40625
+ );
40626
+ var DEFAULT_SOURCES = ALL_SLOTS2.reduce(
40627
+ (acc, slot) => {
40628
+ acc[slot] = {};
40629
+ return acc;
40630
+ },
40631
+ {}
40632
+ );
40617
40633
  var idCounter = 0;
40618
40634
  function generateId() {
40619
40635
  return `slot-content-${++idCounter}-${Date.now()}`;
40620
40636
  }
40637
+ function aggregateSlot(sources) {
40638
+ if (!sources) return null;
40639
+ const entries = Object.entries(sources);
40640
+ if (entries.length === 0) return null;
40641
+ if (entries.length === 1) return entries[0][1];
40642
+ const children = entries.map(([, entry]) => ({
40643
+ type: entry.pattern,
40644
+ ...entry.props
40645
+ }));
40646
+ const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
40647
+ return {
40648
+ id: stackId,
40649
+ pattern: "stack",
40650
+ props: {
40651
+ direction: "vertical",
40652
+ gap: "lg",
40653
+ children
40654
+ },
40655
+ priority: 0,
40656
+ animation: "fade",
40657
+ sourceTrait: MULTI_SOURCE_STACK_TRAIT
40658
+ };
40659
+ }
40621
40660
  function useUISlotManager() {
40622
- const [slots, setSlots] = useState(DEFAULT_SLOTS);
40661
+ const [sources, setSources] = useState(DEFAULT_SOURCES);
40623
40662
  const subscribersRef = useRef(/* @__PURE__ */ new Set());
40624
40663
  const timersRef = useRef(/* @__PURE__ */ new Map());
40625
40664
  const traitIndexRef = useRef(/* @__PURE__ */ new Map());
40626
40665
  const traitSubscribersRef = useRef(/* @__PURE__ */ new Map());
40666
+ const slots = useMemo(() => {
40667
+ const out = { ...DEFAULT_SLOTS };
40668
+ for (const slot of ALL_SLOTS2) {
40669
+ out[slot] = aggregateSlot(sources[slot]);
40670
+ }
40671
+ return out;
40672
+ }, [sources]);
40627
40673
  useEffect(() => {
40628
40674
  return () => {
40629
40675
  timersRef.current.forEach((timer) => clearTimeout(timer));
@@ -40662,103 +40708,160 @@ function useUISlotManager() {
40662
40708
  const unindexTrait = useCallback((traitName) => {
40663
40709
  traitIndexRef.current.delete(traitName);
40664
40710
  }, []);
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
- }
40711
+ const render = useCallback(
40712
+ (config) => {
40713
+ const id = generateId();
40714
+ const sourceKey = config.sourceTrait ?? DEFAULT_SOURCE_KEY;
40715
+ const content = {
40716
+ id,
40717
+ pattern: config.pattern,
40718
+ props: config.props ?? {},
40719
+ priority: config.priority ?? 0,
40720
+ animation: config.animation ?? "fade",
40721
+ onDismiss: config.onDismiss,
40722
+ sourceTrait: config.sourceTrait
40723
+ };
40724
+ if (config.autoDismissMs && config.autoDismissMs > 0) {
40725
+ content.autoDismissAt = Date.now() + config.autoDismissMs;
40726
+ const timer = setTimeout(() => {
40727
+ setSources((prev) => {
40728
+ const slotSources = prev[config.target];
40729
+ if (slotSources && slotSources[sourceKey]?.id === id) {
40730
+ content.onDismiss?.();
40731
+ const next = { ...slotSources };
40732
+ delete next[sourceKey];
40733
+ const updated = { ...prev, [config.target]: next };
40734
+ notifySubscribers(config.target, aggregateSlot(next));
40735
+ return updated;
40736
+ }
40737
+ return prev;
40738
+ });
40739
+ timersRef.current.delete(id);
40740
+ }, config.autoDismissMs);
40741
+ timersRef.current.set(id, timer);
40742
+ }
40743
+ setSources((prev) => {
40744
+ const slotSources = prev[config.target] ?? {};
40745
+ const existing = slotSources[sourceKey];
40746
+ if (existing && existing.priority > content.priority) {
40747
+ console.warn(
40748
+ `[UISlots] Slot "${config.target}" source "${sourceKey}" already has higher priority content (${existing.priority} > ${content.priority})`
40749
+ );
40685
40750
  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
40751
  }
40717
- content.onDismiss?.();
40752
+ const nextSources = {
40753
+ ...slotSources,
40754
+ [sourceKey]: content
40755
+ };
40756
+ const nextAll = { ...prev, [config.target]: nextSources };
40718
40757
  if (content.sourceTrait) {
40719
- unindexTrait(content.sourceTrait);
40720
- notifyTraitSubscribers(content.sourceTrait, null);
40758
+ indexTraitRender(content.sourceTrait, content);
40759
+ notifyTraitSubscribers(content.sourceTrait, content);
40760
+ }
40761
+ notifySubscribers(config.target, aggregateSlot(nextSources));
40762
+ return nextAll;
40763
+ });
40764
+ return id;
40765
+ },
40766
+ [notifySubscribers, notifyTraitSubscribers, indexTraitRender]
40767
+ );
40768
+ const clear = useCallback(
40769
+ (slot) => {
40770
+ setSources((prev) => {
40771
+ const slotSources = prev[slot];
40772
+ if (!slotSources || Object.keys(slotSources).length === 0) {
40773
+ return prev;
40774
+ }
40775
+ for (const content of Object.values(slotSources)) {
40776
+ const timer = timersRef.current.get(content.id);
40777
+ if (timer) {
40778
+ clearTimeout(timer);
40779
+ timersRef.current.delete(content.id);
40780
+ }
40781
+ content.onDismiss?.();
40782
+ if (content.sourceTrait) {
40783
+ unindexTrait(content.sourceTrait);
40784
+ notifyTraitSubscribers(content.sourceTrait, null);
40785
+ }
40721
40786
  }
40722
40787
  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);
40788
+ return { ...prev, [slot]: {} };
40789
+ });
40790
+ },
40791
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40792
+ );
40793
+ const clearBySource = useCallback(
40794
+ (slot, sourceTrait) => {
40795
+ const sourceKey = sourceTrait;
40796
+ setSources((prev) => {
40797
+ const slotSources = prev[slot];
40798
+ if (!slotSources || !(sourceKey in slotSources)) return prev;
40799
+ const content = slotSources[sourceKey];
40800
+ const timer = timersRef.current.get(content.id);
40733
40801
  if (timer) {
40734
40802
  clearTimeout(timer);
40735
- timersRef.current.delete(id);
40803
+ timersRef.current.delete(content.id);
40736
40804
  }
40737
40805
  content.onDismiss?.();
40738
40806
  if (content.sourceTrait) {
40739
40807
  unindexTrait(content.sourceTrait);
40740
40808
  notifyTraitSubscribers(content.sourceTrait, null);
40741
40809
  }
40742
- notifySubscribers(slot, null);
40743
- return { ...prev, [slot]: null };
40744
- }
40745
- return prev;
40746
- });
40747
- }, [notifySubscribers, notifyTraitSubscribers, unindexTrait]);
40810
+ const nextSources = { ...slotSources };
40811
+ delete nextSources[sourceKey];
40812
+ notifySubscribers(slot, aggregateSlot(nextSources));
40813
+ return { ...prev, [slot]: nextSources };
40814
+ });
40815
+ },
40816
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40817
+ );
40818
+ const clearById = useCallback(
40819
+ (id) => {
40820
+ setSources((prev) => {
40821
+ for (const slot of ALL_SLOTS2) {
40822
+ const slotSources = prev[slot];
40823
+ if (!slotSources) continue;
40824
+ const matchKey = Object.keys(slotSources).find(
40825
+ (k) => slotSources[k].id === id
40826
+ );
40827
+ if (!matchKey) continue;
40828
+ const content = slotSources[matchKey];
40829
+ const timer = timersRef.current.get(id);
40830
+ if (timer) {
40831
+ clearTimeout(timer);
40832
+ timersRef.current.delete(id);
40833
+ }
40834
+ content.onDismiss?.();
40835
+ if (content.sourceTrait) {
40836
+ unindexTrait(content.sourceTrait);
40837
+ notifyTraitSubscribers(content.sourceTrait, null);
40838
+ }
40839
+ const nextSources = { ...slotSources };
40840
+ delete nextSources[matchKey];
40841
+ notifySubscribers(slot, aggregateSlot(nextSources));
40842
+ return { ...prev, [slot]: nextSources };
40843
+ }
40844
+ return prev;
40845
+ });
40846
+ },
40847
+ [notifySubscribers, notifyTraitSubscribers, unindexTrait]
40848
+ );
40748
40849
  const clearAll = useCallback(() => {
40749
40850
  timersRef.current.forEach((timer) => clearTimeout(timer));
40750
40851
  timersRef.current.clear();
40751
- setSlots((prev) => {
40752
- Object.entries(prev).forEach(([slot, content]) => {
40753
- if (content) {
40852
+ setSources((prev) => {
40853
+ for (const slot of ALL_SLOTS2) {
40854
+ const slotSources = prev[slot];
40855
+ if (!slotSources) continue;
40856
+ for (const content of Object.values(slotSources)) {
40754
40857
  content.onDismiss?.();
40755
40858
  if (content.sourceTrait) {
40756
40859
  notifyTraitSubscribers(content.sourceTrait, null);
40757
40860
  }
40758
- notifySubscribers(slot, null);
40759
40861
  }
40760
- });
40761
- return DEFAULT_SLOTS;
40862
+ notifySubscribers(slot, null);
40863
+ }
40864
+ return DEFAULT_SOURCES;
40762
40865
  });
40763
40866
  traitIndexRef.current.clear();
40764
40867
  }, [notifySubscribers, notifyTraitSubscribers]);
@@ -40768,16 +40871,16 @@ function useUISlotManager() {
40768
40871
  subscribersRef.current.delete(callback);
40769
40872
  };
40770
40873
  }, []);
40771
- const hasContent = useCallback((slot) => {
40772
- return slots[slot] !== null;
40773
- }, [slots]);
40774
- const getContent = useCallback((slot) => {
40775
- return slots[slot];
40776
- }, [slots]);
40874
+ const hasContent = useCallback(
40875
+ (slot) => slots[slot] !== null,
40876
+ [slots]
40877
+ );
40878
+ const getContent = useCallback(
40879
+ (slot) => slots[slot],
40880
+ [slots]
40881
+ );
40777
40882
  const getTraitContent = useCallback(
40778
- (traitName) => {
40779
- return traitIndexRef.current.get(traitName) ?? null;
40780
- },
40883
+ (traitName) => traitIndexRef.current.get(traitName) ?? null,
40781
40884
  []
40782
40885
  );
40783
40886
  const subscribeTrait = useCallback(
@@ -40803,6 +40906,7 @@ function useUISlotManager() {
40803
40906
  slots,
40804
40907
  render,
40805
40908
  clear,
40909
+ clearBySource,
40806
40910
  clearById,
40807
40911
  clearAll,
40808
40912
  subscribe: subscribe2,