@ponti-studios/ui 2.0.1 → 3.0.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 (319) hide show
  1. package/README.md +36 -3
  2. package/dist/auth/index.d.ts +3 -0
  3. package/dist/auth/index.js +3 -0
  4. package/dist/components/data-display/accordion.d.ts +10 -0
  5. package/dist/components/data-display/accordion.js +53 -0
  6. package/{src/components/data-display/index.ts → dist/components/data-display/index.d.ts} +1 -10
  7. package/dist/components/data-display/index.js +8 -0
  8. package/dist/components/data-display/metric-card.d.ts +9 -0
  9. package/dist/components/data-display/metric-card.js +25 -0
  10. package/dist/components/data-display/sort-controls.d.ts +13 -0
  11. package/dist/components/data-display/sort-controls.js +57 -0
  12. package/dist/components/data-display/sort-row.d.ts +10 -0
  13. package/dist/components/data-display/sort-row.js +52 -0
  14. package/dist/components/data-display/table.d.ts +10 -0
  15. package/dist/components/data-display/table.js +57 -0
  16. package/dist/components/feedback/alert.d.ts +9 -0
  17. package/dist/components/feedback/alert.js +38 -0
  18. package/dist/components/feedback/empty-state.d.ts +18 -0
  19. package/dist/components/feedback/empty-state.js +36 -0
  20. package/{src/components/feedback/index.ts → dist/components/feedback/index.d.ts} +2 -0
  21. package/dist/components/feedback/index.js +7 -0
  22. package/dist/components/feedback/progress.d.ts +6 -0
  23. package/dist/components/feedback/progress.js +25 -0
  24. package/dist/components/feedback/skeleton.d.ts +2 -0
  25. package/dist/components/feedback/skeleton.js +11 -0
  26. package/dist/components/feedback/spinner.d.ts +14 -0
  27. package/dist/components/feedback/spinner.js +27 -0
  28. package/dist/components/feedback/update-guard.d.ts +13 -0
  29. package/dist/components/feedback/update-guard.js +38 -0
  30. package/dist/components/filters/active-filters-bar.d.ts +14 -0
  31. package/dist/components/filters/active-filters-bar.js +44 -0
  32. package/dist/components/filters/filter-chip.d.ts +11 -0
  33. package/dist/components/filters/filter-chip.js +33 -0
  34. package/dist/components/filters/filter-select.d.ts +17 -0
  35. package/dist/components/filters/filter-select.js +46 -0
  36. package/dist/components/filters/index.js +4 -0
  37. package/dist/components/forms/checkbox.d.ts +4 -0
  38. package/dist/components/forms/checkbox.js +24 -0
  39. package/dist/components/forms/date-month-select.d.ts +11 -0
  40. package/dist/components/forms/date-month-select.js +47 -0
  41. package/dist/components/forms/date-picker.d.ts +60 -0
  42. package/dist/components/forms/date-picker.js +193 -0
  43. package/dist/components/forms/date-utils.d.ts +14 -0
  44. package/dist/components/forms/date-utils.js +18 -0
  45. package/dist/components/forms/drop-zone.d.ts +42 -0
  46. package/dist/components/forms/drop-zone.js +184 -0
  47. package/{src/components/forms/index.ts → dist/components/forms/index.d.ts} +3 -9
  48. package/dist/components/forms/index.js +17 -0
  49. package/dist/components/forms/input.d.ts +3 -0
  50. package/dist/components/forms/input.js +15 -0
  51. package/dist/components/forms/label.d.ts +3 -0
  52. package/dist/components/forms/label.js +14 -0
  53. package/dist/components/forms/passkey-management.d.ts +14 -0
  54. package/dist/components/forms/passkey-management.js +132 -0
  55. package/dist/components/forms/radio-group.d.ts +6 -0
  56. package/dist/components/forms/radio-group.js +28 -0
  57. package/dist/components/forms/select.d.ts +18 -0
  58. package/dist/components/forms/select.js +103 -0
  59. package/dist/components/forms/slider.d.ts +9 -0
  60. package/dist/components/forms/slider.js +25 -0
  61. package/dist/components/forms/stepper.d.ts +15 -0
  62. package/dist/components/forms/stepper.js +41 -0
  63. package/dist/components/forms/switch.d.ts +6 -0
  64. package/dist/components/forms/switch.js +21 -0
  65. package/dist/components/forms/text-field.d.ts +15 -0
  66. package/dist/components/forms/text-field.js +46 -0
  67. package/dist/components/forms/text-field.types.d.ts +8 -0
  68. package/dist/components/forms/textarea.d.ts +3 -0
  69. package/dist/components/forms/textarea.js +14 -0
  70. package/dist/components/layout/index.js +5 -0
  71. package/dist/components/layout/particle-background.d.ts +19 -0
  72. package/dist/components/layout/particle-background.js +171 -0
  73. package/dist/components/layout/scroll-area.d.ts +9 -0
  74. package/dist/components/layout/scroll-area.js +35 -0
  75. package/dist/components/layout/section-intro.d.ts +12 -0
  76. package/dist/components/layout/section-intro.js +28 -0
  77. package/dist/components/layout/surface-panel.d.ts +7 -0
  78. package/dist/components/layout/surface-panel.js +11 -0
  79. package/dist/components/navigation/app-navigation.d.ts +67 -0
  80. package/dist/components/navigation/app-navigation.js +106 -0
  81. package/{src/components/navigation/index.ts → dist/components/navigation/index.d.ts} +1 -7
  82. package/dist/components/navigation/index.js +4 -0
  83. package/dist/components/navigation/pagination-controls.d.ts +7 -0
  84. package/dist/components/navigation/pagination-controls.js +50 -0
  85. package/dist/components/navigation/tabs.d.ts +7 -0
  86. package/dist/components/navigation/tabs.js +35 -0
  87. package/dist/components/overlays/bottom-sheet.d.ts +20 -0
  88. package/dist/components/overlays/bottom-sheet.js +101 -0
  89. package/dist/components/overlays/command.d.ts +29 -0
  90. package/dist/components/overlays/command.js +123 -0
  91. package/dist/components/overlays/dialog.d.ts +30 -0
  92. package/dist/components/overlays/dialog.js +105 -0
  93. package/dist/components/overlays/dropdown-menu.d.ts +29 -0
  94. package/dist/components/overlays/dropdown-menu.js +128 -0
  95. package/dist/components/overlays/index.d.ts +7 -0
  96. package/dist/components/overlays/index.js +8 -0
  97. package/dist/components/overlays/popover.d.ts +14 -0
  98. package/dist/components/overlays/popover.js +56 -0
  99. package/dist/components/overlays/sheet.d.ts +27 -0
  100. package/dist/components/overlays/sheet.js +81 -0
  101. package/dist/components/overlays/tooltip.d.ts +10 -0
  102. package/dist/components/overlays/tooltip.js +23 -0
  103. package/dist/components/primitives/avatar.d.ts +14 -0
  104. package/dist/components/primitives/avatar.js +72 -0
  105. package/dist/components/primitives/badge.d.ts +7 -0
  106. package/dist/components/primitives/badge.js +27 -0
  107. package/dist/components/primitives/button.d.ts +13 -0
  108. package/dist/components/primitives/button.js +113 -0
  109. package/{src/components/primitives/button.types.ts → dist/components/primitives/button.types.d.ts} +4 -6
  110. package/dist/components/primitives/card.d.ts +9 -0
  111. package/dist/components/primitives/card.js +56 -0
  112. package/{src/components/primitives/index.ts → dist/components/primitives/index.d.ts} +1 -9
  113. package/dist/components/primitives/index.js +7 -0
  114. package/dist/components/primitives/segmented-control.d.ts +20 -0
  115. package/dist/components/primitives/segmented-control.js +27 -0
  116. package/dist/components/primitives/separator.d.ts +4 -0
  117. package/dist/components/primitives/separator.js +16 -0
  118. package/dist/constants/chart-colors.d.ts +33 -0
  119. package/dist/constants/chart-colors.js +31 -0
  120. package/dist/hooks/index.js +9 -0
  121. package/{src/hooks/sort.types.ts → dist/hooks/sort.types.d.ts} +2 -4
  122. package/dist/hooks/use-api-client.d.ts +30 -0
  123. package/dist/hooks/use-api-client.js +106 -0
  124. package/dist/hooks/use-debounced-value.d.ts +1 -0
  125. package/dist/hooks/use-debounced-value.js +12 -0
  126. package/dist/hooks/use-derived-filter-state.d.ts +20 -0
  127. package/dist/hooks/use-derived-filter-state.js +39 -0
  128. package/dist/hooks/use-filter-state.d.ts +12 -0
  129. package/dist/hooks/use-filter-state.js +37 -0
  130. package/dist/hooks/use-media-query.d.ts +6 -0
  131. package/dist/hooks/use-media-query.js +27 -0
  132. package/dist/hooks/use-mobile.d.ts +1 -0
  133. package/dist/hooks/use-mobile.js +14 -0
  134. package/dist/hooks/use-sort.d.ts +11 -0
  135. package/dist/hooks/use-sort.js +14 -0
  136. package/{src/index.ts → dist/index.d.ts} +4 -32
  137. package/dist/index.js +15 -0
  138. package/dist/integrations/service-worker.d.ts +2 -0
  139. package/dist/integrations/service-worker.js +2 -0
  140. package/dist/lib/auth.d.ts +2 -0
  141. package/dist/lib/auth.js +7 -0
  142. package/dist/lib/clipboard.d.ts +1 -0
  143. package/dist/lib/clipboard.js +10 -0
  144. package/dist/lib/index.js +4 -0
  145. package/{src/lib/slot.tsx → dist/lib/slot.d.ts} +2 -15
  146. package/dist/lib/slot.js +14 -0
  147. package/dist/lib/utils.d.ts +2 -0
  148. package/dist/lib/utils.js +8 -0
  149. package/dist/native/components.d.ts +41 -0
  150. package/dist/native/components.js +135 -0
  151. package/dist/native/index.js +3 -0
  152. package/dist/native/theme.d.ts +19 -0
  153. package/dist/native/theme.js +58 -0
  154. package/dist/styles/tokens/css-vars.d.ts +7 -0
  155. package/dist/styles/tokens/css-vars.js +5 -0
  156. package/dist/styles/tokens/generated/dark.colors.generated.d.ts +40 -0
  157. package/dist/styles/tokens/generated/dark.colors.generated.js +39 -0
  158. package/dist/styles/tokens/generated/foundations.generated.d.ts +323 -0
  159. package/dist/styles/tokens/generated/foundations.generated.js +453 -0
  160. package/dist/styles/tokens/generated/light.colors.generated.d.ts +40 -0
  161. package/dist/styles/tokens/generated/light.colors.generated.js +39 -0
  162. package/dist/styles/tokens/index.d.ts +317 -0
  163. package/dist/styles/tokens/index.js +14 -0
  164. package/dist/styles.css +1 -1
  165. package/dist/translations/en.d.ts +34 -0
  166. package/dist/translations/index.d.ts +39 -0
  167. package/dist/translations/ui-provider.d.ts +9 -0
  168. package/dist/translations/ui-provider.js +16 -0
  169. package/dist/types/upload.d.ts +36 -0
  170. package/package.json +50 -33
  171. package/src/components/data-display/accordion.stories.tsx +0 -57
  172. package/src/components/data-display/accordion.tsx +0 -86
  173. package/src/components/data-display/metric-card.stories.tsx +0 -48
  174. package/src/components/data-display/metric-card.tsx +0 -20
  175. package/src/components/data-display/sort-controls.stories.tsx +0 -45
  176. package/src/components/data-display/sort-controls.tsx +0 -96
  177. package/src/components/data-display/sort-row.tsx +0 -88
  178. package/src/components/data-display/table.stories.tsx +0 -75
  179. package/src/components/data-display/table.tsx +0 -80
  180. package/src/components/feedback/alert.stories.tsx +0 -51
  181. package/src/components/feedback/alert.tsx +0 -64
  182. package/src/components/feedback/empty-state.tsx +0 -76
  183. package/src/components/feedback/progress.stories.tsx +0 -54
  184. package/src/components/feedback/progress.tsx +0 -41
  185. package/src/components/feedback/skeleton.stories.tsx +0 -36
  186. package/src/components/feedback/skeleton.tsx +0 -7
  187. package/src/components/feedback/spinner.stories.tsx +0 -52
  188. package/src/components/feedback/spinner.tsx +0 -47
  189. package/src/components/feedback/update-guard.stories.tsx +0 -28
  190. package/src/components/feedback/update-guard.tsx +0 -57
  191. package/src/components/filters/active-filters-bar.stories.tsx +0 -114
  192. package/src/components/filters/active-filters-bar.tsx +0 -61
  193. package/src/components/filters/filter-chip.tsx +0 -57
  194. package/src/components/filters/filter-select.stories.tsx +0 -71
  195. package/src/components/filters/filter-select.tsx +0 -68
  196. package/src/components/forms/checkbox.stories.tsx +0 -35
  197. package/src/components/forms/checkbox.tsx +0 -38
  198. package/src/components/forms/date-month-select.stories.tsx +0 -26
  199. package/src/components/forms/date-month-select.tsx +0 -79
  200. package/src/components/forms/date-picker.stories.tsx +0 -188
  201. package/src/components/forms/date-picker.tsx +0 -303
  202. package/src/components/forms/date-utils.ts +0 -37
  203. package/src/components/forms/drop-zone.stories.tsx +0 -140
  204. package/src/components/forms/drop-zone.tsx +0 -298
  205. package/src/components/forms/input.stories.tsx +0 -47
  206. package/src/components/forms/input.tsx +0 -24
  207. package/src/components/forms/label.stories.tsx +0 -16
  208. package/src/components/forms/label.tsx +0 -25
  209. package/src/components/forms/passkey-management.stories.tsx +0 -85
  210. package/src/components/forms/passkey-management.tsx +0 -168
  211. package/src/components/forms/radio-group.stories.tsx +0 -46
  212. package/src/components/forms/radio-group.tsx +0 -44
  213. package/src/components/forms/select.stories.tsx +0 -207
  214. package/src/components/forms/select.tsx +0 -182
  215. package/src/components/forms/slider.stories.tsx +0 -70
  216. package/src/components/forms/slider.tsx +0 -50
  217. package/src/components/forms/stepper.stories.tsx +0 -111
  218. package/src/components/forms/stepper.tsx +0 -66
  219. package/src/components/forms/switch.stories.tsx +0 -144
  220. package/src/components/forms/switch.tsx +0 -39
  221. package/src/components/forms/text-field.stories.tsx +0 -87
  222. package/src/components/forms/text-field.tsx +0 -75
  223. package/src/components/forms/text-field.types.ts +0 -9
  224. package/src/components/forms/textarea.stories.tsx +0 -150
  225. package/src/components/forms/textarea.tsx +0 -22
  226. package/src/components/layout/particle-background.stories.tsx +0 -38
  227. package/src/components/layout/particle-background.tsx +0 -378
  228. package/src/components/layout/scroll-area.stories.tsx +0 -91
  229. package/src/components/layout/scroll-area.tsx +0 -79
  230. package/src/components/layout/section-intro.stories.tsx +0 -29
  231. package/src/components/layout/section-intro.tsx +0 -31
  232. package/src/components/layout/surface-panel.stories.tsx +0 -32
  233. package/src/components/layout/surface-panel.tsx +0 -23
  234. package/src/components/navigation/app-navigation.stories.tsx +0 -217
  235. package/src/components/navigation/app-navigation.tsx +0 -234
  236. package/src/components/navigation/pagination-controls.stories.tsx +0 -41
  237. package/src/components/navigation/pagination-controls.tsx +0 -46
  238. package/src/components/navigation/tabs.stories.tsx +0 -48
  239. package/src/components/navigation/tabs.tsx +0 -52
  240. package/src/components/overlays/bottom-sheet.stories.tsx +0 -52
  241. package/src/components/overlays/bottom-sheet.tsx +0 -179
  242. package/src/components/overlays/command.stories.tsx +0 -65
  243. package/src/components/overlays/command.tsx +0 -227
  244. package/src/components/overlays/dialog.stories.tsx +0 -148
  245. package/src/components/overlays/dialog.tsx +0 -203
  246. package/src/components/overlays/dropdown-menu.stories.tsx +0 -74
  247. package/src/components/overlays/dropdown-menu.tsx +0 -236
  248. package/src/components/overlays/index.ts +0 -56
  249. package/src/components/overlays/popover.stories.tsx +0 -51
  250. package/src/components/overlays/popover.tsx +0 -78
  251. package/src/components/overlays/sheet.stories.tsx +0 -68
  252. package/src/components/overlays/sheet.tsx +0 -155
  253. package/src/components/overlays/tooltip.stories.tsx +0 -29
  254. package/src/components/overlays/tooltip.tsx +0 -41
  255. package/src/components/primitives/avatar-placeholder.svg +0 -13
  256. package/src/components/primitives/avatar.stories.tsx +0 -72
  257. package/src/components/primitives/avatar.tsx +0 -136
  258. package/src/components/primitives/badge.stories.tsx +0 -43
  259. package/src/components/primitives/badge.tsx +0 -43
  260. package/src/components/primitives/button.stories.tsx +0 -113
  261. package/src/components/primitives/button.tsx +0 -131
  262. package/src/components/primitives/card.stories.tsx +0 -59
  263. package/src/components/primitives/card.tsx +0 -66
  264. package/src/components/primitives/segmented-control.stories.tsx +0 -54
  265. package/src/components/primitives/segmented-control.tsx +0 -73
  266. package/src/components/primitives/separator.stories.tsx +0 -34
  267. package/src/components/primitives/separator.tsx +0 -27
  268. package/src/constants/chart-colors.ts +0 -39
  269. package/src/env.d.ts +0 -9
  270. package/src/hooks/use-api-client.ts +0 -122
  271. package/src/hooks/use-debounced-value.ts +0 -12
  272. package/src/hooks/use-derived-filter-state.ts +0 -70
  273. package/src/hooks/use-filter-state.ts +0 -66
  274. package/src/hooks/use-media-query.ts +0 -69
  275. package/src/hooks/use-mobile.tsx +0 -19
  276. package/src/hooks/use-sort.ts +0 -20
  277. package/src/lib/auth.ts +0 -5
  278. package/src/lib/clipboard.ts +0 -8
  279. package/src/lib/utils.ts +0 -6
  280. package/src/native/components.tsx +0 -198
  281. package/src/native/theme.tsx +0 -69
  282. package/src/storybook/controls.ts +0 -117
  283. package/src/storybook/options.ts +0 -52
  284. package/src/styles/build.ts +0 -1
  285. package/src/styles/index.css +0 -423
  286. package/src/styles/nokia.css +0 -36
  287. package/src/styles/package.css +0 -3
  288. package/src/styles/tokens/chart-colors.stories.tsx +0 -189
  289. package/src/styles/tokens/color-systems.stories.tsx +0 -190
  290. package/src/styles/tokens/css-vars.ts +0 -15
  291. package/src/styles/tokens/generated/dark-class.css +0 -39
  292. package/src/styles/tokens/generated/dark.colors.generated.ts +0 -39
  293. package/src/styles/tokens/generated/dark.css +0 -39
  294. package/src/styles/tokens/generated/foundations.css +0 -149
  295. package/src/styles/tokens/generated/foundations.generated.ts +0 -454
  296. package/src/styles/tokens/generated/light.colors.generated.ts +0 -39
  297. package/src/styles/tokens/generated/light.css +0 -39
  298. package/src/styles/tokens/index.ts +0 -70
  299. package/src/styles/tokens/layout.stories.tsx +0 -50
  300. package/src/styles/tokens/scripts/check-foundations.mjs +0 -126
  301. package/src/styles/tokens/scripts/check-source.mjs +0 -53
  302. package/src/styles/tokens/source/dark.tokens.json +0 -138
  303. package/src/styles/tokens/source/foundations.tokens.json +0 -344
  304. package/src/styles/tokens/source/light.tokens.json +0 -138
  305. package/src/styles/tokens/style-dictionary.dark-class.json +0 -16
  306. package/src/styles/tokens/style-dictionary.dark-storybook.json +0 -16
  307. package/src/styles/tokens/style-dictionary.dark.json +0 -21
  308. package/src/styles/tokens/style-dictionary.foundations.json +0 -21
  309. package/src/styles/tokens/style-dictionary.light-storybook.json +0 -16
  310. package/src/styles/tokens/style-dictionary.light.json +0 -21
  311. package/src/styles/tokens/typography.stories.tsx +0 -157
  312. package/src/translations/en.ts +0 -34
  313. package/src/translations/index.ts +0 -32
  314. package/src/types/upload.ts +0 -42
  315. /package/{src/components/filters/index.ts → dist/components/filters/index.d.ts} +0 -0
  316. /package/{src/components/layout/index.ts → dist/components/layout/index.d.ts} +0 -0
  317. /package/{src/hooks/index.ts → dist/hooks/index.d.ts} +0 -0
  318. /package/{src/lib/index.ts → dist/lib/index.d.ts} +0 -0
  319. /package/{src/native/index.ts → dist/native/index.d.ts} +0 -0
@@ -1,122 +0,0 @@
1
- import { useCallback, useMemo, useState } from "react";
2
-
3
- const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
4
-
5
- type FetchOptions<T> = {
6
- method?: "GET" | "POST" | "PUT" | "DELETE";
7
- body?: T | undefined;
8
- headers?: Record<string, string>;
9
- stream?: boolean;
10
- };
11
-
12
- type ApiState = {
13
- isLoading: boolean;
14
- error: Error | null;
15
- };
16
-
17
- /**
18
- * React hook for API client that handles fetch requests with authentication
19
- */
20
- export function useApiClient() {
21
- const [state, setState] = useState<ApiState>({
22
- isLoading: false,
23
- error: null,
24
- });
25
-
26
- /**
27
- * Base fetch function with authentication
28
- */
29
- const fetchApi = useCallback(
30
- async <T, S>(endpoint: string, options: FetchOptions<T> = {}): Promise<S> => {
31
- const { method = "GET", body, headers = {}, stream = false } = options;
32
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
33
-
34
- try {
35
- // Default headers
36
- const defaultHeaders: Record<string, string> = {};
37
-
38
- // Only set Content-Type for non-FormData requests
39
- if (!(body instanceof FormData)) {
40
- defaultHeaders["Content-Type"] = "application/json";
41
- }
42
-
43
- const fetchBody: BodyInit | null =
44
- body instanceof FormData ? body : body ? JSON.stringify(body) : null;
45
-
46
- const res = await fetch(`${API_BASE_URL}${endpoint}`, {
47
- method,
48
- headers: {
49
- ...defaultHeaders,
50
- ...headers,
51
- },
52
- body: fetchBody,
53
- credentials: "include",
54
- });
55
-
56
- if (!res.ok) {
57
- const error = await res.json().catch(() => ({}));
58
- throw new Error(error.message || "An error occurred");
59
- }
60
-
61
- if (stream) {
62
- setState((prev) => ({ ...prev, isLoading: false }));
63
- return res as S;
64
- }
65
-
66
- const data = (await res.json()) as S;
67
- setState((prev) => ({ ...prev, isLoading: false }));
68
- return data;
69
- } catch (error) {
70
- setState((prev) => ({
71
- ...prev,
72
- isLoading: false,
73
- error: error instanceof Error ? error : new Error("An unknown error occurred"),
74
- }));
75
- throw error;
76
- }
77
- },
78
- [],
79
- );
80
-
81
- /**
82
- * API client methods for common operations - memoized to prevent infinite re-renders
83
- */
84
- const api = useMemo(
85
- () => ({
86
- get: <body, returnType>(
87
- endpoint: string,
88
- options?: Omit<FetchOptions<body>, "method" | "body">,
89
- ) => fetchApi<body, returnType>(endpoint, { ...options, method: "GET" }),
90
-
91
- post: <T, S>(endpoint: string, data?: T, options?: Omit<FetchOptions<T>, "method">) =>
92
- fetchApi<T, S>(endpoint, { ...options, method: "POST", body: data || undefined }),
93
-
94
- postStream: <T>(
95
- endpoint: string,
96
- data: T,
97
- options?: Omit<FetchOptions<T>, "method" | "stream">,
98
- ) =>
99
- fetchApi<T, Response>(endpoint, { ...options, method: "POST", body: data, stream: true }),
100
-
101
- postFormData: <S>(
102
- endpoint: string,
103
- formData: FormData,
104
- options?: Omit<FetchOptions<FormData>, "method">,
105
- ) => fetchApi<FormData, S>(endpoint, { ...options, method: "POST", body: formData }),
106
-
107
- put: <T, S>(endpoint: string, data: T, options?: Omit<FetchOptions<T>, "method">) =>
108
- fetchApi<T, S>(endpoint, { ...options, method: "PUT", body: data }),
109
-
110
- delete: <T, S>(endpoint: string, options?: Omit<FetchOptions<T>, "method">) =>
111
- // We add body because `fetchApi` use `application/json` as default content type
112
- fetchApi<T, S>(endpoint, { ...options, method: "DELETE", body: {} as T }),
113
- }),
114
- [fetchApi],
115
- );
116
-
117
- return {
118
- ...api,
119
- isLoading: state.isLoading,
120
- error: state.error,
121
- };
122
- }
@@ -1,12 +0,0 @@
1
- import { useEffect, useState } from "react";
2
-
3
- export function useDebouncedValue<T>(value: T, delayMs: number): T {
4
- const [debouncedValue, setDebouncedValue] = useState(value);
5
-
6
- useEffect(() => {
7
- const timeoutId = setTimeout(() => setDebouncedValue(value), delayMs);
8
- return () => clearTimeout(timeoutId);
9
- }, [delayMs, value]);
10
-
11
- return debouncedValue;
12
- }
@@ -1,70 +0,0 @@
1
- import { useCallback, useMemo, useState } from "react";
2
-
3
- import type { ActiveFilter } from "../components/filters/active-filters-bar";
4
-
5
- export interface FilterConfig {
6
- default: string;
7
- label?: (value: string) => string;
8
- }
9
-
10
- interface UseDerivedFilterStateOptions<T extends Record<string, FilterConfig>> {
11
- fields: T;
12
- sync: {
13
- read: () => Record<string, string>;
14
- write: (values: Record<string, string>) => void;
15
- };
16
- }
17
-
18
- export function useDerivedFilterState<T extends Record<string, FilterConfig>>({
19
- fields,
20
- sync,
21
- }: UseDerivedFilterStateOptions<T>) {
22
- const [values, setValues] = useState<Record<string, string>>(() => {
23
- const read = sync.read();
24
- const initial: Record<string, string> = {};
25
- for (const key of Object.keys(fields)) {
26
- initial[key] = read[key] ?? fields[key].default;
27
- }
28
- return initial;
29
- });
30
-
31
- const setValue = useCallback(
32
- (key: string, value: string) => {
33
- setValues((prev) => {
34
- const next = { ...prev, [key]: value };
35
- sync.write(next);
36
- return next;
37
- });
38
- },
39
- [sync],
40
- );
41
-
42
- const clearAll = useCallback(() => {
43
- const reset: Record<string, string> = {};
44
- for (const key of Object.keys(fields)) {
45
- reset[key] = fields[key].default;
46
- }
47
- setValues(reset);
48
- sync.write(reset);
49
- }, [fields, sync]);
50
-
51
- const activeFilters: ActiveFilter[] = useMemo(() => {
52
- return Object.entries(values)
53
- .filter(([, v]) => v !== "")
54
- .map(([key, v]) => ({
55
- id: key,
56
- label: fields[key]?.label ? fields[key].label!(v) : `${key}: ${v}`,
57
- onRemove: () => setValue(key, ""),
58
- }));
59
- }, [values, fields, setValue]);
60
-
61
- const hasActive = activeFilters.length > 0;
62
-
63
- return {
64
- values,
65
- setValue,
66
- activeFilters,
67
- clearAll,
68
- hasActive,
69
- };
70
- }
@@ -1,66 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from "react";
2
-
3
- interface UseFilterStateOptions<T> {
4
- initialFilters: T;
5
- onFiltersChange?: (filters: T) => void;
6
- debounceMs?: number;
7
- }
8
-
9
- export function useFilterState<T extends Record<string, unknown>>(
10
- options: UseFilterStateOptions<T>,
11
- ) {
12
- const { initialFilters, onFiltersChange, debounceMs } = options;
13
- const [filters, setFiltersState] = useState<T>(initialFilters);
14
- const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
15
- const onFiltersChangeRef = useRef(onFiltersChange);
16
- onFiltersChangeRef.current = onFiltersChange;
17
-
18
- const setFilters = useCallback(
19
- (newFilters: T | ((prev: T) => T)) => {
20
- setFiltersState((prev) => {
21
- const updatedFilters = typeof newFilters === "function" ? newFilters(prev) : newFilters;
22
-
23
- if (debounceMs && debounceMs > 0) {
24
- if (debounceTimerRef.current) {
25
- clearTimeout(debounceTimerRef.current);
26
- }
27
- debounceTimerRef.current = setTimeout(() => {
28
- onFiltersChangeRef.current?.(updatedFilters);
29
- }, debounceMs);
30
- } else {
31
- onFiltersChangeRef.current?.(updatedFilters);
32
- }
33
-
34
- return updatedFilters;
35
- });
36
- },
37
- [debounceMs],
38
- );
39
-
40
- const updateFilter = useCallback(
41
- <K extends keyof T>(key: K, value: T[K]) => {
42
- setFilters((prev) => ({ ...prev, [key]: value }));
43
- },
44
- [setFilters],
45
- );
46
-
47
- const clearFilters = useCallback(() => {
48
- setFiltersState(initialFilters);
49
- onFiltersChangeRef.current?.(initialFilters);
50
- }, [initialFilters]);
51
-
52
- useEffect(() => {
53
- return () => {
54
- if (debounceTimerRef.current) {
55
- clearTimeout(debounceTimerRef.current);
56
- }
57
- };
58
- }, []);
59
-
60
- return {
61
- filters,
62
- setFilters,
63
- updateFilter,
64
- clearFilters,
65
- };
66
- }
@@ -1,69 +0,0 @@
1
- import { useCallback, useSyncExternalStore } from "react";
2
-
3
- interface MediaQueryOptions {
4
- width?: number;
5
- height?: number;
6
- }
7
-
8
- /**
9
- * A utility function to check if a media query matches the current viewport.
10
- * @param query - The media query string to check.
11
- * @param options - Optional width and height values for testing
12
- * @returns A boolean indicating whether the media query matches.
13
- */
14
- function mediaQuery(query: string, options?: MediaQueryOptions) {
15
- if (options?.width !== undefined) {
16
- // For test environment where we provide custom dimensions
17
- const minWidthMatch = query.match(/\(min-width:\s*(\d+)px\)/);
18
- const maxWidthMatch = query.match(/\(max-width:\s*(\d+)px\)/);
19
-
20
- if (minWidthMatch && minWidthMatch[1]) {
21
- return options.width >= Number.parseInt(minWidthMatch[1], 10);
22
- }
23
- if (maxWidthMatch && maxWidthMatch[1]) {
24
- return options.width <= Number.parseInt(maxWidthMatch[1], 10);
25
- }
26
- }
27
-
28
- const mql = window.matchMedia(query);
29
- return mql.matches;
30
- }
31
-
32
- function getServerSnapshot() {
33
- return false;
34
- }
35
-
36
- /**
37
- * Listens for changes to a media query and returns a boolean indicating whether the query matches.
38
- * @param query - The media query string to listen for.
39
- * @returns A boolean indicating whether the media query matches.
40
- */
41
- export function useMediaQuery(query: string) {
42
- const subscribe = useCallback(
43
- (onStoreChange: () => void) => {
44
- if (typeof window === "undefined") {
45
- return () => {};
46
- }
47
-
48
- const mql = window.matchMedia(query);
49
- const onChange = () => {
50
- onStoreChange();
51
- };
52
-
53
- mql.addEventListener("change", onChange);
54
- return () => {
55
- mql.removeEventListener("change", onChange);
56
- };
57
- },
58
- [query],
59
- );
60
-
61
- const getSnapshot = useCallback(() => {
62
- if (typeof window === "undefined") {
63
- return false;
64
- }
65
- return mediaQuery(query);
66
- }, [query]);
67
-
68
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
69
- }
@@ -1,19 +0,0 @@
1
- import * as React from "react";
2
-
3
- const MOBILE_BREAKPOINT = 768;
4
-
5
- export function useIsMobile() {
6
- const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
7
-
8
- React.useEffect(() => {
9
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
10
- const onChange = () => {
11
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
12
- };
13
- mql.addEventListener("change", onChange);
14
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
15
- return () => mql.removeEventListener("change", onChange);
16
- }, []);
17
-
18
- return !!isMobile;
19
- }
@@ -1,20 +0,0 @@
1
- import { useState } from "react";
2
-
3
- import type { SortOption } from "./sort.types";
4
-
5
- interface UseSortOptions {
6
- initialSortOptions?: SortOption[];
7
- }
8
-
9
- export function useSort(options: UseSortOptions = {}) {
10
- const [sortOptions, setSortOptions] = useState<SortOption[]>(options.initialSortOptions ?? []);
11
-
12
- return {
13
- sortOptions,
14
- addSortOption: (opt: SortOption) => setSortOptions((prev) => [...prev, opt]),
15
- updateSortOption: (index: number, opt: SortOption) =>
16
- setSortOptions((prev) => prev.map((o, i) => (i === index ? opt : o))),
17
- removeSortOption: (index: number) =>
18
- setSortOptions((prev) => prev.filter((_, i) => i !== index)),
19
- };
20
- }
package/src/lib/auth.ts DELETED
@@ -1,5 +0,0 @@
1
- export const OTP_LENGTH = 6;
2
-
3
- export function normalizeOtp(value: string, length = OTP_LENGTH): string {
4
- return value.replace(/\D/g, "").slice(0, length);
5
- }
@@ -1,8 +0,0 @@
1
- export async function copyToClipboard(text: string): Promise<boolean> {
2
- try {
3
- await navigator.clipboard.writeText(text);
4
- return true;
5
- } catch {
6
- return false;
7
- }
8
- }
package/src/lib/utils.ts DELETED
@@ -1,6 +0,0 @@
1
- import { type ClassValue, clsx } from "clsx";
2
- import { twMerge } from "tailwind-merge";
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
6
- }
@@ -1,198 +0,0 @@
1
- import React, { type ReactNode } from "react";
2
- import { Pressable, Text, View, type PressableProps, type StyleProp, type ViewStyle } from "react-native";
3
- import { useNativeTheme } from "./theme";
4
-
5
- export type NativeButtonVariant = "primary" | "secondary" | "ghost" | "destructive";
6
- export type NativeButtonSize = "small" | "medium" | "large";
7
-
8
- export interface NativeButtonProps {
9
- label: string;
10
- onPress: PressableProps["onPress"];
11
- variant?: NativeButtonVariant;
12
- size?: NativeButtonSize;
13
- disabled?: boolean;
14
- loading?: boolean;
15
- accessibilityLabel?: string;
16
- accessibilityHint?: string;
17
- leading?: ReactNode;
18
- style?: StyleProp<ViewStyle>;
19
- }
20
-
21
- export function NativeButton({
22
- label,
23
- onPress,
24
- variant = "primary",
25
- size = "medium",
26
- disabled = false,
27
- loading = false,
28
- accessibilityLabel,
29
- accessibilityHint,
30
- leading,
31
- style,
32
- }: NativeButtonProps) {
33
- const { colors, spacing, textSizes, fontWeights, radii } = useNativeTheme();
34
- const isDisabled = disabled || loading;
35
- const [backgroundColor, foregroundColor] = isDisabled
36
- ? [colors.muted, colors.tertiary]
37
- : buttonColors(variant, colors);
38
- const verticalPadding = size === "small" ? spacing["2"] : size === "large" ? spacing["4"] : spacing["3"];
39
- const horizontalPadding = size === "small" ? spacing["3"] : spacing["4"];
40
- const fontSize = size === "small" ? textSizes.sm : size === "large" ? textSizes.lg : textSizes.base;
41
-
42
- return (
43
- <Pressable
44
- accessibilityRole="button"
45
- accessibilityLabel={accessibilityLabel ?? label}
46
- accessibilityHint={accessibilityHint}
47
- accessibilityState={{ disabled: isDisabled, busy: loading }}
48
- disabled={isDisabled}
49
- onPress={onPress}
50
- style={[
51
- {
52
- minHeight: size === "large" ? spacing["14"] : spacing["12"],
53
- paddingHorizontal: horizontalPadding,
54
- paddingVertical: verticalPadding,
55
- borderRadius: radii.lg,
56
- backgroundColor,
57
- alignItems: "center",
58
- justifyContent: "center",
59
- flexDirection: "row",
60
- gap: spacing["2"],
61
- },
62
- style,
63
- ]}
64
- >
65
- {leading}
66
- <Text style={{ color: foregroundColor, fontSize, fontWeight: fontWeights.semibold }}>{label}</Text>
67
- </Pressable>
68
- );
69
- }
70
-
71
- function buttonColors(variant: NativeButtonVariant, colors: ReturnType<typeof useNativeTheme>["colors"]): [string, string] {
72
- switch (variant) {
73
- case "primary":
74
- return [colors.primary, colors["primary-foreground"]];
75
- case "destructive":
76
- return [colors.destructive, colors["destructive-foreground"]];
77
- case "secondary":
78
- return [colors.secondary, colors["text-primary"]];
79
- case "ghost":
80
- return ["transparent", colors["text-primary"]];
81
- }
82
- }
83
-
84
- export interface NativeSurfaceProps {
85
- children: ReactNode;
86
- tone?: "card" | "muted" | "background";
87
- style?: StyleProp<ViewStyle>;
88
- }
89
-
90
- export function NativeSurface({ children, tone = "card", style }: NativeSurfaceProps) {
91
- const { colors, spacing, radii } = useNativeTheme();
92
- const backgroundColor = tone === "muted" ? colors.muted : tone === "background" ? colors.background : colors.card;
93
- return (
94
- <View
95
- style={[
96
- {
97
- backgroundColor,
98
- borderColor: colors["border-default"],
99
- borderWidth: spacing.px,
100
- borderRadius: radii.xl,
101
- padding: spacing["4"],
102
- gap: spacing["2"],
103
- },
104
- style,
105
- ]}
106
- >
107
- {children}
108
- </View>
109
- );
110
- }
111
-
112
- export type NativeBadgeVariant = "default" | "secondary" | "accent" | "success" | "warning" | "destructive";
113
-
114
- export interface NativeBadgeProps {
115
- label: string;
116
- variant?: NativeBadgeVariant;
117
- accessibilityLabel?: string;
118
- }
119
-
120
- export function NativeBadge({ label, variant = "default", accessibilityLabel }: NativeBadgeProps) {
121
- const { colors, spacing, textSizes, fontWeights, radii } = useNativeTheme();
122
- const [backgroundColor, foregroundColor] = badgeColors(variant, colors);
123
- return (
124
- <View
125
- accessibilityRole="text"
126
- accessibilityLabel={accessibilityLabel ?? label}
127
- style={{ alignSelf: "flex-start", paddingHorizontal: spacing["2"], paddingVertical: spacing["1"], borderRadius: radii.full, backgroundColor }}
128
- >
129
- <Text style={{ color: foregroundColor, fontSize: textSizes.sm, fontWeight: fontWeights.medium }}>{label}</Text>
130
- </View>
131
- );
132
- }
133
-
134
- function badgeColors(variant: NativeBadgeVariant, colors: ReturnType<typeof useNativeTheme>["colors"]): [string, string] {
135
- switch (variant) {
136
- case "secondary":
137
- return [colors.secondary, colors["text-primary"]];
138
- case "accent":
139
- return [colors.accent, colors["text-primary"]];
140
- case "success":
141
- return [colors.success, colors["success-foreground"]];
142
- case "warning":
143
- return [colors.warning, colors["warning-foreground"]];
144
- case "destructive":
145
- return [colors.destructive, colors["destructive-foreground"]];
146
- case "default":
147
- return [colors.primary, colors["primary-foreground"]];
148
- }
149
- }
150
-
151
- export interface NativeTabItem<Value extends string = string> {
152
- value: Value;
153
- label: string;
154
- accessibilityLabel?: string;
155
- }
156
-
157
- export interface NativeTabBarProps<Value extends string> {
158
- items: readonly NativeTabItem<Value>[];
159
- value: Value;
160
- onChange: (value: Value) => void;
161
- }
162
-
163
- export function NativeTabBar<Value extends string>({ items, value, onChange }: NativeTabBarProps<Value>) {
164
- const { colors, spacing, textSizes, fontWeights, radii } = useNativeTheme();
165
- return (
166
- <View
167
- accessibilityRole="tablist"
168
- style={{ flexDirection: "row", backgroundColor: colors.card, borderTopColor: colors["border-default"], borderTopWidth: spacing.px, padding: spacing["2"], gap: spacing["1"] }}
169
- >
170
- {items.map((item) => {
171
- const selected = item.value === value;
172
- return (
173
- <Pressable
174
- key={item.value}
175
- accessibilityRole="tab"
176
- accessibilityLabel={item.accessibilityLabel ?? item.label}
177
- accessibilityState={{ selected }}
178
- onPress={() => onChange(item.value)}
179
- style={({ pressed }) => ({
180
- flex: 1,
181
- minHeight: spacing["12"],
182
- paddingHorizontal: spacing["2"],
183
- paddingVertical: spacing["2"],
184
- borderRadius: radii.lg,
185
- backgroundColor: selected ? colors.accent : pressed ? colors.secondary : colors.card,
186
- alignItems: "center",
187
- justifyContent: "center",
188
- })}
189
- >
190
- <Text style={{ color: selected ? colors["text-primary"] : colors["text-secondary"], fontSize: textSizes.sm, fontWeight: selected ? fontWeights.semibold : fontWeights.normal }}>
191
- {item.label}
192
- </Text>
193
- </Pressable>
194
- );
195
- })}
196
- </View>
197
- );
198
- }
@@ -1,69 +0,0 @@
1
- import React, { createContext, useContext, useMemo } from "react";
2
- import { useColorScheme, type TextStyle } from "react-native";
3
- import { colorThemes, fontWeights, radii, spacing, textLineHeights, textSizes, type ColorMode, type ColorTheme } from "../styles/tokens";
4
-
5
- export type NativeColorPreference = ColorMode | "system";
6
-
7
- export interface NativeTheme {
8
- mode: ColorMode;
9
- colors: ColorTheme;
10
- spacing: typeof spacing;
11
- textSizes: typeof textSizes;
12
- textLineHeights: typeof textLineHeights;
13
- fontWeights: Readonly<Record<keyof typeof fontWeights, NonNullable<TextStyle["fontWeight"]>>>;
14
- radii: typeof radii;
15
- }
16
-
17
- function nativeFontWeight(token: keyof typeof fontWeights): NonNullable<TextStyle["fontWeight"]> {
18
- switch (fontWeights[token]) {
19
- case "100": return "100";
20
- case "200": return "200";
21
- case "300": return "300";
22
- case "400": return "400";
23
- case "500": return "500";
24
- case "600": return "600";
25
- case "700": return "700";
26
- case "800": return "800";
27
- case "900": return "900";
28
- default: throw new Error(`Unsupported native font-weight token: ${fontWeights[token]}`);
29
- }
30
- }
31
-
32
- const nativeFontWeights: NativeTheme["fontWeights"] = {
33
- thin: nativeFontWeight("thin"),
34
- extralight: nativeFontWeight("extralight"),
35
- light: nativeFontWeight("light"),
36
- normal: nativeFontWeight("normal"),
37
- medium: nativeFontWeight("medium"),
38
- semibold: nativeFontWeight("semibold"),
39
- bold: nativeFontWeight("bold"),
40
- extrabold: nativeFontWeight("extrabold"),
41
- black: nativeFontWeight("black"),
42
- };
43
-
44
- const NativeThemeContext = createContext<NativeTheme>({
45
- mode: "light",
46
- colors: colorThemes.light,
47
- spacing,
48
- textSizes,
49
- textLineHeights,
50
- fontWeights: nativeFontWeights,
51
- radii,
52
- });
53
-
54
- export interface NativeThemeProviderProps {
55
- children: React.ReactNode;
56
- colorPreference?: NativeColorPreference;
57
- }
58
-
59
- export function NativeThemeProvider({ children, colorPreference = "system" }: NativeThemeProviderProps) {
60
- const systemMode = useColorScheme();
61
- const mode: ColorMode = colorPreference === "system" ? (systemMode === "dark" ? "dark" : "light") : colorPreference;
62
- const value = useMemo<NativeTheme>(() => ({ mode, colors: colorThemes[mode], spacing, textSizes, textLineHeights, fontWeights: nativeFontWeights, radii }), [mode]);
63
-
64
- return <NativeThemeContext.Provider value={value}>{children}</NativeThemeContext.Provider>;
65
- }
66
-
67
- export function useNativeTheme(): NativeTheme {
68
- return useContext(NativeThemeContext);
69
- }