vorma 0.86.0-pre.2 → 0.86.0-pre.3

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 (104) hide show
  1. package/.dist/core/_index.d.ts +1 -0
  2. package/.dist/core/_index.d.ts.map +1 -1
  3. package/.dist/core/_index.js +6 -0
  4. package/.dist/core/_index.js.map +1 -1
  5. package/.dist/core/vorma_client_wasm_bg.wasm +0 -0
  6. package/.dist/ui/solid/solid.js +29 -39
  7. package/.dist/ui/solid/solid.js.map +1 -1
  8. package/core/client_wasm/vorma_client_wasm_bg.wasm +0 -0
  9. package/core/create_client_core.ts +9 -1
  10. package/package.json +1 -16
  11. package/ui/solid/solid.tsx +29 -10
  12. package/.dist/kit/lab/design/components/remix/remix.d.ts +0 -2309
  13. package/.dist/kit/lab/design/components/remix/remix.d.ts.map +0 -1
  14. package/.dist/kit/lab/design/components/remix/remix.js +0 -7022
  15. package/.dist/kit/lab/design/components/remix/remix.js.map +0 -1
  16. package/.dist/kit/lab/design/core/core.d.ts +0 -527
  17. package/.dist/kit/lab/design/core/core.d.ts.map +0 -1
  18. package/.dist/kit/lab/design/core/core.js +0 -668
  19. package/.dist/kit/lab/design/core/core.js.map +0 -1
  20. package/.dist/kit/matcher/matcher.d.ts +0 -78
  21. package/.dist/kit/matcher/matcher.d.ts.map +0 -1
  22. package/.dist/kit/matcher/matcher.js +0 -517
  23. package/.dist/kit/matcher/matcher.js.map +0 -1
  24. package/.dist/ui/remix/remix.d.ts +0 -73
  25. package/.dist/ui/remix/remix.d.ts.map +0 -1
  26. package/.dist/ui/remix/remix.js +0 -409
  27. package/.dist/ui/remix/remix.js.map +0 -1
  28. package/kit/lab/design/components/remix/accordion.ts +0 -474
  29. package/kit/lab/design/components/remix/alert-dialog.ts +0 -512
  30. package/kit/lab/design/components/remix/alert.ts +0 -213
  31. package/kit/lab/design/components/remix/aspect-ratio.ts +0 -111
  32. package/kit/lab/design/components/remix/badge.ts +0 -59
  33. package/kit/lab/design/components/remix/box.ts +0 -49
  34. package/kit/lab/design/components/remix/button.ts +0 -314
  35. package/kit/lab/design/components/remix/callout.ts +0 -127
  36. package/kit/lab/design/components/remix/checkable-state.ts +0 -187
  37. package/kit/lab/design/components/remix/checkbox-group.ts +0 -443
  38. package/kit/lab/design/components/remix/checkbox.ts +0 -215
  39. package/kit/lab/design/components/remix/chip.ts +0 -165
  40. package/kit/lab/design/components/remix/code-block.ts +0 -181
  41. package/kit/lab/design/components/remix/collapsible.ts +0 -325
  42. package/kit/lab/design/components/remix/component-state.ts +0 -55
  43. package/kit/lab/design/components/remix/component-style.ts +0 -364
  44. package/kit/lab/design/components/remix/composite-navigation.ts +0 -71
  45. package/kit/lab/design/components/remix/conditions.ts +0 -25
  46. package/kit/lab/design/components/remix/controllable-state.ts +0 -58
  47. package/kit/lab/design/components/remix/description-list.ts +0 -275
  48. package/kit/lab/design/components/remix/dialog.ts +0 -653
  49. package/kit/lab/design/components/remix/empty-state.ts +0 -146
  50. package/kit/lab/design/components/remix/field.ts +0 -418
  51. package/kit/lab/design/components/remix/fieldset.ts +0 -153
  52. package/kit/lab/design/components/remix/form-mirror.ts +0 -94
  53. package/kit/lab/design/components/remix/form-reset.ts +0 -85
  54. package/kit/lab/design/components/remix/form.ts +0 -109
  55. package/kit/lab/design/components/remix/grid.ts +0 -187
  56. package/kit/lab/design/components/remix/group-label.ts +0 -47
  57. package/kit/lab/design/components/remix/icon.ts +0 -176
  58. package/kit/lab/design/components/remix/input.ts +0 -163
  59. package/kit/lab/design/components/remix/kbd.ts +0 -58
  60. package/kit/lab/design/components/remix/list.ts +0 -120
  61. package/kit/lab/design/components/remix/listbox.ts +0 -1116
  62. package/kit/lab/design/components/remix/menu.ts +0 -1477
  63. package/kit/lab/design/components/remix/ordered-collection.ts +0 -95
  64. package/kit/lab/design/components/remix/popover-scroll-lock.ts +0 -89
  65. package/kit/lab/design/components/remix/popover.ts +0 -576
  66. package/kit/lab/design/components/remix/popup-behavior.ts +0 -96
  67. package/kit/lab/design/components/remix/progress.ts +0 -185
  68. package/kit/lab/design/components/remix/radio-group.ts +0 -420
  69. package/kit/lab/design/components/remix/recipe.ts +0 -70
  70. package/kit/lab/design/components/remix/remix.ts +0 -683
  71. package/kit/lab/design/components/remix/responsive.ts +0 -106
  72. package/kit/lab/design/components/remix/root.ts +0 -137
  73. package/kit/lab/design/components/remix/select.ts +0 -1546
  74. package/kit/lab/design/components/remix/separator.ts +0 -108
  75. package/kit/lab/design/components/remix/slider.ts +0 -308
  76. package/kit/lab/design/components/remix/spinner.ts +0 -114
  77. package/kit/lab/design/components/remix/stack.ts +0 -205
  78. package/kit/lab/design/components/remix/stat.ts +0 -127
  79. package/kit/lab/design/components/remix/surface.ts +0 -71
  80. package/kit/lab/design/components/remix/switch.ts +0 -219
  81. package/kit/lab/design/components/remix/table.ts +0 -395
  82. package/kit/lab/design/components/remix/tabs.ts +0 -404
  83. package/kit/lab/design/components/remix/text.ts +0 -169
  84. package/kit/lab/design/components/remix/textarea.ts +0 -164
  85. package/kit/lab/design/components/remix/toast.ts +0 -299
  86. package/kit/lab/design/components/remix/tooltip.ts +0 -330
  87. package/kit/lab/design/components/remix/typeahead.ts +0 -81
  88. package/kit/lab/design/components/remix/types.ts +0 -19
  89. package/kit/lab/design/components/remix/visually-hidden.ts +0 -100
  90. package/kit/lab/design/core/color.ts +0 -46
  91. package/kit/lab/design/core/core.ts +0 -111
  92. package/kit/lab/design/core/create_primitive.ts +0 -455
  93. package/kit/lab/design/core/create_system.ts +0 -303
  94. package/kit/lab/design/core/css.ts +0 -127
  95. package/kit/lab/design/core/define_system.ts +0 -508
  96. package/kit/lab/design/core/math.ts +0 -12
  97. package/kit/lab/design/core/object.ts +0 -31
  98. package/kit/lab/design/core/recipe/create_recipe.ts +0 -185
  99. package/kit/lab/design/core/recipe/recipe.ts +0 -26
  100. package/kit/lab/design/core/recipe/style.ts +0 -62
  101. package/kit/lab/design/core/recipe/types.ts +0 -160
  102. package/kit/lab/design/core/resolve_token.ts +0 -118
  103. package/kit/lab/design/core/types.ts +0 -636
  104. package/ui/remix/remix.tsx +0 -901
@@ -1,901 +0,0 @@
1
- /// <reference types="vite/client" />
2
-
3
- import { createElement, on, type Handle, type Props, type RemixNode } from "remix/ui";
4
- import {
5
- apply_scroll,
6
- create_adapter_base,
7
- get_entry_key,
8
- make_entry_id,
9
- make_link_props,
10
- resolve_outlet_slot,
11
- select_link_route_state,
12
- select_link_work_state,
13
- type AdapterClientOptions,
14
- type AppConfig,
15
- type DecomposedCommit,
16
- type DecomposedState,
17
- type LinkPropsResult,
18
- type RouteState,
19
- type ScrollIntent,
20
- type ToApiDecorator,
21
- type ToDefineViewArgs,
22
- type ToLinkProps,
23
- type ToRouteSyncArgs,
24
- type ToViewComponentProps,
25
- type ToViewOutput,
26
- type ToViewPattern,
27
- type ViewDefinition,
28
- type VormaClient,
29
- type WorkState,
30
- } from "vorma/__internal";
31
- import { jsonDeepEquals } from "vorma/kit/json";
32
- import type { LinkPropsBase } from "../../core/types.ts";
33
-
34
- export { MutationError, QueryError } from "vorma/__internal";
35
- export type {
36
- BeforeRouteCommitFn,
37
- BeforeRouteTransitionArgs,
38
- BeforeRouteYieldFn,
39
- BuildSkewDetectedEvent,
40
- MutationResult,
41
- QueryResult,
42
- RevalidationReason,
43
- RevalidationResult,
44
- RouteErrorState,
45
- RouteState,
46
- RouteUpdateReason,
47
- ToApiClient,
48
- ToApiDecorator,
49
- ToApiDecoratorContext,
50
- ToClientLoaderArgs,
51
- ToLinkProps,
52
- ToMutationArgs,
53
- ToMutationError,
54
- ToMutationInput,
55
- ToMutationMethod,
56
- ToMutationOutput,
57
- ToMutationPattern,
58
- ToNavigateArgs,
59
- ToNavigationTarget,
60
- ToQueryArgs,
61
- ToQueryError,
62
- ToQueryInput,
63
- ToQueryMethod,
64
- ToQueryOutput,
65
- ToQueryPattern,
66
- ToRouteDestination,
67
- ToRouteSyncArgs,
68
- ToViewComponentProps,
69
- ToViewInput,
70
- ToViewOutput,
71
- ToViewPattern,
72
- AppConfig as VormaClientSeed,
73
- WorkIndicator,
74
- WorkIndicatorOptions,
75
- WorkState,
76
- } from "vorma/__internal";
77
-
78
- const CLICK_EVENT = "click";
79
- const POINTER_DOWN_EVENT = "pointerdown";
80
- const POINTER_ENTER_EVENT = "pointerenter";
81
- const FOCUS_EVENT = "focus";
82
- const POINTER_LEAVE_EVENT = "pointerleave";
83
- const BLUR_EVENT = "blur";
84
- const TOUCH_CANCEL_EVENT = "touchcancel";
85
- const route_state_subscription_key = "route-state";
86
- const work_state_subscription_key = "work-state";
87
- const route_sync_route_subscription_key = "route-sync-route";
88
- const route_sync_work_subscription_key = "route-sync-work";
89
-
90
- type RootOutletProps = { idx?: number } & Record<string, unknown>;
91
-
92
- export type RemixComponent<P extends object = Record<string, unknown>> = (
93
- handle: Handle<P>,
94
- ) => (props: P) => RemixNode;
95
-
96
- type RemixHybridComponent<P extends object> = RemixComponent<P> &
97
- ((props?: P) => RemixNode);
98
-
99
- type RemixAnchorProps = Props<"a">;
100
-
101
- type RemixLinkProps<A extends AppConfig, P extends ToViewPattern<A>> = Omit<
102
- RemixAnchorProps,
103
- "href"
104
- > &
105
- ToLinkProps<A, P>;
106
-
107
- type RemixLink<A extends AppConfig> = {
108
- <P extends ToViewPattern<A>>(props: RemixLinkProps<A, P>): RemixNode;
109
- (
110
- handle: Handle<RemixLinkProps<A, ToViewPattern<A>>>,
111
- ): <P extends ToViewPattern<A>>(props: RemixLinkProps<A, P>) => RemixNode;
112
- };
113
-
114
- type RemixDefineViewArgs<A extends AppConfig, P extends ToViewPattern<A>, T> = Omit<
115
- ToDefineViewArgs<A, P, T, RemixNode>,
116
- "component" | "errorBoundary"
117
- > & {
118
- component: RemixViewComponent<A, P, T>;
119
- errorBoundary?: RemixErrorBoundaryComponent<A>;
120
- };
121
-
122
- type RemixStateSelector<TState, TSelected> = (state: TState) => TSelected;
123
-
124
- export type RemixViewScope<A extends AppConfig> = {
125
- routeState: {
126
- (): RouteState;
127
- <T>(selector: (state: RouteState) => T): T;
128
- };
129
- workState: {
130
- (): WorkState;
131
- <T>(selector: (state: WorkState) => T): T;
132
- };
133
- routeSync: <P extends ToViewPattern<A>>(args: ToRouteSyncArgs<A, P>) => void;
134
- viewData: <P extends ToViewPattern<A>, T = any>(
135
- props: ToViewComponentProps<A, P, T>,
136
- ) => ToViewOutput<A, P>;
137
- patternViewData: <P extends ToViewPattern<A>>(
138
- pattern: P,
139
- ) => ToViewOutput<A, P> | undefined;
140
- clientLoaderData: <P extends ToViewPattern<A>, T>(
141
- props: ToViewComponentProps<A, P, T>,
142
- ) => T;
143
- patternClientLoaderData: <T>(pattern: ToViewPattern<A>) => T | undefined;
144
- };
145
-
146
- export type RemixViewComponent<
147
- A extends AppConfig,
148
- P extends ToViewPattern<A>,
149
- T = any,
150
- > = (
151
- handle: Handle<ToViewComponentProps<A, P, T>>,
152
- v: RemixViewScope<A>,
153
- ) => (props: ToViewComponentProps<A, P, T>) => RemixNode;
154
-
155
- type RemixErrorBoundaryComponent<A extends AppConfig> = (
156
- handle: Handle<{ error: unknown }>,
157
- v: RemixViewScope<A>,
158
- ) => (props: { error: unknown }) => RemixNode;
159
-
160
- export type RemixVormaClient<A extends AppConfig> = Omit<
161
- VormaClient<A, RemixNode, RemixAnchorProps, "value">,
162
- | "RootOutlet"
163
- | "Link"
164
- | "defineView"
165
- | "useRouteState"
166
- | "useRouteSync"
167
- | "useWorkState"
168
- | "useViewData"
169
- | "usePatternViewData"
170
- | "useClientLoaderData"
171
- | "usePatternClientLoaderData"
172
- > & {
173
- RootOutlet: RemixHybridComponent<RootOutletProps>;
174
- Link: RemixLink<A>;
175
- defineView: <P extends ToViewPattern<A>, T = any>(
176
- input: RemixDefineViewArgs<A, P, T>,
177
- ) => ViewDefinition;
178
- };
179
-
180
- type StateSubscription<TState, TSelected> = {
181
- selected: TSelected;
182
- selector: RemixStateSelector<TState, TSelected>;
183
- };
184
-
185
- type StateSubscriptions<TState> = Map<string, StateSubscription<TState, unknown>>;
186
-
187
- type StateSubscriptionMap<TState> = Map<Handle<any>, StateSubscriptions<TState>>;
188
-
189
- type RouteSyncState = {
190
- pending_href?: string;
191
- timeout_id?: number;
192
- };
193
-
194
- type CreateVormaClientOptions<A extends AppConfig> = AdapterClientOptions<
195
- RemixHybridComponent<RootOutletProps>
196
- > & {
197
- linkDefaultProps?: Partial<Omit<RemixAnchorProps & LinkPropsBase, "href">>;
198
- apiDecorator?: ToApiDecorator<A>;
199
- };
200
-
201
- export function createVormaClient<A extends AppConfig>(
202
- app_config: A,
203
- options?: CreateVormaClientOptions<A>,
204
- ): RemixVormaClient<A> {
205
- let store: DecomposedState = {
206
- entries: [],
207
- error: null,
208
- views_data: [],
209
- client_loaders_data: [],
210
- matched_patterns: [],
211
- import_urls: [],
212
- entry_keys: [],
213
- params: {},
214
- splat_values: [],
215
- client_build_id: "",
216
- history_state: undefined,
217
- };
218
- let route_store: RouteState | null = null;
219
- let work_store: WorkState = {
220
- navigation: null,
221
- revalidation: null,
222
- prefetch: null,
223
- apiRequests: [],
224
- };
225
- const route_render_handles = new Set<Handle<any>>();
226
- const link_handles = new Set<Handle<any>>();
227
- const route_state_subscriptions: StateSubscriptionMap<RouteState> = new Map();
228
- const work_state_subscriptions: StateSubscriptionMap<WorkState> = new Map();
229
- const route_sync_states = new Map<Handle<any>, RouteSyncState>();
230
-
231
- let pending_scroll_intent: ScrollIntent | undefined;
232
-
233
- const adapter_base_res = create_adapter_base(
234
- app_config,
235
- (adapter_commit: DecomposedCommit) => {
236
- const previous_link_work_state = select_link_work_state(work_store);
237
- let should_notify_route_render = false;
238
- let should_notify_route = false;
239
- let should_notify_work = false;
240
- let should_notify_links = false;
241
- if (adapter_commit.scroll_intent) {
242
- pending_scroll_intent = adapter_commit.scroll_intent;
243
- }
244
- if (adapter_commit.state) {
245
- store = adapter_commit.state;
246
- should_notify_route_render = true;
247
- }
248
- if (adapter_commit.route) {
249
- route_store = adapter_commit.route;
250
- should_notify_route = true;
251
- should_notify_links = true;
252
- }
253
- if (adapter_commit.link_state_version !== undefined) {
254
- should_notify_links = true;
255
- }
256
- if (adapter_commit.work) {
257
- work_store = adapter_commit.work;
258
- should_notify_work = true;
259
- }
260
- const next_link_work_state = select_link_work_state(work_store);
261
- if (!jsonDeepEquals(previous_link_work_state, next_link_work_state)) {
262
- should_notify_links = true;
263
- }
264
- if (should_notify_route_render) {
265
- notify_handle_set(route_render_handles);
266
- }
267
- if (should_notify_route && route_store) {
268
- notify_state_subscriptions(route_state_subscriptions, route_store);
269
- }
270
- if (should_notify_work) {
271
- notify_state_subscriptions(work_state_subscriptions, work_store);
272
- }
273
- if (should_notify_links) {
274
- notify_handle_set(link_handles);
275
- }
276
- },
277
- options?.apiDecorator,
278
- );
279
- if (!adapter_base_res.ok) {
280
- throw new Error(`Failed to create Vorma client: ${adapter_base_res.err}`);
281
- }
282
-
283
- const { core, nav_fns, passthrough } = adapter_base_res.val;
284
-
285
- function default_selector<TState>(state: TState): TState {
286
- return state;
287
- }
288
-
289
- function track_handle_set(handles: Set<Handle<any>>, handle: Handle<any>): void {
290
- if (handles.has(handle)) {
291
- return;
292
- }
293
- handles.add(handle);
294
- handle.signal.addEventListener(
295
- "abort",
296
- () => {
297
- handles.delete(handle);
298
- },
299
- { once: true },
300
- );
301
- }
302
-
303
- function track_handle_map<TValue>(
304
- handles: Map<Handle<any>, TValue>,
305
- handle: Handle<any>,
306
- ): void {
307
- if (handles.has(handle)) {
308
- return;
309
- }
310
- handle.signal.addEventListener(
311
- "abort",
312
- () => {
313
- handles.delete(handle);
314
- },
315
- { once: true },
316
- );
317
- }
318
-
319
- function notify_handle_set(handles: Set<Handle<any>>): void {
320
- handles.forEach((handle) => {
321
- void handle.update();
322
- });
323
- }
324
-
325
- function track_state_subscription<TState, TSelected>(
326
- subscriptions: StateSubscriptionMap<TState>,
327
- subscription_key: string,
328
- handle: Handle<any>,
329
- state: TState,
330
- selector?: RemixStateSelector<TState, TSelected>,
331
- ): TSelected {
332
- track_handle_map(subscriptions, handle);
333
- const state_selector =
334
- selector ?? (default_selector as RemixStateSelector<TState, TSelected>);
335
- const selected = state_selector(state);
336
- let handle_subscriptions = subscriptions.get(handle);
337
- if (!handle_subscriptions) {
338
- handle_subscriptions = new Map();
339
- subscriptions.set(handle, handle_subscriptions);
340
- }
341
- handle_subscriptions.set(subscription_key, {
342
- selected,
343
- selector: state_selector as RemixStateSelector<TState, unknown>,
344
- });
345
- return selected;
346
- }
347
-
348
- function notify_state_subscriptions<TState>(
349
- subscriptions: StateSubscriptionMap<TState>,
350
- state: TState,
351
- ): void {
352
- subscriptions.forEach((handle_subscriptions, handle) => {
353
- let should_update = false;
354
- handle_subscriptions.forEach((subscription) => {
355
- const selected = subscription.selector(state);
356
- if (jsonDeepEquals(subscription.selected, selected)) {
357
- return;
358
- }
359
- subscription.selected = selected;
360
- should_update = true;
361
- });
362
- if (should_update) {
363
- void handle.update();
364
- }
365
- });
366
- }
367
-
368
- function clear_route_sync_state(state: RouteSyncState): void {
369
- if (state.timeout_id !== undefined) {
370
- window.clearTimeout(state.timeout_id);
371
- }
372
- state.timeout_id = undefined;
373
- state.pending_href = undefined;
374
- }
375
-
376
- function get_route_sync_state(handle: Handle<any>): RouteSyncState {
377
- const existing = route_sync_states.get(handle);
378
- if (existing) {
379
- return existing;
380
- }
381
-
382
- const state: RouteSyncState = {};
383
- route_sync_states.set(handle, state);
384
- handle.signal.addEventListener(
385
- "abort",
386
- () => {
387
- clear_route_sync_state(state);
388
- route_sync_states.delete(handle);
389
- },
390
- { once: true },
391
- );
392
- return state;
393
- }
394
-
395
- function is_remix_handle<P extends object>(
396
- value: Handle<P> | P | undefined,
397
- ): value is Handle<P> {
398
- return (
399
- !!value &&
400
- typeof value === "object" &&
401
- "props" in value &&
402
- "signal" in value &&
403
- "update" in value
404
- );
405
- }
406
-
407
- function make_hybrid_component<P extends object>(
408
- component: RemixComponent<P>,
409
- ): RemixHybridComponent<P> {
410
- return ((input?: Handle<P> | P) => {
411
- if (is_remix_handle(input)) {
412
- return component(input);
413
- }
414
- return create_remix_element(component, (input ?? {}) as P);
415
- }) as RemixHybridComponent<P>;
416
- }
417
-
418
- function create_remix_element<P extends object>(
419
- type: RemixComponent<P>,
420
- props: P,
421
- ): RemixNode {
422
- const next_props = { ...props } as P & { children?: RemixNode };
423
- const children = next_props.children;
424
- delete next_props.children;
425
- if (children === undefined) {
426
- return createElement(type, next_props);
427
- }
428
- const child_nodes = Array.isArray(children) ? children : [children];
429
- return createElement(type, next_props, ...child_nodes);
430
- }
431
-
432
- function get_route_snapshot(): RouteState {
433
- if (!route_store) {
434
- throw new Error("Vorma not booted");
435
- }
436
- return route_store;
437
- }
438
-
439
- function get_work_snapshot(): WorkState {
440
- return work_store;
441
- }
442
-
443
- function route_state(handle: Handle<any>): RouteState;
444
- function route_state<T>(handle: Handle<any>, selector: (route: RouteState) => T): T;
445
- function route_state<T>(
446
- handle: Handle<any>,
447
- selector?: (route: RouteState) => T,
448
- ): RouteState | T {
449
- const route = get_route_snapshot();
450
- return track_state_subscription(
451
- route_state_subscriptions,
452
- route_state_subscription_key,
453
- handle,
454
- route,
455
- selector,
456
- );
457
- }
458
-
459
- function work_state(handle: Handle<any>): WorkState;
460
- function work_state<T>(handle: Handle<any>, selector: (work: WorkState) => T): T;
461
- function work_state<T>(
462
- handle: Handle<any>,
463
- selector?: (work: WorkState) => T,
464
- ): WorkState | T {
465
- const work = get_work_snapshot();
466
- return track_state_subscription(
467
- work_state_subscriptions,
468
- work_state_subscription_key,
469
- handle,
470
- work,
471
- selector,
472
- );
473
- }
474
-
475
- function route_sync<P extends ToViewPattern<A>>(
476
- handle: Handle<any>,
477
- args: ToRouteSyncArgs<A, P>,
478
- ): void;
479
- function route_sync<P extends ToViewPattern<A>>(
480
- handle: Handle<any>,
481
- args: ToRouteSyncArgs<A, P>,
482
- ): void {
483
- const route_sync_state = get_route_sync_state(handle);
484
-
485
- track_state_subscription(
486
- route_state_subscriptions,
487
- route_sync_route_subscription_key,
488
- handle,
489
- get_route_snapshot(),
490
- (route) => {
491
- return route.href;
492
- },
493
- );
494
- track_state_subscription(
495
- work_state_subscriptions,
496
- route_sync_work_subscription_key,
497
- handle,
498
- work_store,
499
- (work) => {
500
- return work.navigation?.href ?? null;
501
- },
502
- );
503
-
504
- const {
505
- debounceMs = 0,
506
- enabled = true,
507
- replace = true,
508
- scrollToTop = false,
509
- ...target
510
- } = args;
511
- if (!enabled) {
512
- clear_route_sync_state(route_sync_state);
513
- return;
514
- }
515
-
516
- const canonical_href = passthrough.toHref(target as any);
517
- const route_href = route_store?.href;
518
- const pending_href = work_store.navigation?.href;
519
- if (canonical_href === route_href || canonical_href === pending_href) {
520
- clear_route_sync_state(route_sync_state);
521
- return;
522
- }
523
- if (canonical_href === route_sync_state.pending_href) {
524
- return;
525
- }
526
-
527
- clear_route_sync_state(route_sync_state);
528
- route_sync_state.pending_href = canonical_href;
529
- route_sync_state.timeout_id = window.setTimeout(() => {
530
- route_sync_state.timeout_id = undefined;
531
- route_sync_state.pending_href = undefined;
532
- if (
533
- canonical_href === route_store?.href ||
534
- canonical_href === work_store.navigation?.href
535
- ) {
536
- return;
537
- }
538
- void passthrough.navigate({
539
- href: canonical_href,
540
- replace,
541
- scrollToTop,
542
- });
543
- }, debounceMs);
544
- }
545
-
546
- function view_data<P extends ToViewPattern<A>, T = any>(
547
- args: ToViewComponentProps<A, P, T>,
548
- ): ToViewOutput<A, P> {
549
- return store.views_data[args.idx] as ToViewOutput<A, P>;
550
- }
551
-
552
- function pattern_view_data<P extends ToViewPattern<A>>(
553
- pattern: P,
554
- ): ToViewOutput<A, P> | undefined {
555
- const idx = store.matched_patterns.indexOf(pattern);
556
- if (idx < 0) {
557
- return undefined;
558
- }
559
- return store.views_data[idx] as ToViewOutput<A, P>;
560
- }
561
-
562
- function client_loader_data<P extends ToViewPattern<A>, T>(
563
- args: ToViewComponentProps<A, P, T>,
564
- ): T {
565
- return store.client_loaders_data[args.idx] as T;
566
- }
567
-
568
- function pattern_client_loader_data<T>(pattern: ToViewPattern<A>): T | undefined {
569
- const idx = store.matched_patterns.indexOf(pattern);
570
- if (idx < 0) {
571
- return undefined;
572
- }
573
- return store.client_loaders_data[idx] as T;
574
- }
575
-
576
- function create_view_scope(handle: Handle<any>): RemixViewScope<A> {
577
- const route_state_fn = (<T,>(
578
- selector?: RemixStateSelector<RouteState, T>,
579
- ): RouteState | T => {
580
- if (selector) {
581
- return route_state(handle, selector);
582
- }
583
- return route_state(handle);
584
- }) as RemixViewScope<A>["routeState"];
585
- const work_state_fn = (<T,>(
586
- selector?: RemixStateSelector<WorkState, T>,
587
- ): WorkState | T => {
588
- if (selector) {
589
- return work_state(handle, selector);
590
- }
591
- return work_state(handle);
592
- }) as RemixViewScope<A>["workState"];
593
-
594
- return {
595
- routeState: route_state_fn,
596
- workState: work_state_fn,
597
- routeSync: <P extends ToViewPattern<A>>(
598
- args: ToRouteSyncArgs<A, P>,
599
- ): void => {
600
- return route_sync(handle, args);
601
- },
602
- viewData: <P extends ToViewPattern<A>, T = any>(
603
- props: ToViewComponentProps<A, P, T>,
604
- ): ToViewOutput<A, P> => {
605
- return view_data(props);
606
- },
607
- patternViewData: <P extends ToViewPattern<A>>(
608
- pattern: P,
609
- ): ToViewOutput<A, P> | undefined => {
610
- return pattern_view_data(pattern);
611
- },
612
- clientLoaderData: <P extends ToViewPattern<A>, T>(
613
- props: ToViewComponentProps<A, P, T>,
614
- ): T => {
615
- return client_loader_data(props);
616
- },
617
- patternClientLoaderData: <T,>(pattern: ToViewPattern<A>): T | undefined => {
618
- return pattern_client_loader_data(pattern);
619
- },
620
- };
621
- }
622
-
623
- function defineView<P extends ToViewPattern<A>, T = any>(
624
- input: RemixDefineViewArgs<A, P, T>,
625
- ): ViewDefinition {
626
- const { component, errorBoundary, ...core_input } = input;
627
- const remix_component: RemixComponent<ToViewComponentProps<A, P, T>> = (
628
- handle,
629
- ) => {
630
- return component(handle, create_view_scope(handle));
631
- };
632
- const remix_error_boundary:
633
- | RemixComponent<{
634
- error: unknown;
635
- }>
636
- | undefined = errorBoundary
637
- ? (handle) => {
638
- return errorBoundary(handle, create_view_scope(handle));
639
- }
640
- : undefined;
641
- return core.defineView({
642
- ...core_input,
643
- component: (props: ToViewComponentProps<A, P, T>) => {
644
- return create_remix_element(remix_component, props);
645
- },
646
- errorBoundary: remix_error_boundary
647
- ? (props: { error: unknown }) => {
648
- return create_remix_element(remix_error_boundary, props);
649
- }
650
- : undefined,
651
- });
652
- }
653
-
654
- function root_outlet_component(
655
- handle: Handle<RootOutletProps>,
656
- ): (props: RootOutletProps) => RemixNode {
657
- track_handle_set(route_render_handles, handle);
658
- return (props: RootOutletProps) => {
659
- return render_root_outlet(handle, props);
660
- };
661
- }
662
-
663
- function render_root_outlet(
664
- handle: Handle<RootOutletProps>,
665
- props: RootOutletProps,
666
- ): RemixNode {
667
- const idx = props.idx ?? 0;
668
-
669
- if (pending_scroll_intent) {
670
- const entry = store.entries[idx];
671
- if (
672
- entry &&
673
- make_entry_id(idx, entry.pattern) ===
674
- pending_scroll_intent.target_entry_id
675
- ) {
676
- const scroll = pending_scroll_intent.scroll;
677
- pending_scroll_intent = undefined;
678
- handle.queueTask((signal: AbortSignal) => {
679
- if (signal.aborted) {
680
- return;
681
- }
682
- apply_scroll(scroll);
683
- });
684
- }
685
- }
686
-
687
- const Outlet = make_outlet(props, idx);
688
- const slot = resolve_outlet_slot(
689
- store.entries,
690
- store.error,
691
- idx,
692
- core.get_default_error_boundary(),
693
- );
694
-
695
- switch (slot.kind) {
696
- case "empty":
697
- return null;
698
- case "pass_through": {
699
- const key =
700
- idx + 1 < store.entries.length
701
- ? get_entry_key(store.entries[idx + 1]!)
702
- : `__empty_${idx + 1}`;
703
- return create_remix_element(Outlet, { key });
704
- }
705
- case "error": {
706
- const key = `__error_${idx}`;
707
- const boundary = slot.boundary;
708
- return boundary({ key, error: slot.error } as any);
709
- }
710
- case "component": {
711
- const key = get_entry_key(store.entries[idx]!);
712
- const component = slot.component;
713
- return component({ key, idx, Outlet });
714
- }
715
- }
716
- }
717
-
718
- const RootOutlet = make_hybrid_component(root_outlet_component);
719
- const RootOutletApp = RootOutlet;
720
-
721
- function make_outlet(
722
- parent_props: RootOutletProps,
723
- idx: number,
724
- ): RemixHybridComponent<Record<string, unknown>> {
725
- return make_hybrid_component((handle) => {
726
- track_handle_set(route_render_handles, handle);
727
- return (local?: Record<string, unknown>) => {
728
- const local_props = local ?? {};
729
- return create_remix_element(RootOutlet, {
730
- ...parent_props,
731
- ...local_props,
732
- idx: idx + 1,
733
- });
734
- };
735
- });
736
- }
737
-
738
- function boot(): ReturnType<typeof core.boot> {
739
- const {
740
- render: render_root,
741
- linkDefaultProps: _link_default_props,
742
- apiDecorator: _api_decorator,
743
- ...core_options
744
- } = options ?? {};
745
- return core.boot({
746
- ...core_options,
747
- render: render_root
748
- ? () => {
749
- return render_root({
750
- RootOutlet: RootOutletApp,
751
- rootEl: core.getRootEl(),
752
- });
753
- }
754
- : undefined,
755
- });
756
- }
757
-
758
- function with_link_mixins(
759
- anchor_props: RemixAnchorProps,
760
- result: LinkPropsResult,
761
- ): RemixAnchorProps {
762
- const mixins: unknown[] = [];
763
- if (anchor_props.mix !== undefined) {
764
- mixins.push(anchor_props.mix);
765
- }
766
- if (result.onClick) {
767
- mixins.push(
768
- on<HTMLAnchorElement, typeof CLICK_EVENT>(CLICK_EVENT, (event) => {
769
- return result.onClick?.(event);
770
- }),
771
- );
772
- }
773
- if (result.onPointerDown) {
774
- mixins.push(
775
- on<HTMLAnchorElement, typeof POINTER_DOWN_EVENT>(
776
- POINTER_DOWN_EVENT,
777
- (event) => {
778
- return result.onPointerDown?.(event);
779
- },
780
- ),
781
- );
782
- }
783
- if (result.onPointerEnter) {
784
- mixins.push(
785
- on<HTMLAnchorElement, typeof POINTER_ENTER_EVENT>(
786
- POINTER_ENTER_EVENT,
787
- (event) => {
788
- return result.onPointerEnter?.(event);
789
- },
790
- ),
791
- );
792
- }
793
- if (result.onFocus) {
794
- mixins.push(
795
- on<HTMLAnchorElement, typeof FOCUS_EVENT>(FOCUS_EVENT, (event) => {
796
- return result.onFocus?.(event);
797
- }),
798
- );
799
- }
800
- if (result.onPointerLeave) {
801
- mixins.push(
802
- on<HTMLAnchorElement, typeof POINTER_LEAVE_EVENT>(
803
- POINTER_LEAVE_EVENT,
804
- (event) => {
805
- return result.onPointerLeave?.(event);
806
- },
807
- ),
808
- );
809
- }
810
- if (result.onBlur) {
811
- mixins.push(
812
- on<HTMLAnchorElement, typeof BLUR_EVENT>(BLUR_EVENT, (event) => {
813
- return result.onBlur?.(event);
814
- }),
815
- );
816
- }
817
- if (result.onTouchCancel) {
818
- mixins.push(
819
- on<HTMLAnchorElement, typeof TOUCH_CANCEL_EVENT>(
820
- TOUCH_CANCEL_EVENT,
821
- (event) => {
822
- return result.onTouchCancel?.(event);
823
- },
824
- ),
825
- );
826
- }
827
-
828
- if (mixins.length === 0) {
829
- return anchor_props;
830
- }
831
- return {
832
- ...anchor_props,
833
- mix: mixins as RemixAnchorProps["mix"],
834
- };
835
- }
836
-
837
- type BaseLinkProps = RemixAnchorProps & LinkPropsBase & { pattern?: string };
838
-
839
- const BaseLink = make_hybrid_component<BaseLinkProps>((handle) => {
840
- track_handle_set(link_handles, handle);
841
- return (props: BaseLinkProps) => {
842
- const route_state = route_store ? select_link_route_state(route_store) : null;
843
- const work_state = select_link_work_state(work_store);
844
- const result = make_link_props(
845
- props as Record<string, unknown>,
846
- nav_fns,
847
- route_state,
848
- work_state,
849
- );
850
- const anchor_props = with_link_mixins(
851
- result.anchor_props as RemixAnchorProps,
852
- result,
853
- );
854
- return (
855
- <a data-external={result.is_external || undefined} {...anchor_props}>
856
- {props.children}
857
- </a>
858
- );
859
- };
860
- });
861
-
862
- function render_link<P extends ToViewPattern<A>>(
863
- raw: RemixLinkProps<A, P>,
864
- ): RemixNode {
865
- const merged = { ...options?.linkDefaultProps, ...raw } as any;
866
- const { href, pattern, params, splatValues, search, hash, ...props } = merged;
867
- return (
868
- <BaseLink
869
- {...props}
870
- pattern={pattern}
871
- href={
872
- href ??
873
- passthrough.toHref({
874
- pattern,
875
- params,
876
- splatValues,
877
- search,
878
- hash,
879
- } as any)
880
- }
881
- />
882
- );
883
- }
884
-
885
- const Link = ((input: unknown) => {
886
- if (is_remix_handle(input as any)) {
887
- return <P extends ToViewPattern<A>>(props: RemixLinkProps<A, P>) => {
888
- return render_link(props);
889
- };
890
- }
891
- return render_link(input as RemixLinkProps<A, ToViewPattern<A>>);
892
- }) as RemixLink<A>;
893
-
894
- return {
895
- ...passthrough,
896
- boot,
897
- defineView,
898
- RootOutlet,
899
- Link,
900
- };
901
- }