@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
package/dist/types.d.ts CHANGED
@@ -1,40 +1,21 @@
1
- /**
2
- * Theme mode type - represents the three possible theme states
3
- */
4
- export type ThemeMode = 'light' | 'dark' | 'system';
5
- /**
6
- * ThemeAdapter interface - allows components to work with different theme providers
7
- * Implementations should map their specific theme library to this interface
8
- */
9
- export interface ThemeAdapter {
10
- /** Current theme mode */
11
- theme: ThemeMode;
12
- /** Function to update the theme */
13
- setTheme: (theme: ThemeMode) => void;
1
+ import type { ComponentType, ReactNode, ErrorInfo } from 'react';
2
+ export interface FallbackProps {
3
+ error: Error;
4
+ resetError: () => void;
14
5
  }
15
- /**
16
- * EnvironmentAdapter interface - abstracts environment detection across frameworks
17
- * Different frameworks (Next.js vs Vite) use different environment variable systems
18
- */
19
- export interface EnvironmentAdapter {
20
- /** Check if running in development mode */
21
- isDevelopment: () => boolean;
22
- /** Check if running in production mode */
23
- isProduction?: () => boolean;
24
- /** Check if running on server */
25
- isServer?: () => boolean;
26
- /** Check if running on client */
27
- isClient?: () => boolean;
28
- }
29
- /**
30
- * ErrorBoundary fallback render function type
31
- */
32
6
  export interface ErrorBoundaryProps {
33
- /** The React children to wrap */
34
- children: React.ReactNode;
35
- /** Optional fallback UI to render on error */
36
- fallback?: React.ReactNode | ((error: Error) => React.ReactNode);
37
- /** Optional callback when an error is caught */
38
- onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
7
+ children: ReactNode;
8
+ /** A React component receiving `{ error, resetError }` — highest priority fallback */
9
+ FallbackComponent?: ComponentType<FallbackProps>;
10
+ /** Render prop receiving `{ error, resetError }` */
11
+ fallbackRender?: (props: FallbackProps) => ReactNode;
12
+ /** Static element or function `(error) => ReactNode` — lower priority than the two above */
13
+ fallback?: ReactNode | ((error: Error) => ReactNode);
14
+ /** Called after every caught error — use for logging/reporting */
15
+ onError?: (error: Error, errorInfo: ErrorInfo) => void;
16
+ /** Called whenever the boundary resets */
17
+ onReset?: () => void;
18
+ /** When any value in this array changes the boundary resets automatically */
19
+ resetKeys?: Array<unknown>;
39
20
  }
40
21
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEnD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,KAAK,EAAE,SAAS,CAAA;IAChB,mCAAmC;IACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;CACrC;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,aAAa,EAAE,MAAM,OAAO,CAAA;IAC5B,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,OAAO,CAAA;IAC5B,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAA;IACxB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAA;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAC,CAAA;IAChE,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAA;CAC7D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEhE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE,MAAM,IAAI,CAAA;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,SAAS,CAAA;IACnB,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IAChD,oDAAoD;IACpD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,SAAS,CAAA;IACpD,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAA;IACpD,kEAAkE;IAClE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAAA;IACtD,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;CAC3B"}
@@ -0,0 +1,3 @@
1
+ import { type ClassValue } from 'clsx';
2
+ export declare function cn(...inputs: ClassValue[]): string;
3
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/utils/cn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAA;AAG5C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAElD"}
@@ -0,0 +1,5 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Thin wrapper around `Intl.DateTimeFormat` with sensible defaults.
3
+ * Covers the 80% case — reach for `date-fns` for complex scheduling logic.
4
+ *
5
+ * @example
6
+ * formatDate(new Date()) // "March 22, 2026"
7
+ * formatDate(new Date(), 'en-US', { dateStyle: 'short' }) // "3/22/26"
8
+ * formatDate('2026-01-01', 'es-ES') // "1 de enero de 2026"
9
+ */
10
+ export declare function formatDate(date: Date | string | number, locale?: string, options?: Intl.DateTimeFormatOptions): string;
11
+ //# sourceMappingURL=format-date.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-date.d.ts","sourceRoot":"","sources":["../../src/utils/format-date.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC5B,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE,IAAI,CAAC,qBAA6C,GAC1D,MAAM,CAER"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Thin wrapper around `Intl.DateTimeFormat` with sensible defaults.
3
+ * Covers the 80% case — reach for `date-fns` for complex scheduling logic.
4
+ *
5
+ * @example
6
+ * formatDate(new Date()) // "March 22, 2026"
7
+ * formatDate(new Date(), 'en-US', { dateStyle: 'short' }) // "3/22/26"
8
+ * formatDate('2026-01-01', 'es-ES') // "1 de enero de 2026"
9
+ */
10
+ export function formatDate(date, locale, options = { dateStyle: 'long' }) {
11
+ return new Intl.DateTimeFormat(locale, options).format(new Date(date));
12
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Thin wrapper around `Intl.NumberFormat` with sensible defaults.
3
+ *
4
+ * @example
5
+ * formatNumber(1234567) // "1,234,567"
6
+ * formatNumber(0.1234, 'en-US', { style: 'percent' }) // "12%"
7
+ * formatNumber(9900, 'en-US', { style: 'currency', currency: 'USD' }) // "$9,900.00"
8
+ * formatNumber(1200000, 'en-US', { notation: 'compact' }) // "1.2M"
9
+ */
10
+ export declare function formatNumber(value: number, locale?: string, options?: Intl.NumberFormatOptions): string;
11
+ //# sourceMappingURL=format-number.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-number.d.ts","sourceRoot":"","sources":["../../src/utils/format-number.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,GACjC,MAAM,CAER"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Thin wrapper around `Intl.NumberFormat` with sensible defaults.
3
+ *
4
+ * @example
5
+ * formatNumber(1234567) // "1,234,567"
6
+ * formatNumber(0.1234, 'en-US', { style: 'percent' }) // "12%"
7
+ * formatNumber(9900, 'en-US', { style: 'currency', currency: 'USD' }) // "$9,900.00"
8
+ * formatNumber(1200000, 'en-US', { notation: 'compact' }) // "1.2M"
9
+ */
10
+ export function formatNumber(value, locale, options) {
11
+ return new Intl.NumberFormat(locale, options).format(value);
12
+ }
@@ -1,6 +1,5 @@
1
- /**
2
- * Utilities - Pure functions and helpers
3
- */
4
- export * from './environment.js';
5
- export * from './msw.js';
1
+ export { cn } from './cn.js';
2
+ export { formatDate } from './format-date.js';
3
+ export { formatNumber } from './format-number.js';
4
+ export { truncate } from './truncate.js';
6
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,kBAAkB,CAAA;AAChC,cAAc,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
@@ -1,5 +1,4 @@
1
- /**
2
- * Utilities - Pure functions and helpers
3
- */
4
- export * from './environment.js';
5
- export * from './msw.js';
1
+ export { cn } from './cn.js';
2
+ export { formatDate } from './format-date.js';
3
+ export { formatNumber } from './format-number.js';
4
+ export { truncate } from './truncate.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Truncates a string to `maxLength` characters, appending `suffix` if truncated.
3
+ * The total length of the result never exceeds `maxLength`.
4
+ *
5
+ * @example
6
+ * truncate('Hello world', 8) // "Hello…"
7
+ * truncate('Short', 10) // "Short"
8
+ * truncate('Hello world', 8, '...') // "Hello..."
9
+ */
10
+ export declare function truncate(str: string, maxLength: number, suffix?: string): string;
11
+ //# sourceMappingURL=truncate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../src/utils/truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,MAAM,CAG7E"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Truncates a string to `maxLength` characters, appending `suffix` if truncated.
3
+ * The total length of the result never exceeds `maxLength`.
4
+ *
5
+ * @example
6
+ * truncate('Hello world', 8) // "Hello…"
7
+ * truncate('Short', 10) // "Short"
8
+ * truncate('Hello world', 8, '...') // "Hello..."
9
+ */
10
+ export function truncate(str, maxLength, suffix = '…') {
11
+ if (str.length <= maxLength)
12
+ return str;
13
+ return str.slice(0, maxLength - suffix.length) + suffix;
14
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@teo-garcia/react-shared",
3
- "version": "0.1.9",
4
- "description": "Shared React components, hooks, utilities, and adapters for fullstack web templates",
3
+ "version": "1.2.0",
4
+ "description": "Shared React hooks, utilities, and test helpers for the teo-garcia template portfolio",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -14,49 +14,133 @@
14
14
  "import": "./dist/components/index.js",
15
15
  "types": "./dist/components/index.d.ts"
16
16
  },
17
- "./components/theme-switch": {
18
- "import": "./dist/components/theme-switch/index.js",
19
- "types": "./dist/components/theme-switch/index.d.ts"
20
- },
21
- "./components/viewport-info": {
22
- "import": "./dist/components/viewport-info/index.js",
23
- "types": "./dist/components/viewport-info/index.d.ts"
24
- },
25
17
  "./components/error-boundary": {
26
18
  "import": "./dist/components/error-boundary/index.js",
27
19
  "types": "./dist/components/error-boundary/index.d.ts"
28
20
  },
21
+ "./components/focus-trap": {
22
+ "import": "./dist/components/focus-trap/index.js",
23
+ "types": "./dist/components/focus-trap/index.d.ts"
24
+ },
25
+ "./components/portal": {
26
+ "import": "./dist/components/portal/index.js",
27
+ "types": "./dist/components/portal/index.d.ts"
28
+ },
29
+ "./components/skeleton": {
30
+ "import": "./dist/components/skeleton/index.js",
31
+ "types": "./dist/components/skeleton/index.d.ts"
32
+ },
33
+ "./components/visually-hidden": {
34
+ "import": "./dist/components/visually-hidden/index.js",
35
+ "types": "./dist/components/visually-hidden/index.d.ts"
36
+ },
37
+ "./components/aspect-ratio": {
38
+ "import": "./dist/components/aspect-ratio/index.js",
39
+ "types": "./dist/components/aspect-ratio/index.d.ts"
40
+ },
41
+ "./components/debug-json": {
42
+ "import": "./dist/components/debug-json/index.js",
43
+ "types": "./dist/components/debug-json/index.d.ts"
44
+ },
45
+ "./components/dev-panel": {
46
+ "import": "./dist/components/dev-panel/index.js",
47
+ "types": "./dist/components/dev-panel/index.d.ts"
48
+ },
49
+ "./components/separator": {
50
+ "import": "./dist/components/separator/index.js",
51
+ "types": "./dist/components/separator/index.d.ts"
52
+ },
53
+ "./components/skip-link": {
54
+ "import": "./dist/components/skip-link/index.js",
55
+ "types": "./dist/components/skip-link/index.d.ts"
56
+ },
29
57
  "./hooks": {
30
58
  "import": "./dist/hooks/index.js",
31
59
  "types": "./dist/hooks/index.d.ts"
32
60
  },
33
- "./hooks/use-healthcheck": {
34
- "import": "./dist/hooks/use-healthcheck.js",
35
- "types": "./dist/hooks/use-healthcheck.d.ts"
61
+ "./hooks/use-debounce": {
62
+ "import": "./dist/hooks/use-debounce.js",
63
+ "types": "./dist/hooks/use-debounce.d.ts"
64
+ },
65
+ "./hooks/use-isomorphic-layout-effect": {
66
+ "import": "./dist/hooks/use-isomorphic-layout-effect.js",
67
+ "types": "./dist/hooks/use-isomorphic-layout-effect.d.ts"
68
+ },
69
+ "./hooks/use-local-storage": {
70
+ "import": "./dist/hooks/use-local-storage.js",
71
+ "types": "./dist/hooks/use-local-storage.d.ts"
72
+ },
73
+ "./hooks/use-media-query": {
74
+ "import": "./dist/hooks/use-media-query.js",
75
+ "types": "./dist/hooks/use-media-query.d.ts"
76
+ },
77
+ "./hooks/use-on-click-outside": {
78
+ "import": "./dist/hooks/use-on-click-outside.js",
79
+ "types": "./dist/hooks/use-on-click-outside.d.ts"
80
+ },
81
+ "./hooks/use-previous": {
82
+ "import": "./dist/hooks/use-previous.js",
83
+ "types": "./dist/hooks/use-previous.d.ts"
84
+ },
85
+ "./hooks/use-copy-to-clipboard": {
86
+ "import": "./dist/hooks/use-copy-to-clipboard.js",
87
+ "types": "./dist/hooks/use-copy-to-clipboard.d.ts"
88
+ },
89
+ "./hooks/use-event-listener": {
90
+ "import": "./dist/hooks/use-event-listener.js",
91
+ "types": "./dist/hooks/use-event-listener.d.ts"
92
+ },
93
+ "./hooks/use-idle": {
94
+ "import": "./dist/hooks/use-idle.js",
95
+ "types": "./dist/hooks/use-idle.d.ts"
96
+ },
97
+ "./hooks/use-intersection-observer": {
98
+ "import": "./dist/hooks/use-intersection-observer.js",
99
+ "types": "./dist/hooks/use-intersection-observer.d.ts"
100
+ },
101
+ "./hooks/use-latest": {
102
+ "import": "./dist/hooks/use-latest.js",
103
+ "types": "./dist/hooks/use-latest.d.ts"
104
+ },
105
+ "./hooks/use-network-status": {
106
+ "import": "./dist/hooks/use-network-status.js",
107
+ "types": "./dist/hooks/use-network-status.d.ts"
108
+ },
109
+ "./hooks/use-render-count": {
110
+ "import": "./dist/hooks/use-render-count.js",
111
+ "types": "./dist/hooks/use-render-count.d.ts"
112
+ },
113
+ "./hooks/use-toggle": {
114
+ "import": "./dist/hooks/use-toggle.js",
115
+ "types": "./dist/hooks/use-toggle.d.ts"
116
+ },
117
+ "./hooks/use-why-did-you-render": {
118
+ "import": "./dist/hooks/use-why-did-you-render.js",
119
+ "types": "./dist/hooks/use-why-did-you-render.d.ts"
36
120
  },
37
121
  "./utils": {
38
122
  "import": "./dist/utils/index.js",
39
123
  "types": "./dist/utils/index.d.ts"
40
124
  },
41
- "./utils/environment": {
42
- "import": "./dist/utils/environment.js",
43
- "types": "./dist/utils/environment.d.ts"
125
+ "./utils/cn": {
126
+ "import": "./dist/utils/cn.js",
127
+ "types": "./dist/utils/cn.d.ts"
44
128
  },
45
- "./utils/msw": {
46
- "import": "./dist/utils/msw.js",
47
- "types": "./dist/utils/msw.d.ts"
129
+ "./utils/format-date": {
130
+ "import": "./dist/utils/format-date.js",
131
+ "types": "./dist/utils/format-date.d.ts"
48
132
  },
49
- "./adapters": {
50
- "import": "./dist/adapters/index.js",
51
- "types": "./dist/adapters/index.d.ts"
133
+ "./utils/format-number": {
134
+ "import": "./dist/utils/format-number.js",
135
+ "types": "./dist/utils/format-number.d.ts"
52
136
  },
53
- "./adapters/theme": {
54
- "import": "./dist/adapters/theme/index.js",
55
- "types": "./dist/adapters/theme/index.d.ts"
137
+ "./utils/truncate": {
138
+ "import": "./dist/utils/truncate.js",
139
+ "types": "./dist/utils/truncate.d.ts"
56
140
  },
57
- "./adapters/environment": {
58
- "import": "./dist/adapters/environment/index.js",
59
- "types": "./dist/adapters/environment/index.d.ts"
141
+ "./test-utils": {
142
+ "import": "./dist/test-utils/index.js",
143
+ "types": "./dist/test-utils/index.d.ts"
60
144
  },
61
145
  "./types": {
62
146
  "import": "./dist/types.js",
@@ -70,13 +154,10 @@
70
154
  ],
71
155
  "keywords": [
72
156
  "react",
73
- "components",
74
157
  "hooks",
75
158
  "utilities",
76
- "shared",
77
- "typescript",
78
- "nextjs",
79
- "react-router"
159
+ "testing",
160
+ "typescript"
80
161
  ],
81
162
  "author": "teo-garcia",
82
163
  "license": "MIT",
@@ -84,35 +165,53 @@
84
165
  "type": "git",
85
166
  "url": "git+https://github.com/teo-garcia/react-shared.git"
86
167
  },
168
+ "prettier": "@teo-garcia/prettier-config-shared",
87
169
  "packageManager": "pnpm@10.2.0",
88
170
  "engines": {
89
171
  "node": ">=24"
90
172
  },
173
+ "dependencies": {
174
+ "clsx": "^2.1.1",
175
+ "tailwind-merge": "^3.0.0"
176
+ },
91
177
  "peerDependencies": {
92
- "lucide-react": "^0.400.0",
93
178
  "react": "^19.0.0",
94
- "react-dom": "^19.0.0"
179
+ "react-dom": "^19.0.0",
180
+ "@tanstack/react-query": "^5.0.0",
181
+ "@testing-library/react": "^16.0.0"
95
182
  },
96
183
  "peerDependenciesMeta": {
97
- "lucide-react": {
98
- "optional": false
184
+ "@tanstack/react-query": {
185
+ "optional": true
186
+ },
187
+ "@testing-library/react": {
188
+ "optional": true
99
189
  }
100
190
  },
101
191
  "devDependencies": {
192
+ "@teo-garcia/prettier-config-shared": "^0.2.9",
102
193
  "@tanstack/react-query": "^5.0.0",
194
+ "@testing-library/jest-dom": "^6.0.0",
195
+ "@testing-library/react": "^16.0.0",
103
196
  "@types/node": "^24.0.0",
104
197
  "@types/react": "^19.0.0",
105
198
  "@types/react-dom": "^19.0.0",
106
- "msw": "^2.0.0",
107
- "next-themes": "^0.4.0",
199
+ "@vitejs/plugin-react": "^5.0.4",
200
+ "happy-dom": "^16.0.0",
108
201
  "prettier": "^3.0.0",
109
- "typescript": "^5.0.0"
202
+ "react": "^19.0.0",
203
+ "react-dom": "^19.0.0",
204
+ "typescript": "^5.0.0",
205
+ "vite-tsconfig-paths": "^6.0.0",
206
+ "vitest": "^4.0.0"
110
207
  },
111
208
  "scripts": {
112
- "build": "tsc",
113
- "check": "pnpm format:check && pnpm build",
209
+ "build": "rm -rf dist && tsc",
210
+ "check": "pnpm format:check && pnpm build && pnpm test",
211
+ "coverage": "vitest run --coverage",
114
212
  "format": "prettier --write .",
115
213
  "format:check": "prettier --check .",
214
+ "test": "vitest run",
116
215
  "prepublishOnly": "pnpm build"
117
216
  }
118
217
  }
@@ -1,6 +0,0 @@
1
- /**
2
- * Environment adapters - abstract environment detection across different frameworks
3
- */
4
- export { nextEnvironmentAdapter } from './next.js';
5
- export { viteEnvironmentAdapter } from './vite.js';
6
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/environment/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA"}
@@ -1,5 +0,0 @@
1
- /**
2
- * Environment adapters - abstract environment detection across different frameworks
3
- */
4
- export { nextEnvironmentAdapter } from './next.js';
5
- export { viteEnvironmentAdapter } from './vite.js';
@@ -1,17 +0,0 @@
1
- import type { EnvironmentAdapter } from '../../types';
2
- /**
3
- * Environment adapter for Next.js applications
4
- * Uses process.env.NODE_ENV for environment detection
5
- *
6
- * @example
7
- * ```tsx
8
- * import { nextEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/environment'
9
- * import { ViewportInfo } from '@teo-garcia/react-shared/components'
10
- *
11
- * function App() {
12
- * return <ViewportInfo environmentAdapter={nextEnvironmentAdapter} />
13
- * }
14
- * ```
15
- */
16
- export declare const nextEnvironmentAdapter: EnvironmentAdapter;
17
- //# sourceMappingURL=next.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../../src/adapters/environment/next.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,EAAE,kBAKpC,CAAA"}
@@ -1,20 +0,0 @@
1
- /**
2
- * Environment adapter for Next.js applications
3
- * Uses process.env.NODE_ENV for environment detection
4
- *
5
- * @example
6
- * ```tsx
7
- * import { nextEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/environment'
8
- * import { ViewportInfo } from '@teo-garcia/react-shared/components'
9
- *
10
- * function App() {
11
- * return <ViewportInfo environmentAdapter={nextEnvironmentAdapter} />
12
- * }
13
- * ```
14
- */
15
- export const nextEnvironmentAdapter = {
16
- isDevelopment: () => process.env.NODE_ENV === 'development',
17
- isProduction: () => process.env.NODE_ENV === 'production',
18
- isServer: () => typeof window === 'undefined',
19
- isClient: () => typeof window !== 'undefined',
20
- };
@@ -1,17 +0,0 @@
1
- import type { EnvironmentAdapter } from '../../types';
2
- /**
3
- * Environment adapter for Vite-based applications (React Router, vanilla Vite)
4
- * Uses import.meta.env for environment detection
5
- *
6
- * @example
7
- * ```tsx
8
- * import { viteEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/environment'
9
- * import { ViewportInfo } from '@teo-garcia/react-shared/components'
10
- *
11
- * function App() {
12
- * return <ViewportInfo environmentAdapter={viteEnvironmentAdapter} />
13
- * }
14
- * ```
15
- */
16
- export declare const viteEnvironmentAdapter: EnvironmentAdapter;
17
- //# sourceMappingURL=vite.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../../../src/adapters/environment/vite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,EAAE,kBAKpC,CAAA"}
@@ -1,20 +0,0 @@
1
- /**
2
- * Environment adapter for Vite-based applications (React Router, vanilla Vite)
3
- * Uses import.meta.env for environment detection
4
- *
5
- * @example
6
- * ```tsx
7
- * import { viteEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/environment'
8
- * import { ViewportInfo } from '@teo-garcia/react-shared/components'
9
- *
10
- * function App() {
11
- * return <ViewportInfo environmentAdapter={viteEnvironmentAdapter} />
12
- * }
13
- * ```
14
- */
15
- export const viteEnvironmentAdapter = {
16
- isDevelopment: () => import.meta.env.DEV === true,
17
- isProduction: () => import.meta.env.PROD === true,
18
- isServer: () => import.meta.env.SSR === true,
19
- isClient: () => import.meta.env.SSR !== true,
20
- };
@@ -1,9 +0,0 @@
1
- /**
2
- * Adapters - bridge between different frameworks and our shared components
3
- *
4
- * Adapters allow our components to work with different theme libraries,
5
- * environment detection systems, and other framework-specific APIs
6
- */
7
- export * from './environment/index.js';
8
- export * from './theme/index.js';
9
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,wBAAwB,CAAA;AACtC,cAAc,kBAAkB,CAAA"}
@@ -1,8 +0,0 @@
1
- /**
2
- * Adapters - bridge between different frameworks and our shared components
3
- *
4
- * Adapters allow our components to work with different theme libraries,
5
- * environment detection systems, and other framework-specific APIs
6
- */
7
- export * from './environment/index.js';
8
- export * from './theme/index.js';
@@ -1,32 +0,0 @@
1
- import type { ThemeAdapter, ThemeMode } from '../../types';
2
- /**
3
- * Custom theme provider result interface
4
- * This matches the common pattern of custom theme providers
5
- */
6
- interface CustomThemeHook {
7
- theme: ThemeMode;
8
- setTheme: (theme: ThemeMode) => void;
9
- }
10
- /**
11
- * Factory function to create a theme adapter from a custom theme hook
12
- * Use this when you have a custom theme provider implementation
13
- *
14
- * @param themeHookResult - The result from your custom useTheme hook
15
- * @returns ThemeAdapter compatible interface
16
- *
17
- * @example
18
- * ```tsx
19
- * import { createCustomThemeAdapter } from '@teo-garcia/react-shared/adapters/theme'
20
- * import { ThemeSwitch } from '@teo-garcia/react-shared/components'
21
- * import { useTheme } from '~/components/theme-provider' // Your custom hook
22
- *
23
- * function App() {
24
- * const customTheme = useTheme()
25
- * const themeAdapter = createCustomThemeAdapter(customTheme)
26
- * return <ThemeSwitch themeAdapter={themeAdapter} />
27
- * }
28
- * ```
29
- */
30
- export declare const createCustomThemeAdapter: (themeHookResult: CustomThemeHook) => ThemeAdapter;
31
- export {};
32
- //# sourceMappingURL=custom.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../../src/adapters/theme/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE1D;;;GAGG;AACH,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAA;IAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;CACrC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,wBAAwB,GAAI,iBAAiB,eAAe,KAAG,YAK3E,CAAA"}