@multiplatform.one/router 5.0.27 → 6.0.1

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 (249) hide show
  1. package/dist/cjs/hooks/index.cjs +31 -0
  2. package/dist/cjs/hooks/index.native.js +34 -0
  3. package/dist/cjs/hooks/index.native.js.map +1 -0
  4. package/dist/cjs/hooks/useUrlState.cjs +185 -0
  5. package/dist/cjs/hooks/useUrlState.native.js +203 -0
  6. package/dist/cjs/hooks/useUrlState.native.js.map +1 -0
  7. package/dist/cjs/hooks/useUrlState.spec.cjs +280 -0
  8. package/dist/cjs/hooks/useUrlState.spec.native.js +315 -0
  9. package/dist/cjs/hooks/useUrlState.spec.native.js.map +1 -0
  10. package/dist/cjs/index.cjs +9 -6
  11. package/dist/cjs/index.native.js +16 -13
  12. package/dist/cjs/index.native.js.map +1 -6
  13. package/dist/cjs/index.storybook.cjs +34 -0
  14. package/dist/cjs/index.storybook.native.js +37 -0
  15. package/dist/cjs/index.storybook.native.js.map +1 -0
  16. package/dist/cjs/router/EmptyRouter.cjs +78 -0
  17. package/dist/cjs/router/EmptyRouter.native.js +106 -0
  18. package/dist/cjs/router/EmptyRouter.native.js.map +1 -0
  19. package/dist/cjs/router/ReactRouter.cjs +107 -0
  20. package/dist/cjs/router/ReactRouter.native.js +135 -0
  21. package/dist/cjs/router/ReactRouter.native.js.map +1 -0
  22. package/dist/cjs/router/index.cjs +17 -67
  23. package/dist/cjs/router/index.native.js +22 -81
  24. package/dist/cjs/router/index.native.js.map +1 -6
  25. package/dist/cjs/router/index.storybook-expo.cjs +8 -6
  26. package/dist/cjs/router/index.storybook-expo.native.js +14 -11
  27. package/dist/cjs/router/index.storybook-expo.native.js.map +1 -6
  28. package/dist/cjs/router/index.storybook.cjs +8 -6
  29. package/dist/cjs/router/index.storybook.native.js +14 -11
  30. package/dist/cjs/router/index.storybook.native.js.map +1 -6
  31. package/dist/cjs/router/index.webext.cjs +8 -6
  32. package/dist/cjs/router/index.webext.native.js +14 -11
  33. package/dist/cjs/router/index.webext.native.js.map +1 -6
  34. package/dist/cjs/types.cjs +7 -5
  35. package/dist/cjs/types.native.js +11 -5
  36. package/dist/cjs/types.native.js.map +1 -6
  37. package/dist/esm/hooks/index.mjs +3 -0
  38. package/dist/esm/hooks/index.mjs.map +1 -0
  39. package/dist/esm/hooks/index.native.js +3 -0
  40. package/dist/esm/hooks/index.native.js.map +1 -0
  41. package/dist/esm/hooks/useUrlState.mjs +157 -0
  42. package/dist/esm/hooks/useUrlState.mjs.map +1 -0
  43. package/dist/esm/hooks/useUrlState.native.js +172 -0
  44. package/dist/esm/hooks/useUrlState.native.js.map +1 -0
  45. package/dist/esm/hooks/useUrlState.spec.mjs +257 -0
  46. package/dist/esm/hooks/useUrlState.spec.mjs.map +1 -0
  47. package/dist/esm/hooks/useUrlState.spec.native.js +289 -0
  48. package/dist/esm/hooks/useUrlState.spec.native.js.map +1 -0
  49. package/dist/esm/index.mjs +1 -0
  50. package/dist/esm/index.mjs.map +1 -1
  51. package/dist/esm/index.native.js +4 -3
  52. package/dist/esm/index.native.js.map +1 -6
  53. package/dist/esm/index.storybook.mjs +5 -0
  54. package/dist/esm/index.storybook.mjs.map +1 -0
  55. package/dist/esm/index.storybook.native.js +5 -0
  56. package/dist/esm/index.storybook.native.js.map +1 -0
  57. package/dist/esm/router/EmptyRouter.mjs +49 -0
  58. package/dist/esm/router/EmptyRouter.mjs.map +1 -0
  59. package/dist/esm/router/EmptyRouter.native.js +74 -0
  60. package/dist/esm/router/EmptyRouter.native.js.map +1 -0
  61. package/dist/esm/router/ReactRouter.mjs +79 -0
  62. package/dist/esm/router/ReactRouter.mjs.map +1 -0
  63. package/dist/esm/router/ReactRouter.native.js +104 -0
  64. package/dist/esm/router/ReactRouter.native.js.map +1 -0
  65. package/dist/esm/router/index.mjs +1 -53
  66. package/dist/esm/router/index.mjs.map +1 -1
  67. package/dist/esm/router/index.native.js +3 -71
  68. package/dist/esm/router/index.native.js.map +1 -6
  69. package/dist/esm/router/index.storybook-expo.mjs +1 -1
  70. package/dist/esm/router/index.storybook-expo.mjs.map +1 -1
  71. package/dist/esm/router/index.storybook-expo.native.js +2 -2
  72. package/dist/esm/router/index.storybook-expo.native.js.map +1 -6
  73. package/dist/esm/router/index.storybook.mjs +1 -1
  74. package/dist/esm/router/index.storybook.mjs.map +1 -1
  75. package/dist/esm/router/index.storybook.native.js +2 -2
  76. package/dist/esm/router/index.storybook.native.js.map +1 -6
  77. package/dist/esm/router/index.webext.mjs +1 -1
  78. package/dist/esm/router/index.webext.mjs.map +1 -1
  79. package/dist/esm/router/index.webext.native.js +2 -2
  80. package/dist/esm/router/index.webext.native.js.map +1 -6
  81. package/dist/esm/types.native.js +2 -1
  82. package/dist/esm/types.native.js.map +1 -6
  83. package/dist/jsx/hooks/index.mjs +3 -0
  84. package/dist/jsx/hooks/index.mjs.map +1 -0
  85. package/dist/jsx/hooks/index.native.js +34 -0
  86. package/dist/jsx/hooks/index.native.js.map +1 -0
  87. package/dist/jsx/hooks/useUrlState.mjs +157 -0
  88. package/dist/jsx/hooks/useUrlState.mjs.map +1 -0
  89. package/dist/jsx/hooks/useUrlState.native.js +203 -0
  90. package/dist/jsx/hooks/useUrlState.native.js.map +1 -0
  91. package/dist/jsx/hooks/useUrlState.spec.mjs +257 -0
  92. package/dist/jsx/hooks/useUrlState.spec.mjs.map +1 -0
  93. package/dist/jsx/hooks/useUrlState.spec.native.js +315 -0
  94. package/dist/jsx/hooks/useUrlState.spec.native.js.map +1 -0
  95. package/dist/jsx/index.js +3 -2
  96. package/dist/jsx/index.js.map +1 -6
  97. package/dist/jsx/index.mjs +1 -0
  98. package/dist/jsx/index.mjs.map +1 -1
  99. package/dist/jsx/index.native.js +25 -3
  100. package/dist/jsx/index.native.js.map +1 -6
  101. package/dist/jsx/index.storybook.mjs +5 -0
  102. package/dist/jsx/index.storybook.mjs.map +1 -0
  103. package/dist/jsx/index.storybook.native.js +37 -0
  104. package/dist/jsx/index.storybook.native.js.map +1 -0
  105. package/dist/jsx/router/EmptyRouter.mjs +49 -0
  106. package/dist/jsx/router/EmptyRouter.mjs.map +1 -0
  107. package/dist/jsx/router/EmptyRouter.native.js +106 -0
  108. package/dist/jsx/router/EmptyRouter.native.js.map +1 -0
  109. package/dist/jsx/router/ReactRouter.mjs +79 -0
  110. package/dist/jsx/router/ReactRouter.mjs.map +1 -0
  111. package/dist/jsx/router/ReactRouter.native.js +135 -0
  112. package/dist/jsx/router/ReactRouter.native.js.map +1 -0
  113. package/dist/jsx/router/index.mjs +1 -53
  114. package/dist/jsx/router/index.mjs.map +1 -1
  115. package/dist/jsx/router/index.native.js +31 -68
  116. package/dist/jsx/router/index.native.js.map +1 -6
  117. package/dist/jsx/router/index.storybook-expo.mjs +1 -1
  118. package/dist/jsx/router/index.storybook-expo.mjs.map +1 -1
  119. package/dist/jsx/router/index.storybook-expo.native.js +23 -2
  120. package/dist/jsx/router/index.storybook-expo.native.js.map +1 -6
  121. package/dist/jsx/router/index.storybook.mjs +1 -1
  122. package/dist/jsx/router/index.storybook.mjs.map +1 -1
  123. package/dist/jsx/router/index.storybook.native.js +23 -2
  124. package/dist/jsx/router/index.storybook.native.js.map +1 -6
  125. package/dist/jsx/router/index.webext.mjs +1 -1
  126. package/dist/jsx/router/index.webext.mjs.map +1 -1
  127. package/dist/jsx/router/index.webext.native.js +23 -2
  128. package/dist/jsx/router/index.webext.native.js.map +1 -6
  129. package/dist/jsx/types.native.js +21 -1
  130. package/dist/jsx/types.native.js.map +1 -6
  131. package/package.json +46 -36
  132. package/src/hooks/README.md +232 -0
  133. package/src/hooks/index.ts +8 -0
  134. package/src/hooks/useUrlState.spec.ts +219 -0
  135. package/src/hooks/useUrlState.ts +231 -0
  136. package/src/index.storybook.ts +3 -0
  137. package/src/index.ts +1 -21
  138. package/src/router/EmptyRouter.tsx +50 -0
  139. package/src/router/{reactRouter.tsx → ReactRouter.tsx} +27 -22
  140. package/src/router/index.storybook-expo.tsx +1 -22
  141. package/src/router/index.storybook.tsx +1 -22
  142. package/src/router/index.tsx +1 -97
  143. package/src/router/index.webext.tsx +1 -22
  144. package/src/types.tsx +3 -24
  145. package/dist/cjs/index.js +0 -16
  146. package/dist/cjs/index.js.map +0 -6
  147. package/dist/cjs/router/emptyRouter.cjs +0 -55
  148. package/dist/cjs/router/emptyRouter.js +0 -47
  149. package/dist/cjs/router/emptyRouter.js.map +0 -6
  150. package/dist/cjs/router/emptyRouter.native.js +0 -77
  151. package/dist/cjs/router/emptyRouter.native.js.map +0 -6
  152. package/dist/cjs/router/index.electron.cjs +0 -18
  153. package/dist/cjs/router/index.electron.js +0 -15
  154. package/dist/cjs/router/index.electron.js.map +0 -6
  155. package/dist/cjs/router/index.electron.native.js +0 -20
  156. package/dist/cjs/router/index.electron.native.js.map +0 -6
  157. package/dist/cjs/router/index.js +0 -63
  158. package/dist/cjs/router/index.js.map +0 -6
  159. package/dist/cjs/router/index.storybook-expo.js +0 -15
  160. package/dist/cjs/router/index.storybook-expo.js.map +0 -6
  161. package/dist/cjs/router/index.storybook.js +0 -15
  162. package/dist/cjs/router/index.storybook.js.map +0 -6
  163. package/dist/cjs/router/index.webext.js +0 -15
  164. package/dist/cjs/router/index.webext.js.map +0 -6
  165. package/dist/cjs/router/reactRouter.cjs +0 -74
  166. package/dist/cjs/router/reactRouter.js +0 -48
  167. package/dist/cjs/router/reactRouter.js.map +0 -6
  168. package/dist/cjs/router/reactRouter.native.js +0 -96
  169. package/dist/cjs/router/reactRouter.native.js.map +0 -6
  170. package/dist/cjs/types.js +0 -14
  171. package/dist/cjs/types.js.map +0 -6
  172. package/dist/esm/index.js +0 -3
  173. package/dist/esm/index.js.map +0 -6
  174. package/dist/esm/router/emptyRouter.js +0 -31
  175. package/dist/esm/router/emptyRouter.js.map +0 -6
  176. package/dist/esm/router/emptyRouter.mjs +0 -29
  177. package/dist/esm/router/emptyRouter.mjs.map +0 -1
  178. package/dist/esm/router/emptyRouter.native.js +0 -54
  179. package/dist/esm/router/emptyRouter.native.js.map +0 -6
  180. package/dist/esm/router/index.electron.js +0 -2
  181. package/dist/esm/router/index.electron.js.map +0 -6
  182. package/dist/esm/router/index.electron.mjs +0 -2
  183. package/dist/esm/router/index.electron.mjs.map +0 -1
  184. package/dist/esm/router/index.electron.native.js +0 -2
  185. package/dist/esm/router/index.electron.native.js.map +0 -6
  186. package/dist/esm/router/index.js +0 -52
  187. package/dist/esm/router/index.js.map +0 -6
  188. package/dist/esm/router/index.storybook-expo.js +0 -2
  189. package/dist/esm/router/index.storybook-expo.js.map +0 -6
  190. package/dist/esm/router/index.storybook.js +0 -2
  191. package/dist/esm/router/index.storybook.js.map +0 -6
  192. package/dist/esm/router/index.webext.js +0 -2
  193. package/dist/esm/router/index.webext.js.map +0 -6
  194. package/dist/esm/router/reactRouter.js +0 -38
  195. package/dist/esm/router/reactRouter.js.map +0 -6
  196. package/dist/esm/router/reactRouter.mjs +0 -48
  197. package/dist/esm/router/reactRouter.mjs.map +0 -1
  198. package/dist/esm/router/reactRouter.native.js +0 -74
  199. package/dist/esm/router/reactRouter.native.js.map +0 -6
  200. package/dist/esm/types.js +0 -1
  201. package/dist/esm/types.js.map +0 -6
  202. package/dist/jsx/router/emptyRouter.js +0 -31
  203. package/dist/jsx/router/emptyRouter.js.map +0 -6
  204. package/dist/jsx/router/emptyRouter.mjs +0 -29
  205. package/dist/jsx/router/emptyRouter.mjs.map +0 -1
  206. package/dist/jsx/router/emptyRouter.native.js +0 -54
  207. package/dist/jsx/router/emptyRouter.native.js.map +0 -6
  208. package/dist/jsx/router/index.electron.js +0 -2
  209. package/dist/jsx/router/index.electron.js.map +0 -6
  210. package/dist/jsx/router/index.electron.mjs +0 -2
  211. package/dist/jsx/router/index.electron.mjs.map +0 -1
  212. package/dist/jsx/router/index.electron.native.js +0 -2
  213. package/dist/jsx/router/index.electron.native.js.map +0 -6
  214. package/dist/jsx/router/index.js +0 -52
  215. package/dist/jsx/router/index.js.map +0 -6
  216. package/dist/jsx/router/index.storybook-expo.js +0 -2
  217. package/dist/jsx/router/index.storybook-expo.js.map +0 -6
  218. package/dist/jsx/router/index.storybook.js +0 -2
  219. package/dist/jsx/router/index.storybook.js.map +0 -6
  220. package/dist/jsx/router/index.webext.js +0 -2
  221. package/dist/jsx/router/index.webext.js.map +0 -6
  222. package/dist/jsx/router/reactRouter.js +0 -38
  223. package/dist/jsx/router/reactRouter.js.map +0 -6
  224. package/dist/jsx/router/reactRouter.mjs +0 -48
  225. package/dist/jsx/router/reactRouter.mjs.map +0 -1
  226. package/dist/jsx/router/reactRouter.native.js +0 -74
  227. package/dist/jsx/router/reactRouter.native.js.map +0 -6
  228. package/dist/jsx/types.js +0 -1
  229. package/dist/jsx/types.js.map +0 -6
  230. package/src/router/emptyRouter.tsx +0 -56
  231. package/src/router/index.electron.tsx +0 -22
  232. package/types/index.d.ts +0 -3
  233. package/types/index.d.ts.map +0 -1
  234. package/types/router/emptyRouter.d.ts +0 -26
  235. package/types/router/emptyRouter.d.ts.map +0 -1
  236. package/types/router/index.d.ts +0 -27
  237. package/types/router/index.d.ts.map +0 -1
  238. package/types/router/index.electron.d.ts +0 -22
  239. package/types/router/index.electron.d.ts.map +0 -1
  240. package/types/router/index.storybook-expo.d.ts +0 -22
  241. package/types/router/index.storybook-expo.d.ts.map +0 -1
  242. package/types/router/index.storybook.d.ts +0 -22
  243. package/types/router/index.storybook.d.ts.map +0 -1
  244. package/types/router/index.webext.d.ts +0 -22
  245. package/types/router/index.webext.d.ts.map +0 -1
  246. package/types/router/reactRouter.d.ts +0 -27
  247. package/types/router/reactRouter.d.ts.map +0 -1
  248. package/types/types.d.ts +0 -60
  249. package/types/types.d.ts.map +0 -1
@@ -0,0 +1,231 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ import { isWeb } from "@multiplatform.one/platform";
3
+ import { useParams, useRouter } from "../router";
4
+
5
+ export type SearchParams = Record<string, string | string[] | undefined>;
6
+
7
+ export interface SetSearchParamsOptions {
8
+ replace?: boolean;
9
+ debounceMs?: number;
10
+ }
11
+
12
+ /**
13
+ * Cross-platform hook for managing URL search parameters
14
+ * Works with both React Router (web) and React Navigation (native)
15
+ */
16
+ export function useSearchParams(): [
17
+ SearchParams,
18
+ (
19
+ params: SearchParams | ((prev: SearchParams) => SearchParams),
20
+ options?: SetSearchParamsOptions,
21
+ ) => void,
22
+ ] {
23
+ const router = useRouter();
24
+ const currentParams = useParams();
25
+ const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
26
+
27
+ // Parse current params into a more usable format
28
+ const searchParams = useMemo<SearchParams>(() => {
29
+ const params: SearchParams = {};
30
+ Object.entries(currentParams).forEach(([key, value]) => {
31
+ if (value !== undefined && value !== null) {
32
+ params[key] = value as string | string[];
33
+ }
34
+ });
35
+ return params;
36
+ }, [currentParams]);
37
+
38
+ const setSearchParams = useCallback(
39
+ (
40
+ newParams: SearchParams | ((prev: SearchParams) => SearchParams),
41
+ options: SetSearchParamsOptions = {},
42
+ ) => {
43
+ const { replace: _replace = true, debounceMs = 0 } = options;
44
+
45
+ const updateParams = () => {
46
+ const updatedParams = typeof newParams === "function" ? newParams(searchParams) : newParams;
47
+
48
+ // Filter out undefined values
49
+ const cleanParams: Record<string, string | string[]> = {};
50
+ Object.entries(updatedParams).forEach(([key, value]) => {
51
+ if (value !== undefined && value !== null && value !== "") {
52
+ cleanParams[key] = value;
53
+ }
54
+ });
55
+
56
+ // Use router.setParams to update the URL
57
+ router.setParams(cleanParams as any);
58
+ };
59
+
60
+ if (debounceMs > 0) {
61
+ if (debounceTimerRef.current) {
62
+ clearTimeout(debounceTimerRef.current);
63
+ }
64
+ debounceTimerRef.current = setTimeout(updateParams, debounceMs);
65
+ } else {
66
+ updateParams();
67
+ }
68
+ },
69
+ [router, searchParams],
70
+ );
71
+
72
+ // Cleanup debounce timer on unmount
73
+ useEffect(() => {
74
+ return () => {
75
+ if (debounceTimerRef.current) {
76
+ clearTimeout(debounceTimerRef.current);
77
+ }
78
+ };
79
+ }, []);
80
+
81
+ return [searchParams, setSearchParams];
82
+ }
83
+
84
+ /**
85
+ * Hook for syncing form state with URL parameters
86
+ * Provides automatic serialization/deserialization and debouncing
87
+ */
88
+ export function useUrlState<T extends Record<string, any>>(
89
+ defaultValues: T,
90
+ options: {
91
+ debounceMs?: number;
92
+ serialize?: (value: T) => SearchParams;
93
+ deserialize?: (params: SearchParams) => T;
94
+ } = {},
95
+ ): [T, (newState: Partial<T> | ((prev: T) => Partial<T>)) => void] {
96
+ const {
97
+ debounceMs = 500,
98
+ serialize = (value) => {
99
+ // Default serialization: convert to string
100
+ const params: SearchParams = {};
101
+ Object.entries(value).forEach(([key, val]) => {
102
+ if (val !== undefined && val !== null && val !== "") {
103
+ if (Array.isArray(val)) {
104
+ params[key] = val.map(String);
105
+ } else if (typeof val === "object") {
106
+ params[key] = JSON.stringify(val);
107
+ } else {
108
+ params[key] = String(val);
109
+ }
110
+ }
111
+ });
112
+ return params;
113
+ },
114
+ deserialize = (params) => {
115
+ // Default deserialization: parse JSON for objects
116
+ const result: any = {};
117
+ Object.entries(params).forEach(([key, value]) => {
118
+ if (key in defaultValues) {
119
+ const defaultValue = defaultValues[key];
120
+ if (value === undefined) {
121
+ result[key] = defaultValue;
122
+ } else if (Array.isArray(defaultValue)) {
123
+ result[key] = Array.isArray(value) ? value : [value];
124
+ } else if (typeof defaultValue === "boolean") {
125
+ result[key] = value === "true";
126
+ } else if (typeof defaultValue === "number") {
127
+ result[key] = Number(value);
128
+ } else if (typeof defaultValue === "object" && defaultValue !== null) {
129
+ try {
130
+ result[key] = JSON.parse(String(value));
131
+ } catch {
132
+ result[key] = defaultValue;
133
+ }
134
+ } else {
135
+ result[key] = value;
136
+ }
137
+ }
138
+ });
139
+ // Fill in missing keys with defaults
140
+ Object.keys(defaultValues).forEach((key) => {
141
+ if (!(key in result)) {
142
+ result[key] = defaultValues[key];
143
+ }
144
+ });
145
+ return result as T;
146
+ },
147
+ } = options;
148
+
149
+ const [searchParams, setSearchParams] = useSearchParams();
150
+
151
+ // Initialize state from URL or defaults
152
+ const currentState = useMemo(() => {
153
+ return deserialize(searchParams);
154
+ }, [searchParams, deserialize]);
155
+
156
+ const setState = useCallback(
157
+ (newState: Partial<T> | ((prev: T) => Partial<T>)) => {
158
+ const updatedState = typeof newState === "function" ? newState(currentState) : newState;
159
+
160
+ const mergedState = { ...currentState, ...updatedState };
161
+ const serialized = serialize(mergedState);
162
+
163
+ setSearchParams(serialized, { debounceMs });
164
+ },
165
+ [currentState, serialize, setSearchParams, debounceMs],
166
+ );
167
+
168
+ return [currentState, setState];
169
+ }
170
+
171
+ /**
172
+ * Hook for creating shareable URLs with current state
173
+ */
174
+ export function useShareableUrl(): string {
175
+ const params = useParams();
176
+
177
+ const shareableUrl = useMemo(() => {
178
+ if (!isWeb || typeof window === "undefined") {
179
+ return "";
180
+ }
181
+
182
+ const url = new URL(window.location.href);
183
+ url.search = "";
184
+
185
+ Object.entries(params).forEach(([key, value]) => {
186
+ if (value !== undefined && value !== null && value !== "") {
187
+ if (Array.isArray(value)) {
188
+ value.forEach((v) => url.searchParams.append(key, String(v)));
189
+ } else {
190
+ url.searchParams.set(key, String(value));
191
+ }
192
+ }
193
+ });
194
+
195
+ return url.toString();
196
+ }, [params]);
197
+
198
+ return shareableUrl;
199
+ }
200
+
201
+ /**
202
+ * Hook for parsing URL parameters with type safety
203
+ */
204
+ export function useTypedSearchParams<T extends Record<string, any>>(schema: {
205
+ [K in keyof T]: {
206
+ default: T[K];
207
+ parse?: (value: string | string[] | undefined) => T[K];
208
+ };
209
+ }): T {
210
+ const params = useParams();
211
+
212
+ const typedParams = useMemo(() => {
213
+ const result: any = {};
214
+
215
+ Object.entries(schema).forEach(([key, config]) => {
216
+ const rawValue = params[key];
217
+
218
+ if (config.parse) {
219
+ result[key] = config.parse(rawValue);
220
+ } else if (rawValue === undefined) {
221
+ result[key] = config.default;
222
+ } else {
223
+ result[key] = rawValue;
224
+ }
225
+ });
226
+
227
+ return result as T;
228
+ }, [params, schema]);
229
+
230
+ return typedParams;
231
+ }
@@ -0,0 +1,3 @@
1
+ export { useRouter, usePathname, useParams, Link } from "./router/EmptyRouter";
2
+ export * from "./types";
3
+ export * from "./hooks";
package/src/index.ts CHANGED
@@ -1,23 +1,3 @@
1
- /*
2
- * File: /src/index.ts
3
- * Project: @multiplatform.one/router
4
- * File Created: 10-01-2025 15:02:36
5
- * Author: Clay Risser
6
- * -----
7
- * BitSpur (c) Copyright 2021 - 2025
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * http://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
1
  export * from "./router/index";
23
2
  export * from "./types";
3
+ export * from "./hooks";
@@ -0,0 +1,50 @@
1
+ import type { Href, LinkComponent, Router } from "../types";
2
+
3
+ const prefix = "[router]";
4
+
5
+ export const useRouter = (): Router => {
6
+ return {
7
+ back: () => console.log(prefix, "back()"),
8
+ canGoBack: () => false,
9
+ push: (href: Href) => console.log(prefix, "push", String(href)),
10
+ navigate: (href: Href) => console.log(prefix, "navigate", String(href)),
11
+ replace: (href: Href) => console.log(prefix, "replace", String(href)),
12
+ dismiss: (count?: number) => console.log(prefix, "dismiss", count ?? 1),
13
+ dismissAll: () => console.log(prefix, "dismissAll()"),
14
+ canDismiss: () => false,
15
+ setParams: (params) => console.log(prefix, "setParams", params),
16
+ subscribe: (listener) => {
17
+ listener("success");
18
+ return () => {};
19
+ },
20
+ onLoadState: (listener) => {
21
+ listener("loaded");
22
+ return () => {};
23
+ },
24
+ };
25
+ };
26
+
27
+ export const usePathname = (): string => "/";
28
+
29
+ export const useParams = () => ({});
30
+
31
+ export const Link: LinkComponent = ({ href, replace, children, ...props }) => {
32
+ const handleClick = (e: React.MouseEvent) => {
33
+ e.preventDefault();
34
+ console.log(prefix, replace ? "replace" : "push", String(href));
35
+ };
36
+ return (
37
+ <a href={href as string} onClick={handleClick} {...props}>
38
+ {children}
39
+ </a>
40
+ );
41
+ };
42
+
43
+ Link.resolveHref = (href: Href) => href.toString();
44
+
45
+ export function useUrlState<T extends Record<string, any>>(
46
+ defaultValues: T,
47
+ ): [T, (newState: Partial<T> | ((prev: T) => Partial<T>)) => void] {
48
+ const setState = () => {};
49
+ return [defaultValues, setState];
50
+ }
@@ -1,29 +1,9 @@
1
- /**
2
- * File: /src/router/reactRouter.tsx
3
- * Project: @multiplatform.one/router
4
- * File Created: 24-01-2025 16:56:40
5
- * Author: Clay Risser
6
- * -----
7
- * BitSpur (c) Copyright 2021 - 2025
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * http://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
1
  import {
23
2
  Link as ReactRouterLink,
24
3
  useLocation,
25
4
  useNavigate,
26
5
  useParams as useReactParams,
6
+ useSearchParams as useReactSearchParams,
27
7
  } from "react-router-dom";
28
8
  import type {
29
9
  Href,
@@ -73,7 +53,32 @@ export const useRouter = (): Router => {
73
53
 
74
54
  export const usePathname = (): string => useLocation().pathname;
75
55
 
76
- export const useParams = useReactParams;
56
+ // Combine route params and search params for React Router
57
+ export const useParams = () => {
58
+ const routeParams = useReactParams();
59
+ const [searchParams] = useReactSearchParams();
60
+ const params: Record<string, string | string[] | undefined> = {};
61
+
62
+ // Add route params
63
+ Object.entries(routeParams).forEach(([key, value]) => {
64
+ if (value !== undefined) {
65
+ params[key] = value;
66
+ }
67
+ });
68
+
69
+ // Add search params
70
+ searchParams.forEach((value, key) => {
71
+ if (params[key]) {
72
+ // If key already exists from route params, make it an array
73
+ const existing = params[key];
74
+ params[key] = Array.isArray(existing) ? [...existing, value] : [existing as string, value];
75
+ } else {
76
+ params[key] = value;
77
+ }
78
+ });
79
+
80
+ return params;
81
+ };
77
82
 
78
83
  export const Link: LinkComponent = ({ href, replace, children, ...props }) => (
79
84
  <ReactRouterLink to={href as string} replace={replace} {...props}>
@@ -1,22 +1 @@
1
- /**
2
- * File: /src/router/index.storybook-expo.tsx
3
- * Project: @multiplatform.one/router
4
- * File Created: 23-01-2025 15:12:32
5
- * Author: Clay Risser
6
- * -----
7
- * BitSpur (c) Copyright 2021 - 2025
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * http://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
- export * from "./emptyRouter";
1
+ export * from "./EmptyRouter";
@@ -1,22 +1 @@
1
- /**
2
- * File: /src/router/index.storybook.tsx
3
- * Project: @multiplatform.one/router
4
- * File Created: 23-01-2025 15:12:32
5
- * Author: Clay Risser
6
- * -----
7
- * BitSpur (c) Copyright 2021 - 2025
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * http://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
- export * from "./emptyRouter";
1
+ export * from "./EmptyRouter";
@@ -1,97 +1 @@
1
- /**
2
- * File: /src/router/index.tsx
3
- * Project: @multiplatform.one/router
4
- * File Created: 23-01-2025 15:17:57
5
- * Author: Clay Risser
6
- * -----
7
- * BitSpur (c) Copyright 2021 - 2025
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * http://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
- import {
23
- Link as OneLink,
24
- usePathname as useOnePathname,
25
- useRouter as useOneRouter,
26
- } from "one";
27
- import type {
28
- Href,
29
- LinkComponent,
30
- LoadingState,
31
- ResultState,
32
- Router,
33
- } from "../types";
34
-
35
- const mapResultState = (state: unknown): ResultState => {
36
- return state === "success" ? "success" : "error";
37
- };
38
-
39
- const mapLoadingState = (state: unknown): LoadingState => {
40
- if (state === "loaded") return "loaded";
41
- if (state === "loading") return "loading";
42
- return "error";
43
- };
44
-
45
- export const useRouter = (): Router => {
46
- const router = useOneRouter();
47
- return {
48
- back: () => router.back(),
49
- canGoBack: () => router.canGoBack(),
50
- push: (href: Href) => router.push(href),
51
- navigate: (href: Href) => router.navigate(href),
52
- replace: (href: Href) => router.replace(href),
53
- dismiss: (count?: number) => router.dismiss(count),
54
- dismissAll: () => router.dismissAll(),
55
- canDismiss: () => router.canDismiss(),
56
- setParams: router.setParams,
57
- subscribe: (listener) => {
58
- const oneListener = (state: unknown) => {
59
- listener(mapResultState(state));
60
- };
61
- return router.subscribe(oneListener);
62
- },
63
- onLoadState: (listener) => {
64
- const oneListener = (state: unknown) => {
65
- listener(mapLoadingState(state));
66
- };
67
- return router.onLoadState(oneListener);
68
- },
69
- };
70
- };
71
-
72
- export const usePathname = useOnePathname;
73
-
74
- export const useParams = () => {
75
- const pathname = useOnePathname();
76
- const searchParams = new URLSearchParams(pathname);
77
- const params: Record<string, string> = {};
78
- searchParams.forEach((value, key) => {
79
- params[key] = value;
80
- });
81
- return params;
82
- };
83
-
84
- export const Link: LinkComponent = ({
85
- href,
86
- replace,
87
- children,
88
- style,
89
- className,
90
- ...props
91
- }) => (
92
- <OneLink href={href} replace={replace} {...props}>
93
- {children}
94
- </OneLink>
95
- );
96
-
97
- Link.resolveHref = (href: Href) => href.toString();
1
+ export { Link, useParams, usePathname, useRouter } from "one";
@@ -1,22 +1 @@
1
- /**
2
- * File: /src/router/index.webext.tsx
3
- * Project: @multiplatform.one/router
4
- * File Created: 10-01-2025 15:02:36
5
- * Author: Clay Risser
6
- * -----
7
- * BitSpur (c) Copyright 2021 - 2025
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * http://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
- export * from "./reactRouter";
1
+ export * from "./ReactRouter";
package/src/types.tsx CHANGED
@@ -1,26 +1,5 @@
1
- /**
2
- * File: /src/types.tsx
3
- * Project: @multiplatform.one/router
4
- * File Created: 23-01-2025 15:28:42
5
- * Author: Clay Risser
6
- * -----
7
- * BitSpur (c) Copyright 2021 - 2025
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * http://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
1
  import type { OneRouter } from "one";
23
- import type { CSSProperties, ReactNode } from "react";
2
+ import type { CSSProperties, ReactElement, ReactNode } from "react";
24
3
 
25
4
  export type Href = OneRouter.Href<{ __branded__: any }>;
26
5
  export type LoadingState = "loading" | "loaded" | "error";
@@ -49,7 +28,7 @@ export interface Router {
49
28
 
50
29
  export type UseRouter = () => Router;
51
30
  export type UsePathname = () => string;
52
- export type UseParams = () => Record<string, string>;
31
+ export type UseParams = () => Record<string, string | string[] | undefined>;
53
32
 
54
33
  export interface LinkProps {
55
34
  href: Href;
@@ -61,6 +40,6 @@ export interface LinkProps {
61
40
  }
62
41
 
63
42
  export interface LinkComponent {
64
- (props: LinkProps): JSX.Element;
43
+ (props: LinkProps): ReactElement;
65
44
  resolveHref: (href: Href) => string;
66
45
  }
package/dist/cjs/index.js DELETED
@@ -1,16 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __copyProps = (to, from, except, desc) => {
6
- if (from && typeof from == "object" || typeof from == "function")
7
- for (let key of __getOwnPropNames(from))
8
- !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
9
- return to;
10
- }, __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
11
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
12
- var index_exports = {};
13
- module.exports = __toCommonJS(index_exports);
14
- __reExport(index_exports, require("./router/index"), module.exports);
15
- __reExport(index_exports, require("./types"), module.exports);
16
- //# sourceMappingURL=index.js.map
@@ -1,6 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/index.ts"],
4
- "mappings": ";;;;;;;;;;;AAAA;AAAA;AAqBA,0BAAc,2BArBd;AAsBA,0BAAc,oBAtBd;",
5
- "names": []
6
- }
@@ -1,55 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all) __defProp(target, name, {
7
- get: all[name],
8
- enumerable: !0
9
- });
10
- },
11
- __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
13
- get: () => from[key],
14
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
- });
16
- return to;
17
- };
18
- var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
19
- value: !0
20
- }), mod);
21
- var emptyRouter_exports = {};
22
- __export(emptyRouter_exports, {
23
- Link: () => Link,
24
- useParams: () => useParams,
25
- usePathname: () => usePathname,
26
- useRouter: () => useRouter
27
- });
28
- module.exports = __toCommonJS(emptyRouter_exports);
29
- var import_jsx_runtime = require("react/jsx-runtime");
30
- const useRouter = () => ({
31
- back: () => {},
32
- canGoBack: () => !1,
33
- push: () => {},
34
- navigate: () => {},
35
- replace: () => {},
36
- dismiss: () => {},
37
- dismissAll: () => {},
38
- canDismiss: () => !1,
39
- setParams: () => {},
40
- subscribe: listener => (listener("success"), () => {}),
41
- onLoadState: listener => (listener("loaded"), () => {})
42
- }),
43
- usePathname = () => "/",
44
- useParams = () => ({}),
45
- Link = ({
46
- href,
47
- replace,
48
- children,
49
- ...props
50
- }) => /* @__PURE__ */(0, import_jsx_runtime.jsx)("a", {
51
- href,
52
- ...props,
53
- children
54
- });
55
- Link.resolveHref = href => href.toString();