flikkui 0.2.0-beta.2 → 0.2.0-beta.4
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/dist/components/ai/PromptInput/PromptInput.js +23 -15
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.d.ts +27 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.js +62 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.d.ts +10 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.js +12 -0
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.types.d.ts +53 -0
- package/dist/components/ai/PromptSuggestions/index.d.ts +4 -2
- package/dist/components/ai/index.d.ts +2 -12
- package/dist/components/charts/ActivityRings/ActivityRings.js +70 -58
- package/dist/components/charts/ActivityRings/ActivityRings.theme.js +0 -1
- package/dist/components/charts/ActivityRings/ActivityRings.types.d.ts +17 -0
- package/dist/components/charts/BarChart/BarChart.js +8 -4
- package/dist/components/charts/BarChart/BarChart.types.d.ts +14 -0
- package/dist/components/charts/DonutChart/DonutChart.js +11 -8
- package/dist/components/charts/DonutChart/DonutChart.theme.d.ts +3 -0
- package/dist/components/charts/DonutChart/DonutChart.theme.js +5 -4
- package/dist/components/charts/DonutChart/donut-utils.d.ts +5 -0
- package/dist/components/charts/DonutChart/donut-utils.js +26 -1
- package/dist/components/charts/Heatmap/Heatmap.theme.js +2 -2
- package/dist/components/charts/shared/ChartAxis/XAxis.d.ts +2 -2
- package/dist/components/charts/shared/ChartAxis/XAxis.js +4 -4
- package/dist/components/charts/shared/ChartAxis/YAxis.d.ts +2 -2
- package/dist/components/charts/shared/ChartAxis/YAxis.js +8 -7
- package/dist/components/charts/shared/ChartGrid/HorizontalGrid.d.ts +1 -1
- package/dist/components/charts/shared/ChartGrid/HorizontalGrid.js +2 -2
- package/dist/components/charts/theme/chart.theme.d.ts +1 -1
- package/dist/components/charts/theme/chart.theme.js +39 -39
- package/dist/components/core/Accordion/Accordion.d.ts +1 -1
- package/dist/components/core/Accordion/Accordion.js +2 -2
- package/dist/components/core/Accordion/Accordion.types.d.ts +8 -0
- package/dist/components/core/Badge/Badge.js +11 -15
- package/dist/components/core/Badge/Badge.theme.js +7 -21
- package/dist/components/core/Badge/Badge.types.d.ts +9 -1
- package/dist/components/core/Button/Button.js +2 -2
- package/dist/components/core/Button/Button.theme.js +1 -1
- package/dist/components/core/Button/Button.types.d.ts +8 -0
- package/dist/components/core/Card/Card.js +8 -2
- package/dist/components/core/Card/Card.theme.js +1 -1
- package/dist/components/core/Card/Card.types.d.ts +24 -1
- package/dist/components/core/Drawer/Drawer.d.ts +1 -1
- package/dist/components/core/Drawer/Drawer.js +10 -40
- package/dist/components/core/Drawer/Drawer.theme.js +2 -1
- package/dist/components/core/Drawer/Drawer.types.d.ts +8 -0
- package/dist/components/core/Dropdown/Dropdown.d.ts +1 -1
- package/dist/components/core/Dropdown/Dropdown.js +2 -2
- package/dist/components/core/Dropdown/Dropdown.types.d.ts +8 -0
- package/dist/components/core/Metric/Metric.d.ts +1 -1
- package/dist/components/core/Metric/Metric.js +9 -5
- package/dist/components/core/Metric/Metric.theme.d.ts +1 -1
- package/dist/components/core/Metric/Metric.theme.js +38 -28
- package/dist/components/core/Metric/Metric.types.d.ts +27 -8
- package/dist/components/core/Modal/Modal.d.ts +1 -1
- package/dist/components/core/Modal/Modal.js +17 -40
- package/dist/components/core/Modal/Modal.theme.js +8 -3
- package/dist/components/core/Modal/Modal.types.d.ts +18 -0
- package/dist/components/core/Modal/index.d.ts +1 -1
- package/dist/components/core/Notification/Notification.js +2 -0
- package/dist/components/core/Pill/Pill.d.ts +6 -11
- package/dist/components/core/Pill/Pill.theme.d.ts +2 -2
- package/dist/components/core/Pill/Pill.types.d.ts +9 -22
- package/dist/components/core/Pill/index.d.ts +1 -1
- package/dist/components/core/Popover/Popover.d.ts +1 -1
- package/dist/components/core/Popover/Popover.js +2 -2
- package/dist/components/core/Popover/Popover.types.d.ts +8 -0
- package/dist/components/core/Progress/Progress.d.ts +28 -0
- package/dist/components/core/Progress/Progress.js +114 -0
- package/dist/components/core/Progress/Progress.theme.d.ts +5 -0
- package/dist/components/core/Progress/Progress.theme.js +33 -0
- package/dist/components/core/Progress/Progress.types.d.ts +92 -0
- package/dist/components/core/Progress/index.d.ts +2 -0
- package/dist/components/core/Tabs/Tabs.js +2 -2
- package/dist/components/core/Tabs/Tabs.types.d.ts +8 -0
- package/dist/components/core/Tag/Tag.animations.d.ts +3 -0
- package/dist/components/core/Tag/Tag.animations.js +31 -0
- package/dist/components/core/Tag/Tag.d.ts +14 -0
- package/dist/components/core/Tag/Tag.js +45 -0
- package/dist/components/core/Tag/Tag.theme.d.ts +2 -0
- package/dist/components/core/Tag/Tag.theme.js +21 -0
- package/dist/components/core/Tag/Tag.types.d.ts +40 -0
- package/dist/components/core/Tag/index.d.ts +3 -0
- package/dist/components/core/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/core/Tooltip/Tooltip.js +3 -3
- package/dist/components/core/Tooltip/Tooltip.theme.js +1 -1
- package/dist/components/core/Tooltip/Tooltip.types.d.ts +17 -0
- package/dist/components/core/index.d.ts +2 -1
- package/dist/components/core/index.js +3 -2
- package/dist/components/effects/CustomCursor/CustomCursor.d.ts +0 -13
- package/dist/components/effects/CustomCursor/CustomCursor.js +26 -2
- package/dist/components/effects/CustomCursor/CustomCursor.theme.js +12 -1
- package/dist/components/effects/CustomCursor/CustomCursor.types.d.ts +14 -1
- package/dist/components/forms/Combobox/Combobox.d.ts +25 -0
- package/dist/components/forms/Combobox/Combobox.js +412 -0
- package/dist/components/forms/Combobox/Combobox.theme.d.ts +6 -0
- package/dist/components/forms/Combobox/Combobox.theme.js +60 -0
- package/dist/components/forms/Combobox/Combobox.types.d.ts +111 -0
- package/dist/components/forms/Combobox/index.d.ts +3 -0
- package/dist/components/forms/FileUpload/FileUpload.js +2 -0
- package/dist/components/forms/Input/Input.js +25 -28
- package/dist/components/forms/Input/inputMasks.d.ts +15 -0
- package/dist/components/forms/Input/inputMasks.js +72 -1
- package/dist/components/forms/InputTag/InputTag.d.ts +40 -0
- package/dist/components/forms/InputTag/InputTag.js +491 -0
- package/dist/components/forms/InputTag/InputTag.theme.d.ts +2 -0
- package/dist/components/forms/InputTag/InputTag.theme.js +16 -0
- package/dist/components/forms/InputTag/InputTag.types.d.ts +107 -0
- package/dist/components/forms/InputTag/index.d.ts +3 -0
- package/dist/components/forms/Select/Select.d.ts +101 -2
- package/dist/components/forms/Select/Select.js +128 -132
- package/dist/components/forms/Select/Select.theme.js +10 -14
- package/dist/components/forms/Select/Select.types.d.ts +6 -2
- package/dist/components/forms/Select/index.d.ts +7 -4
- package/dist/components/forms/Select/useSelectState.d.ts +66 -0
- package/dist/components/forms/Select/useSelectState.js +134 -0
- package/dist/components/forms/SelectExpand/SelectExpand.animations.d.ts +20 -0
- package/dist/components/forms/SelectExpand/SelectExpand.animations.js +74 -0
- package/dist/components/forms/SelectExpand/SelectExpand.d.ts +9 -0
- package/dist/components/forms/SelectExpand/SelectExpand.js +223 -0
- package/dist/components/forms/SelectExpand/SelectExpand.theme.d.ts +5 -0
- package/dist/components/forms/SelectExpand/SelectExpand.theme.js +74 -0
- package/dist/components/forms/SelectExpand/SelectExpand.types.d.ts +126 -0
- package/dist/components/forms/SelectExpand/index.d.ts +4 -0
- package/dist/components/forms/Switch/Switch.js +3 -3
- package/dist/components/forms/Switch/Switch.theme.d.ts +1 -1
- package/dist/components/forms/Switch/Switch.theme.js +2 -2
- package/dist/components/forms/TimePicker/TimePicker.animations.d.ts +0 -46
- package/dist/components/forms/TimePicker/TimePicker.d.ts +15 -6
- package/dist/components/forms/TimePicker/TimePicker.js +285 -124
- package/dist/components/forms/TimePicker/TimePicker.theme.d.ts +1 -1
- package/dist/components/forms/TimePicker/TimePicker.theme.js +39 -22
- package/dist/components/forms/TimePicker/TimePicker.types.d.ts +88 -34
- package/dist/components/forms/TimePicker/TimePickerContent.d.ts +7 -10
- package/dist/components/forms/TimePicker/TimePickerContent.js +149 -16
- package/dist/components/forms/TimePicker/TimePickerTrigger.d.ts +3 -3
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +22 -19
- package/dist/components/forms/TimePicker/WheelColumn.d.ts +14 -0
- package/dist/components/forms/TimePicker/WheelColumn.js +90 -0
- package/dist/components/forms/TimePicker/index.d.ts +4 -1
- package/dist/components/forms/TimePicker/useWheelPicker.d.ts +37 -0
- package/dist/components/forms/TimePicker/useWheelPicker.js +138 -0
- package/dist/components/forms/forms.theme.d.ts +14 -0
- package/dist/components/forms/forms.theme.js +31 -0
- package/dist/components/forms/index.d.ts +9 -3
- package/dist/components/forms/index.js +73 -2
- package/dist/hooks/index.d.ts +0 -4
- package/dist/icons/Icon.d.ts +7 -0
- package/dist/icons/Icon.js +6 -2
- package/dist/index.js +12 -16
- package/dist/styles.css +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/optimisticErrors.js +1 -70
- package/package.json +1 -1
- package/dist/components/ai/EditingIndicator/EditingIndicator.animations.d.ts +0 -31
- package/dist/components/ai/EditingIndicator/EditingIndicator.animations.js +0 -115
- package/dist/components/ai/EditingIndicator/EditingIndicator.d.ts +0 -35
- package/dist/components/ai/EditingIndicator/EditingIndicator.js +0 -94
- package/dist/components/ai/EditingIndicator/EditingIndicator.theme.d.ts +0 -2
- package/dist/components/ai/EditingIndicator/EditingIndicator.theme.js +0 -13
- package/dist/components/ai/EditingIndicator/EditingIndicator.types.d.ts +0 -54
- package/dist/components/ai/EditingIndicator/index.d.ts +0 -9
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.d.ts +0 -3
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.js +0 -126
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.theme.d.ts +0 -2
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.theme.js +0 -8
- package/dist/components/ai/GenerativeRenderer/GenerativeRenderer.types.d.ts +0 -45
- package/dist/components/ai/GenerativeRenderer/index.d.ts +0 -3
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.animations.d.ts +0 -17
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.animations.js +0 -56
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.d.ts +0 -38
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.js +0 -110
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.theme.d.ts +0 -2
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.theme.js +0 -13
- package/dist/components/ai/PresenceIndicator/PresenceIndicator.types.d.ts +0 -53
- package/dist/components/ai/PresenceIndicator/index.d.ts +0 -8
- package/dist/components/ai/PresenceProvider/PresenceContext.d.ts +0 -24
- package/dist/components/ai/PresenceProvider/PresenceContext.js +0 -34
- package/dist/components/ai/PresenceProvider/PresenceProvider.d.ts +0 -32
- package/dist/components/ai/PresenceProvider/PresenceProvider.js +0 -321
- package/dist/components/ai/PresenceProvider/PresenceProvider.types.d.ts +0 -140
- package/dist/components/ai/PresenceProvider/adapters/MockAdapter.d.ts +0 -102
- package/dist/components/ai/PresenceProvider/adapters/MockAdapter.js +0 -331
- package/dist/components/ai/PresenceProvider/adapters/PresenceAdapter.d.ts +0 -93
- package/dist/components/ai/PresenceProvider/adapters/SupabaseAdapter.d.ts +0 -134
- package/dist/components/ai/PresenceProvider/adapters/WebSocketAdapter.d.ts +0 -149
- package/dist/components/ai/PresenceProvider/adapters/index.d.ts +0 -11
- package/dist/components/ai/PresenceProvider/index.d.ts +0 -10
- package/dist/components/ai/PromptSuggestions/PromptSuggestions.d.ts +0 -27
- package/dist/components/ai/PromptSuggestions/PromptSuggestions.js +0 -61
- package/dist/components/ai/PromptSuggestions/PromptSuggestions.types.d.ts +0 -65
- package/dist/components/ai/VersionSlider/VersionSlider.d.ts +0 -3
- package/dist/components/ai/VersionSlider/VersionSlider.js +0 -97
- package/dist/components/ai/VersionSlider/VersionSlider.theme.d.ts +0 -2
- package/dist/components/ai/VersionSlider/VersionSlider.theme.js +0 -18
- package/dist/components/ai/VersionSlider/VersionSlider.types.d.ts +0 -77
- package/dist/components/ai/VersionSlider/index.d.ts +0 -3
- package/dist/components/core/Pill/Pill.animations.js +0 -25
- package/dist/components/core/Pill/Pill.js +0 -145
- package/dist/components/core/Pill/Pill.theme.js +0 -65
- package/dist/components/core/RetryBoundary/RetryBoundary.d.ts +0 -35
- package/dist/components/core/RetryBoundary/RetryBoundary.js +0 -154
- package/dist/components/core/RetryBoundary/RetryBoundary.theme.d.ts +0 -2
- package/dist/components/core/RetryBoundary/RetryBoundary.theme.js +0 -7
- package/dist/components/core/RetryBoundary/RetryBoundary.types.d.ts +0 -51
- package/dist/components/core/RetryBoundary/index.d.ts +0 -3
- package/dist/components/forms/OptimisticForm/OptimisticForm.d.ts +0 -33
- package/dist/components/forms/OptimisticForm/OptimisticForm.js +0 -87
- package/dist/components/forms/OptimisticForm/OptimisticForm.theme.d.ts +0 -2
- package/dist/components/forms/OptimisticForm/OptimisticForm.theme.js +0 -8
- package/dist/components/forms/OptimisticForm/OptimisticForm.types.d.ts +0 -74
- package/dist/components/forms/OptimisticForm/index.d.ts +0 -3
- package/dist/hooks/useOptimisticMutation.d.ts +0 -109
- package/dist/hooks/useOptimisticMutation.js +0 -171
- package/dist/hooks/usePresence.d.ts +0 -88
- package/dist/utils/presenceUtils.d.ts +0 -66
- package/dist/utils/presenceUtils.js +0 -107
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
import React__default, { useState, useRef, useCallback, useMemo, useEffect } from 'react';
|
|
2
|
-
import { PresenceContext } from './PresenceContext.js';
|
|
3
|
-
import { useNetworkStatus } from '../../../hooks/useNetworkStatus.js';
|
|
4
|
-
import { debounce } from '../../../utils/debounce.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Presence Provider Component
|
|
8
|
-
*
|
|
9
|
-
* Root provider that manages real-time presence state via adapter pattern.
|
|
10
|
-
* Provides presence context to child components.
|
|
11
|
-
*
|
|
12
|
-
* Features:
|
|
13
|
-
* - Backend-agnostic adapter pattern
|
|
14
|
-
* - Network-aware reconnection
|
|
15
|
-
* - Typing state management with debouncing
|
|
16
|
-
* - Auto-cleanup on unmount
|
|
17
|
-
*/
|
|
18
|
-
/**
|
|
19
|
-
* PresenceProvider - Real-time collaboration provider
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```tsx
|
|
23
|
-
* const adapter = new MockPresenceAdapter();
|
|
24
|
-
* const currentUser = { id: '1', name: 'John Doe', status: 'online' };
|
|
25
|
-
*
|
|
26
|
-
* <PresenceProvider channel="chat-room-123" currentUser={currentUser} adapter={adapter}>
|
|
27
|
-
* <PresenceIndicator />
|
|
28
|
-
* <ChatInterface>
|
|
29
|
-
* <MessageHistory />
|
|
30
|
-
* <EditingIndicator />
|
|
31
|
-
* </ChatInterface>
|
|
32
|
-
* </PresenceProvider>
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
const PresenceProvider = React__default.forwardRef(({ channel, currentUser, adapter, autoConnect = true, typingDebounce = 300, typingTimeout = 3000, autoReconnect = true, onPresenceChange, onConnectionChange, onError, children, className, ...props }, ref) => {
|
|
36
|
-
// ===== State =====
|
|
37
|
-
const [users, setUsers] = useState([]);
|
|
38
|
-
const [typingUsers, setTypingUsers] = useState([]);
|
|
39
|
-
const [connectionStatus, setConnectionStatus] = useState('disconnected');
|
|
40
|
-
const [error, setError] = useState(null);
|
|
41
|
-
// ===== Refs =====
|
|
42
|
-
const typingTimeoutRef = useRef(undefined);
|
|
43
|
-
const isConnectingRef = useRef(false);
|
|
44
|
-
const hasConnectedOnceRef = useRef(false);
|
|
45
|
-
// ===== Network status =====
|
|
46
|
-
const { isOnline, wasOffline } = useNetworkStatus();
|
|
47
|
-
// ===== Derived state =====
|
|
48
|
-
const isConnected = connectionStatus === 'connected';
|
|
49
|
-
const isConnecting = connectionStatus === 'connecting';
|
|
50
|
-
// ===== Connection management =====
|
|
51
|
-
/**
|
|
52
|
-
* Connect to presence channel
|
|
53
|
-
*/
|
|
54
|
-
const connect = useCallback(async () => {
|
|
55
|
-
// Use ref to check if already connecting to avoid dependency on connectionStatus
|
|
56
|
-
if (isConnectingRef.current) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
isConnectingRef.current = true;
|
|
60
|
-
setConnectionStatus('connecting');
|
|
61
|
-
setError(null);
|
|
62
|
-
try {
|
|
63
|
-
await adapter.connect({
|
|
64
|
-
channel,
|
|
65
|
-
currentUser,
|
|
66
|
-
typingDebounce,
|
|
67
|
-
typingTimeout,
|
|
68
|
-
});
|
|
69
|
-
hasConnectedOnceRef.current = true;
|
|
70
|
-
setConnectionStatus('connected');
|
|
71
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
72
|
-
console.log('[PresenceProvider]: Connected to channel:', channel);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
const error = err instanceof Error ? err : new Error('Connection failed');
|
|
77
|
-
setError(error);
|
|
78
|
-
setConnectionStatus('disconnected');
|
|
79
|
-
onError === null || onError === void 0 ? void 0 : onError(error);
|
|
80
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
81
|
-
console.error('[PresenceProvider]: Connection error:', error);
|
|
82
|
-
}
|
|
83
|
-
// Attempt reconnection if enabled
|
|
84
|
-
if (autoReconnect && hasConnectedOnceRef.current) {
|
|
85
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
86
|
-
console.log('[PresenceProvider]: Scheduling reconnection...');
|
|
87
|
-
}
|
|
88
|
-
setTimeout(() => {
|
|
89
|
-
if (isOnline) {
|
|
90
|
-
connect();
|
|
91
|
-
}
|
|
92
|
-
}, 3000);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
finally {
|
|
96
|
-
isConnectingRef.current = false;
|
|
97
|
-
}
|
|
98
|
-
}, [
|
|
99
|
-
adapter,
|
|
100
|
-
channel,
|
|
101
|
-
currentUser,
|
|
102
|
-
typingDebounce,
|
|
103
|
-
typingTimeout,
|
|
104
|
-
autoReconnect,
|
|
105
|
-
isOnline,
|
|
106
|
-
onError,
|
|
107
|
-
]);
|
|
108
|
-
/**
|
|
109
|
-
* Disconnect from channel
|
|
110
|
-
*/
|
|
111
|
-
const disconnect = useCallback(async () => {
|
|
112
|
-
try {
|
|
113
|
-
await adapter.disconnect();
|
|
114
|
-
setConnectionStatus('disconnected');
|
|
115
|
-
setUsers([]);
|
|
116
|
-
setTypingUsers([]);
|
|
117
|
-
setError(null);
|
|
118
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
119
|
-
console.log('[PresenceProvider]: Disconnected from channel');
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
124
|
-
console.error('[PresenceProvider]: Disconnect error:', err);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}, [adapter]);
|
|
128
|
-
// ===== Typing management =====
|
|
129
|
-
/**
|
|
130
|
-
* Start typing indicator (not debounced - debouncing is handled internally)
|
|
131
|
-
*/
|
|
132
|
-
const startTypingInternal = useCallback(() => {
|
|
133
|
-
if (connectionStatus !== 'connected')
|
|
134
|
-
return;
|
|
135
|
-
adapter.sendTypingStart();
|
|
136
|
-
// Clear existing timeout
|
|
137
|
-
if (typingTimeoutRef.current) {
|
|
138
|
-
clearTimeout(typingTimeoutRef.current);
|
|
139
|
-
}
|
|
140
|
-
// Auto-stop after timeout
|
|
141
|
-
typingTimeoutRef.current = setTimeout(() => {
|
|
142
|
-
stopTyping();
|
|
143
|
-
}, typingTimeout);
|
|
144
|
-
}, [adapter, connectionStatus, typingTimeout]);
|
|
145
|
-
/**
|
|
146
|
-
* Start typing indicator (debounced)
|
|
147
|
-
*/
|
|
148
|
-
const startTyping = useMemo(() => debounce(startTypingInternal, typingDebounce), [startTypingInternal, typingDebounce]);
|
|
149
|
-
/**
|
|
150
|
-
* Stop typing indicator
|
|
151
|
-
*/
|
|
152
|
-
const stopTyping = useCallback(() => {
|
|
153
|
-
if (connectionStatus !== 'connected')
|
|
154
|
-
return;
|
|
155
|
-
adapter.sendTypingStop();
|
|
156
|
-
// Clear timeout
|
|
157
|
-
if (typingTimeoutRef.current) {
|
|
158
|
-
clearTimeout(typingTimeoutRef.current);
|
|
159
|
-
}
|
|
160
|
-
}, [adapter, connectionStatus]);
|
|
161
|
-
/**
|
|
162
|
-
* Update current user metadata
|
|
163
|
-
*/
|
|
164
|
-
const updateUser = useCallback((updates) => {
|
|
165
|
-
if (connectionStatus !== 'connected')
|
|
166
|
-
return;
|
|
167
|
-
adapter.updateUserMetadata(updates);
|
|
168
|
-
}, [adapter, connectionStatus]);
|
|
169
|
-
/**
|
|
170
|
-
* Send custom event
|
|
171
|
-
*/
|
|
172
|
-
const sendEvent = useCallback((event, data) => {
|
|
173
|
-
if (connectionStatus !== 'connected')
|
|
174
|
-
return;
|
|
175
|
-
adapter.sendCustomEvent(event, data);
|
|
176
|
-
}, [adapter, connectionStatus]);
|
|
177
|
-
// ===== Effects =====
|
|
178
|
-
/**
|
|
179
|
-
* Subscribe to adapter events
|
|
180
|
-
*/
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
// Subscribe to presence changes
|
|
183
|
-
const unsubscribePresence = adapter.onPresenceChange((newUsers) => {
|
|
184
|
-
setUsers(newUsers);
|
|
185
|
-
// Notify callback
|
|
186
|
-
if (onPresenceChange && newUsers.length > users.length) {
|
|
187
|
-
// User joined
|
|
188
|
-
const newUser = newUsers.find(u => !users.find(existing => existing.id === u.id));
|
|
189
|
-
if (newUser) {
|
|
190
|
-
const event = { type: 'user-joined', user: newUser };
|
|
191
|
-
onPresenceChange(event);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
else if (onPresenceChange && newUsers.length < users.length) {
|
|
195
|
-
// User left
|
|
196
|
-
const leftUser = users.find(u => !newUsers.find(existing => existing.id === u.id));
|
|
197
|
-
if (leftUser) {
|
|
198
|
-
const event = { type: 'user-left', userId: leftUser.id };
|
|
199
|
-
onPresenceChange(event);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
// Subscribe to typing changes
|
|
204
|
-
const unsubscribeTyping = adapter.onTypingChange((newTypingUsers) => {
|
|
205
|
-
setTypingUsers(newTypingUsers);
|
|
206
|
-
// Notify callback
|
|
207
|
-
if (onPresenceChange) {
|
|
208
|
-
const startedTyping = newTypingUsers.find(u => !typingUsers.find(existing => existing.id === u.id));
|
|
209
|
-
const stoppedTyping = typingUsers.find(u => !newTypingUsers.find(existing => existing.id === u.id));
|
|
210
|
-
if (startedTyping) {
|
|
211
|
-
const event = {
|
|
212
|
-
type: 'typing-started',
|
|
213
|
-
userId: startedTyping.id,
|
|
214
|
-
userName: startedTyping.name,
|
|
215
|
-
};
|
|
216
|
-
onPresenceChange(event);
|
|
217
|
-
}
|
|
218
|
-
if (stoppedTyping) {
|
|
219
|
-
const event = {
|
|
220
|
-
type: 'typing-stopped',
|
|
221
|
-
userId: stoppedTyping.id,
|
|
222
|
-
};
|
|
223
|
-
onPresenceChange(event);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
// Subscribe to connection changes
|
|
228
|
-
const unsubscribeConnection = adapter.onConnectionChange((status) => {
|
|
229
|
-
setConnectionStatus(status);
|
|
230
|
-
onConnectionChange === null || onConnectionChange === void 0 ? void 0 : onConnectionChange(status);
|
|
231
|
-
if (status === 'connected' && onPresenceChange) {
|
|
232
|
-
const event = { type: 'reconnected' };
|
|
233
|
-
onPresenceChange(event);
|
|
234
|
-
}
|
|
235
|
-
else if (status === 'connecting' && onPresenceChange) {
|
|
236
|
-
const event = { type: 'reconnecting' };
|
|
237
|
-
onPresenceChange(event);
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
// Subscribe to errors
|
|
241
|
-
const unsubscribeError = adapter.onError((err) => {
|
|
242
|
-
setError(err);
|
|
243
|
-
onError === null || onError === void 0 ? void 0 : onError(err);
|
|
244
|
-
if (onPresenceChange) {
|
|
245
|
-
const event = { type: 'connection-error', error: err };
|
|
246
|
-
onPresenceChange(event);
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
// Cleanup
|
|
250
|
-
return () => {
|
|
251
|
-
unsubscribePresence();
|
|
252
|
-
unsubscribeTyping();
|
|
253
|
-
unsubscribeConnection();
|
|
254
|
-
unsubscribeError();
|
|
255
|
-
};
|
|
256
|
-
}, [adapter, users, typingUsers, onPresenceChange, onConnectionChange, onError]);
|
|
257
|
-
/**
|
|
258
|
-
* Auto-connect on mount
|
|
259
|
-
*/
|
|
260
|
-
useEffect(() => {
|
|
261
|
-
if (autoConnect) {
|
|
262
|
-
connect();
|
|
263
|
-
}
|
|
264
|
-
// Cleanup on unmount
|
|
265
|
-
return () => {
|
|
266
|
-
disconnect();
|
|
267
|
-
// Clear typing timeout
|
|
268
|
-
if (typingTimeoutRef.current) {
|
|
269
|
-
clearTimeout(typingTimeoutRef.current);
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
}, [autoConnect, connect, disconnect]);
|
|
273
|
-
/**
|
|
274
|
-
* Handle network recovery
|
|
275
|
-
*/
|
|
276
|
-
useEffect(() => {
|
|
277
|
-
if (wasOffline && isOnline && autoReconnect && hasConnectedOnceRef.current) {
|
|
278
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
279
|
-
console.log('[PresenceProvider]: Network recovered, reconnecting...');
|
|
280
|
-
}
|
|
281
|
-
connect();
|
|
282
|
-
}
|
|
283
|
-
}, [wasOffline, isOnline, autoReconnect, connect]);
|
|
284
|
-
// ===== Context value =====
|
|
285
|
-
const contextValue = useMemo(() => ({
|
|
286
|
-
users,
|
|
287
|
-
typingUsers,
|
|
288
|
-
currentUser,
|
|
289
|
-
connectionStatus,
|
|
290
|
-
isConnected,
|
|
291
|
-
isConnecting,
|
|
292
|
-
error,
|
|
293
|
-
connect,
|
|
294
|
-
disconnect,
|
|
295
|
-
startTyping,
|
|
296
|
-
stopTyping,
|
|
297
|
-
updateUser,
|
|
298
|
-
sendEvent,
|
|
299
|
-
}), [
|
|
300
|
-
users,
|
|
301
|
-
typingUsers,
|
|
302
|
-
currentUser,
|
|
303
|
-
connectionStatus,
|
|
304
|
-
isConnected,
|
|
305
|
-
isConnecting,
|
|
306
|
-
error,
|
|
307
|
-
connect,
|
|
308
|
-
disconnect,
|
|
309
|
-
startTyping,
|
|
310
|
-
stopTyping,
|
|
311
|
-
updateUser,
|
|
312
|
-
sendEvent,
|
|
313
|
-
]);
|
|
314
|
-
// ===== Render =====
|
|
315
|
-
return (React__default.createElement(PresenceContext.Provider, { value: contextValue },
|
|
316
|
-
React__default.createElement("div", { ref: ref, className: className, "data-channel": channel, "data-connected": isConnected, "data-user-count": users.length, "data-typing-count": typingUsers.length, ...props }, children)));
|
|
317
|
-
});
|
|
318
|
-
// Set display name for dev tools
|
|
319
|
-
PresenceProvider.displayName = 'PresenceProvider';
|
|
320
|
-
|
|
321
|
-
export { PresenceProvider };
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Real-Time Collaboration - Core Type Definitions
|
|
3
|
-
*
|
|
4
|
-
* Defines the foundational types for the presence system including
|
|
5
|
-
* users, typing states, events, and provider configuration.
|
|
6
|
-
*/
|
|
7
|
-
import React from 'react';
|
|
8
|
-
import { PresenceAdapter } from './adapters/PresenceAdapter';
|
|
9
|
-
/**
|
|
10
|
-
* User presence data structure
|
|
11
|
-
* Represents a user's current state in the collaboration channel
|
|
12
|
-
*/
|
|
13
|
-
export interface PresenceUser {
|
|
14
|
-
/** Unique user identifier */
|
|
15
|
-
id: string;
|
|
16
|
-
/** Display name */
|
|
17
|
-
name: string;
|
|
18
|
-
/** Avatar image URL (optional) */
|
|
19
|
-
avatar?: string;
|
|
20
|
-
/** User status indicator */
|
|
21
|
-
status?: 'online' | 'offline' | 'busy' | 'away';
|
|
22
|
-
/** Custom metadata (JSON serializable) */
|
|
23
|
-
metadata?: Record<string, unknown>;
|
|
24
|
-
/** Timestamp when user joined the channel */
|
|
25
|
-
joinedAt?: Date;
|
|
26
|
-
/** Last activity timestamp */
|
|
27
|
-
lastSeenAt?: Date;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Typing state for a user
|
|
31
|
-
* Tracks when a user is actively typing
|
|
32
|
-
*/
|
|
33
|
-
export interface TypingUser {
|
|
34
|
-
/** User ID */
|
|
35
|
-
id: string;
|
|
36
|
-
/** User name for display */
|
|
37
|
-
name: string;
|
|
38
|
-
/** Avatar URL (optional) */
|
|
39
|
-
avatar?: string;
|
|
40
|
-
/** Timestamp when typing started */
|
|
41
|
-
startedAt: Date;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Connection status states
|
|
45
|
-
*/
|
|
46
|
-
export type ConnectionStatus = 'connected' | 'disconnected' | 'connecting';
|
|
47
|
-
/**
|
|
48
|
-
* Presence event types
|
|
49
|
-
* Union type representing all possible presence-related events
|
|
50
|
-
*/
|
|
51
|
-
export type PresenceEvent = {
|
|
52
|
-
type: 'user-joined';
|
|
53
|
-
user: PresenceUser;
|
|
54
|
-
} | {
|
|
55
|
-
type: 'user-left';
|
|
56
|
-
userId: string;
|
|
57
|
-
} | {
|
|
58
|
-
type: 'user-updated';
|
|
59
|
-
user: PresenceUser;
|
|
60
|
-
} | {
|
|
61
|
-
type: 'typing-started';
|
|
62
|
-
userId: string;
|
|
63
|
-
userName: string;
|
|
64
|
-
} | {
|
|
65
|
-
type: 'typing-stopped';
|
|
66
|
-
userId: string;
|
|
67
|
-
} | {
|
|
68
|
-
type: 'connection-error';
|
|
69
|
-
error: Error;
|
|
70
|
-
} | {
|
|
71
|
-
type: 'reconnecting';
|
|
72
|
-
} | {
|
|
73
|
-
type: 'reconnected';
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Context value provided to child components
|
|
77
|
-
* Shared state accessible via usePresenceContext hook
|
|
78
|
-
*/
|
|
79
|
-
export interface PresenceContextValue {
|
|
80
|
-
/** All users currently in the channel */
|
|
81
|
-
users: PresenceUser[];
|
|
82
|
-
/** Users currently typing */
|
|
83
|
-
typingUsers: TypingUser[];
|
|
84
|
-
/** Current user data */
|
|
85
|
-
currentUser: PresenceUser;
|
|
86
|
-
/** Current connection status */
|
|
87
|
-
connectionStatus: ConnectionStatus;
|
|
88
|
-
/** Is actively connected */
|
|
89
|
-
isConnected: boolean;
|
|
90
|
-
/** Is connecting or reconnecting */
|
|
91
|
-
isConnecting: boolean;
|
|
92
|
-
/** Connection error (if any) */
|
|
93
|
-
error: Error | null;
|
|
94
|
-
/** Manually connect to channel */
|
|
95
|
-
connect: () => Promise<void>;
|
|
96
|
-
/** Manually disconnect from channel */
|
|
97
|
-
disconnect: () => Promise<void>;
|
|
98
|
-
/** Start typing indicator */
|
|
99
|
-
startTyping: () => void;
|
|
100
|
-
/** Stop typing indicator */
|
|
101
|
-
stopTyping: () => void;
|
|
102
|
-
/** Update current user metadata */
|
|
103
|
-
updateUser: (updates: Partial<PresenceUser>) => void;
|
|
104
|
-
/** Send custom presence event */
|
|
105
|
-
sendEvent: (event: string, data?: unknown) => void;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* PresenceProvider component props
|
|
109
|
-
*/
|
|
110
|
-
export interface PresenceProviderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onError'> {
|
|
111
|
-
/** Unique channel/room identifier */
|
|
112
|
-
channel: string;
|
|
113
|
-
/** Current user data */
|
|
114
|
-
currentUser: PresenceUser;
|
|
115
|
-
/** Backend adapter instance */
|
|
116
|
-
adapter: PresenceAdapter;
|
|
117
|
-
/** Auto-connect on mount (default: true) */
|
|
118
|
-
autoConnect?: boolean;
|
|
119
|
-
/** Debounce delay for typing events in milliseconds (default: 300) */
|
|
120
|
-
typingDebounce?: number;
|
|
121
|
-
/** Auto stop typing after inactivity in milliseconds (default: 3000) */
|
|
122
|
-
typingTimeout?: number;
|
|
123
|
-
/** Enable automatic reconnection (default: true) */
|
|
124
|
-
autoReconnect?: boolean;
|
|
125
|
-
/** Callback when presence event occurs */
|
|
126
|
-
onPresenceChange?: (event: PresenceEvent) => void;
|
|
127
|
-
/** Callback when connection status changes */
|
|
128
|
-
onConnectionChange?: (status: ConnectionStatus) => void;
|
|
129
|
-
/** Callback when error occurs */
|
|
130
|
-
onError?: (error: Error) => void;
|
|
131
|
-
/** Children components */
|
|
132
|
-
children?: React.ReactNode;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Theme overrides for PresenceProvider
|
|
136
|
-
* Currently unused but kept for future styling needs
|
|
137
|
-
*/
|
|
138
|
-
export interface PresenceProviderTheme {
|
|
139
|
-
baseStyle?: string;
|
|
140
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock Presence Adapter
|
|
3
|
-
*
|
|
4
|
-
* Simulates real-time presence behavior for development and Storybook demos.
|
|
5
|
-
* No external dependencies - pure client-side simulation.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Simulates 4-5 users joining at staggered intervals
|
|
9
|
-
* - Random typing events every 5 seconds
|
|
10
|
-
* - Auto-stop typing after 2-5 seconds
|
|
11
|
-
* - Connection status simulation
|
|
12
|
-
*/
|
|
13
|
-
import { PresenceAdapter, PresenceAdapterConfig } from './PresenceAdapter';
|
|
14
|
-
import { PresenceUser, TypingUser, ConnectionStatus } from '../PresenceProvider.types';
|
|
15
|
-
/**
|
|
16
|
-
* Mock adapter implementation
|
|
17
|
-
* Simulates presence behavior without backend
|
|
18
|
-
*/
|
|
19
|
-
export declare class MockPresenceAdapter implements PresenceAdapter {
|
|
20
|
-
private config;
|
|
21
|
-
private connectionStatus;
|
|
22
|
-
private users;
|
|
23
|
-
private typingUsers;
|
|
24
|
-
private intervals;
|
|
25
|
-
private timeouts;
|
|
26
|
-
private presenceCallbacks;
|
|
27
|
-
private typingCallbacks;
|
|
28
|
-
private connectionCallbacks;
|
|
29
|
-
private errorCallbacks;
|
|
30
|
-
/**
|
|
31
|
-
* Connect to mock presence channel
|
|
32
|
-
*/
|
|
33
|
-
connect(config: PresenceAdapterConfig): Promise<void>;
|
|
34
|
-
/**
|
|
35
|
-
* Disconnect from mock channel
|
|
36
|
-
*/
|
|
37
|
-
disconnect(): Promise<void>;
|
|
38
|
-
/**
|
|
39
|
-
* Subscribe to presence changes
|
|
40
|
-
*/
|
|
41
|
-
onPresenceChange(callback: (users: PresenceUser[]) => void): () => void;
|
|
42
|
-
/**
|
|
43
|
-
* Subscribe to typing changes
|
|
44
|
-
*/
|
|
45
|
-
onTypingChange(callback: (users: TypingUser[]) => void): () => void;
|
|
46
|
-
/**
|
|
47
|
-
* Subscribe to connection changes
|
|
48
|
-
*/
|
|
49
|
-
onConnectionChange(callback: (status: ConnectionStatus) => void): () => void;
|
|
50
|
-
/**
|
|
51
|
-
* Subscribe to errors
|
|
52
|
-
*/
|
|
53
|
-
onError(callback: (error: Error) => void): () => void;
|
|
54
|
-
/**
|
|
55
|
-
* Send typing start (current user)
|
|
56
|
-
*/
|
|
57
|
-
sendTypingStart(): void;
|
|
58
|
-
/**
|
|
59
|
-
* Send typing stop (current user)
|
|
60
|
-
*/
|
|
61
|
-
sendTypingStop(): void;
|
|
62
|
-
/**
|
|
63
|
-
* Update current user metadata
|
|
64
|
-
*/
|
|
65
|
-
updateUserMetadata(metadata: Partial<PresenceUser>): void;
|
|
66
|
-
/**
|
|
67
|
-
* Send custom event (mock implementation)
|
|
68
|
-
*/
|
|
69
|
-
sendCustomEvent(event: string, data?: unknown): void;
|
|
70
|
-
/**
|
|
71
|
-
* Get current connection status
|
|
72
|
-
*/
|
|
73
|
-
getConnectionStatus(): ConnectionStatus;
|
|
74
|
-
/**
|
|
75
|
-
* Get current user
|
|
76
|
-
*/
|
|
77
|
-
getCurrentUser(): PresenceUser;
|
|
78
|
-
/**
|
|
79
|
-
* Simulate realistic user activity
|
|
80
|
-
*/
|
|
81
|
-
private simulateUserActivity;
|
|
82
|
-
/**
|
|
83
|
-
* Simulate typing start for a user
|
|
84
|
-
*/
|
|
85
|
-
private simulateTypingStart;
|
|
86
|
-
/**
|
|
87
|
-
* Simulate typing stop for a user
|
|
88
|
-
*/
|
|
89
|
-
private simulateTypingStop;
|
|
90
|
-
/**
|
|
91
|
-
* Notify all presence callbacks
|
|
92
|
-
*/
|
|
93
|
-
private notifyPresenceChange;
|
|
94
|
-
/**
|
|
95
|
-
* Notify all typing callbacks
|
|
96
|
-
*/
|
|
97
|
-
private notifyTypingChange;
|
|
98
|
-
/**
|
|
99
|
-
* Notify all connection callbacks
|
|
100
|
-
*/
|
|
101
|
-
private notifyConnectionChange;
|
|
102
|
-
}
|