@real-router/solid 0.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 (73) hide show
  1. package/README.md +313 -0
  2. package/dist/cjs/index.d.ts +103 -0
  3. package/dist/cjs/index.js +351 -0
  4. package/dist/esm/index.d.mts +103 -0
  5. package/dist/esm/index.mjs +334 -0
  6. package/dist/types/RouterProvider.d.ts +8 -0
  7. package/dist/types/RouterProvider.d.ts.map +1 -0
  8. package/dist/types/components/Link.d.ts +5 -0
  9. package/dist/types/components/Link.d.ts.map +1 -0
  10. package/dist/types/components/RouteView/RouteView.d.ts +13 -0
  11. package/dist/types/components/RouteView/RouteView.d.ts.map +1 -0
  12. package/dist/types/components/RouteView/components.d.ts +25 -0
  13. package/dist/types/components/RouteView/components.d.ts.map +1 -0
  14. package/dist/types/components/RouteView/helpers.d.ts +8 -0
  15. package/dist/types/components/RouteView/helpers.d.ts.map +1 -0
  16. package/dist/types/components/RouteView/index.d.ts +3 -0
  17. package/dist/types/components/RouteView/index.d.ts.map +1 -0
  18. package/dist/types/components/RouteView/types.d.ts +15 -0
  19. package/dist/types/components/RouteView/types.d.ts.map +1 -0
  20. package/dist/types/constants.d.ts +9 -0
  21. package/dist/types/constants.d.ts.map +1 -0
  22. package/dist/types/context.d.ts +11 -0
  23. package/dist/types/context.d.ts.map +1 -0
  24. package/dist/types/createSignalFromSource.d.ts +4 -0
  25. package/dist/types/createSignalFromSource.d.ts.map +1 -0
  26. package/dist/types/createStoreFromSource.d.ts +3 -0
  27. package/dist/types/createStoreFromSource.d.ts.map +1 -0
  28. package/dist/types/directives/link.d.ts +11 -0
  29. package/dist/types/directives/link.d.ts.map +1 -0
  30. package/dist/types/hooks/useNavigator.d.ts +3 -0
  31. package/dist/types/hooks/useNavigator.d.ts.map +1 -0
  32. package/dist/types/hooks/useRoute.d.ts +4 -0
  33. package/dist/types/hooks/useRoute.d.ts.map +1 -0
  34. package/dist/types/hooks/useRouteNode.d.ts +4 -0
  35. package/dist/types/hooks/useRouteNode.d.ts.map +1 -0
  36. package/dist/types/hooks/useRouteNodeStore.d.ts +3 -0
  37. package/dist/types/hooks/useRouteNodeStore.d.ts.map +1 -0
  38. package/dist/types/hooks/useRouteStore.d.ts +3 -0
  39. package/dist/types/hooks/useRouteStore.d.ts.map +1 -0
  40. package/dist/types/hooks/useRouteUtils.d.ts +3 -0
  41. package/dist/types/hooks/useRouteUtils.d.ts.map +1 -0
  42. package/dist/types/hooks/useRouter.d.ts +3 -0
  43. package/dist/types/hooks/useRouter.d.ts.map +1 -0
  44. package/dist/types/hooks/useRouterTransition.d.ts +4 -0
  45. package/dist/types/hooks/useRouterTransition.d.ts.map +1 -0
  46. package/dist/types/index.d.ts +21 -0
  47. package/dist/types/index.d.ts.map +1 -0
  48. package/dist/types/types.d.ts +17 -0
  49. package/dist/types/types.d.ts.map +1 -0
  50. package/package.json +89 -0
  51. package/src/RouterProvider.tsx +60 -0
  52. package/src/components/Link.tsx +91 -0
  53. package/src/components/RouteView/RouteView.tsx +53 -0
  54. package/src/components/RouteView/components.tsx +50 -0
  55. package/src/components/RouteView/helpers.tsx +108 -0
  56. package/src/components/RouteView/index.ts +7 -0
  57. package/src/components/RouteView/types.ts +17 -0
  58. package/src/constants.ts +9 -0
  59. package/src/context.ts +15 -0
  60. package/src/createSignalFromSource.ts +20 -0
  61. package/src/createStoreFromSource.ts +20 -0
  62. package/src/directives/link.tsx +79 -0
  63. package/src/directives.d.ts +10 -0
  64. package/src/hooks/useNavigator.tsx +15 -0
  65. package/src/hooks/useRoute.tsx +16 -0
  66. package/src/hooks/useRouteNode.tsx +14 -0
  67. package/src/hooks/useRouteNodeStore.tsx +12 -0
  68. package/src/hooks/useRouteStore.tsx +20 -0
  69. package/src/hooks/useRouteUtils.tsx +12 -0
  70. package/src/hooks/useRouter.tsx +15 -0
  71. package/src/hooks/useRouterTransition.tsx +14 -0
  72. package/src/index.tsx +43 -0
  73. package/src/types.ts +24 -0
@@ -0,0 +1,351 @@
1
+ 'use strict';
2
+
3
+ var web = require('solid-js/web');
4
+ var sources = require('@real-router/sources');
5
+ var solidJs = require('solid-js');
6
+ var api = require('@real-router/core/api');
7
+ var routeUtils = require('@real-router/route-utils');
8
+ var store = require('solid-js/store');
9
+ var core = require('@real-router/core');
10
+
11
+ const MATCH_MARKER = Symbol.for("RouteView.Match");
12
+ const NOT_FOUND_MARKER = Symbol.for("RouteView.NotFound");
13
+ function Match(props) {
14
+ const result = {
15
+ $$type: MATCH_MARKER,
16
+ segment: props.segment,
17
+ exact: props.exact ?? false,
18
+ fallback: props.fallback,
19
+ get children() {
20
+ return props.children;
21
+ }
22
+ };
23
+ return result;
24
+ }
25
+ Match.displayName = "RouteView.Match";
26
+ function NotFound(props) {
27
+ const result = {
28
+ $$type: NOT_FOUND_MARKER,
29
+ get children() {
30
+ return props.children;
31
+ }
32
+ };
33
+ return result;
34
+ }
35
+ NotFound.displayName = "RouteView.NotFound";
36
+
37
+ function isSegmentMatch(routeName, fullSegmentName, exact) {
38
+ if (exact) {
39
+ return routeName === fullSegmentName;
40
+ }
41
+ return routeUtils.startsWithSegment(routeName, fullSegmentName);
42
+ }
43
+ function isMatchMarker(value) {
44
+ return value != null && typeof value === "object" && "$$type" in value && value.$$type === MATCH_MARKER;
45
+ }
46
+ function isNotFoundMarker(value) {
47
+ return value != null && typeof value === "object" && "$$type" in value && value.$$type === NOT_FOUND_MARKER;
48
+ }
49
+ function collectElements(children, result) {
50
+ if (children == null) {
51
+ return;
52
+ }
53
+ if (Array.isArray(children)) {
54
+ for (const child of children) {
55
+ collectElements(child, result);
56
+ }
57
+ return;
58
+ }
59
+ if (isMatchMarker(children) || isNotFoundMarker(children)) {
60
+ result.push(children);
61
+ }
62
+ }
63
+ function buildRenderList(elements, routeName, nodeName) {
64
+ let notFoundChildren = null;
65
+ let activeMatchFound = false;
66
+ const rendered = [];
67
+ for (const child of elements) {
68
+ if (isNotFoundMarker(child)) {
69
+ notFoundChildren = child.children;
70
+ continue;
71
+ }
72
+ const {
73
+ segment,
74
+ exact,
75
+ fallback
76
+ } = child;
77
+ const fullSegmentName = nodeName ? `${nodeName}.${segment}` : segment;
78
+ const isActive = !activeMatchFound && isSegmentMatch(routeName, fullSegmentName, exact);
79
+ if (isActive) {
80
+ activeMatchFound = true;
81
+ const matchContent = child.children;
82
+ const content = fallback === undefined ? matchContent : web.createComponent(solidJs.Suspense, {
83
+ fallback: fallback,
84
+ children: matchContent
85
+ });
86
+ rendered.push(content);
87
+ }
88
+ }
89
+ if (!activeMatchFound && routeName === core.UNKNOWN_ROUTE && notFoundChildren !== null) {
90
+ rendered.push(notFoundChildren);
91
+ }
92
+ return {
93
+ rendered,
94
+ activeMatchFound
95
+ };
96
+ }
97
+
98
+ function createSignalFromSource(source) {
99
+ const [value, setValue] = solidJs.createSignal(source.getSnapshot());
100
+ const unsubscribe = source.subscribe(() => {
101
+ setValue(() => source.getSnapshot());
102
+ });
103
+ solidJs.onCleanup(() => {
104
+ unsubscribe();
105
+ });
106
+ return value;
107
+ }
108
+
109
+ const RouterContext = solidJs.createContext(null);
110
+ const RouteContext = solidJs.createContext(null);
111
+
112
+ const useRouter = () => {
113
+ const ctx = solidJs.useContext(RouterContext);
114
+ if (!ctx) {
115
+ throw new Error("useRouter must be used within a RouterProvider");
116
+ }
117
+ return ctx.router;
118
+ };
119
+
120
+ function useRouteNode(nodeName) {
121
+ const router = useRouter();
122
+ const store = sources.createRouteNodeSource(router, nodeName);
123
+ return createSignalFromSource(store);
124
+ }
125
+
126
+ function RouteViewRoot(props) {
127
+ const routeState = useRouteNode(props.nodeName);
128
+ const resolved = solidJs.children(() => props.children);
129
+ return web.memo(() => {
130
+ const state = routeState();
131
+ if (!state.route) {
132
+ return null;
133
+ }
134
+ const elements = [];
135
+ collectElements(resolved(), elements);
136
+ const {
137
+ rendered
138
+ } = buildRenderList(elements, state.route.name, props.nodeName);
139
+ if (rendered.length > 0) {
140
+ return rendered;
141
+ }
142
+ return null;
143
+ });
144
+ }
145
+ RouteViewRoot.displayName = "RouteView";
146
+ const RouteView = Object.assign(RouteViewRoot, {
147
+ Match,
148
+ NotFound
149
+ });
150
+
151
+ var t="data-real-router-announcer";function e(e,n){const r="Navigated to ";let o,u=true,c=false,a=false,s="";const l=function(){const e=document.querySelector(`[${t}]`);if(e)return e;const n=document.createElement("div");return n.setAttribute("style","position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0"),n.setAttribute("aria-live","assertive"),n.setAttribute("aria-atomic","true"),n.setAttribute(t,""),document.body.prepend(n),n}(),m=setTimeout(()=>{c=true;},100),d=e.subscribe(({route:t})=>{u?u=false:requestAnimationFrame(()=>{requestAnimationFrame(()=>{if(a)return;const e=function(t,e,n){const r=document.querySelector("h1"),i=r?.textContent.trim()??"",o=t.name.startsWith("@@")?"":t.name;return `${e}${i||document.title||o||globalThis.location.pathname}`}(t,r);e&&e!==s&&c&&(s=e,clearTimeout(o),l.textContent=e,o=setTimeout(()=>{l.textContent="",s="";},7e3),function(){const t=document.querySelector("h1");t&&(t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1"),t.focus({preventScroll:true}));}());});});});return {destroy(){a=true,d(),clearTimeout(o),clearTimeout(m),document.querySelector(`[${t}]`)?.remove();}}}function n(t){return !(0!==t.button||t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function r(t,e,n){const r=t.buildUrl;return r?r(e,n):t.buildPath(e,n)}function i(t,e,n){return t&&e?n?`${n} ${e}`.trim():e:n??void 0}function o(t){t instanceof HTMLAnchorElement||t instanceof HTMLButtonElement||(t.getAttribute("role")||t.setAttribute("role","link"),t.getAttribute("tabindex")||t.setAttribute("tabindex","0"));}
152
+
153
+ /**
154
+ * Stable empty object for default params
155
+ */
156
+ const EMPTY_PARAMS = Object.freeze({});
157
+
158
+ /**
159
+ * Stable empty options object
160
+ */
161
+ const EMPTY_OPTIONS = Object.freeze({});
162
+
163
+ var _tmpl$ = /*#__PURE__*/web.template(`<a>`);
164
+ function Link(props) {
165
+ const merged = solidJs.mergeProps({
166
+ routeParams: EMPTY_PARAMS,
167
+ routeOptions: EMPTY_OPTIONS,
168
+ activeClassName: "active",
169
+ activeStrict: false,
170
+ ignoreQueryParams: true
171
+ }, props);
172
+ const [local, rest] = solidJs.splitProps(merged, ["routeName", "routeParams", "routeOptions", "activeClassName", "activeStrict", "ignoreQueryParams", "onClick", "target", "class", "children"]);
173
+ const router = useRouter();
174
+ const ctx = solidJs.useContext(RouterContext);
175
+ const useFastPath = ctx?.routeSelector && !local.activeStrict && local.ignoreQueryParams && local.routeParams === EMPTY_PARAMS;
176
+ const isActive = useFastPath ? () => ctx.routeSelector(local.routeName) : createSignalFromSource(sources.createActiveRouteSource(router, local.routeName, local.routeParams, {
177
+ strict: local.activeStrict,
178
+ ignoreQueryParams: local.ignoreQueryParams
179
+ }));
180
+ const href = solidJs.createMemo(() => r(router, local.routeName, local.routeParams));
181
+ const handleClick = evt => {
182
+ if (local.onClick) {
183
+ local.onClick(evt);
184
+ if (evt.defaultPrevented) {
185
+ return;
186
+ }
187
+ }
188
+ if (!n(evt) || local.target === "_blank") {
189
+ return;
190
+ }
191
+ evt.preventDefault();
192
+ router.navigate(local.routeName, local.routeParams, local.routeOptions).catch(() => {});
193
+ };
194
+ const finalClassName = solidJs.createMemo(() => i(isActive(), local.activeClassName, local.class));
195
+ return (() => {
196
+ var _el$ = _tmpl$();
197
+ web.spread(_el$, web.mergeProps(rest, {
198
+ get href() {
199
+ return href();
200
+ },
201
+ get ["class"]() {
202
+ return finalClassName();
203
+ },
204
+ "onClick": handleClick
205
+ }), false, true);
206
+ web.insert(_el$, () => local.children);
207
+ return _el$;
208
+ })();
209
+ }
210
+
211
+ function link(element, accessor) {
212
+ const router = useRouter();
213
+ const options = accessor();
214
+
215
+ // Set href on <a> elements
216
+ if (element instanceof HTMLAnchorElement) {
217
+ element.href = router.buildPath(options.routeName, options.routeParams ?? EMPTY_PARAMS);
218
+ }
219
+ o(element);
220
+
221
+ // Active class tracking (reactive)
222
+ if (options.activeClassName) {
223
+ const activeClassName = options.activeClassName;
224
+ const activeSource = sources.createActiveRouteSource(router, options.routeName, options.routeParams ?? EMPTY_PARAMS, {
225
+ strict: options.activeStrict ?? false,
226
+ ignoreQueryParams: options.ignoreQueryParams ?? true
227
+ });
228
+ const isActive = createSignalFromSource(activeSource);
229
+ solidJs.createEffect(() => {
230
+ element.classList.toggle(activeClassName, isActive());
231
+ });
232
+ }
233
+
234
+ // Click handler
235
+ function handleClick(evt) {
236
+ if (!n(evt)) {
237
+ return;
238
+ }
239
+ if (element instanceof HTMLAnchorElement) {
240
+ evt.preventDefault();
241
+ }
242
+ router.navigate(options.routeName, options.routeParams ?? EMPTY_PARAMS, options.routeOptions ?? EMPTY_OPTIONS).catch(() => {});
243
+ }
244
+ element.addEventListener("click", handleClick);
245
+ solidJs.onCleanup(() => {
246
+ element.removeEventListener("click", handleClick);
247
+ });
248
+ }
249
+
250
+ const useNavigator = () => {
251
+ const ctx = solidJs.useContext(RouterContext);
252
+ if (!ctx) {
253
+ throw new Error("useNavigator must be used within a RouterProvider");
254
+ }
255
+ return ctx.navigator;
256
+ };
257
+
258
+ const useRouteUtils = () => {
259
+ const router = useRouter();
260
+ return routeUtils.getRouteUtils(api.getPluginApi(router).getTree());
261
+ };
262
+
263
+ const useRoute = () => {
264
+ const routeSignal = solidJs.useContext(RouteContext);
265
+ if (!routeSignal) {
266
+ throw new Error("useRoute must be used within a RouterProvider");
267
+ }
268
+ return routeSignal;
269
+ };
270
+
271
+ function createStoreFromSource(source) {
272
+ const [state, setState] = store.createStore(structuredClone(source.getSnapshot()));
273
+ const unsubscribe = source.subscribe(() => {
274
+ setState(store.reconcile(source.getSnapshot()));
275
+ });
276
+ solidJs.onCleanup(unsubscribe);
277
+ return state;
278
+ }
279
+
280
+ function useRouteStore() {
281
+ const ctx = solidJs.useContext(RouteContext);
282
+ if (!ctx) {
283
+ throw new Error("useRouteStore must be used within a RouterProvider");
284
+ }
285
+ const router = useRouter();
286
+ return createStoreFromSource(sources.createRouteSource(router));
287
+ }
288
+
289
+ function useRouteNodeStore(nodeName) {
290
+ const router = useRouter();
291
+ return createStoreFromSource(sources.createRouteNodeSource(router, nodeName));
292
+ }
293
+
294
+ function useRouterTransition() {
295
+ const router = useRouter();
296
+ const store = sources.createTransitionSource(router);
297
+ return createSignalFromSource(store);
298
+ }
299
+
300
+ function isRouteActive(linkRouteName, currentRouteName) {
301
+ return currentRouteName === linkRouteName || currentRouteName.startsWith(`${linkRouteName}.`);
302
+ }
303
+ function RouterProvider(props) {
304
+ solidJs.onMount(() => {
305
+ if (!props.announceNavigation) {
306
+ return;
307
+ }
308
+ const announcer = e(props.router);
309
+ solidJs.onCleanup(() => {
310
+ announcer.destroy();
311
+ });
312
+ });
313
+ const navigator = core.getNavigator(props.router);
314
+ const routeSource = sources.createRouteSource(props.router);
315
+ const routeSignal = createSignalFromSource(routeSource);
316
+ const routeSelector = solidJs.createSelector(() => routeSignal().route?.name ?? "", isRouteActive);
317
+ return web.createComponent(RouterContext.Provider, {
318
+ get value() {
319
+ return {
320
+ router: props.router,
321
+ navigator,
322
+ routeSelector
323
+ };
324
+ },
325
+ get children() {
326
+ return web.createComponent(RouteContext.Provider, {
327
+ value: routeSignal,
328
+ get children() {
329
+ return props.children;
330
+ }
331
+ });
332
+ }
333
+ });
334
+ }
335
+
336
+ exports.Link = Link;
337
+ exports.RouteContext = RouteContext;
338
+ exports.RouteView = RouteView;
339
+ exports.RouterContext = RouterContext;
340
+ exports.RouterProvider = RouterProvider;
341
+ exports.createSignalFromSource = createSignalFromSource;
342
+ exports.createStoreFromSource = createStoreFromSource;
343
+ exports.link = link;
344
+ exports.useNavigator = useNavigator;
345
+ exports.useRoute = useRoute;
346
+ exports.useRouteNode = useRouteNode;
347
+ exports.useRouteNodeStore = useRouteNodeStore;
348
+ exports.useRouteStore = useRouteStore;
349
+ exports.useRouteUtils = useRouteUtils;
350
+ exports.useRouter = useRouter;
351
+ exports.useRouterTransition = useRouterTransition;
@@ -0,0 +1,103 @@
1
+ import * as solid_js from 'solid-js';
2
+ import { JSX, Accessor, ParentProps } from 'solid-js';
3
+ import * as _real_router_core from '@real-router/core';
4
+ import { Params, NavigationOptions, State, Router, Navigator } from '@real-router/core';
5
+ export { Navigator } from '@real-router/core';
6
+ import { RouteUtils } from '@real-router/route-utils';
7
+ import { RouterTransitionSnapshot, RouterSource } from '@real-router/sources';
8
+ export { RouterTransitionSnapshot } from '@real-router/sources';
9
+
10
+ interface RouteViewProps {
11
+ readonly nodeName: string;
12
+ readonly children: JSX.Element;
13
+ }
14
+ interface MatchProps {
15
+ readonly segment: string;
16
+ readonly exact?: boolean;
17
+ readonly fallback?: JSX.Element;
18
+ readonly children: JSX.Element;
19
+ }
20
+ interface NotFoundProps {
21
+ readonly children: JSX.Element;
22
+ }
23
+
24
+ declare function Match(props: MatchProps): JSX.Element;
25
+ declare namespace Match {
26
+ var displayName: string;
27
+ }
28
+ declare function NotFound(props: NotFoundProps): JSX.Element;
29
+ declare namespace NotFound {
30
+ var displayName: string;
31
+ }
32
+
33
+ declare function RouteViewRoot(props: Readonly<RouteViewProps>): JSX.Element;
34
+ declare namespace RouteViewRoot {
35
+ var displayName: string;
36
+ }
37
+ declare const RouteView: typeof RouteViewRoot & {
38
+ Match: typeof Match;
39
+ NotFound: typeof NotFound;
40
+ };
41
+
42
+ interface RouteState<P extends Params = Params, MP extends Params = Params> {
43
+ route: State<P, MP> | undefined;
44
+ previousRoute?: State | undefined;
45
+ }
46
+ interface LinkProps<P extends Params = Params> extends Omit<JSX.HTMLAttributes<HTMLAnchorElement>, "onClick"> {
47
+ routeName: string;
48
+ routeParams?: P;
49
+ routeOptions?: NavigationOptions;
50
+ activeClassName?: string;
51
+ activeStrict?: boolean;
52
+ ignoreQueryParams?: boolean;
53
+ target?: string;
54
+ onClick?: (evt: MouseEvent) => void;
55
+ }
56
+
57
+ declare function Link<P extends Params = Params>(props: Readonly<LinkProps<P>>): JSX.Element;
58
+
59
+ interface LinkDirectiveOptions<P extends Params = Params> {
60
+ routeName: string;
61
+ routeParams?: P;
62
+ routeOptions?: Record<string, unknown>;
63
+ activeClassName?: string;
64
+ activeStrict?: boolean;
65
+ ignoreQueryParams?: boolean;
66
+ }
67
+ declare function link<P extends Params = Params>(element: HTMLElement, accessor: () => LinkDirectiveOptions<P>): void;
68
+
69
+ declare const useRouter: () => Router;
70
+
71
+ declare const useNavigator: () => Navigator;
72
+
73
+ declare const useRouteUtils: () => RouteUtils;
74
+
75
+ declare const useRoute: () => Accessor<RouteState>;
76
+
77
+ declare function useRouteNode(nodeName: string): Accessor<RouteState>;
78
+
79
+ declare function useRouteStore(): RouteState;
80
+
81
+ declare function useRouteNodeStore(nodeName: string): RouteState;
82
+
83
+ declare function useRouterTransition(): Accessor<RouterTransitionSnapshot>;
84
+
85
+ interface RouteProviderProps {
86
+ router: Router;
87
+ announceNavigation?: boolean;
88
+ }
89
+ declare function RouterProvider(props: ParentProps<RouteProviderProps>): JSX.Element;
90
+
91
+ interface RouterContextValue {
92
+ router: Router;
93
+ navigator: Navigator;
94
+ routeSelector: (routeName: string) => boolean;
95
+ }
96
+ declare const RouterContext: solid_js.Context<RouterContextValue | null>;
97
+ declare const RouteContext: solid_js.Context<Accessor<RouteState<_real_router_core.Params, _real_router_core.Params>> | null>;
98
+
99
+ declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>;
100
+
101
+ declare function createStoreFromSource<T extends object>(source: RouterSource<T>): T;
102
+
103
+ export { Link, type LinkDirectiveOptions, type LinkProps, RouteContext, type RouteState, RouteView, type MatchProps as RouteViewMatchProps, type NotFoundProps as RouteViewNotFoundProps, type RouteViewProps, RouterContext, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };