@teo-garcia/react-shared 0.1.9 → 1.2.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 (177) hide show
  1. package/README.md +127 -99
  2. package/dist/components/aspect-ratio/aspect-ratio.d.ts +17 -0
  3. package/dist/components/aspect-ratio/aspect-ratio.d.ts.map +1 -0
  4. package/dist/components/aspect-ratio/aspect-ratio.js +14 -0
  5. package/dist/components/aspect-ratio/index.d.ts +2 -0
  6. package/dist/components/aspect-ratio/index.d.ts.map +1 -0
  7. package/dist/components/aspect-ratio/index.js +1 -0
  8. package/dist/components/debug-json/debug-json.d.ts +14 -0
  9. package/dist/components/debug-json/debug-json.d.ts.map +1 -0
  10. package/dist/components/debug-json/debug-json.js +32 -0
  11. package/dist/components/debug-json/index.d.ts +2 -0
  12. package/dist/components/debug-json/index.d.ts.map +1 -0
  13. package/dist/components/debug-json/index.js +1 -0
  14. package/dist/components/dev-panel/dev-panel.d.ts +30 -0
  15. package/dist/components/dev-panel/dev-panel.d.ts.map +1 -0
  16. package/dist/components/dev-panel/dev-panel.js +155 -0
  17. package/dist/components/dev-panel/index.d.ts +2 -0
  18. package/dist/components/dev-panel/index.d.ts.map +1 -0
  19. package/dist/components/dev-panel/index.js +1 -0
  20. package/dist/components/error-boundary/error-boundary.d.ts +3 -58
  21. package/dist/components/error-boundary/error-boundary.d.ts.map +1 -1
  22. package/dist/components/error-boundary/error-boundary.js +51 -77
  23. package/dist/components/error-boundary/index.d.ts +1 -0
  24. package/dist/components/error-boundary/index.d.ts.map +1 -1
  25. package/dist/components/focus-trap/focus-trap.d.ts +16 -0
  26. package/dist/components/focus-trap/focus-trap.d.ts.map +1 -0
  27. package/dist/components/focus-trap/focus-trap.js +57 -0
  28. package/dist/components/focus-trap/index.d.ts +2 -0
  29. package/dist/components/focus-trap/index.d.ts.map +1 -0
  30. package/dist/components/focus-trap/index.js +1 -0
  31. package/dist/components/index.d.ts +9 -5
  32. package/dist/components/index.d.ts.map +1 -1
  33. package/dist/components/index.js +9 -5
  34. package/dist/components/portal/index.d.ts +2 -0
  35. package/dist/components/portal/index.d.ts.map +1 -0
  36. package/dist/components/portal/index.js +1 -0
  37. package/dist/components/portal/portal.d.ts +14 -0
  38. package/dist/components/portal/portal.d.ts.map +1 -0
  39. package/dist/components/portal/portal.js +21 -0
  40. package/dist/components/separator/index.d.ts +2 -0
  41. package/dist/components/separator/index.d.ts.map +1 -0
  42. package/dist/components/separator/index.js +1 -0
  43. package/dist/components/separator/separator.d.ts +11 -0
  44. package/dist/components/separator/separator.d.ts.map +1 -0
  45. package/dist/components/separator/separator.js +11 -0
  46. package/dist/components/skeleton/index.d.ts +2 -0
  47. package/dist/components/skeleton/index.d.ts.map +1 -0
  48. package/dist/components/skeleton/index.js +1 -0
  49. package/dist/components/skeleton/skeleton.d.ts +3 -0
  50. package/dist/components/skeleton/skeleton.d.ts.map +1 -0
  51. package/dist/components/skeleton/skeleton.js +5 -0
  52. package/dist/components/skip-link/index.d.ts +2 -0
  53. package/dist/components/skip-link/index.d.ts.map +1 -0
  54. package/dist/components/skip-link/index.js +1 -0
  55. package/dist/components/skip-link/skip-link.d.ts +13 -0
  56. package/dist/components/skip-link/skip-link.d.ts.map +1 -0
  57. package/dist/components/skip-link/skip-link.js +26 -0
  58. package/dist/components/visually-hidden/index.d.ts +2 -0
  59. package/dist/components/visually-hidden/index.d.ts.map +1 -0
  60. package/dist/components/visually-hidden/index.js +1 -0
  61. package/dist/components/visually-hidden/visually-hidden.d.ts +3 -0
  62. package/dist/components/visually-hidden/visually-hidden.d.ts.map +1 -0
  63. package/dist/components/visually-hidden/visually-hidden.js +15 -0
  64. package/dist/hooks/index.d.ts +15 -5
  65. package/dist/hooks/index.d.ts.map +1 -1
  66. package/dist/hooks/index.js +15 -4
  67. package/dist/hooks/use-copy-to-clipboard.d.ts +7 -0
  68. package/dist/hooks/use-copy-to-clipboard.d.ts.map +1 -0
  69. package/dist/hooks/use-copy-to-clipboard.js +23 -0
  70. package/dist/hooks/use-debounce.d.ts +2 -0
  71. package/dist/hooks/use-debounce.d.ts.map +1 -0
  72. package/dist/hooks/use-debounce.js +9 -0
  73. package/dist/hooks/use-event-listener.d.ts +4 -0
  74. package/dist/hooks/use-event-listener.d.ts.map +1 -0
  75. package/dist/hooks/use-event-listener.js +13 -0
  76. package/dist/hooks/use-idle.d.ts +7 -0
  77. package/dist/hooks/use-idle.d.ts.map +1 -0
  78. package/dist/hooks/use-idle.js +35 -0
  79. package/dist/hooks/use-intersection-observer.d.ts +15 -0
  80. package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
  81. package/dist/hooks/use-intersection-observer.js +22 -0
  82. package/dist/hooks/use-isomorphic-layout-effect.d.ts +3 -0
  83. package/dist/hooks/use-isomorphic-layout-effect.d.ts.map +1 -0
  84. package/dist/hooks/use-isomorphic-layout-effect.js +4 -0
  85. package/dist/hooks/use-latest.d.ts +7 -0
  86. package/dist/hooks/use-latest.d.ts.map +1 -0
  87. package/dist/hooks/use-latest.js +11 -0
  88. package/dist/hooks/use-local-storage.d.ts +2 -0
  89. package/dist/hooks/use-local-storage.d.ts.map +1 -0
  90. package/dist/hooks/use-local-storage.js +37 -0
  91. package/dist/hooks/use-media-query.d.ts +2 -0
  92. package/dist/hooks/use-media-query.d.ts.map +1 -0
  93. package/dist/hooks/use-media-query.js +18 -0
  94. package/dist/hooks/use-network-status.d.ts +10 -0
  95. package/dist/hooks/use-network-status.d.ts.map +1 -0
  96. package/dist/hooks/use-network-status.js +19 -0
  97. package/dist/hooks/use-on-click-outside.d.ts +3 -0
  98. package/dist/hooks/use-on-click-outside.d.ts.map +1 -0
  99. package/dist/hooks/use-on-click-outside.js +17 -0
  100. package/dist/hooks/use-previous.d.ts +2 -0
  101. package/dist/hooks/use-previous.d.ts.map +1 -0
  102. package/dist/hooks/use-previous.js +8 -0
  103. package/dist/hooks/use-render-count.d.ts +7 -0
  104. package/dist/hooks/use-render-count.d.ts.map +1 -0
  105. package/dist/hooks/use-render-count.js +15 -0
  106. package/dist/hooks/use-toggle.d.ts +6 -0
  107. package/dist/hooks/use-toggle.d.ts.map +1 -0
  108. package/dist/hooks/use-toggle.js +12 -0
  109. package/dist/hooks/use-why-did-you-render.d.ts +8 -0
  110. package/dist/hooks/use-why-did-you-render.d.ts.map +1 -0
  111. package/dist/hooks/use-why-did-you-render.js +38 -0
  112. package/dist/index.d.ts +6 -4
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +6 -9
  115. package/dist/test-utils/index.d.ts +14 -0
  116. package/dist/test-utils/index.d.ts.map +1 -0
  117. package/dist/test-utils/index.js +22 -0
  118. package/dist/types.d.ts +17 -36
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/utils/cn.d.ts +3 -0
  121. package/dist/utils/cn.d.ts.map +1 -0
  122. package/dist/utils/cn.js +5 -0
  123. package/dist/utils/format-date.d.ts +11 -0
  124. package/dist/utils/format-date.d.ts.map +1 -0
  125. package/dist/utils/format-date.js +12 -0
  126. package/dist/utils/format-number.d.ts +11 -0
  127. package/dist/utils/format-number.d.ts.map +1 -0
  128. package/dist/utils/format-number.js +12 -0
  129. package/dist/utils/index.d.ts +4 -5
  130. package/dist/utils/index.d.ts.map +1 -1
  131. package/dist/utils/index.js +4 -5
  132. package/dist/utils/truncate.d.ts +11 -0
  133. package/dist/utils/truncate.d.ts.map +1 -0
  134. package/dist/utils/truncate.js +14 -0
  135. package/package.json +141 -42
  136. package/dist/adapters/environment/index.d.ts +0 -6
  137. package/dist/adapters/environment/index.d.ts.map +0 -1
  138. package/dist/adapters/environment/index.js +0 -5
  139. package/dist/adapters/environment/next.d.ts +0 -17
  140. package/dist/adapters/environment/next.d.ts.map +0 -1
  141. package/dist/adapters/environment/next.js +0 -20
  142. package/dist/adapters/environment/vite.d.ts +0 -17
  143. package/dist/adapters/environment/vite.d.ts.map +0 -1
  144. package/dist/adapters/environment/vite.js +0 -20
  145. package/dist/adapters/index.d.ts +0 -9
  146. package/dist/adapters/index.d.ts.map +0 -1
  147. package/dist/adapters/index.js +0 -8
  148. package/dist/adapters/theme/custom.d.ts +0 -32
  149. package/dist/adapters/theme/custom.d.ts.map +0 -1
  150. package/dist/adapters/theme/custom.js +0 -26
  151. package/dist/adapters/theme/index.d.ts +0 -6
  152. package/dist/adapters/theme/index.d.ts.map +0 -1
  153. package/dist/adapters/theme/index.js +0 -5
  154. package/dist/adapters/theme/next-themes.d.ts +0 -18
  155. package/dist/adapters/theme/next-themes.d.ts.map +0 -1
  156. package/dist/adapters/theme/next-themes.js +0 -23
  157. package/dist/components/theme-switch/index.d.ts +0 -3
  158. package/dist/components/theme-switch/index.d.ts.map +0 -1
  159. package/dist/components/theme-switch/index.js +0 -1
  160. package/dist/components/theme-switch/theme-switch.d.ts +0 -36
  161. package/dist/components/theme-switch/theme-switch.d.ts.map +0 -1
  162. package/dist/components/theme-switch/theme-switch.js +0 -74
  163. package/dist/components/viewport-info/index.d.ts +0 -3
  164. package/dist/components/viewport-info/index.d.ts.map +0 -1
  165. package/dist/components/viewport-info/index.js +0 -1
  166. package/dist/components/viewport-info/viewport-info.d.ts +0 -40
  167. package/dist/components/viewport-info/viewport-info.d.ts.map +0 -1
  168. package/dist/components/viewport-info/viewport-info.js +0 -69
  169. package/dist/hooks/use-healthcheck.d.ts +0 -42
  170. package/dist/hooks/use-healthcheck.d.ts.map +0 -1
  171. package/dist/hooks/use-healthcheck.js +0 -53
  172. package/dist/utils/environment.d.ts +0 -71
  173. package/dist/utils/environment.d.ts.map +0 -1
  174. package/dist/utils/environment.js +0 -86
  175. package/dist/utils/msw.d.ts +0 -54
  176. package/dist/utils/msw.d.ts.map +0 -1
  177. package/dist/utils/msw.js +0 -62
@@ -1,70 +1,15 @@
1
1
  import { Component, type ReactNode } from 'react';
2
- import type { ErrorBoundaryProps } from '../../types';
2
+ import type { ErrorBoundaryProps } from '../../types.js';
3
3
  interface ErrorBoundaryState {
4
4
  hasError: boolean;
5
5
  error: Error | null;
6
6
  }
7
- /**
8
- * ErrorBoundary component - Catches JavaScript errors in child components
9
- *
10
- * This component wraps your application (or part of it) to catch runtime errors
11
- * and display a fallback UI instead of crashing the entire app.
12
- *
13
- * Features:
14
- * - Catches errors in child component tree
15
- * - Displays custom fallback UI
16
- * - Optional error callback for logging
17
- * - Follows React error boundary best practices
18
- *
19
- * @example Basic usage
20
- * ```tsx
21
- * import { ErrorBoundary } from '@teo-garcia/react-shared/components'
22
- *
23
- * function App() {
24
- * return (
25
- * <ErrorBoundary fallback={<div>Something went wrong</div>}>
26
- * <YourApp />
27
- * </ErrorBoundary>
28
- * )
29
- * }
30
- * ```
31
- *
32
- * @example With dynamic fallback
33
- * ```tsx
34
- * import { ErrorBoundary } from '@teo-garcia/react-shared/components'
35
- *
36
- * function App() {
37
- * return (
38
- * <ErrorBoundary
39
- * fallback={(error) => (
40
- * <div>
41
- * <h1>Error: {error.message}</h1>
42
- * <button onClick={() => window.location.reload()}>Reload</button>
43
- * </div>
44
- * )}
45
- * onError={(error, errorInfo) => {
46
- * console.error('Error caught:', error, errorInfo)
47
- * // Send to error tracking service
48
- * }}
49
- * >
50
- * <YourApp />
51
- * </ErrorBoundary>
52
- * )
53
- * }
54
- * ```
55
- */
56
7
  export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
57
8
  constructor(props: ErrorBoundaryProps);
58
- /**
59
- * Static method called when an error is thrown in a child component
60
- * Updates state to trigger fallback UI rendering
61
- */
62
9
  static getDerivedStateFromError(error: Error): ErrorBoundaryState;
63
- /**
64
- * Called after an error is caught
65
- * Used for side effects like logging
66
- */
67
10
  componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
11
+ componentDidUpdate(prevProps: ErrorBoundaryProps): void;
12
+ resetError(): void;
68
13
  render(): ReactNode;
69
14
  }
70
15
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"error-boundary.d.ts","sourceRoot":"","sources":["../../../src/components/error-boundary/error-boundary.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,qBAAa,aAAc,SAAQ,SAAS,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;gBACtE,KAAK,EAAE,kBAAkB;IAKrC;;;OAGG;IACH,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAIjE;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI;IAOjE,MAAM,IAAI,SAAS;CAwCpB"}
1
+ {"version":3,"file":"error-boundary.d.ts","sourceRoot":"","sources":["../../../src/components/error-boundary/error-boundary.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAiB,MAAM,gBAAgB,CAAA;AAEvE,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAED,qBAAa,aAAc,SAAQ,SAAS,CAC1C,kBAAkB,EAClB,kBAAkB,CACnB;gBACa,KAAK,EAAE,kBAAkB;IAMrC,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAIjE,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI;IAIjE,kBAAkB,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI;IAQvD,UAAU,IAAI,IAAI;IAKlB,MAAM,IAAI,SAAS;CA2EpB"}
@@ -1,100 +1,74 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Component } from 'react';
4
- /**
5
- * ErrorBoundary component - Catches JavaScript errors in child components
6
- *
7
- * This component wraps your application (or part of it) to catch runtime errors
8
- * and display a fallback UI instead of crashing the entire app.
9
- *
10
- * Features:
11
- * - Catches errors in child component tree
12
- * - Displays custom fallback UI
13
- * - Optional error callback for logging
14
- * - Follows React error boundary best practices
15
- *
16
- * @example Basic usage
17
- * ```tsx
18
- * import { ErrorBoundary } from '@teo-garcia/react-shared/components'
19
- *
20
- * function App() {
21
- * return (
22
- * <ErrorBoundary fallback={<div>Something went wrong</div>}>
23
- * <YourApp />
24
- * </ErrorBoundary>
25
- * )
26
- * }
27
- * ```
28
- *
29
- * @example With dynamic fallback
30
- * ```tsx
31
- * import { ErrorBoundary } from '@teo-garcia/react-shared/components'
32
- *
33
- * function App() {
34
- * return (
35
- * <ErrorBoundary
36
- * fallback={(error) => (
37
- * <div>
38
- * <h1>Error: {error.message}</h1>
39
- * <button onClick={() => window.location.reload()}>Reload</button>
40
- * </div>
41
- * )}
42
- * onError={(error, errorInfo) => {
43
- * console.error('Error caught:', error, errorInfo)
44
- * // Send to error tracking service
45
- * }}
46
- * >
47
- * <YourApp />
48
- * </ErrorBoundary>
49
- * )
50
- * }
51
- * ```
52
- */
53
4
  export class ErrorBoundary extends Component {
54
5
  constructor(props) {
55
6
  super(props);
56
7
  this.state = { hasError: false, error: null };
8
+ this.resetError = this.resetError.bind(this);
57
9
  }
58
- /**
59
- * Static method called when an error is thrown in a child component
60
- * Updates state to trigger fallback UI rendering
61
- */
62
10
  static getDerivedStateFromError(error) {
63
11
  return { hasError: true, error };
64
12
  }
65
- /**
66
- * Called after an error is caught
67
- * Used for side effects like logging
68
- */
69
13
  componentDidCatch(error, errorInfo) {
70
- // Call optional error handler prop
71
- if (this.props.onError) {
72
- this.props.onError(error, errorInfo);
73
- }
14
+ this.props.onError?.(error, errorInfo);
15
+ }
16
+ componentDidUpdate(prevProps) {
17
+ if (!this.state.hasError)
18
+ return;
19
+ const prevKeys = prevProps.resetKeys ?? [];
20
+ const nextKeys = this.props.resetKeys ?? [];
21
+ const changed = nextKeys.some((key, i) => key !== prevKeys[i]);
22
+ if (changed)
23
+ this.resetError();
24
+ }
25
+ resetError() {
26
+ this.props.onReset?.();
27
+ this.setState({ hasError: false, error: null });
74
28
  }
75
29
  render() {
76
- // If an error was caught, render fallback UI
77
- if (this.state.hasError && this.state.error) {
78
- const { fallback } = this.props;
79
- // If fallback is a function, call it with the error
80
- if (typeof fallback === 'function') {
81
- return fallback(this.state.error);
82
- }
83
- // If fallback is provided, render it
84
- if (fallback) {
30
+ const { hasError, error } = this.state;
31
+ if (hasError && error) {
32
+ const { FallbackComponent, fallbackRender, fallback } = this.props;
33
+ const fallbackProps = {
34
+ error,
35
+ resetError: this.resetError,
36
+ };
37
+ if (FallbackComponent)
38
+ return _jsx(FallbackComponent, { ...fallbackProps });
39
+ if (fallbackRender)
40
+ return fallbackRender(fallbackProps);
41
+ if (typeof fallback === 'function')
42
+ return fallback(error);
43
+ if (fallback != null)
85
44
  return fallback;
86
- }
87
- // Default fallback UI if none provided
88
- return (_jsxs("div", { role: "alert", style: {
89
- padding: '20px',
90
- margin: '20px',
45
+ return (_jsxs("div", { role: 'alert', style: {
46
+ padding: '1rem',
91
47
  border: '1px solid #f5c6cb',
92
48
  borderRadius: '4px',
93
49
  backgroundColor: '#f8d7da',
94
50
  color: '#721c24',
95
- }, children: [_jsx("h2", { style: { marginTop: 0 }, children: "Something went wrong" }), _jsxs("details", { style: { whiteSpace: 'pre-wrap' }, children: [_jsx("summary", { style: { cursor: 'pointer', marginBottom: '10px' }, children: "Error details" }), this.state.error.toString()] })] }));
51
+ fontFamily: 'inherit',
52
+ }, children: [_jsx("p", { style: { margin: 0, fontWeight: 600 }, children: "Something went wrong" }), _jsx("p", { style: { margin: '0.5rem 0 0', fontSize: '0.875rem' }, children: error.message }), error.stack && (_jsxs("details", { style: { marginTop: '0.5rem' }, children: [_jsx("summary", { style: {
53
+ cursor: 'pointer',
54
+ fontSize: '0.875rem',
55
+ userSelect: 'none',
56
+ }, children: "Stack trace" }), _jsx("pre", { style: {
57
+ marginTop: '0.5rem',
58
+ whiteSpace: 'pre-wrap',
59
+ fontSize: '0.75rem',
60
+ overflowX: 'auto',
61
+ }, children: error.stack })] })), _jsx("button", { onClick: this.resetError, style: {
62
+ marginTop: '0.75rem',
63
+ padding: '0.25rem 0.75rem',
64
+ cursor: 'pointer',
65
+ fontSize: '0.875rem',
66
+ border: '1px solid #721c24',
67
+ borderRadius: '4px',
68
+ background: 'transparent',
69
+ color: '#721c24',
70
+ }, children: "Try again" })] }));
96
71
  }
97
- // No error, render children normally
98
72
  return this.props.children;
99
73
  }
100
74
  }
@@ -1,2 +1,3 @@
1
1
  export { ErrorBoundary } from './error-boundary.js';
2
+ export type { FallbackProps } from '../../types.js';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/error-boundary/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/error-boundary/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,16 @@
1
+ import { type ReactNode } from 'react';
2
+ interface FocusTrapProps {
3
+ children: ReactNode;
4
+ /** Whether the trap is active. Defaults to `true`. */
5
+ active?: boolean;
6
+ /** Focus the first focusable element on activation. Defaults to `true`. */
7
+ initialFocus?: boolean;
8
+ }
9
+ /**
10
+ * Traps keyboard focus within its container while active.
11
+ * Restores focus to the previously focused element on deactivation or unmount.
12
+ * Required for accessible modals, dialogs, and drawers.
13
+ */
14
+ export declare function FocusTrap({ children, active, initialFocus, }: FocusTrapProps): import("react/jsx-runtime").JSX.Element;
15
+ export {};
16
+ //# sourceMappingURL=focus-trap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focus-trap.d.ts","sourceRoot":"","sources":["../../../src/components/focus-trap/focus-trap.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAYzD,UAAU,cAAc;IACtB,QAAQ,EAAE,SAAS,CAAA;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,MAAa,EACb,YAAmB,GACpB,EAAE,cAAc,2CA8ChB"}
@@ -0,0 +1,57 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from 'react';
4
+ const FOCUSABLE_SELECTORS = [
5
+ 'a[href]',
6
+ 'area[href]',
7
+ 'button:not([disabled])',
8
+ 'input:not([disabled])',
9
+ 'select:not([disabled])',
10
+ 'textarea:not([disabled])',
11
+ '[tabindex]:not([tabindex="-1"])',
12
+ ].join(', ');
13
+ /**
14
+ * Traps keyboard focus within its container while active.
15
+ * Restores focus to the previously focused element on deactivation or unmount.
16
+ * Required for accessible modals, dialogs, and drawers.
17
+ */
18
+ export function FocusTrap({ children, active = true, initialFocus = true, }) {
19
+ const containerRef = useRef(null);
20
+ const previousFocusRef = useRef(null);
21
+ useEffect(() => {
22
+ if (!active || !containerRef.current)
23
+ return;
24
+ previousFocusRef.current = document.activeElement;
25
+ const container = containerRef.current;
26
+ const getFocusable = () => Array.from(container.querySelectorAll(FOCUSABLE_SELECTORS));
27
+ if (initialFocus) {
28
+ getFocusable()[0]?.focus();
29
+ }
30
+ function handleKeyDown(event) {
31
+ if (event.key !== 'Tab')
32
+ return;
33
+ const focusable = getFocusable();
34
+ const first = focusable[0];
35
+ const last = focusable.at(-1);
36
+ const current = document.activeElement;
37
+ if (event.shiftKey) {
38
+ if (current === first || !container.contains(current)) {
39
+ event.preventDefault();
40
+ last?.focus();
41
+ }
42
+ }
43
+ else {
44
+ if (current === last || !container.contains(current)) {
45
+ event.preventDefault();
46
+ first?.focus();
47
+ }
48
+ }
49
+ }
50
+ document.addEventListener('keydown', handleKeyDown);
51
+ return () => {
52
+ document.removeEventListener('keydown', handleKeyDown);
53
+ previousFocusRef.current?.focus();
54
+ };
55
+ }, [active, initialFocus]);
56
+ return _jsx("div", { ref: containerRef, children: children });
57
+ }
@@ -0,0 +1,2 @@
1
+ export { FocusTrap } from './focus-trap.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/focus-trap/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1 @@
1
+ export { FocusTrap } from './focus-trap.js';
@@ -1,7 +1,11 @@
1
- /**
2
- * Components - Reusable React UI components
3
- */
1
+ export * from './aspect-ratio/index.js';
2
+ export * from './debug-json/index.js';
3
+ export * from './dev-panel/index.js';
4
4
  export * from './error-boundary/index.js';
5
- export * from './theme-switch/index.js';
6
- export * from './viewport-info/index.js';
5
+ export * from './focus-trap/index.js';
6
+ export * from './portal/index.js';
7
+ export * from './separator/index.js';
8
+ export * from './skeleton/index.js';
9
+ export * from './skip-link/index.js';
10
+ export * from './visually-hidden/index.js';
7
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA"}
@@ -1,6 +1,10 @@
1
- /**
2
- * Components - Reusable React UI components
3
- */
1
+ export * from './aspect-ratio/index.js';
2
+ export * from './debug-json/index.js';
3
+ export * from './dev-panel/index.js';
4
4
  export * from './error-boundary/index.js';
5
- export * from './theme-switch/index.js';
6
- export * from './viewport-info/index.js';
5
+ export * from './focus-trap/index.js';
6
+ export * from './portal/index.js';
7
+ export * from './separator/index.js';
8
+ export * from './skeleton/index.js';
9
+ export * from './skip-link/index.js';
10
+ export * from './visually-hidden/index.js';
@@ -0,0 +1,2 @@
1
+ export { Portal } from './portal.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/portal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1 @@
1
+ export { Portal } from './portal.js';
@@ -0,0 +1,14 @@
1
+ import { type ReactNode } from 'react';
2
+ interface PortalProps {
3
+ children: ReactNode;
4
+ /** Target DOM element. Defaults to `document.body`. */
5
+ container?: Element | null;
6
+ }
7
+ /**
8
+ * Renders children into a DOM node outside the component tree.
9
+ * SSR-safe: returns null on the server and on first paint to avoid hydration
10
+ * mismatch.
11
+ */
12
+ export declare function Portal({ children, container }: PortalProps): import("react").ReactPortal | null;
13
+ export {};
14
+ //# sourceMappingURL=portal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/components/portal/portal.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAG3D,UAAU,WAAW;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,WAAW,sCAY1D"}
@@ -0,0 +1,21 @@
1
+ 'use client';
2
+ import { useEffect, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ /**
5
+ * Renders children into a DOM node outside the component tree.
6
+ * SSR-safe: returns null on the server and on first paint to avoid hydration
7
+ * mismatch.
8
+ */
9
+ export function Portal({ children, container }) {
10
+ const [mounted, setMounted] = useState(false);
11
+ useEffect(() => {
12
+ setMounted(true);
13
+ return () => setMounted(false);
14
+ }, []);
15
+ if (!mounted)
16
+ return null;
17
+ // null means the container element is not yet available — do not render
18
+ if (container === null)
19
+ return null;
20
+ return createPortal(children, container ?? document.body);
21
+ }
@@ -0,0 +1,2 @@
1
+ export { Separator } from './separator.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/separator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1 @@
1
+ export { Separator } from './separator.js';
@@ -0,0 +1,11 @@
1
+ interface SeparatorProps {
2
+ orientation?: 'horizontal' | 'vertical';
3
+ className?: string;
4
+ }
5
+ /**
6
+ * Semantic separator with Tailwind styling.
7
+ * RSC-safe. Use `orientation="vertical"` in flex rows.
8
+ */
9
+ export declare function Separator({ orientation, className, }: SeparatorProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=separator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"separator.d.ts","sourceRoot":"","sources":["../../../src/components/separator/separator.tsx"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EACxB,WAA0B,EAC1B,SAAS,GACV,EAAE,cAAc,2CAchB"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '../../utils/cn.js';
3
+ /**
4
+ * Semantic separator with Tailwind styling.
5
+ * RSC-safe. Use `orientation="vertical"` in flex rows.
6
+ */
7
+ export function Separator({ orientation = 'horizontal', className, }) {
8
+ return (_jsx("hr", { role: 'separator', "aria-orientation": orientation, className: cn(orientation === 'horizontal'
9
+ ? 'my-2 w-full border-t'
10
+ : 'mx-2 h-full border-l', 'border-black/10 dark:border-white/10', className) }));
11
+ }
@@ -0,0 +1,2 @@
1
+ export { Skeleton } from './skeleton.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/skeleton/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1 @@
1
+ export { Skeleton } from './skeleton.js';
@@ -0,0 +1,3 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ export declare function Skeleton({ className, ...props }: HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=skeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/skeleton/skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAA;AAI3C,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,cAAc,CAAC,2CAUhC"}
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '../../utils/cn.js';
3
+ export function Skeleton({ className, ...props }) {
4
+ return (_jsx("div", { className: cn('animate-pulse rounded bg-black/10 dark:bg-white/10', className), ...props }));
5
+ }
@@ -0,0 +1,2 @@
1
+ export { SkipLink } from './skip-link.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/skip-link/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1 @@
1
+ export { SkipLink } from './skip-link.js';
@@ -0,0 +1,13 @@
1
+ import { type AnchorHTMLAttributes } from 'react';
2
+ interface SkipLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
3
+ /** The `id` of the main content element to jump to, e.g. `"main-content"`. */
4
+ href: string;
5
+ }
6
+ /**
7
+ * Visually hidden link that appears on focus.
8
+ * Required by WCAG 2.4.1 — every WCAG audit flags its absence.
9
+ * Renders before any other content in the document.
10
+ */
11
+ export declare function SkipLink({ href, children, ...props }: SkipLinkProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
13
+ //# sourceMappingURL=skip-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skip-link.d.ts","sourceRoot":"","sources":["../../../src/components/skip-link/skip-link.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAE3D,UAAU,aAAc,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACrE,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,QAAiC,EACjC,GAAG,KAAK,EACT,EAAE,aAAa,2CA4Bf"}
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ /**
5
+ * Visually hidden link that appears on focus.
6
+ * Required by WCAG 2.4.1 — every WCAG audit flags its absence.
7
+ * Renders before any other content in the document.
8
+ */
9
+ export function SkipLink({ href, children = 'Skip to main content', ...props }) {
10
+ const [focused, setFocused] = useState(false);
11
+ return (_jsx("a", { href: href, onFocus: () => setFocused(true), onBlur: () => setFocused(false), style: {
12
+ position: 'absolute',
13
+ top: focused ? '0.5rem' : '-100%',
14
+ left: '0.5rem',
15
+ zIndex: 9999,
16
+ padding: '0.5rem 1rem',
17
+ background: '#000',
18
+ color: '#fff',
19
+ textDecoration: 'none',
20
+ borderRadius: '4px',
21
+ fontSize: '0.875rem',
22
+ fontWeight: 500,
23
+ transition: 'top 0.1s',
24
+ outline: '2px solid transparent',
25
+ }, ...props, children: children }));
26
+ }
@@ -0,0 +1,2 @@
1
+ export { VisuallyHidden } from './visually-hidden.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/visually-hidden/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1 @@
1
+ export { VisuallyHidden } from './visually-hidden.js';
@@ -0,0 +1,3 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ export declare function VisuallyHidden({ children, ...props }: HTMLAttributes<HTMLSpanElement>): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=visually-hidden.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visually-hidden.d.ts","sourceRoot":"","sources":["../../../src/components/visually-hidden/visually-hidden.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAA;AAc3C,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,eAAe,CAAC,2CAMjC"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ const style = {
3
+ position: 'absolute',
4
+ width: '1px',
5
+ height: '1px',
6
+ padding: 0,
7
+ margin: '-1px',
8
+ overflow: 'hidden',
9
+ clip: 'rect(0, 0, 0, 0)',
10
+ whiteSpace: 'nowrap',
11
+ borderWidth: 0,
12
+ };
13
+ export function VisuallyHidden({ children, ...props }) {
14
+ return (_jsx("span", { style: style, ...props, children: children }));
15
+ }
@@ -1,6 +1,16 @@
1
- /**
2
- * Hooks - Reusable React hooks for common functionality
3
- */
4
- export { useHealthcheck } from './use-healthcheck.js';
5
- export type { UseHealthcheckOptions } from './use-healthcheck.js';
1
+ export { useCopyToClipboard } from './use-copy-to-clipboard.js';
2
+ export { useDebounce } from './use-debounce.js';
3
+ export { useEventListener } from './use-event-listener.js';
4
+ export { useIdle } from './use-idle.js';
5
+ export { useIntersectionObserver } from './use-intersection-observer.js';
6
+ export { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect.js';
7
+ export { useLatest } from './use-latest.js';
8
+ export { useLocalStorage } from './use-local-storage.js';
9
+ export { useMediaQuery } from './use-media-query.js';
10
+ export { useNetworkStatus } from './use-network-status.js';
11
+ export { useOnClickOutside } from './use-on-click-outside.js';
12
+ export { usePrevious } from './use-previous.js';
13
+ export { useRenderCount } from './use-render-count.js';
14
+ export { useToggle } from './use-toggle.js';
15
+ export { useWhyDidYouRender } from './use-why-did-you-render.js';
6
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA"}