@cossistant/react 0.0.20 → 0.0.23

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 (91) hide show
  1. package/conversation.d.ts +28 -0
  2. package/conversation.d.ts.map +1 -1
  3. package/hooks/index.d.ts +4 -1
  4. package/hooks/index.js +4 -1
  5. package/hooks/private/use-grouped-messages.d.ts.map +1 -1
  6. package/hooks/private/use-grouped-messages.js +3 -17
  7. package/hooks/private/use-grouped-messages.js.map +1 -1
  8. package/hooks/private/use-multimodal-input.d.ts.map +1 -1
  9. package/hooks/private/use-multimodal-input.js +16 -3
  10. package/hooks/private/use-multimodal-input.js.map +1 -1
  11. package/hooks/use-composer-refocus.js +1 -1
  12. package/hooks/use-composer-refocus.js.map +1 -1
  13. package/hooks/use-conversation-auto-seen.d.ts +1 -1
  14. package/hooks/use-conversation-auto-seen.js +30 -46
  15. package/hooks/use-conversation-auto-seen.js.map +1 -1
  16. package/hooks/use-conversation-seen.d.ts.map +1 -1
  17. package/hooks/use-conversation-seen.js +7 -3
  18. package/hooks/use-conversation-seen.js.map +1 -1
  19. package/hooks/use-new-message-sound.d.ts +23 -0
  20. package/hooks/use-new-message-sound.d.ts.map +1 -0
  21. package/hooks/use-new-message-sound.js +34 -0
  22. package/hooks/use-new-message-sound.js.map +1 -0
  23. package/hooks/use-sound-effect.d.ts +30 -0
  24. package/hooks/use-sound-effect.d.ts.map +1 -0
  25. package/hooks/use-sound-effect.js +104 -0
  26. package/hooks/use-sound-effect.js.map +1 -0
  27. package/hooks/use-typing-sound.d.ts +18 -0
  28. package/hooks/use-typing-sound.d.ts.map +1 -0
  29. package/hooks/use-typing-sound.js +38 -0
  30. package/hooks/use-typing-sound.js.map +1 -0
  31. package/index.d.ts +5 -2
  32. package/index.js +8 -6
  33. package/package.json +3 -3
  34. package/primitives/avatar/image.d.ts +1 -1
  35. package/primitives/bubble.js +1 -1
  36. package/primitives/index.d.ts +3 -5
  37. package/primitives/index.js +3 -9
  38. package/primitives/index.parts.d.ts +2 -4
  39. package/primitives/index.parts.js +2 -4
  40. package/primitives/router.d.ts +19 -20
  41. package/primitives/router.d.ts.map +1 -1
  42. package/primitives/router.js +17 -11
  43. package/primitives/router.js.map +1 -1
  44. package/realtime/index.js +1 -1
  45. package/realtime/provider.js +1 -1
  46. package/realtime-events.d.ts +83 -0
  47. package/realtime-events.d.ts.map +1 -1
  48. package/schemas3.d.ts +7 -0
  49. package/schemas3.d.ts.map +1 -1
  50. package/support/components/bubble.d.ts.map +1 -1
  51. package/support/components/bubble.js +27 -4
  52. package/support/components/bubble.js.map +1 -1
  53. package/support/components/button.d.ts +1 -1
  54. package/support/components/conversation-event.js +1 -1
  55. package/support/components/conversation-event.js.map +1 -1
  56. package/support/components/conversation-timeline.d.ts.map +1 -1
  57. package/support/components/conversation-timeline.js +5 -0
  58. package/support/components/conversation-timeline.js.map +1 -1
  59. package/support/components/multimodal-input.d.ts.map +1 -1
  60. package/support/components/multimodal-input.js +6 -2
  61. package/support/components/multimodal-input.js.map +1 -1
  62. package/support/components/support-content.d.ts +2 -0
  63. package/support/components/support-content.d.ts.map +1 -1
  64. package/support/components/support-content.js +5 -2
  65. package/support/components/support-content.js.map +1 -1
  66. package/support/components/timeline-message-group.js +2 -2
  67. package/support/components/timeline-message-group.js.map +1 -1
  68. package/support/components/timeline-message-item.js +2 -2
  69. package/support/components/timeline-message-item.js.map +1 -1
  70. package/support/index.d.ts +12 -7
  71. package/support/index.d.ts.map +1 -1
  72. package/support/index.js +28 -29
  73. package/support/index.js.map +1 -1
  74. package/support/pages/conversation.d.ts.map +1 -1
  75. package/support/pages/conversation.js +19 -1
  76. package/support/pages/conversation.js.map +1 -1
  77. package/support/router.d.ts +19 -9
  78. package/support/router.d.ts.map +1 -1
  79. package/support/router.js +31 -30
  80. package/support/router.js.map +1 -1
  81. package/timeline-item.d.ts +14 -0
  82. package/timeline-item.d.ts.map +1 -1
  83. package/utils/use-render-element.d.ts.map +1 -1
  84. package/primitives/page-registry.d.ts +0 -30
  85. package/primitives/page-registry.d.ts.map +0 -1
  86. package/primitives/page-registry.js +0 -45
  87. package/primitives/page-registry.js.map +0 -1
  88. package/primitives/page.d.ts +0 -21
  89. package/primitives/page.d.ts.map +0 -1
  90. package/primitives/page.js +0 -18
  91. package/primitives/page.js.map +0 -1
@@ -0,0 +1,34 @@
1
+ import { useSoundEffect } from "./use-sound-effect.js";
2
+ import { useCallback } from "react";
3
+
4
+ //#region src/hooks/use-new-message-sound.ts
5
+ const NEW_MESSAGE_SOUND_PATH = "/sounds/new-message.wav";
6
+ /**
7
+ * Hook to play a sound when a new message arrives.
8
+ *
9
+ * @param options - Optional configuration for volume and playback speed
10
+ * @returns Function to play the new message sound
11
+ *
12
+ * @example
13
+ * const playNewMessageSound = useNewMessageSound({ volume: 0.8, playbackRate: 1.1 });
14
+ *
15
+ * useEffect(() => {
16
+ * if (hasNewMessage) {
17
+ * playNewMessageSound();
18
+ * }
19
+ * }, [hasNewMessage]);
20
+ */
21
+ function useNewMessageSound(options) {
22
+ const { play } = useSoundEffect(NEW_MESSAGE_SOUND_PATH, {
23
+ loop: false,
24
+ volume: options?.volume ?? .7,
25
+ playbackRate: options?.playbackRate ?? 1
26
+ });
27
+ return useCallback(() => {
28
+ play();
29
+ }, [play]);
30
+ }
31
+
32
+ //#endregion
33
+ export { useNewMessageSound };
34
+ //# sourceMappingURL=use-new-message-sound.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-new-message-sound.js","names":[],"sources":["../../src/hooks/use-new-message-sound.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useSoundEffect } from \"./use-sound-effect\";\n\n// Use a path that can be served from public directory\nconst NEW_MESSAGE_SOUND_PATH = \"/sounds/new-message.wav\";\n\n/**\n * Hook to play a sound when a new message arrives.\n *\n * @param options - Optional configuration for volume and playback speed\n * @returns Function to play the new message sound\n *\n * @example\n * const playNewMessageSound = useNewMessageSound({ volume: 0.8, playbackRate: 1.1 });\n *\n * useEffect(() => {\n * if (hasNewMessage) {\n * playNewMessageSound();\n * }\n * }, [hasNewMessage]);\n */\nexport function useNewMessageSound(options?: {\n\tvolume?: number;\n\tplaybackRate?: number;\n}): () => void {\n\tconst { play } = useSoundEffect(NEW_MESSAGE_SOUND_PATH, {\n\t\tloop: false,\n\t\tvolume: options?.volume ?? 0.7,\n\t\tplaybackRate: options?.playbackRate ?? 1.0,\n\t});\n\n\treturn useCallback(() => {\n\t\tplay();\n\t}, [play]);\n}\n"],"mappings":";;;;AAIA,MAAM,yBAAyB;;;;;;;;;;;;;;;;AAiB/B,SAAgB,mBAAmB,SAGpB;CACd,MAAM,EAAE,SAAS,eAAe,wBAAwB;EACvD,MAAM;EACN,QAAQ,SAAS,UAAU;EAC3B,cAAc,SAAS,gBAAgB;EACvC,CAAC;AAEF,QAAO,kBAAkB;AACxB,QAAM;IACJ,CAAC,KAAK,CAAC"}
@@ -0,0 +1,30 @@
1
+ //#region src/hooks/use-sound-effect.d.ts
2
+ type UseSoundEffectOptions = {
3
+ loop?: boolean;
4
+ volume?: number;
5
+ playbackRate?: number;
6
+ };
7
+ type UseSoundEffectReturn = {
8
+ play: () => void;
9
+ stop: () => void;
10
+ isPlaying: boolean;
11
+ isLoading: boolean;
12
+ error: Error | null;
13
+ };
14
+ /**
15
+ * Hook to play sound effects using the Web Audio API.
16
+ *
17
+ * @param soundPath - Path to the sound file (relative to public directory or absolute URL)
18
+ * @param options - Configuration options for the sound
19
+ * @returns Object with play, stop functions and state
20
+ *
21
+ * @example
22
+ * const { play, stop, isPlaying } = useSoundEffect('/sounds/notification.wav', {
23
+ * loop: false,
24
+ * volume: 0.5
25
+ * });
26
+ */
27
+ declare function useSoundEffect(soundPath: string, options?: UseSoundEffectOptions): UseSoundEffectReturn;
28
+ //#endregion
29
+ export { UseSoundEffectOptions, UseSoundEffectReturn, useSoundEffect };
30
+ //# sourceMappingURL=use-sound-effect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sound-effect.d.ts","names":[],"sources":["../../src/hooks/use-sound-effect.ts"],"sourcesContent":[],"mappings":";KAEY,qBAAA;EAAA,IAAA,CAAA,EAAA,OAAA;EAMA,MAAA,CAAA,EAAA,MAAA;EAqBI,YAAA,CAAA,EAAA,MAAc;;KArBlB,oBAAA;;;;;SAKJ;;;;;;;;;;;;;;;iBAgBQ,cAAA,8BAEN,wBACP"}
@@ -0,0 +1,104 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+
3
+ //#region src/hooks/use-sound-effect.ts
4
+ /**
5
+ * Hook to play sound effects using the Web Audio API.
6
+ *
7
+ * @param soundPath - Path to the sound file (relative to public directory or absolute URL)
8
+ * @param options - Configuration options for the sound
9
+ * @returns Object with play, stop functions and state
10
+ *
11
+ * @example
12
+ * const { play, stop, isPlaying } = useSoundEffect('/sounds/notification.wav', {
13
+ * loop: false,
14
+ * volume: 0.5
15
+ * });
16
+ */
17
+ function useSoundEffect(soundPath, options = {}) {
18
+ const { loop = false, volume = 1, playbackRate = 1 } = options;
19
+ const [isPlaying, setIsPlaying] = useState(false);
20
+ const [isLoading, setIsLoading] = useState(true);
21
+ const [error, setError] = useState(null);
22
+ const audioContextRef = useRef(null);
23
+ const audioBufferRef = useRef(null);
24
+ const sourceNodeRef = useRef(null);
25
+ const gainNodeRef = useRef(null);
26
+ useEffect(() => {
27
+ let mounted = true;
28
+ const initAudio = async () => {
29
+ try {
30
+ if (!audioContextRef.current) audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
31
+ const response = await fetch(soundPath);
32
+ if (!response.ok) throw new Error(`Failed to load sound: ${response.statusText}`);
33
+ const arrayBuffer = await response.arrayBuffer();
34
+ const audioBuffer = await audioContextRef.current.decodeAudioData(arrayBuffer);
35
+ if (mounted) {
36
+ audioBufferRef.current = audioBuffer;
37
+ setIsLoading(false);
38
+ }
39
+ } catch (err) {
40
+ if (mounted) {
41
+ setError(err instanceof Error ? err : /* @__PURE__ */ new Error("Failed to load sound"));
42
+ setIsLoading(false);
43
+ }
44
+ }
45
+ };
46
+ initAudio();
47
+ return () => {
48
+ mounted = false;
49
+ };
50
+ }, [soundPath]);
51
+ const play = useCallback(() => {
52
+ const audioContext = audioContextRef.current;
53
+ const audioBuffer = audioBufferRef.current;
54
+ if (!(audioContext && audioBuffer && !isLoading && !error)) return;
55
+ if (sourceNodeRef.current) try {
56
+ sourceNodeRef.current.stop();
57
+ } catch {}
58
+ const source = audioContext.createBufferSource();
59
+ source.buffer = audioBuffer;
60
+ source.loop = loop;
61
+ source.playbackRate.value = playbackRate;
62
+ const gainNode = audioContext.createGain();
63
+ gainNode.gain.value = volume;
64
+ source.connect(gainNode);
65
+ gainNode.connect(audioContext.destination);
66
+ sourceNodeRef.current = source;
67
+ gainNodeRef.current = gainNode;
68
+ source.onended = () => {
69
+ if (!loop) setIsPlaying(false);
70
+ };
71
+ source.start(0);
72
+ setIsPlaying(true);
73
+ }, [
74
+ loop,
75
+ volume,
76
+ playbackRate,
77
+ isLoading,
78
+ error
79
+ ]);
80
+ const stop = useCallback(() => {
81
+ if (sourceNodeRef.current) {
82
+ try {
83
+ sourceNodeRef.current.stop();
84
+ sourceNodeRef.current.disconnect();
85
+ } catch {}
86
+ sourceNodeRef.current = null;
87
+ }
88
+ setIsPlaying(false);
89
+ }, []);
90
+ useEffect(() => () => {
91
+ stop();
92
+ }, [stop]);
93
+ return {
94
+ play,
95
+ stop,
96
+ isPlaying,
97
+ isLoading,
98
+ error
99
+ };
100
+ }
101
+
102
+ //#endregion
103
+ export { useSoundEffect };
104
+ //# sourceMappingURL=use-sound-effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sound-effect.js","names":[],"sources":["../../src/hooks/use-sound-effect.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport type UseSoundEffectOptions = {\n\tloop?: boolean;\n\tvolume?: number;\n\tplaybackRate?: number;\n};\n\nexport type UseSoundEffectReturn = {\n\tplay: () => void;\n\tstop: () => void;\n\tisPlaying: boolean;\n\tisLoading: boolean;\n\terror: Error | null;\n};\n\n/**\n * Hook to play sound effects using the Web Audio API.\n *\n * @param soundPath - Path to the sound file (relative to public directory or absolute URL)\n * @param options - Configuration options for the sound\n * @returns Object with play, stop functions and state\n *\n * @example\n * const { play, stop, isPlaying } = useSoundEffect('/sounds/notification.wav', {\n * loop: false,\n * volume: 0.5\n * });\n */\nexport function useSoundEffect(\n\tsoundPath: string,\n\toptions: UseSoundEffectOptions = {}\n): UseSoundEffectReturn {\n\tconst { loop = false, volume = 1.0, playbackRate = 1.0 } = options;\n\n\tconst [isPlaying, setIsPlaying] = useState(false);\n\tconst [isLoading, setIsLoading] = useState(true);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst audioContextRef = useRef<AudioContext | null>(null);\n\tconst audioBufferRef = useRef<AudioBuffer | null>(null);\n\tconst sourceNodeRef = useRef<AudioBufferSourceNode | null>(null);\n\tconst gainNodeRef = useRef<GainNode | null>(null);\n\n\t// Initialize audio context and load sound\n\tuseEffect(() => {\n\t\tlet mounted = true;\n\n\t\tconst initAudio = async () => {\n\t\t\ttry {\n\t\t\t\t// Create audio context if it doesn't exist\n\t\t\t\tif (!audioContextRef.current) {\n\t\t\t\t\taudioContextRef.current = new (\n\t\t\t\t\t\twindow.AudioContext ||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\twindow as typeof window & {\n\t\t\t\t\t\t\t\twebkitAudioContext?: typeof AudioContext;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t).webkitAudioContext\n\t\t\t\t\t)();\n\t\t\t\t}\n\n\t\t\t\t// Load the audio file\n\t\t\t\tconst response = await fetch(soundPath);\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`Failed to load sound: ${response.statusText}`);\n\t\t\t\t}\n\n\t\t\t\tconst arrayBuffer = await response.arrayBuffer();\n\t\t\t\tconst audioBuffer =\n\t\t\t\t\tawait audioContextRef.current.decodeAudioData(arrayBuffer);\n\n\t\t\t\tif (mounted) {\n\t\t\t\t\taudioBufferRef.current = audioBuffer;\n\t\t\t\t\tsetIsLoading(false);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tif (mounted) {\n\t\t\t\t\tsetError(\n\t\t\t\t\t\terr instanceof Error ? err : new Error(\"Failed to load sound\")\n\t\t\t\t\t);\n\t\t\t\t\tsetIsLoading(false);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tinitAudio();\n\n\t\treturn () => {\n\t\t\tmounted = false;\n\t\t};\n\t}, [soundPath]);\n\n\t// Play sound\n\tconst play = useCallback(() => {\n\t\tconst audioContext = audioContextRef.current;\n\t\tconst audioBuffer = audioBufferRef.current;\n\n\t\tconst canPlay = audioContext && audioBuffer && !isLoading && !error;\n\n\t\tif (!canPlay) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Stop any currently playing sound\n\t\tif (sourceNodeRef.current) {\n\t\t\ttry {\n\t\t\t\tsourceNodeRef.current.stop();\n\t\t\t} catch {\n\t\t\t\t// Ignore errors if already stopped\n\t\t\t}\n\t\t}\n\n\t\t// Create new source node\n\t\tconst source = audioContext.createBufferSource();\n\t\tsource.buffer = audioBuffer;\n\t\tsource.loop = loop;\n\t\tsource.playbackRate.value = playbackRate;\n\n\t\t// Create gain node for volume control\n\t\tconst gainNode = audioContext.createGain();\n\t\tgainNode.gain.value = volume;\n\n\t\t// Connect nodes: source -> gain -> destination\n\t\tsource.connect(gainNode);\n\t\tgainNode.connect(audioContext.destination);\n\n\t\t// Store references\n\t\tsourceNodeRef.current = source;\n\t\tgainNodeRef.current = gainNode;\n\n\t\t// Handle end event\n\t\tsource.onended = () => {\n\t\t\tif (!loop) {\n\t\t\t\tsetIsPlaying(false);\n\t\t\t}\n\t\t};\n\n\t\t// Start playback\n\t\tsource.start(0);\n\t\tsetIsPlaying(true);\n\t}, [loop, volume, playbackRate, isLoading, error]);\n\n\t// Stop sound\n\tconst stop = useCallback(() => {\n\t\tif (sourceNodeRef.current) {\n\t\t\ttry {\n\t\t\t\tsourceNodeRef.current.stop();\n\t\t\t\tsourceNodeRef.current.disconnect();\n\t\t\t} catch {\n\t\t\t\t// Ignore errors if already stopped\n\t\t\t}\n\t\t\tsourceNodeRef.current = null;\n\t\t}\n\t\tsetIsPlaying(false);\n\t}, []);\n\n\t// Cleanup on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tstop();\n\t\t},\n\t\t[stop]\n\t);\n\n\treturn {\n\t\tplay,\n\t\tstop,\n\t\tisPlaying,\n\t\tisLoading,\n\t\terror,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA6BA,SAAgB,eACf,WACA,UAAiC,EAAE,EACZ;CACvB,MAAM,EAAE,OAAO,OAAO,SAAS,GAAK,eAAe,MAAQ;CAE3D,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,kBAAkB,OAA4B,KAAK;CACzD,MAAM,iBAAiB,OAA2B,KAAK;CACvD,MAAM,gBAAgB,OAAqC,KAAK;CAChE,MAAM,cAAc,OAAwB,KAAK;AAGjD,iBAAgB;EACf,IAAI,UAAU;EAEd,MAAM,YAAY,YAAY;AAC7B,OAAI;AAEH,QAAI,CAAC,gBAAgB,QACpB,iBAAgB,UAAU,KACzB,OAAO,gBAEN,OAGC,qBACA;IAIJ,MAAM,WAAW,MAAM,MAAM,UAAU;AACvC,QAAI,CAAC,SAAS,GACb,OAAM,IAAI,MAAM,yBAAyB,SAAS,aAAa;IAGhE,MAAM,cAAc,MAAM,SAAS,aAAa;IAChD,MAAM,cACL,MAAM,gBAAgB,QAAQ,gBAAgB,YAAY;AAE3D,QAAI,SAAS;AACZ,oBAAe,UAAU;AACzB,kBAAa,MAAM;;YAEZ,KAAK;AACb,QAAI,SAAS;AACZ,cACC,eAAe,QAAQ,sBAAM,IAAI,MAAM,uBAAuB,CAC9D;AACD,kBAAa,MAAM;;;;AAKtB,aAAW;AAEX,eAAa;AACZ,aAAU;;IAET,CAAC,UAAU,CAAC;CAGf,MAAM,OAAO,kBAAkB;EAC9B,MAAM,eAAe,gBAAgB;EACrC,MAAM,cAAc,eAAe;AAInC,MAAI,EAFY,gBAAgB,eAAe,CAAC,aAAa,CAAC,OAG7D;AAID,MAAI,cAAc,QACjB,KAAI;AACH,iBAAc,QAAQ,MAAM;UACrB;EAMT,MAAM,SAAS,aAAa,oBAAoB;AAChD,SAAO,SAAS;AAChB,SAAO,OAAO;AACd,SAAO,aAAa,QAAQ;EAG5B,MAAM,WAAW,aAAa,YAAY;AAC1C,WAAS,KAAK,QAAQ;AAGtB,SAAO,QAAQ,SAAS;AACxB,WAAS,QAAQ,aAAa,YAAY;AAG1C,gBAAc,UAAU;AACxB,cAAY,UAAU;AAGtB,SAAO,gBAAgB;AACtB,OAAI,CAAC,KACJ,cAAa,MAAM;;AAKrB,SAAO,MAAM,EAAE;AACf,eAAa,KAAK;IAChB;EAAC;EAAM;EAAQ;EAAc;EAAW;EAAM,CAAC;CAGlD,MAAM,OAAO,kBAAkB;AAC9B,MAAI,cAAc,SAAS;AAC1B,OAAI;AACH,kBAAc,QAAQ,MAAM;AAC5B,kBAAc,QAAQ,YAAY;WAC3B;AAGR,iBAAc,UAAU;;AAEzB,eAAa,MAAM;IACjB,EAAE,CAAC;AAGN,uBACa;AACX,QAAM;IAEP,CAAC,KAAK,CACN;AAED,QAAO;EACN;EACA;EACA;EACA;EACA;EACA"}
@@ -0,0 +1,18 @@
1
+ //#region src/hooks/use-typing-sound.d.ts
2
+ /**
3
+ * Hook to play a looping typing sound while someone is typing.
4
+ *
5
+ * @param isTyping - Whether someone is currently typing
6
+ * @param options - Optional configuration for volume and playback speed
7
+ *
8
+ * @example
9
+ * const { isTyping } = useTypingIndicator();
10
+ * useTypingSound(isTyping, { volume: 1.0, playbackRate: 1.2 });
11
+ */
12
+ declare function useTypingSound(isTyping: boolean, options?: {
13
+ volume?: number;
14
+ playbackRate?: number;
15
+ }): void;
16
+ //#endregion
17
+ export { useTypingSound };
18
+ //# sourceMappingURL=use-typing-sound.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-typing-sound.d.ts","names":[],"sources":["../../src/hooks/use-typing-sound.ts"],"sourcesContent":[],"mappings":";;AAiBA;;;;;;;;;iBAAgB,cAAA"}
@@ -0,0 +1,38 @@
1
+ import { useSoundEffect } from "./use-sound-effect.js";
2
+ import { useEffect } from "react";
3
+
4
+ //#region src/hooks/use-typing-sound.ts
5
+ const TYPING_SOUND_PATH = "/sounds/typing-loop.wav";
6
+ /**
7
+ * Hook to play a looping typing sound while someone is typing.
8
+ *
9
+ * @param isTyping - Whether someone is currently typing
10
+ * @param options - Optional configuration for volume and playback speed
11
+ *
12
+ * @example
13
+ * const { isTyping } = useTypingIndicator();
14
+ * useTypingSound(isTyping, { volume: 1.0, playbackRate: 1.2 });
15
+ */
16
+ function useTypingSound(isTyping, options) {
17
+ const { play, stop, isPlaying } = useSoundEffect(TYPING_SOUND_PATH, {
18
+ loop: true,
19
+ volume: options?.volume ?? 1.2,
20
+ playbackRate: options?.playbackRate ?? 1
21
+ });
22
+ useEffect(() => {
23
+ if (isTyping && !isPlaying) play();
24
+ else if (!isTyping && isPlaying) stop();
25
+ }, [
26
+ isTyping,
27
+ isPlaying,
28
+ play,
29
+ stop
30
+ ]);
31
+ useEffect(() => () => {
32
+ stop();
33
+ }, [stop]);
34
+ }
35
+
36
+ //#endregion
37
+ export { useTypingSound };
38
+ //# sourceMappingURL=use-typing-sound.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-typing-sound.js","names":[],"sources":["../../src/hooks/use-typing-sound.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { useSoundEffect } from \"./use-sound-effect\";\n\n// Use a data URL or base64 encoded sound, or a CDN URL\n// For now, we'll use a path that can be served from public directory\nconst TYPING_SOUND_PATH = \"/sounds/typing-loop.wav\";\n\n/**\n * Hook to play a looping typing sound while someone is typing.\n *\n * @param isTyping - Whether someone is currently typing\n * @param options - Optional configuration for volume and playback speed\n *\n * @example\n * const { isTyping } = useTypingIndicator();\n * useTypingSound(isTyping, { volume: 1.0, playbackRate: 1.2 });\n */\nexport function useTypingSound(\n\tisTyping: boolean,\n\toptions?: { volume?: number; playbackRate?: number }\n): void {\n\tconst { play, stop, isPlaying } = useSoundEffect(TYPING_SOUND_PATH, {\n\t\tloop: true,\n\t\tvolume: options?.volume ?? 1.2,\n\t\tplaybackRate: options?.playbackRate ?? 1.0,\n\t});\n\n\tuseEffect(() => {\n\t\tif (isTyping && !isPlaying) {\n\t\t\tplay();\n\t\t} else if (!isTyping && isPlaying) {\n\t\t\tstop();\n\t\t}\n\t}, [isTyping, isPlaying, play, stop]);\n\n\t// Cleanup on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tstop();\n\t\t},\n\t\t[stop]\n\t);\n}\n"],"mappings":";;;;AAKA,MAAM,oBAAoB;;;;;;;;;;;AAY1B,SAAgB,eACf,UACA,SACO;CACP,MAAM,EAAE,MAAM,MAAM,cAAc,eAAe,mBAAmB;EACnE,MAAM;EACN,QAAQ,SAAS,UAAU;EAC3B,cAAc,SAAS,gBAAgB;EACvC,CAAC;AAEF,iBAAgB;AACf,MAAI,YAAY,CAAC,UAChB,OAAM;WACI,CAAC,YAAY,UACvB,OAAM;IAEL;EAAC;EAAU;EAAW;EAAM;EAAK,CAAC;AAGrC,uBACa;AACX,QAAM;IAEP,CAAC,KAAK,CACN"}
package/index.d.ts CHANGED
@@ -19,15 +19,17 @@ import { UseConversationsOptions, UseConversationsResult, useConversations } fro
19
19
  import { CreateConversationVariables, UseCreateConversationOptions, UseCreateConversationResult, useCreateConversation } from "./hooks/use-create-conversation.js";
20
20
  import { UseHomePageOptions, UseHomePageReturn, useHomePage } from "./hooks/use-home-page.js";
21
21
  import { UseMessageComposerOptions, UseMessageComposerReturn, useMessageComposer } from "./hooks/use-message-composer.js";
22
+ import { useNewMessageSound } from "./hooks/use-new-message-sound.js";
22
23
  import { UseRealtimeSupportOptions, UseRealtimeSupportResult, useRealtimeSupport } from "./hooks/use-realtime-support.js";
23
24
  import { UseScrollMaskOptions, UseScrollMaskReturn, useScrollMask } from "./hooks/use-scroll-mask.js";
24
25
  import { SendMessageOptions, SendMessageResult, UseSendMessageOptions, UseSendMessageResult, useSendMessage } from "./hooks/use-send-message.js";
26
+ import { UseSoundEffectOptions, UseSoundEffectReturn, useSoundEffect } from "./hooks/use-sound-effect.js";
27
+ import { useTypingSound } from "./hooks/use-typing-sound.js";
25
28
  import { UseVisitorReturn, useVisitor } from "./hooks/use-visitor.js";
26
29
  import { WindowVisibilityFocusState, useWindowVisibilityFocus } from "./hooks/use-window-visibility-focus.js";
27
30
  import "./hooks/index.js";
28
31
  import { IdentifySupportVisitor, IdentifySupportVisitorProps } from "./identify-visitor.js";
29
32
  import { SupportConfig, SupportConfigProps } from "./support-config.js";
30
- import { Page, PageProps } from "./primitives/page.js";
31
33
  import { index_d_exports } from "./primitives/index.js";
32
34
  import { CossistantContextValue, CossistantProviderProps, SupportContext, SupportProvider, SupportProviderProps, UseSupportValue, useSupport } from "./provider.js";
33
35
  import { RealtimeAuthConfig, RealtimeContextValue, RealtimeProvider, RealtimeProviderProps, useRealtimeConnection } from "./realtime/provider.js";
@@ -36,6 +38,7 @@ import { SupportRealtimeProvider } from "./realtime/support-provider.js";
36
38
  import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./realtime/typing-store.js";
37
39
  import { RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, useRealtime } from "./realtime/use-realtime.js";
38
40
  import "./realtime/index.js";
41
+ import { CustomPage } from "./support/router.js";
39
42
  import { Text, useSupportText } from "./support/text/index.js";
40
43
  import { BubbleSlotProps, ContainerSlotProps, RouterSlotProps } from "./support/types.js";
41
44
  import { CoButton } from "./support/components/button.js";
@@ -43,4 +46,4 @@ import { Header } from "./support/components/header.js";
43
46
  import { WebSocketContextValue, WebSocketProvider, useWebSocket } from "./support/context/websocket.js";
44
47
  import { useSupportConfig, useSupportNavigation, useSupportStore } from "./support/store/support-store.js";
45
48
  import { DefaultRoutes, NavigationState, RouteRegistry, Support, SupportPage, SupportProps } from "./support/index.js";
46
- export { BubbleSlotProps, CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, ContainerSlotProps, ConversationItem, ConversationLifecycleState, ConversationPreviewAssignedAgent, ConversationPreviewLastMessage, ConversationPreviewTypingParticipant, ConversationPreviewTypingState, ConversationTimelineTypingParticipant, ConversationTypingParticipant, CossistantContextValue, CossistantProviderProps, CreateConversationVariables, DefaultRoutes, GroupedMessage, Header, IdentifySupportVisitor, IdentifySupportVisitorProps, NavigationState, Page, PageProps, index_d_exports as Primitives, RealtimeAuthConfig, RealtimeContextValue, RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, RealtimeProvider, RealtimeProviderProps, RouteRegistry, RouterSlotProps, SendMessageOptions, SendMessageResult, Support, SupportConfig, SupportConfigProps, SupportContext, SupportLocale, SupportPage, SupportProps, SupportProvider, SupportProviderProps, SupportRealtimeProvider, SupportTextContentOverrides, Text, TimelineEventItem, TimelineToolItem, UseClientResult, UseComposerRefocusOptions, UseComposerRefocusReturn, UseConversationAutoSeenOptions, UseConversationHistoryPageOptions, UseConversationHistoryPageReturn, UseConversationLifecycleOptions, UseConversationLifecycleReturn, UseConversationOptions, UseConversationPageOptions, UseConversationPageReturn, UseConversationPreviewOptions, UseConversationPreviewReturn, UseConversationResult, UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, UseConversationTimelineOptions, UseConversationTimelineReturn, UseConversationsOptions, UseConversationsResult, UseCreateConversationOptions, UseCreateConversationResult, UseGroupedMessagesOptions, UseGroupedMessagesProps, UseHomePageOptions, UseHomePageReturn, UseMessageComposerOptions, UseMessageComposerReturn, UseMultimodalInputOptions, UseMultimodalInputReturn, UseRealtimeSupportOptions, UseRealtimeSupportResult, UseScrollMaskOptions, UseScrollMaskReturn, UseSendMessageOptions, UseSendMessageResult, UseSupportValue, UseVisitorReturn, WebSocketContextValue, WebSocketProvider, WindowVisibilityFocusState, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
49
+ export { BubbleSlotProps, CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, ContainerSlotProps, ConversationItem, ConversationLifecycleState, ConversationPreviewAssignedAgent, ConversationPreviewLastMessage, ConversationPreviewTypingParticipant, ConversationPreviewTypingState, ConversationTimelineTypingParticipant, ConversationTypingParticipant, CossistantContextValue, CossistantProviderProps, CreateConversationVariables, CustomPage, DefaultRoutes, GroupedMessage, Header, IdentifySupportVisitor, IdentifySupportVisitorProps, NavigationState, index_d_exports as Primitives, RealtimeAuthConfig, RealtimeContextValue, RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, RealtimeProvider, RealtimeProviderProps, RouteRegistry, RouterSlotProps, SendMessageOptions, SendMessageResult, Support, SupportConfig, SupportConfigProps, SupportContext, SupportLocale, SupportPage, SupportProps, SupportProvider, SupportProviderProps, SupportRealtimeProvider, SupportTextContentOverrides, Text, TimelineEventItem, TimelineToolItem, UseClientResult, UseComposerRefocusOptions, UseComposerRefocusReturn, UseConversationAutoSeenOptions, UseConversationHistoryPageOptions, UseConversationHistoryPageReturn, UseConversationLifecycleOptions, UseConversationLifecycleReturn, UseConversationOptions, UseConversationPageOptions, UseConversationPageReturn, UseConversationPreviewOptions, UseConversationPreviewReturn, UseConversationResult, UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, UseConversationTimelineOptions, UseConversationTimelineReturn, UseConversationsOptions, UseConversationsResult, UseCreateConversationOptions, UseCreateConversationResult, UseGroupedMessagesOptions, UseGroupedMessagesProps, UseHomePageOptions, UseHomePageReturn, UseMessageComposerOptions, UseMessageComposerReturn, UseMultimodalInputOptions, UseMultimodalInputReturn, UseRealtimeSupportOptions, UseRealtimeSupportResult, UseScrollMaskOptions, UseScrollMaskReturn, UseSendMessageOptions, UseSendMessageResult, UseSoundEffectOptions, UseSoundEffectReturn, UseSupportValue, UseVisitorReturn, WebSocketContextValue, WebSocketProvider, WindowVisibilityFocusState, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useNewMessageSound, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSoundEffect, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useTypingSound, useVisitor, useWebSocket, useWindowVisibilityFocus };
package/index.js CHANGED
@@ -1,15 +1,14 @@
1
1
  import { useClientQuery } from "./hooks/private/use-client-query.js";
2
2
  import { useClient } from "./hooks/private/use-rest-client.js";
3
3
  import { applyConversationSeenEvent, hydrateConversationSeen, upsertConversationSeen } from "./realtime/seen-store.js";
4
- import { SupportConfig } from "./support-config.js";
4
+ import { RealtimeProvider, useRealtimeConnection } from "./realtime/provider.js";
5
5
  import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./realtime/typing-store.js";
6
+ import { useRealtime } from "./realtime/use-realtime.js";
7
+ import { SupportRealtimeProvider } from "./realtime/support-provider.js";
8
+ import { SupportConfig } from "./support-config.js";
6
9
  import { useScrollMask } from "./hooks/use-scroll-mask.js";
7
- import { Page } from "./primitives/page.js";
8
10
  import { useSupportConfig, useSupportNavigation, useSupportStore } from "./support/store/support-store.js";
9
11
  import { primitives_exports } from "./primitives/index.js";
10
- import { RealtimeProvider, useRealtimeConnection } from "./realtime/provider.js";
11
- import { useRealtime } from "./realtime/use-realtime.js";
12
- import { SupportRealtimeProvider } from "./realtime/support-provider.js";
13
12
  import { CoButton } from "./support/components/button.js";
14
13
  import { Header } from "./support/components/header.js";
15
14
  import { Text, useSupportText } from "./support/text/index.js";
@@ -22,10 +21,13 @@ import { useMultimodalInput } from "./hooks/private/use-multimodal-input.js";
22
21
  import { useSendMessage } from "./hooks/use-send-message.js";
23
22
  import { useMessageComposer } from "./hooks/use-message-composer.js";
24
23
  import { useConversationPage } from "./hooks/use-conversation-page.js";
24
+ import { useSoundEffect } from "./hooks/use-sound-effect.js";
25
+ import { useNewMessageSound } from "./hooks/use-new-message-sound.js";
25
26
  import { useGroupedMessages } from "./hooks/private/use-grouped-messages.js";
26
27
  import { useConversationSeen, useDebouncedConversationSeen } from "./hooks/use-conversation-seen.js";
27
28
  import { useConversationTyping } from "./hooks/use-conversation-typing.js";
28
29
  import { useConversationTimeline } from "./hooks/use-conversation-timeline.js";
30
+ import { useTypingSound } from "./hooks/use-typing-sound.js";
29
31
  import { useComposerRefocus } from "./hooks/use-composer-refocus.js";
30
32
  import { useVisitor } from "./hooks/use-visitor.js";
31
33
  import { useConversations } from "./hooks/use-conversations.js";
@@ -40,4 +42,4 @@ import { useCreateConversation } from "./hooks/use-create-conversation.js";
40
42
  import { useRealtimeSupport } from "./hooks/use-realtime-support.js";
41
43
  import { IdentifySupportVisitor } from "./identify-visitor.js";
42
44
 
43
- export { CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, Header, IdentifySupportVisitor, Page, primitives_exports as Primitives, RealtimeProvider, Support, SupportConfig, SupportContext, SupportProvider, SupportRealtimeProvider, Text, WebSocketProvider, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
45
+ export { CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, Header, IdentifySupportVisitor, primitives_exports as Primitives, RealtimeProvider, Support, SupportConfig, SupportContext, SupportProvider, SupportRealtimeProvider, Text, WebSocketProvider, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useNewMessageSound, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSoundEffect, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useTypingSound, useVisitor, useWebSocket, useWindowVisibilityFocus };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cossistant/react",
3
3
  "type": "module",
4
- "version": "0.0.20",
4
+ "version": "0.0.23",
5
5
  "private": false,
6
6
  "author": "Cossistant team",
7
7
  "description": "Headless React SDK for building AI-powered support/chat widgets. Hooks + primitives, WS-driven, TypeScript-first. Next.js-ready, Tailwind optional.",
@@ -88,8 +88,8 @@
88
88
  "*.css"
89
89
  ],
90
90
  "dependencies": {
91
- "@cossistant/core": "0.0.20",
92
- "@cossistant/types": "0.0.20",
91
+ "@cossistant/core": "0.0.23",
92
+ "@cossistant/types": "0.0.23",
93
93
  "class-variance-authority": "^0.7.1",
94
94
  "clsx": "^2.1.1",
95
95
  "nanoid": "^5.1.5",
@@ -15,7 +15,7 @@ type AvatarImageProps = Omit<React$1.ImgHTMLAttributes<HTMLImageElement>, "src"
15
15
  * Controlled `<img>` that syncs its loading status back to the avatar context
16
16
  * so fallbacks know when to display.
17
17
  */
18
- declare const AvatarImage: React$1.ForwardRefExoticComponent<Omit<React$1.ImgHTMLAttributes<HTMLImageElement>, "src" | "alt"> & {
18
+ declare const AvatarImage: React$1.ForwardRefExoticComponent<Omit<React$1.ImgHTMLAttributes<HTMLImageElement>, "alt" | "src"> & {
19
19
  src: string;
20
20
  alt?: string;
21
21
  asChild?: boolean;
@@ -1,5 +1,5 @@
1
- import { useRenderElement } from "../utils/use-render-element.js";
2
1
  import { useTypingStore } from "../realtime/typing-store.js";
2
+ import { useRenderElement } from "../utils/use-render-element.js";
3
3
  import { useSupportConfig } from "../support/store/support-store.js";
4
4
  import { useSupport } from "../provider.js";
5
5
  import * as React$1 from "react";
@@ -7,9 +7,7 @@ import { SupportBubble } from "./bubble.js";
7
7
  import { Button } from "./button.js";
8
8
  import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
9
9
  import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
10
- import { Page, PageProps } from "./page.js";
11
- import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
12
- import { Router, RouterProps } from "./router.js";
10
+ import { PageDefinition, Router, RouterProps } from "./router.js";
13
11
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
14
12
  import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
15
13
  import { SupportWindow } from "./window.js";
@@ -17,8 +15,8 @@ import "./index.parts.js";
17
15
 
18
16
  //#region src/primitives/index.d.ts
19
17
  declare namespace index_d_exports {
20
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageProps, PageRegistryProvider, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, usePageRegistry, useRegisterPage };
18
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, PageDefinition, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window };
21
19
  }
22
20
  //#endregion
23
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageProps, PageRegistryProvider, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, index_d_exports, usePageRegistry, useRegisterPage };
21
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, PageDefinition, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, index_d_exports };
24
22
  //# sourceMappingURL=index.d.ts.map
@@ -1,15 +1,13 @@
1
1
  import { __export } from "../_virtual/rolldown_runtime.js";
2
+ import { SupportConfig } from "../support-config.js";
2
3
  import { Avatar } from "./avatar/avatar.js";
3
4
  import { AvatarFallback } from "./avatar/fallback.js";
4
5
  import { AvatarImage } from "./avatar/image.js";
5
6
  import { TypingIndicator } from "../support/components/typing-indicator.js";
6
- import { SupportConfig } from "../support-config.js";
7
7
  import { SupportBubble } from "./bubble.js";
8
8
  import { Button } from "./button.js";
9
9
  import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
10
10
  import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
11
- import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
12
- import { Page } from "./page.js";
13
11
  import { Router } from "./router.js";
14
12
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
15
13
  import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
@@ -30,8 +28,6 @@ var primitives_exports = /* @__PURE__ */ __export({
30
28
  FileInput: () => FileInput,
31
29
  Input: () => SupportInput,
32
30
  MultimodalInput: () => MultimodalInput,
33
- Page: () => Page,
34
- PageRegistryProvider: () => PageRegistryProvider,
35
31
  Router: () => Router,
36
32
  TimelineItem: () => TimelineItem,
37
33
  TimelineItemContent: () => TimelineItemContent,
@@ -43,11 +39,9 @@ var primitives_exports = /* @__PURE__ */ __export({
43
39
  TimelineItemGroupSeenIndicator: () => TimelineItemGroupSeenIndicator,
44
40
  TimelineItemTimestamp: () => TimelineItemTimestamp,
45
41
  TypingIndicator: () => TypingIndicator,
46
- Window: () => SupportWindow,
47
- usePageRegistry: () => usePageRegistry,
48
- useRegisterPage: () => useRegisterPage
42
+ Window: () => SupportWindow
49
43
  });
50
44
 
51
45
  //#endregion
52
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageRegistryProvider, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, primitives_exports, usePageRegistry, useRegisterPage };
46
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, primitives_exports };
53
47
  //# sourceMappingURL=index.js.map
@@ -8,10 +8,8 @@ import { SupportBubble } from "./bubble.js";
8
8
  import { Button } from "./button.js";
9
9
  import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
10
10
  import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
11
- import { Page, PageProps } from "./page.js";
12
- import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
13
- import { Router, RouterProps } from "./router.js";
11
+ import { PageDefinition, Router, RouterProps } from "./router.js";
14
12
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
15
13
  import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
16
14
  import { SupportWindow } from "./window.js";
17
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, type PageProps, PageRegistryProvider, Router, type RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType, SupportWindow as Window, usePageRegistry, useRegisterPage };
15
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, type PageDefinition, Router, type RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType, SupportWindow as Window };
@@ -1,17 +1,15 @@
1
+ import { SupportConfig } from "../support-config.js";
1
2
  import { Avatar } from "./avatar/avatar.js";
2
3
  import { AvatarFallback } from "./avatar/fallback.js";
3
4
  import { AvatarImage } from "./avatar/image.js";
4
5
  import { TypingIndicator } from "../support/components/typing-indicator.js";
5
- import { SupportConfig } from "../support-config.js";
6
6
  import { SupportBubble } from "./bubble.js";
7
7
  import { Button } from "./button.js";
8
8
  import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
9
9
  import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
10
- import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
11
- import { Page } from "./page.js";
12
10
  import { Router } from "./router.js";
13
11
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
14
12
  import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
15
13
  import { SupportWindow } from "./window.js";
16
14
 
17
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageRegistryProvider, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, usePageRegistry, useRegisterPage };
15
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window };
@@ -1,35 +1,34 @@
1
1
  import React from "react";
2
+ import { RouteRegistry } from "@cossistant/core";
2
3
 
3
4
  //#region src/primitives/router.d.ts
5
+ type PageDefinition<K extends keyof RouteRegistry = keyof RouteRegistry> = {
6
+ name: K;
7
+ component: React.ComponentType<{
8
+ params?: RouteRegistry[K];
9
+ }>;
10
+ };
4
11
  type RouterProps = {
5
- /**
6
- * Current page name to render
7
- */
8
- page: string;
9
- /**
10
- * Params to pass to the page component
11
- */
12
- params?: unknown;
13
- /**
14
- * Fallback component when page is not found
15
- */
12
+ page: keyof RouteRegistry;
13
+ params?: RouteRegistry[keyof RouteRegistry];
14
+ pages: PageDefinition[];
16
15
  fallback?: React.ComponentType<{
17
16
  params?: unknown;
18
17
  }>;
19
- /**
20
- * Children (Page components for registration)
21
- */
22
- children?: React.ReactNode;
23
18
  };
24
19
  /**
25
- * Router that renders registered pages based on current page name.
20
+ * Type-safe router that renders pages based on current page name.
21
+ * Pages are matched synchronously without effects or registries.
26
22
  *
27
23
  * @example
28
- * <Router page={currentPage} params={params} fallback={NotFoundPage}>
29
- * <Page name="HOME" component={HomePage} />
30
- * </Router>
24
+ * const pages = [
25
+ * { name: "HOME", component: HomePage },
26
+ * { name: "SETTINGS", component: SettingsPage }
27
+ * ];
28
+ *
29
+ * <Router page={currentPage} params={params} pages={pages} fallback={NotFoundPage} />
31
30
  */
32
31
  declare const Router: React.FC<RouterProps>;
33
32
  //#endregion
34
- export { Router, RouterProps };
33
+ export { PageDefinition, Router, RouterProps };
35
34
  //# sourceMappingURL=router.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","names":[],"sources":["../../src/primitives/router.tsx"],"sourcesContent":[],"mappings":";;;KAGY,WAAA;;AAAZ;AA8BA;;;;;;;;;aAhBY,KAAA,CAAM;;;;;;aAKN,KAAA,CAAM;;;;;;;;;;cAWL,QAAQ,KAAA,CAAM,GAAG"}
1
+ {"version":3,"file":"router.d.ts","names":[],"sources":["../../src/primitives/router.tsx"],"sourcesContent":[],"mappings":";;;;KAIY,+BACK,sBAAsB;QAEhC;EAHK,SAAA,EAIA,KAAA,CAAM,aAJQ,CAAA;IACT,MAAA,CAAA,EAG0B,aAH1B,CAGwC,CAHxC,CAAA;EAAsB,CAAA,CAAA;CAEhC;AACoC,KAI/B,WAAA,GAJ+B;EAAc,IAAA,EAAA,MAK5C,aAL4C;EAA7C,MAAM,CAAA,EAMR,aANQ,CAAA,MAMY,aANZ,CAAA;EAAa,KAAA,EAOvB,cAPuB,EAAA;EAInB,QAAA,CAAA,EAIA,KAAA,CAAM,aAJK,CAAA;IACV,MAAA,CAAA,EAAA,OAAA;EACH,CAAA,CAAA;CAAoB;;;;AAiB9B;;;;;;;;;cAAa,QAAQ,KAAA,CAAM,GAAG"}
@@ -1,20 +1,26 @@
1
- import { usePageRegistry } from "./page-registry.js";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1
+ import { jsx } from "react/jsx-runtime";
3
2
 
4
3
  //#region src/primitives/router.tsx
5
4
  /**
6
- * Router that renders registered pages based on current page name.
5
+ * Type-safe router that renders pages based on current page name.
6
+ * Pages are matched synchronously without effects or registries.
7
7
  *
8
8
  * @example
9
- * <Router page={currentPage} params={params} fallback={NotFoundPage}>
10
- * <Page name="HOME" component={HomePage} />
11
- * </Router>
9
+ * const pages = [
10
+ * { name: "HOME", component: HomePage },
11
+ * { name: "SETTINGS", component: SettingsPage }
12
+ * ];
13
+ *
14
+ * <Router page={currentPage} params={params} pages={pages} fallback={NotFoundPage} />
12
15
  */
13
- const Router = ({ page, params, fallback: Fallback, children }) => {
14
- const PageComponent = usePageRegistry().get(page);
15
- if (PageComponent) return /* @__PURE__ */ jsxs(Fragment, { children: [children, /* @__PURE__ */ jsx(PageComponent, { params })] });
16
- if (Fallback) return /* @__PURE__ */ jsxs(Fragment, { children: [children, /* @__PURE__ */ jsx(Fallback, { params })] });
17
- return /* @__PURE__ */ jsx(Fragment, { children });
16
+ const Router = ({ page, params, pages, fallback: Fallback }) => {
17
+ const matchedPage = pages.find((p) => p.name === page);
18
+ if (matchedPage) {
19
+ const Component = matchedPage.component;
20
+ return /* @__PURE__ */ jsx(Component, { params });
21
+ }
22
+ if (Fallback) return /* @__PURE__ */ jsx(Fallback, { params });
23
+ return null;
18
24
  };
19
25
 
20
26
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","names":["Router: React.FC<RouterProps>"],"sources":["../../src/primitives/router.tsx"],"sourcesContent":["import type React from \"react\";\nimport { usePageRegistry } from \"./page-registry\";\n\nexport type RouterProps = {\n\t/**\n\t * Current page name to render\n\t */\n\tpage: string;\n\n\t/**\n\t * Params to pass to the page component\n\t */\n\tparams?: unknown;\n\n\t/**\n\t * Fallback component when page is not found\n\t */\n\tfallback?: React.ComponentType<{ params?: unknown }>;\n\n\t/**\n\t * Children (Page components for registration)\n\t */\n\tchildren?: React.ReactNode;\n};\n\n/**\n * Router that renders registered pages based on current page name.\n *\n * @example\n * <Router page={currentPage} params={params} fallback={NotFoundPage}>\n * <Page name=\"HOME\" component={HomePage} />\n * </Router>\n */\nexport const Router: React.FC<RouterProps> = ({\n\tpage,\n\tparams,\n\tfallback: Fallback,\n\tchildren,\n}) => {\n\tconst registry = usePageRegistry();\n\n\t// Render children first (they register pages via useEffect)\n\t// Page components return null, so this is effectively a no-op render\n\n\t// Get the page component from registry\n\tconst PageComponent = registry.get(page);\n\n\tif (PageComponent) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{children}\n\t\t\t\t<PageComponent params={params} />\n\t\t\t</>\n\t\t);\n\t}\n\n\t// Fall back if provided\n\tif (Fallback) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{children}\n\t\t\t\t<Fallback params={params} />\n\t\t\t</>\n\t\t);\n\t}\n\n\treturn <>{children}</>;\n};\n"],"mappings":";;;;;;;;;;;;AAiCA,MAAaA,UAAiC,EAC7C,MACA,QACA,UAAU,UACV,eACK;CAOL,MAAM,gBANW,iBAAiB,CAMH,IAAI,KAAK;AAExC,KAAI,cACH,QACC,4CACE,UACD,oBAAC,iBAAsB,SAAU,IAC/B;AAKL,KAAI,SACH,QACC,4CACE,UACD,oBAAC,YAAiB,SAAU,IAC1B;AAIL,QAAO,gCAAG,WAAY"}
1
+ {"version":3,"file":"router.js","names":["Router: React.FC<RouterProps>"],"sources":["../../src/primitives/router.tsx"],"sourcesContent":["import type { RouteRegistry } from \"@cossistant/core\";\nimport type React from \"react\";\n\n// Type-safe page definition that extracts params from RouteRegistry\nexport type PageDefinition<\n\tK extends keyof RouteRegistry = keyof RouteRegistry,\n> = {\n\tname: K;\n\tcomponent: React.ComponentType<{ params?: RouteRegistry[K] }>;\n};\n\n// Router props that maintain type safety\nexport type RouterProps = {\n\tpage: keyof RouteRegistry;\n\tparams?: RouteRegistry[keyof RouteRegistry];\n\tpages: PageDefinition[];\n\tfallback?: React.ComponentType<{ params?: unknown }>;\n};\n\n/**\n * Type-safe router that renders pages based on current page name.\n * Pages are matched synchronously without effects or registries.\n *\n * @example\n * const pages = [\n * { name: \"HOME\", component: HomePage },\n * { name: \"SETTINGS\", component: SettingsPage }\n * ];\n *\n * <Router page={currentPage} params={params} pages={pages} fallback={NotFoundPage} />\n */\nexport const Router: React.FC<RouterProps> = ({\n\tpage,\n\tparams,\n\tpages,\n\tfallback: Fallback,\n}) => {\n\t// Find matching page (synchronous, no effects!)\n\tconst matchedPage = pages.find((p) => p.name === page);\n\n\tif (matchedPage) {\n\t\tconst Component = matchedPage.component;\n\t\treturn <Component params={params} />;\n\t}\n\n\t// Fall back if provided\n\tif (Fallback) {\n\t\treturn <Fallback params={params} />;\n\t}\n\n\treturn null;\n};\n"],"mappings":";;;;;;;;;;;;;;;AA+BA,MAAaA,UAAiC,EAC7C,MACA,QACA,OACA,UAAU,eACL;CAEL,MAAM,cAAc,MAAM,MAAM,MAAM,EAAE,SAAS,KAAK;AAEtD,KAAI,aAAa;EAChB,MAAM,YAAY,YAAY;AAC9B,SAAO,oBAAC,aAAkB,SAAU;;AAIrC,KAAI,SACH,QAAO,oBAAC,YAAiB,SAAU;AAGpC,QAAO"}
package/realtime/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { applyConversationSeenEvent, hydrateConversationSeen, upsertConversationSeen } from "./seen-store.js";
2
- import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./typing-store.js";
3
2
  import { RealtimeProvider, useRealtimeConnection } from "./provider.js";
3
+ import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./typing-store.js";
4
4
  import { useRealtime } from "./use-realtime.js";
5
5
  import { SupportRealtimeProvider } from "./support-provider.js";
6
6