@quiltt/react 5.0.0 → 5.0.2

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 (82) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +12 -0
  3. package/dist/components/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
  4. package/dist/components/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  5. package/dist/components/index.cjs +212 -0
  6. package/dist/components/index.d.ts +56 -0
  7. package/dist/components/index.js +209 -0
  8. package/dist/{useQuilttConnector-12s-DfCZ1lpS.js → components/useQuilttConnector-12s-3VgurfwU.js} +6 -77
  9. package/dist/components/useQuilttConnector-12s-zU4NFJ-H.cjs +174 -0
  10. package/dist/components/useQuilttRenderGuard-12s-D9WbRzZO.cjs +36 -0
  11. package/dist/components/useQuilttSession-12s-BjyJL1qZ.cjs +133 -0
  12. package/dist/components/useQuilttSession-12s-VOH0S5zh.js +133 -0
  13. package/dist/components/useQuilttSettings-12s-aDLXY6z3.cjs +10 -0
  14. package/dist/components/useScript-12s-CMIDUHrx.cjs +92 -0
  15. package/dist/{useSession-12s-BlrWOArd.js → components/useSession-12s-BNPsfKY-.js} +27 -6
  16. package/dist/components/useSession-12s-BNotXj5T.cjs +90 -0
  17. package/dist/components/useStorage-12s-D7nllsrI.cjs +61 -0
  18. package/dist/contexts/QuilttSettings-12s-BK-0SQME.js +6 -0
  19. package/dist/contexts/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  20. package/dist/contexts/index.cjs +7 -0
  21. package/dist/contexts/index.d.ts +8 -0
  22. package/dist/contexts/index.js +1 -0
  23. package/dist/hooks/QuilttProviderRender-12s-DtQtubjL.js +6 -0
  24. package/dist/hooks/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
  25. package/dist/hooks/QuilttSettings-12s-BK-0SQME.js +6 -0
  26. package/dist/hooks/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  27. package/dist/hooks/index.cjs +31 -0
  28. package/dist/hooks/index.d.ts +142 -0
  29. package/dist/hooks/index.js +11 -0
  30. package/dist/hooks/useEventListener-12s-CV8cLxWu.cjs +34 -0
  31. package/dist/hooks/useIsomorphicLayoutEffect-12s-B8KjaroI.cjs +9 -0
  32. package/dist/hooks/useQuilttClient-12s-flQYSVdG.cjs +6 -0
  33. package/dist/hooks/useQuilttConnector-12s-BLZ0GoAH.js +174 -0
  34. package/dist/hooks/useQuilttConnector-12s-sP-k4D3J.cjs +175 -0
  35. package/dist/hooks/useQuilttInstitutions-12s-BU_Vm7TY.cjs +82 -0
  36. package/dist/{useQuilttInstitutions-12s-ClSQJPmP.js → hooks/useQuilttInstitutions-12s-ByXIt9W6.js} +3 -2
  37. package/dist/hooks/useQuilttRenderGuard-12s-CsS2Ma6Q.js +36 -0
  38. package/dist/hooks/useQuilttRenderGuard-12s-D9WbRzZO.cjs +36 -0
  39. package/dist/{useQuilttResolvable-12s-Dm4vsARj.js → hooks/useQuilttResolvable-12s-C5DByktm.js} +3 -2
  40. package/dist/hooks/useQuilttResolvable-12s-CGEfKPVU.cjs +76 -0
  41. package/dist/hooks/useQuilttSession-12s-C8kq5S2Y.cjs +139 -0
  42. package/dist/{useQuilttSession-12s-_8sB_8aP.js → hooks/useQuilttSession-12s-DQFfjmob.js} +1 -1
  43. package/dist/hooks/useQuilttSettings-12s--rCJoNHD.js +10 -0
  44. package/dist/hooks/useQuilttSettings-12s-aDLXY6z3.cjs +10 -0
  45. package/dist/hooks/useScript-12s-CMIDUHrx.cjs +92 -0
  46. package/dist/hooks/useScript-12s-JCgaTW9n.js +92 -0
  47. package/dist/hooks/useSession-12s-BNPsfKY-.js +90 -0
  48. package/dist/hooks/useSession-12s-BNotXj5T.cjs +90 -0
  49. package/dist/hooks/useStorage-12s-CpG6X57D.js +61 -0
  50. package/dist/hooks/useStorage-12s-D7nllsrI.cjs +61 -0
  51. package/dist/index.cjs +149 -0
  52. package/dist/index.d.ts +3 -216
  53. package/dist/index.js +3 -190
  54. package/dist/{QuilttAuthProvider-12s-C_Wt9rkK.js → providers/QuilttAuthProvider-12s-CDgQbarX.js} +14 -12
  55. package/dist/providers/QuilttAuthProvider-12s-D__FY1Qn.cjs +60 -0
  56. package/dist/providers/QuilttProviderRender-12s-DtQtubjL.js +6 -0
  57. package/dist/providers/QuilttProviderRender-12s-pvnc98Lj.cjs +6 -0
  58. package/dist/providers/QuilttSettings-12s-BK-0SQME.js +6 -0
  59. package/dist/providers/QuilttSettings-12s-cLPT_GLC.cjs +6 -0
  60. package/dist/providers/QuilttSettingsProvider-12s-D7e8dsOE.cjs +19 -0
  61. package/dist/{QuilttSettingsProvider-12s-ZcmFmOiZ.js → providers/QuilttSettingsProvider-12s-DND2gPQm.js} +8 -5
  62. package/dist/providers/index.cjs +34 -0
  63. package/dist/providers/index.d.ts +28 -0
  64. package/dist/providers/index.js +30 -0
  65. package/dist/utils/index.cjs +89 -0
  66. package/dist/utils/index.d.ts +31 -0
  67. package/dist/utils/index.js +77 -0
  68. package/package.json +33 -7
  69. package/src/components/QuilttContainer.tsx +3 -0
  70. package/src/hooks/useSession.ts +32 -6
  71. package/src/providers/QuilttAuthProvider.tsx +8 -2
  72. package/src/providers/QuilttProvider.tsx +5 -1
  73. package/src/providers/QuilttSettingsProvider.tsx +4 -5
  74. /package/dist/{QuilttProviderRender-12s-DtQtubjL.js → components/QuilttProviderRender-12s-DtQtubjL.js} +0 -0
  75. /package/dist/{QuilttSettings-12s-BK-0SQME.js → components/QuilttSettings-12s-BK-0SQME.js} +0 -0
  76. /package/dist/{useQuilttRenderGuard-12s-CsS2Ma6Q.js → components/useQuilttRenderGuard-12s-CsS2Ma6Q.js} +0 -0
  77. /package/dist/{useQuilttSettings-12s--rCJoNHD.js → components/useQuilttSettings-12s--rCJoNHD.js} +0 -0
  78. /package/dist/{useScript-12s-JCgaTW9n.js → components/useScript-12s-JCgaTW9n.js} +0 -0
  79. /package/dist/{useStorage-12s-CpG6X57D.js → components/useStorage-12s-CpG6X57D.js} +0 -0
  80. /package/dist/{useEventListener-12s-D_-6QIXa.js → hooks/useEventListener-12s-D_-6QIXa.js} +0 -0
  81. /package/dist/{useIsomorphicLayoutEffect-12s-DeTHOKz1.js → hooks/useIsomorphicLayoutEffect-12s-DeTHOKz1.js} +0 -0
  82. /package/dist/{useQuilttClient-12s-Dj_MtYTU.js → hooks/useQuilttClient-12s-Dj_MtYTU.js} +0 -0
@@ -0,0 +1,92 @@
1
+ 'use client';
2
+ var react = require('react');
3
+
4
+ // Cached script statuses
5
+ const cachedScriptStatuses = {};
6
+ function getScriptNode(src) {
7
+ const node = document.querySelector(`script[src="${src}"]`);
8
+ const status = node?.getAttribute('data-status');
9
+ return {
10
+ node,
11
+ status
12
+ };
13
+ }
14
+ // @see https://usehooks-ts.com/react-hook/use-script
15
+ function useScript(src, options) {
16
+ const [status, setStatus] = react.useState(()=>{
17
+ if (!src || options?.shouldPreventLoad) {
18
+ return 'idle';
19
+ }
20
+ if (typeof window === 'undefined') {
21
+ // SSR Handling - always return 'loading'
22
+ return 'loading';
23
+ }
24
+ return cachedScriptStatuses[src] ?? 'loading';
25
+ });
26
+ react.useEffect(()=>{
27
+ if (!src || options?.shouldPreventLoad) {
28
+ return;
29
+ }
30
+ const cachedScriptStatus = cachedScriptStatuses[src];
31
+ if (cachedScriptStatus === 'ready' || cachedScriptStatus === 'error') {
32
+ // If the script is already cached, set its status immediately
33
+ setStatus(cachedScriptStatus);
34
+ return;
35
+ }
36
+ // Fetch existing script element by src
37
+ // It may have been added by another instance of this hook
38
+ const script = getScriptNode(src);
39
+ let scriptNode = script.node;
40
+ if (!scriptNode) {
41
+ // Create script element and add it to document body
42
+ scriptNode = document.createElement('script');
43
+ scriptNode.src = src;
44
+ scriptNode.async = true;
45
+ if (options?.nonce && options.nonce.trim() !== '') {
46
+ scriptNode.nonce = options.nonce;
47
+ }
48
+ scriptNode.setAttribute('data-status', 'loading');
49
+ document.body.appendChild(scriptNode);
50
+ // Store status in attribute on script
51
+ // This can be read by other instances of this hook
52
+ const setAttributeFromEvent = (event)=>{
53
+ const scriptStatus = event.type === 'load' ? 'ready' : 'error';
54
+ scriptNode?.setAttribute('data-status', scriptStatus);
55
+ };
56
+ scriptNode.addEventListener('load', setAttributeFromEvent);
57
+ scriptNode.addEventListener('error', setAttributeFromEvent);
58
+ } else {
59
+ // Grab existing script status from attribute and set to state.
60
+ setStatus(script.status ?? cachedScriptStatus ?? 'loading');
61
+ }
62
+ // Script event handler to update status in state
63
+ // Note: Even if the script already exists we still need to add
64
+ // event handlers to update the state for *this* hook instance.
65
+ const setStateFromEvent = (event)=>{
66
+ const newStatus = event.type === 'load' ? 'ready' : 'error';
67
+ setStatus(newStatus);
68
+ cachedScriptStatuses[src] = newStatus;
69
+ };
70
+ // Add event listeners
71
+ scriptNode.addEventListener('load', setStateFromEvent);
72
+ scriptNode.addEventListener('error', setStateFromEvent);
73
+ // Remove event listeners on cleanup
74
+ return ()=>{
75
+ if (scriptNode) {
76
+ scriptNode.removeEventListener('load', setStateFromEvent);
77
+ scriptNode.removeEventListener('error', setStateFromEvent);
78
+ }
79
+ if (scriptNode && options?.removeOnUnmount) {
80
+ scriptNode.remove();
81
+ }
82
+ };
83
+ }, [
84
+ src,
85
+ options?.shouldPreventLoad,
86
+ options?.nonce,
87
+ options?.removeOnUnmount
88
+ ]);
89
+ return status;
90
+ }
91
+
92
+ exports.useScript = useScript;
@@ -0,0 +1,92 @@
1
+ 'use client';
2
+ import { useState, useEffect } from 'react';
3
+
4
+ // Cached script statuses
5
+ const cachedScriptStatuses = {};
6
+ function getScriptNode(src) {
7
+ const node = document.querySelector(`script[src="${src}"]`);
8
+ const status = node?.getAttribute('data-status');
9
+ return {
10
+ node,
11
+ status
12
+ };
13
+ }
14
+ // @see https://usehooks-ts.com/react-hook/use-script
15
+ function useScript(src, options) {
16
+ const [status, setStatus] = useState(()=>{
17
+ if (!src || options?.shouldPreventLoad) {
18
+ return 'idle';
19
+ }
20
+ if (typeof window === 'undefined') {
21
+ // SSR Handling - always return 'loading'
22
+ return 'loading';
23
+ }
24
+ return cachedScriptStatuses[src] ?? 'loading';
25
+ });
26
+ useEffect(()=>{
27
+ if (!src || options?.shouldPreventLoad) {
28
+ return;
29
+ }
30
+ const cachedScriptStatus = cachedScriptStatuses[src];
31
+ if (cachedScriptStatus === 'ready' || cachedScriptStatus === 'error') {
32
+ // If the script is already cached, set its status immediately
33
+ setStatus(cachedScriptStatus);
34
+ return;
35
+ }
36
+ // Fetch existing script element by src
37
+ // It may have been added by another instance of this hook
38
+ const script = getScriptNode(src);
39
+ let scriptNode = script.node;
40
+ if (!scriptNode) {
41
+ // Create script element and add it to document body
42
+ scriptNode = document.createElement('script');
43
+ scriptNode.src = src;
44
+ scriptNode.async = true;
45
+ if (options?.nonce && options.nonce.trim() !== '') {
46
+ scriptNode.nonce = options.nonce;
47
+ }
48
+ scriptNode.setAttribute('data-status', 'loading');
49
+ document.body.appendChild(scriptNode);
50
+ // Store status in attribute on script
51
+ // This can be read by other instances of this hook
52
+ const setAttributeFromEvent = (event)=>{
53
+ const scriptStatus = event.type === 'load' ? 'ready' : 'error';
54
+ scriptNode?.setAttribute('data-status', scriptStatus);
55
+ };
56
+ scriptNode.addEventListener('load', setAttributeFromEvent);
57
+ scriptNode.addEventListener('error', setAttributeFromEvent);
58
+ } else {
59
+ // Grab existing script status from attribute and set to state.
60
+ setStatus(script.status ?? cachedScriptStatus ?? 'loading');
61
+ }
62
+ // Script event handler to update status in state
63
+ // Note: Even if the script already exists we still need to add
64
+ // event handlers to update the state for *this* hook instance.
65
+ const setStateFromEvent = (event)=>{
66
+ const newStatus = event.type === 'load' ? 'ready' : 'error';
67
+ setStatus(newStatus);
68
+ cachedScriptStatuses[src] = newStatus;
69
+ };
70
+ // Add event listeners
71
+ scriptNode.addEventListener('load', setStateFromEvent);
72
+ scriptNode.addEventListener('error', setStateFromEvent);
73
+ // Remove event listeners on cleanup
74
+ return ()=>{
75
+ if (scriptNode) {
76
+ scriptNode.removeEventListener('load', setStateFromEvent);
77
+ scriptNode.removeEventListener('error', setStateFromEvent);
78
+ }
79
+ if (scriptNode && options?.removeOnUnmount) {
80
+ scriptNode.remove();
81
+ }
82
+ };
83
+ }, [
84
+ src,
85
+ options?.shouldPreventLoad,
86
+ options?.nonce,
87
+ options?.removeOnUnmount
88
+ ]);
89
+ return status;
90
+ }
91
+
92
+ export { useScript as u };
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+ import { useMemo, useEffect, useCallback } from 'react';
3
+ import { Timeoutable, JsonWebTokenParse } from '@quiltt/core';
4
+ import { u as useStorage } from './useStorage-12s-CpG6X57D.js';
5
+
6
+ // Initialize JWT parser with our specific claims type
7
+ const parse = JsonWebTokenParse;
8
+ // Global timer to manage token expiration across all hook instances
9
+ const sessionTimer = new Timeoutable();
10
+ /**
11
+ * Custom hook to manage JWT session state with automatic expiration handling.
12
+ * Provides global singleton access to the session across components and windows.
13
+ *
14
+ * TODO: Support Rotation before Expiry
15
+ *
16
+ * Handles two types of data flow:
17
+ * 1. Bottom-up (Login): Token passed through setSession callback
18
+ * 2. Top-down (Refresh): State reinitialized on page reload
19
+ *
20
+ * @param storageKey - Key used for storing session in useStorage (defaults to 'session')
21
+ * @returns [session, setSession] - Current session state and setter function
22
+ */ const useSession = (storageKey = 'session')=>{
23
+ const [token, setToken] = useStorage(storageKey);
24
+ // Parse token into session data, updates when token changes
25
+ const session = useMemo(()=>parse(token), [
26
+ token
27
+ ]);
28
+ // Handle session expiration
29
+ useEffect(()=>{
30
+ if (!session) return;
31
+ const expirationMS = session.claims.exp * 1000;
32
+ const expire = ()=>setToken(null);
33
+ const checkExpiration = ()=>{
34
+ if (Date.now() >= expirationMS) {
35
+ expire();
36
+ return true;
37
+ }
38
+ return false;
39
+ };
40
+ // Clear immediately if already expired
41
+ if (checkExpiration()) {
42
+ return;
43
+ }
44
+ // Set timer to clear session at expiration time
45
+ sessionTimer.set(expire, expirationMS - Date.now());
46
+ // Also check expiration when tab becomes visible (handles idle sessions)
47
+ const handleVisibilityChange = ()=>{
48
+ if (!document.hidden) {
49
+ checkExpiration();
50
+ }
51
+ };
52
+ // Only add listener in browser environment
53
+ if (typeof document !== 'undefined') {
54
+ document.addEventListener('visibilitychange', handleVisibilityChange);
55
+ }
56
+ return ()=>{
57
+ sessionTimer.clear(expire);
58
+ if (typeof document !== 'undefined') {
59
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
60
+ }
61
+ };
62
+ }, [
63
+ session,
64
+ setToken
65
+ ]);
66
+ /**
67
+ * Validates and updates the session token.
68
+ * - Handles both direct values and updater functions
69
+ * - Validates new tokens before setting them
70
+ * - Prevents unnecessary updates for same token value
71
+ * - Allows clearing the session with null/undefined
72
+ */ const setSession = useCallback((nextState)=>{
73
+ const newState = nextState instanceof Function ? nextState(token) : nextState;
74
+ // Only update if:
75
+ // 1. The token has actually changed AND
76
+ // 2. Either the new state is falsy (clearing session) OR it's a valid token
77
+ if (token !== newState && (!newState || parse(newState))) {
78
+ setToken(newState);
79
+ }
80
+ }, [
81
+ token,
82
+ setToken
83
+ ]);
84
+ return [
85
+ session,
86
+ setSession
87
+ ];
88
+ };
89
+
90
+ export { useSession as u };
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+ var react = require('react');
3
+ var core = require('@quiltt/core');
4
+ var useStorage12s = require('./useStorage-12s-D7nllsrI.cjs');
5
+
6
+ // Initialize JWT parser with our specific claims type
7
+ const parse = core.JsonWebTokenParse;
8
+ // Global timer to manage token expiration across all hook instances
9
+ const sessionTimer = new core.Timeoutable();
10
+ /**
11
+ * Custom hook to manage JWT session state with automatic expiration handling.
12
+ * Provides global singleton access to the session across components and windows.
13
+ *
14
+ * TODO: Support Rotation before Expiry
15
+ *
16
+ * Handles two types of data flow:
17
+ * 1. Bottom-up (Login): Token passed through setSession callback
18
+ * 2. Top-down (Refresh): State reinitialized on page reload
19
+ *
20
+ * @param storageKey - Key used for storing session in useStorage (defaults to 'session')
21
+ * @returns [session, setSession] - Current session state and setter function
22
+ */ const useSession = (storageKey = 'session')=>{
23
+ const [token, setToken] = useStorage12s.useStorage(storageKey);
24
+ // Parse token into session data, updates when token changes
25
+ const session = react.useMemo(()=>parse(token), [
26
+ token
27
+ ]);
28
+ // Handle session expiration
29
+ react.useEffect(()=>{
30
+ if (!session) return;
31
+ const expirationMS = session.claims.exp * 1000;
32
+ const expire = ()=>setToken(null);
33
+ const checkExpiration = ()=>{
34
+ if (Date.now() >= expirationMS) {
35
+ expire();
36
+ return true;
37
+ }
38
+ return false;
39
+ };
40
+ // Clear immediately if already expired
41
+ if (checkExpiration()) {
42
+ return;
43
+ }
44
+ // Set timer to clear session at expiration time
45
+ sessionTimer.set(expire, expirationMS - Date.now());
46
+ // Also check expiration when tab becomes visible (handles idle sessions)
47
+ const handleVisibilityChange = ()=>{
48
+ if (!document.hidden) {
49
+ checkExpiration();
50
+ }
51
+ };
52
+ // Only add listener in browser environment
53
+ if (typeof document !== 'undefined') {
54
+ document.addEventListener('visibilitychange', handleVisibilityChange);
55
+ }
56
+ return ()=>{
57
+ sessionTimer.clear(expire);
58
+ if (typeof document !== 'undefined') {
59
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
60
+ }
61
+ };
62
+ }, [
63
+ session,
64
+ setToken
65
+ ]);
66
+ /**
67
+ * Validates and updates the session token.
68
+ * - Handles both direct values and updater functions
69
+ * - Validates new tokens before setting them
70
+ * - Prevents unnecessary updates for same token value
71
+ * - Allows clearing the session with null/undefined
72
+ */ const setSession = react.useCallback((nextState)=>{
73
+ const newState = nextState instanceof Function ? nextState(token) : nextState;
74
+ // Only update if:
75
+ // 1. The token has actually changed AND
76
+ // 2. Either the new state is falsy (clearing session) OR it's a valid token
77
+ if (token !== newState && (!newState || parse(newState))) {
78
+ setToken(newState);
79
+ }
80
+ }, [
81
+ token,
82
+ setToken
83
+ ]);
84
+ return [
85
+ session,
86
+ setSession
87
+ ];
88
+ };
89
+
90
+ exports.useSession = useSession;
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+ import { useCallback, useState, useEffect } from 'react';
3
+ import { GlobalStorage } from '@quiltt/core';
4
+
5
+ /**
6
+ * Attempt to persist state with local storage, so it remains after refresh and
7
+ * across open documents. Falls back to in memory storage when localStorage is
8
+ * unavailable.
9
+ *
10
+ * This hook is used in the same way as useState except that you must pass the
11
+ * storage key in the 1st parameter. If the window object is not present (as in SSR),
12
+ * useStorage() will return the default nextState.
13
+ *
14
+ * Expect values to remain in sync
15
+ * Across Hooks
16
+ * Across Reloads
17
+ * Across Windows (Documents)
18
+ *
19
+ * @param key
20
+ * @param initialState
21
+ * @returns {Array} [storage, setStorage]
22
+ */ const useStorage = (key, initialState)=>{
23
+ const getStorage = useCallback(()=>{
24
+ const state = GlobalStorage.get(key);
25
+ if (state !== undefined) {
26
+ return state;
27
+ }
28
+ return initialState;
29
+ }, [
30
+ key,
31
+ initialState
32
+ ]);
33
+ const [hookState, setHookState] = useState(getStorage());
34
+ const setStorage = useCallback((nextState)=>{
35
+ const newState = nextState instanceof Function ? nextState(hookState) : nextState;
36
+ if (hookState !== newState) {
37
+ GlobalStorage.set(key, newState);
38
+ // Immediately update hook state as well
39
+ setHookState(newState);
40
+ }
41
+ }, [
42
+ key,
43
+ hookState
44
+ ]);
45
+ useEffect(()=>{
46
+ // Subscribe to storage changes from other sources (e.g., other hook instances, browser tabs)
47
+ const handleStorageChange = (newValue)=>{
48
+ setHookState(newValue);
49
+ };
50
+ GlobalStorage.subscribe(key, handleStorageChange);
51
+ return ()=>GlobalStorage.unsubscribe(key, handleStorageChange);
52
+ }, [
53
+ key
54
+ ]);
55
+ return [
56
+ hookState,
57
+ setStorage
58
+ ];
59
+ };
60
+
61
+ export { useStorage as u };
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+ var react = require('react');
3
+ var core = require('@quiltt/core');
4
+
5
+ /**
6
+ * Attempt to persist state with local storage, so it remains after refresh and
7
+ * across open documents. Falls back to in memory storage when localStorage is
8
+ * unavailable.
9
+ *
10
+ * This hook is used in the same way as useState except that you must pass the
11
+ * storage key in the 1st parameter. If the window object is not present (as in SSR),
12
+ * useStorage() will return the default nextState.
13
+ *
14
+ * Expect values to remain in sync
15
+ * Across Hooks
16
+ * Across Reloads
17
+ * Across Windows (Documents)
18
+ *
19
+ * @param key
20
+ * @param initialState
21
+ * @returns {Array} [storage, setStorage]
22
+ */ const useStorage = (key, initialState)=>{
23
+ const getStorage = react.useCallback(()=>{
24
+ const state = core.GlobalStorage.get(key);
25
+ if (state !== undefined) {
26
+ return state;
27
+ }
28
+ return initialState;
29
+ }, [
30
+ key,
31
+ initialState
32
+ ]);
33
+ const [hookState, setHookState] = react.useState(getStorage());
34
+ const setStorage = react.useCallback((nextState)=>{
35
+ const newState = nextState instanceof Function ? nextState(hookState) : nextState;
36
+ if (hookState !== newState) {
37
+ core.GlobalStorage.set(key, newState);
38
+ // Immediately update hook state as well
39
+ setHookState(newState);
40
+ }
41
+ }, [
42
+ key,
43
+ hookState
44
+ ]);
45
+ react.useEffect(()=>{
46
+ // Subscribe to storage changes from other sources (e.g., other hook instances, browser tabs)
47
+ const handleStorageChange = (newValue)=>{
48
+ setHookState(newValue);
49
+ };
50
+ core.GlobalStorage.subscribe(key, handleStorageChange);
51
+ return ()=>core.GlobalStorage.unsubscribe(key, handleStorageChange);
52
+ }, [
53
+ key
54
+ ]);
55
+ return [
56
+ hookState,
57
+ setStorage
58
+ ];
59
+ };
60
+
61
+ exports.useStorage = useStorage;
package/dist/index.cjs ADDED
@@ -0,0 +1,149 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ var client = require('@apollo/client');
4
+ var errors = require('@apollo/client/errors');
5
+ var react = require('@apollo/client/react');
6
+ var react$1 = require('@apollo/client/testing/react');
7
+ var core = require('@quiltt/core');
8
+ var index_cjs = require('./components/index.cjs');
9
+ var index_cjs$1 = require('./hooks/index.cjs');
10
+ var index_cjs$2 = require('./providers/index.cjs');
11
+
12
+
13
+
14
+ Object.defineProperty(exports, "ApolloClient", {
15
+ enumerable: true,
16
+ get: function () { return client.ApolloClient; }
17
+ });
18
+ Object.defineProperty(exports, "InMemoryCache", {
19
+ enumerable: true,
20
+ get: function () { return client.InMemoryCache; }
21
+ });
22
+ Object.defineProperty(exports, "NetworkStatus", {
23
+ enumerable: true,
24
+ get: function () { return client.NetworkStatus; }
25
+ });
26
+ Object.defineProperty(exports, "ObservableQuery", {
27
+ enumerable: true,
28
+ get: function () { return client.ObservableQuery; }
29
+ });
30
+ Object.defineProperty(exports, "gql", {
31
+ enumerable: true,
32
+ get: function () { return client.gql; }
33
+ });
34
+ Object.defineProperty(exports, "CombinedGraphQLErrors", {
35
+ enumerable: true,
36
+ get: function () { return errors.CombinedGraphQLErrors; }
37
+ });
38
+ Object.defineProperty(exports, "CombinedProtocolErrors", {
39
+ enumerable: true,
40
+ get: function () { return errors.CombinedProtocolErrors; }
41
+ });
42
+ Object.defineProperty(exports, "LinkError", {
43
+ enumerable: true,
44
+ get: function () { return errors.LinkError; }
45
+ });
46
+ Object.defineProperty(exports, "LocalStateError", {
47
+ enumerable: true,
48
+ get: function () { return errors.LocalStateError; }
49
+ });
50
+ Object.defineProperty(exports, "ServerError", {
51
+ enumerable: true,
52
+ get: function () { return errors.ServerError; }
53
+ });
54
+ Object.defineProperty(exports, "ServerParseError", {
55
+ enumerable: true,
56
+ get: function () { return errors.ServerParseError; }
57
+ });
58
+ Object.defineProperty(exports, "UnconventionalError", {
59
+ enumerable: true,
60
+ get: function () { return errors.UnconventionalError; }
61
+ });
62
+ Object.defineProperty(exports, "ApolloProvider", {
63
+ enumerable: true,
64
+ get: function () { return react.ApolloProvider; }
65
+ });
66
+ Object.defineProperty(exports, "createQueryPreloader", {
67
+ enumerable: true,
68
+ get: function () { return react.createQueryPreloader; }
69
+ });
70
+ Object.defineProperty(exports, "skipToken", {
71
+ enumerable: true,
72
+ get: function () { return react.skipToken; }
73
+ });
74
+ Object.defineProperty(exports, "useApolloClient", {
75
+ enumerable: true,
76
+ get: function () { return react.useApolloClient; }
77
+ });
78
+ Object.defineProperty(exports, "useBackgroundQuery", {
79
+ enumerable: true,
80
+ get: function () { return react.useBackgroundQuery; }
81
+ });
82
+ Object.defineProperty(exports, "useFragment", {
83
+ enumerable: true,
84
+ get: function () { return react.useFragment; }
85
+ });
86
+ Object.defineProperty(exports, "useLazyQuery", {
87
+ enumerable: true,
88
+ get: function () { return react.useLazyQuery; }
89
+ });
90
+ Object.defineProperty(exports, "useLoadableQuery", {
91
+ enumerable: true,
92
+ get: function () { return react.useLoadableQuery; }
93
+ });
94
+ Object.defineProperty(exports, "useMutation", {
95
+ enumerable: true,
96
+ get: function () { return react.useMutation; }
97
+ });
98
+ Object.defineProperty(exports, "useQuery", {
99
+ enumerable: true,
100
+ get: function () { return react.useQuery; }
101
+ });
102
+ Object.defineProperty(exports, "useQueryRefHandlers", {
103
+ enumerable: true,
104
+ get: function () { return react.useQueryRefHandlers; }
105
+ });
106
+ Object.defineProperty(exports, "useReactiveVar", {
107
+ enumerable: true,
108
+ get: function () { return react.useReactiveVar; }
109
+ });
110
+ Object.defineProperty(exports, "useReadQuery", {
111
+ enumerable: true,
112
+ get: function () { return react.useReadQuery; }
113
+ });
114
+ Object.defineProperty(exports, "useSubscription", {
115
+ enumerable: true,
116
+ get: function () { return react.useSubscription; }
117
+ });
118
+ Object.defineProperty(exports, "useSuspenseQuery", {
119
+ enumerable: true,
120
+ get: function () { return react.useSuspenseQuery; }
121
+ });
122
+ Object.defineProperty(exports, "MockedProvider", {
123
+ enumerable: true,
124
+ get: function () { return react$1.MockedProvider; }
125
+ });
126
+ Object.keys(core).forEach(function (k) {
127
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
128
+ enumerable: true,
129
+ get: function () { return core[k]; }
130
+ });
131
+ });
132
+ Object.keys(index_cjs).forEach(function (k) {
133
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
134
+ enumerable: true,
135
+ get: function () { return index_cjs[k]; }
136
+ });
137
+ });
138
+ Object.keys(index_cjs$1).forEach(function (k) {
139
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
140
+ enumerable: true,
141
+ get: function () { return index_cjs$1[k]; }
142
+ });
143
+ });
144
+ Object.keys(index_cjs$2).forEach(function (k) {
145
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
146
+ enumerable: true,
147
+ get: function () { return index_cjs$2[k]; }
148
+ });
149
+ });