@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.
- package/conversation.d.ts +28 -0
- package/conversation.d.ts.map +1 -1
- package/hooks/index.d.ts +4 -1
- package/hooks/index.js +4 -1
- package/hooks/private/use-grouped-messages.d.ts.map +1 -1
- package/hooks/private/use-grouped-messages.js +3 -17
- package/hooks/private/use-grouped-messages.js.map +1 -1
- package/hooks/private/use-multimodal-input.d.ts.map +1 -1
- package/hooks/private/use-multimodal-input.js +16 -3
- package/hooks/private/use-multimodal-input.js.map +1 -1
- package/hooks/use-composer-refocus.js +1 -1
- package/hooks/use-composer-refocus.js.map +1 -1
- package/hooks/use-conversation-auto-seen.d.ts +1 -1
- package/hooks/use-conversation-auto-seen.js +30 -46
- package/hooks/use-conversation-auto-seen.js.map +1 -1
- package/hooks/use-conversation-seen.d.ts.map +1 -1
- package/hooks/use-conversation-seen.js +7 -3
- package/hooks/use-conversation-seen.js.map +1 -1
- package/hooks/use-new-message-sound.d.ts +23 -0
- package/hooks/use-new-message-sound.d.ts.map +1 -0
- package/hooks/use-new-message-sound.js +34 -0
- package/hooks/use-new-message-sound.js.map +1 -0
- package/hooks/use-sound-effect.d.ts +30 -0
- package/hooks/use-sound-effect.d.ts.map +1 -0
- package/hooks/use-sound-effect.js +104 -0
- package/hooks/use-sound-effect.js.map +1 -0
- package/hooks/use-typing-sound.d.ts +18 -0
- package/hooks/use-typing-sound.d.ts.map +1 -0
- package/hooks/use-typing-sound.js +38 -0
- package/hooks/use-typing-sound.js.map +1 -0
- package/index.d.ts +5 -2
- package/index.js +8 -6
- package/package.json +3 -3
- package/primitives/avatar/image.d.ts +1 -1
- package/primitives/bubble.js +1 -1
- package/primitives/index.d.ts +3 -5
- package/primitives/index.js +3 -9
- package/primitives/index.parts.d.ts +2 -4
- package/primitives/index.parts.js +2 -4
- package/primitives/router.d.ts +19 -20
- package/primitives/router.d.ts.map +1 -1
- package/primitives/router.js +17 -11
- package/primitives/router.js.map +1 -1
- package/realtime/index.js +1 -1
- package/realtime/provider.js +1 -1
- package/realtime-events.d.ts +83 -0
- package/realtime-events.d.ts.map +1 -1
- package/schemas3.d.ts +7 -0
- package/schemas3.d.ts.map +1 -1
- package/support/components/bubble.d.ts.map +1 -1
- package/support/components/bubble.js +27 -4
- package/support/components/bubble.js.map +1 -1
- package/support/components/button.d.ts +1 -1
- package/support/components/conversation-event.js +1 -1
- package/support/components/conversation-event.js.map +1 -1
- package/support/components/conversation-timeline.d.ts.map +1 -1
- package/support/components/conversation-timeline.js +5 -0
- package/support/components/conversation-timeline.js.map +1 -1
- package/support/components/multimodal-input.d.ts.map +1 -1
- package/support/components/multimodal-input.js +6 -2
- package/support/components/multimodal-input.js.map +1 -1
- package/support/components/support-content.d.ts +2 -0
- package/support/components/support-content.d.ts.map +1 -1
- package/support/components/support-content.js +5 -2
- package/support/components/support-content.js.map +1 -1
- package/support/components/timeline-message-group.js +2 -2
- package/support/components/timeline-message-group.js.map +1 -1
- package/support/components/timeline-message-item.js +2 -2
- package/support/components/timeline-message-item.js.map +1 -1
- package/support/index.d.ts +12 -7
- package/support/index.d.ts.map +1 -1
- package/support/index.js +28 -29
- package/support/index.js.map +1 -1
- package/support/pages/conversation.d.ts.map +1 -1
- package/support/pages/conversation.js +19 -1
- package/support/pages/conversation.js.map +1 -1
- package/support/router.d.ts +19 -9
- package/support/router.d.ts.map +1 -1
- package/support/router.js +31 -30
- package/support/router.js.map +1 -1
- package/timeline-item.d.ts +14 -0
- package/timeline-item.d.ts.map +1 -1
- package/utils/use-render-element.d.ts.map +1 -1
- package/primitives/page-registry.d.ts +0 -30
- package/primitives/page-registry.d.ts.map +0 -1
- package/primitives/page-registry.js +0 -45
- package/primitives/page-registry.js.map +0 -1
- package/primitives/page.d.ts +0 -21
- package/primitives/page.d.ts.map +0 -1
- package/primitives/page.js +0 -18
- 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,
|
|
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 {
|
|
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,
|
|
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.
|
|
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.
|
|
92
|
-
"@cossistant/types": "0.0.
|
|
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>, "
|
|
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;
|
package/primitives/bubble.js
CHANGED
|
@@ -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";
|
package/primitives/index.d.ts
CHANGED
|
@@ -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 {
|
|
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,
|
|
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,
|
|
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
|
package/primitives/index.js
CHANGED
|
@@ -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,
|
|
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 {
|
|
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,
|
|
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,
|
|
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 };
|
package/primitives/router.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
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":"
|
|
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"}
|
package/primitives/router.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import {
|
|
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
|
-
*
|
|
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
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
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
|
package/primitives/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","names":["Router: React.FC<RouterProps>"],"sources":["../../src/primitives/router.tsx"],"sourcesContent":["import type
|
|
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
|
|