react-broadcast-sync 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +59 -11
  2. package/dist/index.cjs.js +1 -1
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.esm.js +1 -1
  5. package/dist/index.esm.js.map +1 -1
  6. package/dist/types/types.d.ts +17 -0
  7. package/package.json +6 -1
  8. package/.eslintignore +0 -5
  9. package/.github/workflows/ci.yml +0 -61
  10. package/.github/workflows/release.yml +0 -39
  11. package/.husky/pre-commit +0 -5
  12. package/.nvmrc +0 -1
  13. package/.prettierignore +0 -4
  14. package/.prettierrc +0 -9
  15. package/.releaserc.json +0 -22
  16. package/CHANGELOG.md +0 -97
  17. package/assets/react-broadcast-sync-logo.png +0 -0
  18. package/commitlint.config.js +0 -3
  19. package/demo/react-broadcast-sync-demo/README.md +0 -130
  20. package/demo/react-broadcast-sync-demo/index.html +0 -14
  21. package/demo/react-broadcast-sync-demo/package-lock.json +0 -6379
  22. package/demo/react-broadcast-sync-demo/package.json +0 -42
  23. package/demo/react-broadcast-sync-demo/public/assets/react-broadcast-sync-demo-video.gif +0 -0
  24. package/demo/react-broadcast-sync-demo/public/assets/react-broadcast-sync-logo.png +0 -0
  25. package/demo/react-broadcast-sync-demo/src/App.tsx +0 -277
  26. package/demo/react-broadcast-sync-demo/src/components/Counter.tsx +0 -63
  27. package/demo/react-broadcast-sync-demo/src/components/TextSync.tsx +0 -61
  28. package/demo/react-broadcast-sync-demo/src/components/TodoList.tsx +0 -186
  29. package/demo/react-broadcast-sync-demo/src/hooks/useCounterBroadcast.ts +0 -96
  30. package/demo/react-broadcast-sync-demo/src/hooks/useTextBroadcast.ts +0 -37
  31. package/demo/react-broadcast-sync-demo/src/hooks/useTodoBroadcast.ts +0 -249
  32. package/demo/react-broadcast-sync-demo/src/main.tsx +0 -11
  33. package/demo/react-broadcast-sync-demo/src/theme.ts +0 -62
  34. package/demo/react-broadcast-sync-demo/tsconfig.json +0 -26
  35. package/demo/react-broadcast-sync-demo/tsconfig.node.json +0 -10
  36. package/demo/react-broadcast-sync-demo/vite.config.ts +0 -12
  37. package/eslint.config.js +0 -38
  38. package/jest.config.cjs +0 -9
  39. package/jest.setup.ts +0 -1
  40. package/rollup.config.mjs +0 -98
  41. package/src/BroadcastProvider.tsx +0 -28
  42. package/src/hooks/useBroadcastChannel.ts +0 -513
  43. package/src/index.ts +0 -9
  44. package/src/tests/BroadcastProvider.test.tsx +0 -157
  45. package/src/tests/debug.test.ts +0 -273
  46. package/src/tests/messageUtils.test.ts +0 -252
  47. package/src/tests/useBroadcastChannel.same-tab.test.tsx +0 -992
  48. package/src/tests/useBroadcastChannel.test.tsx +0 -1243
  49. package/src/types/types.ts +0 -124
  50. package/src/utils/debug.ts +0 -80
  51. package/src/utils/messageUtils.ts +0 -122
  52. package/tsconfig.json +0 -36
@@ -1,96 +0,0 @@
1
- /**
2
- * Custom hook for managing counter state synchronization across browser tabs.
3
- *
4
- * This hook provides functionality for:
5
- * 1. Synchronizing a counter value across multiple browser tabs
6
- * 2. Broadcasting hover state for visual feedback
7
- * 3. Maintaining consistent state across all instances
8
- *
9
- * @returns {Object} Counter state and handlers
10
- * @property {number} count - Current counter value
11
- * @property {boolean} isHovered - Whether the counter is currently hovered
12
- * @property {Function} increment - Function to increment the counter
13
- * @property {Function} decrement - Function to decrement the counter
14
- * @property {Function} handleMouseEnter - Function to handle mouse enter event
15
- * @property {Function} handleMouseLeave - Function to handle mouse leave event
16
- */
17
- import { useState, useEffect, useRef } from 'react';
18
- import { useBroadcastChannel } from 'react-broadcast-sync';
19
-
20
- export const useCounterBroadcast = () => {
21
- const { messages, postMessage } = useBroadcastChannel('counter', {
22
- keepLatestMessage: true,
23
- namespace: 'demo-app',
24
- });
25
-
26
- const [count, setCount] = useState<number>(0);
27
- const [isSyncing, setIsSyncing] = useState(false);
28
- const [showCheckmark, setShowCheckmark] = useState(false);
29
- const lastTimestampRef = useRef<number>(0);
30
-
31
- const syncTimeoutRef = useRef<NodeJS.Timeout>();
32
- const checkmarkTimeoutRef = useRef<NodeJS.Timeout>();
33
-
34
- // Update count when new messages arrive
35
- useEffect(() => {
36
- const lastMessage = messages[messages.length - 1];
37
- if (lastMessage?.message !== undefined && lastMessage.timestamp > lastTimestampRef.current) {
38
- // Clear any existing timeouts
39
- if (syncTimeoutRef.current) {
40
- clearTimeout(syncTimeoutRef.current);
41
- }
42
- if (checkmarkTimeoutRef.current) {
43
- clearTimeout(checkmarkTimeoutRef.current);
44
- }
45
-
46
- // Reset states
47
- setIsSyncing(true);
48
- setShowCheckmark(false);
49
-
50
- // Update count and timestamp
51
- setCount(lastMessage.message);
52
- lastTimestampRef.current = lastMessage.timestamp;
53
-
54
- // Show checkmark after a short delay
55
- syncTimeoutRef.current = setTimeout(() => {
56
- setIsSyncing(false);
57
- setShowCheckmark(true);
58
-
59
- // Hide checkmark after showing it
60
- checkmarkTimeoutRef.current = setTimeout(() => {
61
- setShowCheckmark(false);
62
- }, 1000);
63
- }, 500);
64
- }
65
-
66
- // Cleanup
67
- return () => {
68
- if (syncTimeoutRef.current) {
69
- clearTimeout(syncTimeoutRef.current);
70
- }
71
- if (checkmarkTimeoutRef.current) {
72
- clearTimeout(checkmarkTimeoutRef.current);
73
- }
74
- };
75
- }, [messages]);
76
-
77
- const increment = () => {
78
- const newCount = count + 1;
79
- setCount(newCount);
80
- postMessage('counter', newCount);
81
- };
82
-
83
- const decrement = () => {
84
- const newCount = count - 1;
85
- setCount(newCount);
86
- postMessage('counter', newCount);
87
- };
88
-
89
- return {
90
- count,
91
- increment,
92
- decrement,
93
- isSyncing,
94
- showCheckmark,
95
- };
96
- };
@@ -1,37 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { useBroadcastChannel } from 'react-broadcast-sync';
3
-
4
- export const useTextBroadcast = () => {
5
- const { messages, postMessage } = useBroadcastChannel('text', {
6
- keepLatestMessage: true,
7
- namespace: 'demo-app',
8
- });
9
-
10
- const lastMessage = messages[messages.length - 1];
11
- const [localText, setLocalText] = useState<string>(lastMessage ? lastMessage.message : '');
12
-
13
- // Update local state when new messages arrive
14
- useEffect(() => {
15
- if (lastMessage) {
16
- setLocalText(lastMessage.message);
17
- }
18
- }, [lastMessage]);
19
-
20
- // Initialize text if no messages exist
21
- useEffect(() => {
22
- if (messages.length === 0) {
23
- postMessage('text', '');
24
- }
25
- }, []);
26
-
27
- const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
28
- const newText = event.target.value;
29
- setLocalText(newText); // Update local state immediately
30
- postMessage('text', newText); // Broadcast to other tabs
31
- };
32
-
33
- return {
34
- localText,
35
- handleChange,
36
- };
37
- };
@@ -1,249 +0,0 @@
1
- /**
2
- * Custom hook for managing todo list synchronization across browser tabs.
3
- *
4
- * This hook provides functionality for:
5
- * 1. Synchronizing todo items across multiple browser tabs
6
- * 2. Broadcasting hover states for visual feedback
7
- * 3. Synchronizing scroll position across tabs
8
- * 4. Managing todo item completion status
9
- *
10
- * @returns {Object} Todo list state and handlers
11
- * @property {Todo[]} todos - Array of todo items
12
- * @property {string} newTodo - Current input value for new todo
13
- * @property {Function} setNewTodo - Function to update new todo input
14
- * @property {number|null} hoveredTodoId - ID of currently hovered todo
15
- * @property {boolean} isScrolling - Whether the list is currently scrolling
16
- * @property {boolean} isSyncing - Whether scroll sync is in progress
17
- * @property {boolean} showCheckmark - Whether to show sync completion indicator
18
- * @property {React.RefObject} scrollContainerRef - Ref for the scroll container
19
- * @property {Function} handleScroll - Function to handle scroll events
20
- * @property {Function} addTodo - Function to add a new todo
21
- * @property {Function} toggleTodo - Function to toggle todo completion
22
- * @property {Function} handleTodoMouseEnter - Function to handle todo hover
23
- * @property {Function} handleTodoMouseLeave - Function to handle todo unhover
24
- */
25
- import { useState, useEffect, useRef } from 'react';
26
- import { useBroadcastChannel } from 'react-broadcast-sync';
27
-
28
- interface Todo {
29
- id: string;
30
- text: string;
31
- completed: boolean;
32
- }
33
-
34
- /**
35
- * Hook for managing todo list synchronization across browser tabs.
36
- * Provides real-time todo updates, completion status tracking, and scroll position sync.
37
- *
38
- * @returns {Object} Todo state and handlers
39
- * @property {Todo[]} todos - List of todos
40
- * @property {string} newTodo - New todo input value
41
- * @property {Function} handleNewTodoChange - Function to handle new todo input changes
42
- * @property {Function} handleAddTodo - Function to add a new todo
43
- * @property {Function} handleToggleTodo - Function to toggle todo completion
44
- * @property {Function} handleDeleteTodo - Function to delete a todo
45
- * @property {Function} handleScroll - Function to handle scroll position sync
46
- */
47
- export const useTodoBroadcast = () => {
48
- const { messages, postMessage } = useBroadcastChannel('todos', {
49
- keepLatestMessage: true,
50
- namespace: 'demo-app',
51
- });
52
-
53
- // Add hover state broadcast channel
54
- const { messages: hoverMessages, postMessage: postHoverMessage } = useBroadcastChannel(
55
- 'todos-hover',
56
- {
57
- keepLatestMessage: true,
58
- namespace: 'demo-app',
59
- }
60
- );
61
-
62
- // Add scroll position broadcast channel
63
- const { messages: scrollMessages, postMessage: postScrollMessage } = useBroadcastChannel(
64
- 'todos-scroll',
65
- {
66
- keepLatestMessage: true,
67
- namespace: 'demo-app',
68
- }
69
- );
70
-
71
- const lastMessage = messages[messages.length - 1];
72
- const lastHoverMessage = hoverMessages[hoverMessages.length - 1];
73
- const lastScrollMessage = scrollMessages[scrollMessages.length - 1];
74
-
75
- const [todos, setTodos] = useState<Todo[]>(lastMessage ? lastMessage.message : []);
76
- const [newTodo, setNewTodo] = useState('');
77
- const [hoveredTodoId, setHoveredTodoId] = useState<string | null>(
78
- lastHoverMessage ? lastHoverMessage.message : null
79
- );
80
- const [isScrolling, setIsScrolling] = useState(false);
81
- const [isSyncing, setIsSyncing] = useState(false);
82
- const [showCheckmark, setShowCheckmark] = useState(false);
83
-
84
- const scrollContainerRef = useRef<HTMLDivElement>(null);
85
- const scrollTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
86
- const syncTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
87
- const checkmarkTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
88
-
89
- // Update local state when new messages arrive
90
- useEffect(() => {
91
- if (lastMessage) {
92
- setTodos(lastMessage.message);
93
- }
94
- }, [lastMessage]);
95
-
96
- // Update hover state when new hover messages arrive
97
- useEffect(() => {
98
- if (lastHoverMessage) {
99
- setHoveredTodoId(lastHoverMessage.message);
100
- }
101
- }, [lastHoverMessage]);
102
-
103
- // Update scroll position when new scroll messages arrive
104
- useEffect(() => {
105
- if (lastScrollMessage && scrollContainerRef.current) {
106
- // Clear any existing timeouts
107
- if (syncTimeoutRef.current) {
108
- clearTimeout(syncTimeoutRef.current);
109
- }
110
- if (checkmarkTimeoutRef.current) {
111
- clearTimeout(checkmarkTimeoutRef.current);
112
- }
113
-
114
- // Reset states
115
- setIsSyncing(true);
116
- setShowCheckmark(false);
117
- setIsScrolling(false);
118
-
119
- // Perform scroll
120
- scrollContainerRef.current.scrollTo({
121
- top: lastScrollMessage.message,
122
- behavior: 'smooth',
123
- });
124
-
125
- // Listen for scroll end
126
- const handleScrollEnd = () => {
127
- setIsSyncing(false);
128
- setShowCheckmark(true);
129
-
130
- // Hide indicator after showing checkmark
131
- checkmarkTimeoutRef.current = setTimeout(() => {
132
- setShowCheckmark(false);
133
- }, 1000);
134
-
135
- // Remove the event listener
136
- scrollContainerRef.current?.removeEventListener('scrollend', handleScrollEnd);
137
- };
138
-
139
- // Add scroll end listener
140
- scrollContainerRef.current.addEventListener('scrollend', handleScrollEnd);
141
-
142
- // Fallback timeout in case scrollend event doesn't fire
143
- syncTimeoutRef.current = setTimeout(() => {
144
- handleScrollEnd();
145
- }, 500);
146
-
147
- // Cleanup
148
- return () => {
149
- scrollContainerRef.current?.removeEventListener('scrollend', handleScrollEnd);
150
- if (syncTimeoutRef.current) {
151
- clearTimeout(syncTimeoutRef.current);
152
- }
153
- if (checkmarkTimeoutRef.current) {
154
- clearTimeout(checkmarkTimeoutRef.current);
155
- }
156
- };
157
- }
158
- }, [lastScrollMessage]);
159
-
160
- // Initialize todos if no messages exist
161
- useEffect(() => {
162
- if (messages.length === 0) {
163
- postMessage('todos', []);
164
- }
165
- }, []);
166
-
167
- const handleScrollSync = (e: React.UIEvent<HTMLDivElement>) => {
168
- const newScrollPosition = e.currentTarget.scrollTop;
169
-
170
- // Clear any existing timeouts
171
- if (scrollTimeoutRef.current) {
172
- clearTimeout(scrollTimeoutRef.current);
173
- }
174
- if (syncTimeoutRef.current) {
175
- clearTimeout(syncTimeoutRef.current);
176
- }
177
- if (checkmarkTimeoutRef.current) {
178
- clearTimeout(checkmarkTimeoutRef.current);
179
- }
180
-
181
- // Reset states
182
- setIsScrolling(true);
183
- setIsSyncing(true);
184
- setShowCheckmark(false);
185
-
186
- // Debounce the scroll message to avoid too many updates
187
- scrollTimeoutRef.current = setTimeout(() => {
188
- postScrollMessage('todos-scroll', newScrollPosition);
189
- }, 100);
190
- };
191
-
192
- const handleNewTodoChange = (event: React.ChangeEvent<HTMLInputElement>) => {
193
- setNewTodo(event.target.value);
194
- };
195
-
196
- const handleAddTodo = (event: React.FormEvent) => {
197
- event.preventDefault();
198
- if (newTodo.trim()) {
199
- const updated = [
200
- ...todos,
201
- { id: Date.now().toString(), text: newTodo.trim(), completed: false },
202
- ];
203
- setTodos(updated);
204
- postMessage('todos', updated);
205
- setNewTodo('');
206
- }
207
- };
208
-
209
- const handleToggleTodo = (id: string) => {
210
- const updated = todos.map(todo =>
211
- todo.id === id ? { ...todo, completed: !todo.completed } : todo
212
- );
213
- setTodos(updated);
214
- postMessage('todos', updated);
215
- };
216
-
217
- const handleDeleteTodo = (id: string) => {
218
- const updated = todos.filter(todo => todo.id !== id);
219
- setTodos(updated);
220
- postMessage('todos', updated);
221
- };
222
-
223
- const handleTodoMouseEnter = (id: string) => {
224
- setHoveredTodoId(id);
225
- postHoverMessage('todos-hover', id);
226
- };
227
-
228
- const handleTodoMouseLeave = () => {
229
- setHoveredTodoId(null);
230
- postHoverMessage('todos-hover', null);
231
- };
232
-
233
- return {
234
- todos,
235
- newTodo,
236
- handleNewTodoChange,
237
- handleAddTodo,
238
- handleToggleTodo,
239
- handleDeleteTodo,
240
- handleScrollSync,
241
- hoveredTodoId,
242
- isScrolling,
243
- isSyncing,
244
- showCheckmark,
245
- scrollContainerRef,
246
- handleTodoMouseEnter,
247
- handleTodoMouseLeave,
248
- };
249
- };
@@ -1,11 +0,0 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom/client';
3
- import App from './App';
4
- import { CssBaseline } from '@mui/material';
5
-
6
- ReactDOM.createRoot(document.getElementById('root')!).render(
7
- <React.StrictMode>
8
- <CssBaseline />
9
- <App />
10
- </React.StrictMode>
11
- );
@@ -1,62 +0,0 @@
1
- import { createTheme } from '@mui/material/styles';
2
-
3
- export const theme = createTheme({
4
- palette: {
5
- primary: {
6
- main: '#5EC13D',
7
- dark: '#3FAD3A',
8
- contrastText: '#fff',
9
- },
10
- secondary: {
11
- main: '#3FAD3A',
12
- contrastText: '#fff',
13
- },
14
- background: {
15
- default: '#0D1117',
16
- paper: '#161B22',
17
- },
18
- text: {
19
- primary: '#fff',
20
- secondary: '#bdbdbd',
21
- },
22
- },
23
- typography: {
24
- fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
25
- h1: {
26
- fontWeight: 700,
27
- },
28
- h2: {
29
- fontWeight: 600,
30
- },
31
- h3: {
32
- fontWeight: 600,
33
- },
34
- h4: {
35
- fontWeight: 600,
36
- },
37
- h5: {
38
- fontWeight: 600,
39
- },
40
- h6: {
41
- fontWeight: 600,
42
- },
43
- },
44
- components: {
45
- MuiButton: {
46
- styleOverrides: {
47
- root: {
48
- textTransform: 'none',
49
- borderRadius: 8,
50
- },
51
- },
52
- },
53
- MuiPaper: {
54
- styleOverrides: {
55
- root: {
56
- borderRadius: 12,
57
- background: '#161B22',
58
- },
59
- },
60
- },
61
- },
62
- });
@@ -1,26 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "useDefineForClassFields": true,
5
- "types": ["node"],
6
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
- "module": "ESNext",
8
- "skipLibCheck": true,
9
-
10
- /* Bundler mode */
11
- "moduleResolution": "bundler",
12
- "allowImportingTsExtensions": true,
13
- "resolveJsonModule": true,
14
- "isolatedModules": true,
15
- "noEmit": true,
16
- "jsx": "react-jsx",
17
-
18
- /* Linting */
19
- "strict": true,
20
- "noUnusedLocals": true,
21
- "noUnusedParameters": true,
22
- "noFallthroughCasesInSwitch": true
23
- },
24
- "include": ["src"],
25
- "references": [{ "path": "./tsconfig.node.json" }]
26
- }
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "composite": true,
4
- "skipLibCheck": true,
5
- "module": "ESNext",
6
- "moduleResolution": "bundler",
7
- "allowSyntheticDefaultImports": true
8
- },
9
- "include": ["vite.config.ts"]
10
- }
@@ -1,12 +0,0 @@
1
- import { defineConfig } from 'vite';
2
- import react from '@vitejs/plugin-react';
3
-
4
- // https://vitejs.dev/config/
5
- export default defineConfig({
6
- plugins: [react()],
7
- server: {
8
- port: 4000,
9
- strictPort: true,
10
- open: true,
11
- },
12
- });
package/eslint.config.js DELETED
@@ -1,38 +0,0 @@
1
- import eslint from '@eslint/js';
2
- import tseslint from 'typescript-eslint';
3
- import reactPlugin from 'eslint-plugin-react';
4
- import reactHooksPlugin from 'eslint-plugin-react-hooks';
5
- import prettierPlugin from 'eslint-plugin-prettier';
6
-
7
- export default [
8
- eslint.configs.recommended,
9
- ...tseslint.configs.recommended,
10
- {
11
- files: ['src/**/*.{ts,tsx}', 'demo/**/*.{ts,tsx}'],
12
- plugins: {
13
- react: reactPlugin,
14
- 'react-hooks': reactHooksPlugin,
15
- prettier: prettierPlugin,
16
- },
17
- rules: {
18
- 'react/react-in-jsx-scope': 'off',
19
- 'react/prop-types': 'off',
20
- '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
21
- '@typescript-eslint/explicit-module-boundary-types': 'off',
22
- '@typescript-eslint/no-explicit-any': [
23
- 'warn',
24
- {
25
- ignoreRestArgs: true,
26
- fixToUnknown: false,
27
- },
28
- ],
29
- 'prettier/prettier': 'error',
30
- },
31
- },
32
- {
33
- files: ['**/*.test.{ts,tsx}', '**/*.d.ts'],
34
- rules: {
35
- '@typescript-eslint/no-explicit-any': 'off',
36
- },
37
- },
38
- ];
package/jest.config.cjs DELETED
@@ -1,9 +0,0 @@
1
- module.exports = {
2
- preset: 'ts-jest',
3
- testEnvironment: 'jsdom',
4
- transform: {
5
- '^.+\\.(ts|tsx)$': 'ts-jest',
6
- },
7
- testMatch: ['**/src/tests/**/*.test.(ts|tsx)'],
8
- moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
9
- };
package/jest.setup.ts DELETED
@@ -1 +0,0 @@
1
- import '@testing-library/jest-dom';
package/rollup.config.mjs DELETED
@@ -1,98 +0,0 @@
1
- import babel from '@rollup/plugin-babel';
2
- import resolve from '@rollup/plugin-node-resolve';
3
- import commonjs from '@rollup/plugin-commonjs';
4
- import typescript from '@rollup/plugin-typescript';
5
- import peerDepsExternal from 'rollup-plugin-peer-deps-external';
6
- import terser from '@rollup/plugin-terser';
7
-
8
- const external = [
9
- 'react',
10
- 'react-dom',
11
- 'react/jsx-runtime',
12
- /^react\//,
13
- /^react-dom\//,
14
- 'typescript',
15
- 'tslib',
16
- '@babel/runtime',
17
- ];
18
-
19
- export default {
20
- input: 'src/index.ts',
21
- output: [
22
- {
23
- file: 'dist/index.esm.js',
24
- format: 'es',
25
- sourcemap: true,
26
- globals: {
27
- react: 'React',
28
- 'react-dom': 'ReactDOM',
29
- typescript: 'ts',
30
- tslib: 'tslib',
31
- '@babel/runtime': 'babelRuntime',
32
- },
33
- exports: 'named',
34
- },
35
- {
36
- file: 'dist/index.cjs.js',
37
- format: 'cjs',
38
- sourcemap: true,
39
- globals: {
40
- react: 'React',
41
- 'react-dom': 'ReactDOM',
42
- typescript: 'ts',
43
- tslib: 'tslib',
44
- '@babel/runtime': 'babelRuntime',
45
- },
46
- exports: 'named',
47
- },
48
- ],
49
- plugins: [
50
- peerDepsExternal({
51
- includeDependencies: false,
52
- }),
53
- resolve({
54
- mainFields: ['module', 'main'],
55
- extensions: ['.js', '.jsx', '.ts', '.tsx'],
56
- preferBuiltins: true,
57
- dedupe: ['react', 'react-dom'],
58
- }),
59
- commonjs({
60
- include: /node_modules/,
61
- transformMixedEsModules: true,
62
- requireReturnsDefault: 'auto',
63
- }),
64
- typescript({
65
- tsconfig: './tsconfig.json',
66
- exclude: ['**/__tests__/**', '**/*.test.ts', '**/*.test.tsx'],
67
- declaration: true,
68
- declarationDir: './dist',
69
- emitDeclarationOnly: false,
70
- sourceMap: true,
71
- }),
72
- babel({
73
- babelHelpers: 'runtime',
74
- presets: [
75
- [
76
- '@babel/preset-react',
77
- {
78
- runtime: 'automatic',
79
- development: process.env.NODE_ENV === 'development',
80
- },
81
- ],
82
- ],
83
- plugins: [
84
- [
85
- '@babel/plugin-transform-runtime',
86
- {
87
- regenerator: true,
88
- useESModules: true,
89
- },
90
- ],
91
- ],
92
- extensions: ['.js', '.jsx', '.ts', '.tsx'],
93
- exclude: 'node_modules/**',
94
- }),
95
- terser(),
96
- ],
97
- external,
98
- };
@@ -1,28 +0,0 @@
1
- import React, { createContext, useContext } from 'react';
2
- import { useBroadcastChannel } from './hooks/useBroadcastChannel';
3
- import { BroadcastActions } from './types/types';
4
-
5
- const BroadcastChannelContext = createContext<BroadcastActions | undefined>(undefined);
6
-
7
- interface BroadcastProviderProps {
8
- channelName: string;
9
- children: React.ReactNode;
10
- }
11
-
12
- export const BroadcastProvider: React.FC<BroadcastProviderProps> = ({ children, channelName }) => {
13
- const BroadcastChannelActions = useBroadcastChannel(channelName);
14
-
15
- return (
16
- <BroadcastChannelContext.Provider value={BroadcastChannelActions}>
17
- {children}
18
- </BroadcastChannelContext.Provider>
19
- );
20
- };
21
-
22
- export const useBroadcastProvider = (): BroadcastActions => {
23
- const context = useContext(BroadcastChannelContext);
24
- if (!context) {
25
- throw new Error('useBroadcastProvider must be used within a BroadcastProvider');
26
- }
27
- return context;
28
- };