@void/react 1.4.0 → 1.6.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.
@@ -1,7 +1,6 @@
1
1
  import { createActionClient } from "void/pages-client";
2
- //#region src/runtime/action.ts
3
- const client = createActionClient();
2
+ // src/runtime/action.ts
3
+ const client = createActionClient({ _resolveOnShell: true });
4
4
  const action = client.action;
5
5
  const setActionRouter = client.setActionRouter;
6
- //#endregion
7
6
  export { setActionRouter as n, action as t };
@@ -1,11 +1,10 @@
1
1
  import { createContext } from "react";
2
2
  import { idleNavigationState } from "void/pages-client";
3
- //#region src/runtime/context.ts
3
+ // src/runtime/context.ts
4
4
  const SharedContext = createContext(null);
5
5
  const ErrorsContext = createContext(null);
6
6
  const ParamsContext = createContext(null);
7
7
  const RouterContext = createContext(null);
8
8
  const NavigationContext = createContext(idleNavigationState());
9
9
  const FrontmatterContext = createContext({});
10
- //#endregion
11
10
  export { RouterContext as a, ParamsContext as i, FrontmatterContext as n, SharedContext as o, NavigationContext as r, ErrorsContext as t };
@@ -1,6 +1,5 @@
1
- //#region src/runtime/deferred-shell.ts
1
+ // src/runtime/deferred-shell.ts
2
2
  const DEFERRED_SHELL_END_ID = "__VOID_DEFERRED_SHELL_END__";
3
3
  const DEFERRED_SHELL_END_MARKER = `<template id="${DEFERRED_SHELL_END_ID}"></template>`;
4
4
  const DEFERRED_SHELL_CANCEL_REASON = "Void deferred shell complete";
5
- //#endregion
6
5
  export { DEFERRED_SHELL_END_ID as n, DEFERRED_SHELL_END_MARKER as r, DEFERRED_SHELL_CANCEL_REASON as t };
package/dist/index.d.mts CHANGED
@@ -1,112 +1,49 @@
1
1
  import { AnchorHTMLAttributes, ButtonHTMLAttributes, Context, FormHTMLAttributes, JSX, ReactElement, ReactNode } from "react";
2
- import { ActionClient, FormMethod, FormModel, FormResetOptions, NavigationState, VoidActionError, VoidRouter } from "void/pages-client";
2
+ import { ActionClient, BaseLinkProps, FormMethod, FormModel, FormState, IslandFormState, NavigationState, VoidActionError, VoidRouter } from "void/pages-client";
3
3
  import { CloudContextVariables, InferProps } from "void";
4
4
  import { ActionFormOptions, ActionUrl, ResolveActionBody } from "void/routes";
5
- //#region src/runtime/form.d.ts
6
5
  type FormProps = Omit<FormHTMLAttributes<HTMLFormElement>, "action" | "onSubmit" | "method" | "onError"> & {
7
6
  form: FormModel<[FormData]>;
8
7
  method?: FormMethod;
9
8
  renderError?: (error: VoidActionError) => ReactNode;
10
9
  };
11
10
  export declare function Form({ form, method, renderError, children, ...props }: FormProps): ReactElement;
12
- //#endregion
13
- //#region src/runtime/link.d.ts
14
- type PrefetchStrategy = "hover" | "click" | "mount" | "visible";
15
- type LinkMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
16
- type CommonProps = {
17
- href: string;
18
- method?: LinkMethod | Lowercase<LinkMethod>;
19
- data?: Record<string, unknown>;
20
- preserveScroll?: boolean;
21
- preserveState?: boolean;
22
- replace?: boolean;
23
- reloadDocument?: boolean;
24
- viewTransition?: boolean;
25
- prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;
26
- cacheFor?: number | string | [string, string];
27
- onNavigate?: (event: {
28
- preventDefault(): void;
29
- }) => void;
30
- };
31
- type LinkProps = CommonProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof CommonProps> & Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof CommonProps>;
32
- export declare function Link({ href, method, data, preserveScroll, preserveState, replace, reloadDocument, viewTransition, prefetch: prefetchProp, cacheFor, onNavigate, children, style, onClick: onClickProp, onMouseEnter: onMouseEnterProp, onMouseLeave: onMouseLeaveProp, onFocus: onFocusProp, onMouseDown: onMouseDownProp, onTouchStart: onTouchStartProp, ...rest }: LinkProps): JSX.Element;
33
- //#endregion
34
- //#region src/runtime/use-router.d.ts
11
+ type LinkProps = BaseLinkProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseLinkProps> & Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof BaseLinkProps>;
12
+ export declare function Link({ href, method, data, preserveScroll, preserveState, replace, reloadDocument, viewTransition, prefetch, cacheFor, activeMatch, onNavigate, children, style, onClick: onClickProp, onMouseEnter: onMouseEnterProp, onMouseLeave: onMouseLeaveProp, onFocus: onFocusProp, onMouseDown: onMouseDownProp, onTouchStart: onTouchStartProp, ...rest }: LinkProps): JSX.Element;
35
13
  export declare function useRouter(): VoidRouter;
36
- //#endregion
37
- //#region src/runtime/use-params.d.ts
38
14
  export declare function useParams<T extends Record<string, string> = Record<string, string>>(): T;
39
- //#endregion
40
- //#region src/runtime/use-shared.d.ts
41
15
  export declare function useShared<T = CloudContextVariables["shared"]>(): T;
42
- //#endregion
43
- //#region src/runtime/use-form.d.ts
16
+ type FormReturn<TData> = FormState<TData, "setters"> & Readonly<{
17
+ setData: <K extends keyof TData & string>(field: K, value: TData[K]) => void;
18
+ post(formData: FormData): void;
19
+ put(formData: FormData): void;
20
+ patch(formData: FormData): void;
21
+ delete(formData: FormData): void;
22
+ }>;
44
23
  type FormOptions = {
45
24
  params?: Record<string, string>;
46
25
  resetOnSuccess?: boolean;
26
+ preserveScroll?: boolean;
47
27
  onSuccess?: () => void | Promise<void>;
48
28
  onError?: (error: Record<string, string> | VoidActionError) => void | Promise<void>;
49
29
  };
50
- export declare function useForm<U extends ActionUrl & string>(url: U, defaults: ResolveActionBody<U>, options?: ActionFormOptions<U> & Pick<FormOptions, "onSuccess" | "onError">): {
51
- data: ResolveActionBody<U>;
52
- setData: <K extends keyof ResolveActionBody<U> & string>(field: K, value: ResolveActionBody<U>[K]) => void;
53
- errors: Partial<Record<keyof ResolveActionBody<U> & string, string>>;
54
- error: VoidActionError | null;
55
- pending: boolean;
56
- hasChanges: boolean;
57
- wasSuccessful: boolean;
58
- recentlySuccessful: boolean;
59
- post(formData: FormData): void;
60
- put(formData: FormData): void;
61
- patch(formData: FormData): void;
62
- delete(formData: FormData): void;
63
- reset(options: FormResetOptions, ...fields: ReadonlyArray<keyof ResolveActionBody<U> & string>): void;
64
- reset(...fields: ReadonlyArray<keyof ResolveActionBody<U> & string>): void;
65
- setError(field: keyof ResolveActionBody<U> & string, message: string): void;
66
- clearErrors(...fields: ReadonlyArray<keyof ResolveActionBody<U> & string>): void;
67
- clearError(): void;
68
- };
69
- //#endregion
70
- //#region src/runtime/use-navigation.d.ts
30
+ export declare function useForm<U extends ActionUrl & string>(url: U, defaults: ResolveActionBody<U>, options?: ActionFormOptions<U> & Pick<FormOptions, "onSuccess" | "onError" | "preserveScroll">): FormReturn<ResolveActionBody<U>>;
71
31
  export declare function useNavigation(): NavigationState;
72
- //#endregion
73
- //#region src/runtime/use-island-form.d.ts
74
- type IslandFormReturn<T extends Record<string, unknown>> = Readonly<{
75
- data: T;
32
+ type IslandFormReturn<T extends Record<string, unknown>> = IslandFormState<T, "setters"> & Readonly<{
76
33
  setData: <K extends keyof T & string>(field: K, value: T[K]) => void;
77
- errors: Record<string, string>;
78
- error: VoidActionError | null;
79
- pending: boolean;
80
- hasChanges: boolean;
81
- wasSuccessful: boolean;
82
- recentlySuccessful: boolean;
83
- reset: (...fields: ReadonlyArray<keyof T & string>) => void;
84
- clearErrors: (...fields: ReadonlyArray<string>) => void;
85
- clearError: () => void;
86
- post: (url: string) => Promise<void>;
87
- put: (url: string) => Promise<void>;
88
- patch: (url: string) => Promise<void>;
89
- delete: (url: string) => Promise<void>;
90
34
  }>;
91
35
  /**
92
36
  * Form hook for island pages. Uses fetch + page reload instead of the
93
37
  * Void Router (which is not available in island mode).
94
38
  */
95
39
  export declare function useIslandForm<T extends Record<string, unknown>>(defaults: T): IslandFormReturn<T>;
96
- //#endregion
97
- //#region src/runtime/action.d.ts
98
40
  export declare const action: ActionClient["action"];
99
41
  export declare const setActionRouter: ActionClient["setActionRouter"];
100
- //#endregion
101
- //#region src/runtime/context.d.ts
102
42
  export declare const SharedContext: Context<Record<string, unknown> | null>;
103
43
  export declare const ErrorsContext: Context<Record<string, string> | null>;
104
44
  export declare const ParamsContext: Context<Record<string, string> | null>;
105
45
  export declare const RouterContext: Context<VoidRouter | null>;
106
46
  export declare const NavigationContext: Context<NavigationState>;
107
47
  export declare const FrontmatterContext: Context<Record<string, unknown>>;
108
- //#endregion
109
- //#region src/runtime/index.d.ts
110
48
  export type Deferred<T> = Promise<T>;
111
- //#endregion
112
49
  export type { InferProps };
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { a as RouterContext, i as ParamsContext, n as FrontmatterContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "./context-D2ctU4yT.mjs";
2
- import { n as setActionRouter, t as action } from "./action-4EvQppia.mjs";
1
+ import { a as RouterContext, i as ParamsContext, n as FrontmatterContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "./context-BQpawTZc.mjs";
2
+ import { n as setActionRouter, t as action } from "./action-CyCVdW12.mjs";
3
3
  import { useActionState, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
4
- import { cloneFormValue, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, interpolateRouteParams, isAbortError, isEqualFormValue, isModifiedEvent, mergeDataIntoHref, parseFormResetArgs, scheduleFormRetry, ssrProxy, submitAction, submitIslandAction } from "void/pages-client";
4
+ import { cloneFormValue, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, handleLinkClick, interpolateRouteParams, isAbortError, isEqualFormValue, linkActiveAttributes, linkPendingAttributes, linkPrefetchStrategies, observeLinkVisible, parseFormResetArgs, prefetchLink, resolveLink, scheduleFormRetry, ssrProxy, submitAction, submitIslandAction } from "void/pages-client";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
- //#region src/runtime/form.tsx
6
+ // src/runtime/form.tsx
7
7
  function Form({ form, method = "post", renderError, children, ...props }) {
8
8
  const [now, setNow] = useState(Date.now);
9
9
  useEffect(() => scheduleFormRetry(form.error, () => setNow(Date.now())), [form.error]);
@@ -24,82 +24,73 @@ function Form({ form, method = "post", renderError, children, ...props }) {
24
24
  }), children]
25
25
  });
26
26
  }
27
- //#endregion
28
- //#region src/runtime/link.tsx
29
- function Link({ href, method = "GET", data, preserveScroll = false, preserveState = false, replace = false, reloadDocument = false, viewTransition, prefetch: prefetchProp = false, cacheFor, onNavigate, children, style, onClick: onClickProp, onMouseEnter: onMouseEnterProp, onMouseLeave: onMouseLeaveProp, onFocus: onFocusProp, onMouseDown: onMouseDownProp, onTouchStart: onTouchStartProp, ...rest }) {
27
+ // src/runtime/link.tsx
28
+ function Link({ href, method = "GET", data, preserveScroll = false, preserveState = false, replace = false, reloadDocument = false, viewTransition, prefetch, cacheFor, activeMatch, onNavigate, children, style, onClick: onClickProp, onMouseEnter: onMouseEnterProp, onMouseLeave: onMouseLeaveProp, onFocus: onFocusProp, onMouseDown: onMouseDownProp, onTouchStart: onTouchStartProp, ...rest }) {
30
29
  const router = useContext(RouterContext);
30
+ const navigation = useContext(NavigationContext);
31
31
  const elementRef = useRef(null);
32
32
  const hoverTimerRef = useRef(null);
33
- const normalizedMethod = useMemo(() => method.toUpperCase(), [method]);
34
- const isGet = normalizedMethod === "GET";
35
- const hrefWithData = useMemo(() => isGet ? mergeDataIntoHref(href, data) : href, [
33
+ const link = useMemo(() => resolveLink({
34
+ href,
35
+ method,
36
+ data,
37
+ prefetch,
38
+ reloadDocument
39
+ }), [
36
40
  data,
37
41
  href,
38
- isGet
42
+ method,
43
+ prefetch,
44
+ reloadDocument
39
45
  ]);
40
- const strategies = useMemo(() => {
41
- if (prefetchProp === false || reloadDocument) return [];
42
- if (prefetchProp === true) return ["hover"];
43
- if (typeof prefetchProp === "string") return [prefetchProp];
44
- return prefetchProp;
45
- }, [prefetchProp, reloadDocument]);
46
- const hoverDelay = router?._hoverDelay ?? 75;
47
- if (prefetchProp !== false && !isGet) throw new Error("Link: prefetch only supports GET links. Remove `prefetch` or use method=\"GET\".");
48
- if (reloadDocument && !isGet) throw new Error("Link: reloadDocument only supports GET links.");
49
- const doPrefetch = useCallback(() => {
50
- if (!router?.prefetch) return;
51
- const current = window.location.pathname + window.location.search;
52
- if (hrefWithData === current) return;
53
- const options = {};
54
- if (cacheFor !== void 0) options.cacheFor = cacheFor;
55
- router.prefetch(hrefWithData, options);
56
- }, [
57
- cacheFor,
58
- hrefWithData,
46
+ const { isGet } = link;
47
+ const defaultStrategy = router?._prefetchDefaultStrategy;
48
+ const strategies = useMemo(() => linkPrefetchStrategies({
49
+ prefetch,
50
+ reloadDocument
51
+ }, { isGet }, defaultStrategy), [
52
+ defaultStrategy,
53
+ isGet,
54
+ prefetch,
55
+ reloadDocument
56
+ ]);
57
+ const activeAttributes = useMemo(() => linkActiveAttributes(router, link, activeMatch), [
58
+ activeMatch,
59
+ link,
59
60
  router
60
61
  ]);
61
- const shouldHandleClick = useCallback((event) => {
62
- if (reloadDocument || !router || event.defaultPrevented || isModifiedEvent(event)) return false;
63
- if (event.currentTarget.hasAttribute("download")) return false;
64
- if (new URL(hrefWithData, window.location.origin).origin !== window.location.origin) return false;
65
- return true;
66
- }, [
67
- hrefWithData,
68
- reloadDocument,
62
+ const pendingAttributes = useMemo(() => linkPendingAttributes(router, navigation, link), [
63
+ link,
64
+ navigation,
65
+ router
66
+ ]);
67
+ const hoverDelay = router?._hoverDelay ?? 75;
68
+ const doPrefetch = useCallback(() => prefetchLink(router, link.href, cacheFor), [
69
+ cacheFor,
70
+ link.href,
69
71
  router
70
72
  ]);
71
73
  const onClick = useCallback((event) => {
72
74
  onClickProp?.(event);
73
- if (!shouldHandleClick(event)) return;
74
- let navigatePrevented = false;
75
- onNavigate?.({ preventDefault() {
76
- navigatePrevented = true;
77
- } });
78
- if (navigatePrevented) {
79
- event.preventDefault();
80
- return;
81
- }
82
- event.preventDefault();
83
- router?.visit(hrefWithData, {
84
- method: normalizedMethod,
85
- data: isGet ? void 0 : data,
75
+ handleLinkClick(event, router, link, {
76
+ data,
86
77
  preserveScroll,
87
78
  preserveState,
88
79
  replace,
89
- viewTransition
80
+ reloadDocument,
81
+ viewTransition,
82
+ onNavigate
90
83
  });
91
84
  }, [
92
85
  data,
93
- hrefWithData,
94
- isGet,
95
- normalizedMethod,
86
+ link,
96
87
  onClickProp,
97
88
  onNavigate,
98
89
  preserveScroll,
99
90
  preserveState,
91
+ reloadDocument,
100
92
  replace,
101
93
  router,
102
- shouldHandleClick,
103
94
  viewTransition
104
95
  ]);
105
96
  const onMouseEnter = useCallback((event) => {
@@ -134,23 +125,13 @@ function Link({ href, method = "GET", data, preserveScroll = false, preserveStat
134
125
  useEffect(() => {
135
126
  if (strategies.length === 0) return;
136
127
  if (strategies.includes("mount")) doPrefetch();
137
- let observer = null;
138
- if (strategies.includes("visible") && elementRef.current) {
139
- observer = new IntersectionObserver((entries) => {
140
- if (entries.some((e) => e.isIntersecting)) {
141
- doPrefetch();
142
- observer?.disconnect();
143
- observer = null;
144
- }
145
- }, { rootMargin: "0px" });
146
- observer.observe(elementRef.current);
147
- }
128
+ const stopObserving = strategies.includes("visible") && elementRef.current ? observeLinkVisible(elementRef.current, doPrefetch) : null;
148
129
  return () => {
149
130
  if (hoverTimerRef.current) {
150
131
  clearTimeout(hoverTimerRef.current);
151
132
  hoverTimerRef.current = null;
152
133
  }
153
- if (observer) observer.disconnect();
134
+ stopObserving?.();
154
135
  };
155
136
  }, [doPrefetch, strategies]);
156
137
  const eventHandlers = useMemo(() => {
@@ -191,10 +172,12 @@ function Link({ href, method = "GET", data, preserveScroll = false, preserveStat
191
172
  touchAction: "manipulation",
192
173
  ...style
193
174
  }), [style]);
194
- if (isGet) return /* @__PURE__ */ jsx("a", {
175
+ if (link.isGet) return /* @__PURE__ */ jsx("a", {
195
176
  ref: elementRef,
196
- href: hrefWithData,
177
+ href: link.href,
197
178
  style: resolvedStyle,
179
+ ...activeAttributes,
180
+ ...pendingAttributes,
198
181
  ...rest,
199
182
  ...eventHandlers,
200
183
  children
@@ -203,32 +186,29 @@ function Link({ href, method = "GET", data, preserveScroll = false, preserveStat
203
186
  ref: elementRef,
204
187
  type: "button",
205
188
  style: resolvedStyle,
189
+ ...pendingAttributes,
206
190
  ...rest,
207
191
  ...eventHandlers,
208
192
  children
209
193
  });
210
194
  }
211
- //#endregion
212
- //#region src/runtime/use-router.ts
195
+ // src/runtime/use-router.ts
213
196
  function useRouter() {
214
197
  return useContext(RouterContext) ?? ssrProxy;
215
198
  }
216
- //#endregion
217
- //#region src/runtime/use-params.ts
199
+ // src/runtime/use-params.ts
218
200
  function useParams() {
219
201
  const params = useContext(ParamsContext);
220
202
  if (params === null) throw new Error("useParams(): must be used inside a Void page.");
221
203
  return params;
222
204
  }
223
- //#endregion
224
- //#region src/runtime/use-shared.ts
205
+ // src/runtime/use-shared.ts
225
206
  function useShared() {
226
207
  const shared = useContext(SharedContext);
227
208
  if (!shared) throw new Error("useShared(): must be used inside a Void page.");
228
209
  return shared;
229
210
  }
230
- //#endregion
231
- //#region src/runtime/use-form.ts
211
+ // src/runtime/use-form.ts
232
212
  function useForm(url, defaults, options) {
233
213
  const router = useContext(RouterContext);
234
214
  const [data, setDataState] = useState(() => cloneFormValue(defaults));
@@ -301,6 +281,7 @@ function useForm(url, defaults, options) {
301
281
  result = await submitAction(router, interpolateRouteParams(url, options?.params), {
302
282
  method,
303
283
  data: { ...dataRef.current },
284
+ preserveScroll: options?.preserveScroll,
304
285
  _resolveOnShell: true
305
286
  });
306
287
  } catch (submitError) {
@@ -364,13 +345,11 @@ function useForm(url, defaults, options) {
364
345
  clearError
365
346
  };
366
347
  }
367
- //#endregion
368
- //#region src/runtime/use-navigation.ts
348
+ // src/runtime/use-navigation.ts
369
349
  function useNavigation() {
370
350
  return useContext(NavigationContext);
371
351
  }
372
- //#endregion
373
- //#region src/runtime/use-island-form.ts
352
+ // src/runtime/use-island-form.ts
374
353
  /**
375
354
  * Form hook for island pages. Uses fetch + page reload instead of the
376
355
  * Void Router (which is not available in island mode).
@@ -458,5 +437,4 @@ function useIslandForm(defaults) {
458
437
  delete: (url) => submit(url, "DELETE")
459
438
  };
460
439
  }
461
- //#endregion
462
440
  export { ErrorsContext, Form, FrontmatterContext, Link, NavigationContext, ParamsContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
package/dist/plugin.d.mts CHANGED
@@ -1,17 +1,9 @@
1
1
  import react from "@vitejs/plugin-react";
2
+ import { PrefetchConfig } from "void/pages";
2
3
  import { Plugin } from "vite";
3
- //#region src/plugin-pages.d.ts
4
- type PrefetchConfig = {
5
- hoverDelay?: number;
6
- cacheFor?: number | string | [string, string];
7
- };
8
- //#endregion
9
- //#region src/plugin.d.ts
10
4
  export type VoidReactOptions = Readonly<{
11
5
  react?: Parameters<typeof react>[0];
12
6
  viewTransitions?: boolean;
13
7
  prefetch?: PrefetchConfig;
14
8
  }>;
15
- export declare function voidReact(options?: VoidReactOptions): Array<Plugin>;
16
- //#endregion
17
- export {};
9
+ export declare function voidReact(options?: VoidReactOptions): Array<Plugin>;
package/dist/plugin.mjs CHANGED
@@ -1,10 +1,9 @@
1
1
  import react from "@vitejs/plugin-react";
2
- import { createPagesPlugin, generateComponentManifest, resolveEffectiveLayoutChain, resolvePagesDir, scanPages } from "void/pages";
2
+ import { createPagesPlugin, generateComponentManifest, resolveEffectiveLayoutChain, resolvePagesDir, resolvePrefetchConfig, scanPages } from "void/pages";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import nodePath from "node:path";
5
- import { normalizePath } from "vite";
6
- import { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, computePagesNeedingClientJS, editIslandSource, findIslandImports, findStaticCssImports, hasIslandPages, islandStylesPlugin, recordIslandStyles, recordedIslandStyles, resolveSpecifier, rewriteCssImportForVirtualModule, watchPagesForRescan } from "void/pages-islands-plugin";
7
- //#region ../../node_modules/.pnpm/pathslash@0.1.0/node_modules/pathslash/dist/index.mjs
5
+ import { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, computePagesNeedingClientJS, createIslandManifest, editIslandSource, findIslandImports, generateIslandClientEntry, islandCssFiles, islandStylesPlugin, islandsBuildConfig, mdClientScriptIds, recordIslandStyles, recordedIslandStyles, resolveSpecifier, watchPagesForRescan } from "void/pages-islands-plugin";
6
+ // ../../node_modules/.pnpm/pathslash@0.1.0/node_modules/pathslash/dist/index.mjs
8
7
  const BACKSLASH_RE = /\\/g;
9
8
  const isWindows = process.platform === "win32";
10
9
  /**
@@ -42,8 +41,7 @@ const posix = { ...nodePath.posix };
42
41
  posix.posix = win32.posix = posix;
43
42
  posix.win32 = win32.win32 = win32;
44
43
  const { basename, delimiter, dirname, extname, format, isAbsolute, join, matchesGlob, normalize, parse, relative, resolve, sep, toNamespacedPath } = isWindows ? win32 : posix;
45
- //#endregion
46
- //#region src/plugin-pages.ts
44
+ // src/plugin-pages.ts
47
45
  const CLIENT_ENTRY_ID = "virtual:void-pages-client";
48
46
  const WORKER_ENVIRONMENT_NAME = "void_worker";
49
47
  const REACT_DEDUPE = ["react", "react-dom"];
@@ -146,12 +144,13 @@ ${generateComponentManifest(scan, pagesDir)}
146
144
 
147
145
  const PREAMBLE_SCRIPT = ${JSON.stringify(preambleScript)};
148
146
 
149
- export async function renderPage(pageObj, assetTags) {
147
+ export async function renderPage(pageObj, assetTags, requestUrl) {
150
148
  return renderReactPage({
151
149
  pageObj,
152
150
  assetTags,
153
151
  components,
154
152
  layoutTree,
153
+ requestUrl,
155
154
  preambleScript: PREAMBLE_SCRIPT,
156
155
  });
157
156
  }
@@ -159,6 +158,7 @@ renderPage.preambleScript = PREAMBLE_SCRIPT;
159
158
  `;
160
159
  }
161
160
  function generateClientEntry(scan, pagesDir, viewTransitions, prefetch, staticPageData) {
161
+ const { defaultStrategy, hoverDelay, cacheFor } = resolvePrefetchConfig(prefetch);
162
162
  return `
163
163
  import { startReactPages } from "@void/react/pages-client";
164
164
  import { parseCacheFor } from "void/pages-prefetch";
@@ -173,45 +173,45 @@ function generateClientEntry(scan, pagesDir, viewTransitions, prefetch, staticPa
173
173
  staticPageData: ${!!staticPageData?.enabled},
174
174
  staticPageDataFastPath: ${!!staticPageData?.fastPath},
175
175
  viewTransitions: ${!!viewTransitions},
176
- prefetchHoverDelay: ${prefetch?.hoverDelay ?? 75},
177
- prefetchDefaultCacheFor: parseCacheFor(${JSON.stringify(prefetch?.cacheFor ?? "30s")}),
176
+ prefetchHoverDelay: ${hoverDelay},
177
+ prefetchDefaultCacheFor: parseCacheFor(${JSON.stringify(cacheFor)}),
178
+ prefetchDefaultStrategy: ${JSON.stringify(defaultStrategy)},
178
179
  });
179
180
  export { router };
180
181
  `;
181
182
  }
182
- //#endregion
183
- //#region src/plugin-islands.ts
183
+ // src/plugin-islands.ts
184
184
  const COMPONENT_EXTENSIONS = [
185
185
  ".tsx",
186
186
  ".jsx",
187
187
  ".ts",
188
188
  ".js"
189
189
  ];
190
+ const HYDRATE_ISLAND = `
191
+ async function hydrateIsland(el, mod, props, frontmatter) {
192
+ const { hydrateRoot } = await import("react-dom/client");
193
+ const React = await import("react");
194
+ const Component = mod.default || mod;
195
+ let island = React.createElement(Component, props);
196
+ if (Object.keys(frontmatter).length > 0) {
197
+ const { FrontmatterContext } = await import("@void/react");
198
+ island = React.createElement(FrontmatterContext.Provider, { value: frontmatter }, island);
199
+ }
200
+ function HydratedIsland() {
201
+ React.useLayoutEffect(() => {
202
+ el.setAttribute("data-hydrated", "true");
203
+ }, []);
204
+ return island;
205
+ }
206
+ hydrateRoot(el, React.createElement(HydratedIsland));
207
+ }`;
190
208
  function islandsPlugin(pagesDir, options) {
191
209
  let pageScan = null;
192
210
  let isDev = false;
193
211
  const root = options?.root ?? dirname(pagesDir);
194
- const islandManifest = /* @__PURE__ */ new Map();
195
- const islandCssFiles = /* @__PURE__ */ new Set();
212
+ const islandManifest = createIslandManifest(root, COMPONENT_EXTENSIONS);
213
+ let cssFiles = /* @__PURE__ */ new Set();
196
214
  let resolvedConfig = null;
197
- /** Resolve an island import and record it in the client manifest. */
198
- function registerIsland(spec, importerDir, hydrate) {
199
- const absPath = resolveSpecifier(spec, importerDir, COMPONENT_EXTENSIONS);
200
- if (!absPath) return {
201
- absPath,
202
- islandId: spec
203
- };
204
- const islandId = normalizePath(relative(root, absPath)).replace(/\.[^.]+$/, "");
205
- islandManifest.set(islandId, {
206
- componentPath: absPath,
207
- islandId,
208
- hydrate
209
- });
210
- return {
211
- absPath,
212
- islandId
213
- };
214
- }
215
215
  return [{
216
216
  name: "void-react:islands",
217
217
  configResolved(config) {
@@ -229,33 +229,8 @@ function islandsPlugin(pagesDir, options) {
229
229
  pagesDir,
230
230
  environment: isDev ? "dev" : "prod"
231
231
  });
232
- const filesToScan = [
233
- ...pageScan.pages.map((page) => ({
234
- filePath: page.componentPath,
235
- island: page.island
236
- })),
237
- ...pageScan.layouts.map((layout) => ({
238
- filePath: layout.filePath,
239
- island: layout.island
240
- })),
241
- ...pageScan.namedLayouts.map((namedLayout) => ({
242
- filePath: namedLayout.filePath,
243
- island: namedLayout.island
244
- }))
245
- ];
246
- for (const entry of filesToScan) {
247
- if (!entry.island) continue;
248
- const filePath = resolve(pagesDir, entry.filePath);
249
- const code = readFileSync(filePath, "utf-8");
250
- const importerDir = dirname(filePath);
251
- for (const islandImport of findIslandImports(code, filePath)) registerIsland(islandImport.specifier, importerDir, islandImport.hydrate);
252
- }
253
- for (const page of pageScan.pages) {
254
- if (!page.island) continue;
255
- if (/\.(tsx|jsx)$/.test(page.componentPath)) islandCssFiles.add(normalizePath(resolve(pagesDir, page.componentPath)));
256
- const layoutChain = resolveEffectiveLayoutChain(page, pageScan.layouts, pageScan.namedLayouts);
257
- for (const layout of layoutChain) islandCssFiles.add(normalizePath(resolve(pagesDir, layout.filePath)));
258
- }
232
+ islandManifest.registerPages(pageScan, pagesDir);
233
+ cssFiles = islandCssFiles(pageScan, pagesDir, /\.(tsx|jsx)$/);
259
234
  }
260
235
  },
261
236
  buildEnd() {
@@ -272,14 +247,20 @@ function islandsPlugin(pagesDir, options) {
272
247
  handler(id) {
273
248
  if (id === "\0" + ISLANDS_RENDERER_ID) {
274
249
  if (!pageScan) return "export function renderIslandPage() { throw new Error('No pages found'); }";
275
- const mdPlugin = resolvedConfig?.plugins?.find((plugin) => plugin.name === "void-md");
276
- const mdScriptIds = new Set(mdPlugin?.api?.getClientScripts?.()?.keys() ?? []);
250
+ const mdScriptIds = mdClientScriptIds(resolvedConfig);
277
251
  const needsJS = computePagesNeedingClientJS(pageScan, pagesDir, resolvedConfig);
278
252
  return generateIslandRenderer(pageScan, pagesDir, isDev, mdScriptIds, needsJS);
279
253
  }
280
254
  if (id === "\0" + ISLANDS_CLIENT_ENTRY_ID) {
281
255
  if (!pageScan) return "";
282
- return generateIslandClientEntry(islandManifest, islandCssFiles, recordedIslandStyles(pagesDir), islandManifest.size > 0 || computePagesNeedingClientJS(pageScan, pagesDir, resolvedConfig).size > 0, isDev);
256
+ return generateIslandClientEntry({
257
+ manifest: islandManifest,
258
+ cssFiles,
259
+ styles: recordedIslandStyles(pagesDir),
260
+ needsRuntime: islandManifest.entries.size > 0 || computePagesNeedingClientJS(pageScan, pagesDir, resolvedConfig).size > 0,
261
+ isDev,
262
+ hydrateIsland: HYDRATE_ISLAND
263
+ });
283
264
  }
284
265
  }
285
266
  },
@@ -297,7 +278,7 @@ function islandsPlugin(pagesDir, options) {
297
278
  const strategy = islandImport.hydrate;
298
279
  const spec = islandImport.specifier;
299
280
  const rawName = `_raw_island_${idx++}`;
300
- const { islandId } = registerIsland(spec, importerDir, strategy);
281
+ const { islandId } = islandManifest.register(spec, importerDir, strategy);
301
282
  const replacement = `import ${rawName} from ${specRaw}`;
302
283
  edits.push({
303
284
  start: islandImport.start,
@@ -313,10 +294,7 @@ function islandsPlugin(pagesDir, options) {
313
294
  }
314
295
  },
315
296
  async config(_, env) {
316
- if (env.command !== "serve" && await hasIslandPages(root, pagesDir)) return { environments: { client: { build: {
317
- manifest: true,
318
- rollupOptions: { input: { "islands-client": ISLANDS_CLIENT_ENTRY_ID } }
319
- } } } };
297
+ if (env.command !== "serve") return islandsBuildConfig(root, pagesDir);
320
298
  }
321
299
  }, islandStylesPlugin(pagesDir)];
322
300
  }
@@ -393,46 +371,7 @@ export async function renderIslandPage(pageObj, assetTags) {
393
371
  }
394
372
  `;
395
373
  }
396
- function generateIslandClientEntry(manifest, cssFiles, styles, needsRuntime, isDev) {
397
- const entries = [...manifest.values()];
398
- const uniqueIslands = /* @__PURE__ */ new Map();
399
- for (const entry of entries) uniqueIslands.set(entry.islandId, entry.componentPath);
400
- const lines = [];
401
- if (!isDev && styles) for (const id of styles) lines.push(`import ${JSON.stringify(id)};`);
402
- else if (!isDev) for (const file of cssFiles) {
403
- const content = readFileSync(file, "utf-8");
404
- for (const item of findStaticCssImports(content, file)) lines.push(rewriteCssImportForVirtualModule(item.statement, item.specifier, file));
405
- }
406
- if (!needsRuntime && !isDev) return lines.join("\n");
407
- lines.push("import { initIslands } from \"void/pages-client\";");
408
- lines.push("const islands = {");
409
- for (const [id, path] of uniqueIslands) lines.push(` ${JSON.stringify(id)}: () => import(${JSON.stringify(path)}),`);
410
- lines.push("};");
411
- lines.push(`
412
- async function hydrateIsland(el, mod, props, frontmatter) {
413
- const { hydrateRoot } = await import("react-dom/client");
414
- const React = await import("react");
415
- const Component = mod.default || mod;
416
- let island = React.createElement(Component, props);
417
- if (Object.keys(frontmatter).length > 0) {
418
- const { FrontmatterContext } = await import("@void/react");
419
- island = React.createElement(FrontmatterContext.Provider, { value: frontmatter }, island);
420
- }
421
- function HydratedIsland() {
422
- React.useLayoutEffect(() => {
423
- el.setAttribute("data-hydrated", "true");
424
- }, []);
425
- return island;
426
- }
427
- hydrateRoot(el, React.createElement(HydratedIsland));
428
- }
429
-
430
- initIslands(islands, hydrateIsland);
431
- `);
432
- return lines.join("\n");
433
- }
434
- //#endregion
435
- //#region src/plugin.ts
374
+ // src/plugin.ts
436
375
  function voidReact(options) {
437
376
  const root = process.cwd();
438
377
  const pagesDir = resolvePagesDir(root);
@@ -446,5 +385,4 @@ function voidReact(options) {
446
385
  ...islandsPlugin(pagesDir, { root })
447
386
  ];
448
387
  }
449
- //#endregion
450
388
  export { voidReact };
@@ -1,8 +1,7 @@
1
1
  import { ComponentType } from "react";
2
2
  import { VoidRouter } from "void/pages-client";
3
- import { CacheForResult } from "void/pages-prefetch";
3
+ import { CacheForResult, LinkPrefetchValue } from "void/pages-prefetch";
4
4
  import { PageObject } from "void/pages-protocol";
5
- //#region src/runtime/pages-client.d.ts
6
5
  type ComponentModule = {
7
6
  default: ComponentType<any>;
8
7
  };
@@ -19,6 +18,7 @@ export type ReactPagesConfig = Readonly<{
19
18
  viewTransitions: boolean;
20
19
  prefetchHoverDelay: number;
21
20
  prefetchDefaultCacheFor: CacheForResult;
21
+ prefetchDefaultStrategy?: LinkPrefetchValue;
22
22
  cacheVisitedPageData?: boolean;
23
23
  /** Show this fallback for client visits whose destination remains pending at the next paint. */
24
24
  navigationFallback?: ComponentType<{
@@ -29,5 +29,4 @@ export type ReactPagesClient = Readonly<{
29
29
  router: VoidRouter;
30
30
  }>;
31
31
  export declare function startReactPages(config: ReactPagesConfig): Promise<ReactPagesClient>;
32
- //#endregion
33
32
  export {};
@@ -1,10 +1,10 @@
1
- import { a as RouterContext, i as ParamsContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "../context-D2ctU4yT.mjs";
2
- import { n as setActionRouter } from "../action-4EvQppia.mjs";
3
- import { n as DEFERRED_SHELL_END_ID } from "../deferred-shell-DOuP2YAo.mjs";
1
+ import { a as RouterContext, i as ParamsContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "../context-BQpawTZc.mjs";
2
+ import { n as setActionRouter } from "../action-CyCVdW12.mjs";
3
+ import { n as DEFERRED_SHELL_END_ID } from "../deferred-shell-D5T32zXz.mjs";
4
4
  import React, { Suspense, startTransition, use, useCallback, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useReducer, useState, useTransition } from "react";
5
- import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError, isCallSiteActionError, refreshPage } from "void/pages-client";
5
+ import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError, isCallSiteActionError, refreshPage, toUrlString } from "void/pages-client";
6
6
  import { createRoot, hydrateRoot } from "react-dom/client";
7
- //#region src/runtime/pages-client.ts
7
+ // src/runtime/pages-client.ts
8
8
  const deferredState = /* @__PURE__ */ new WeakMap();
9
9
  const viewTransitionWaiters = /* @__PURE__ */ new Map();
10
10
  const pendingVisitSettlers = /* @__PURE__ */ new Map();
@@ -51,8 +51,9 @@ function currentUrl() {
51
51
  return window.location.pathname + window.location.search + window.location.hash;
52
52
  }
53
53
  function normalizeUrl(value) {
54
- if (typeof value === "string" && value.startsWith("#")) return value;
55
- const url = value instanceof URL ? value : new URL(value, window.location.origin);
54
+ const urlString = toUrlString(value);
55
+ if (urlString.startsWith("#")) return urlString;
56
+ const url = new URL(urlString, window.location.href);
56
57
  return url.origin === window.location.origin ? url.pathname + url.search + url.hash : url.href;
57
58
  }
58
59
  /** Page data holds a decoded path. Compare it with browser URLs in their encoded form. */
@@ -141,6 +142,7 @@ function appReducer(state, action) {
141
142
  function createRouter(engine) {
142
143
  const router = {
143
144
  _hoverDelay: engine._hoverDelay,
145
+ _prefetchDefaultStrategy: engine._prefetchDefaultStrategy,
144
146
  get url() {
145
147
  return new URL(currentUrl(), window.location.origin);
146
148
  },
@@ -306,6 +308,7 @@ function App({ engine, router, viewTransitions, navigationFallback: NavigationFa
306
308
  }, []);
307
309
  const schedule = useCallback((url, options = {}) => {
308
310
  const prepared = engine.prepareVisit(url, options);
311
+ const resolveOnData = prepared.options.resolveOn === "data" || prepared.options._resolveOnShell;
309
312
  if (prepared.immediate) {
310
313
  const navigation = navigationForResource(prepared);
311
314
  activePendingNavigationId = prepared.id;
@@ -355,7 +358,7 @@ function App({ engine, router, viewTransitions, navigationFallback: NavigationFa
355
358
  location: currentUrl()
356
359
  });
357
360
  resolveVisit(void 0);
358
- } else if (prepared.options._resolveOnShell) {
361
+ } else if (resolveOnData) {
359
362
  pendingVisitSettlers.delete(prepared.id);
360
363
  resolveVisit(result.pageData);
361
364
  }
@@ -370,7 +373,7 @@ function App({ engine, router, viewTransitions, navigationFallback: NavigationFa
370
373
  if (prepared.method.toUpperCase() === "GET" && !prepared.options._resolveOnShell && isAbortError(error)) resolveVisit(void 0);
371
374
  else rejectVisit(error);
372
375
  if (activePendingNavigationId === prepared.id) activePendingNavigationId = null;
373
- if (NavigationFallback || prepared.options._resolveOnShell || isAbortError(error) || isCallSiteActionError(error)) {
376
+ if (NavigationFallback || resolveOnData || isAbortError(error) || isCallSiteActionError(error)) {
374
377
  dispatch({
375
378
  type: "abandon",
376
379
  resource: prepared,
@@ -490,6 +493,7 @@ async function startReactPages(config) {
490
493
  viewTransitions: config.viewTransitions,
491
494
  prefetchHoverDelay: config.prefetchHoverDelay,
492
495
  prefetchDefaultCacheFor: config.prefetchDefaultCacheFor,
496
+ prefetchDefaultStrategy: config.prefetchDefaultStrategy,
493
497
  cacheVisitedPageData: config.cacheVisitedPageData
494
498
  });
495
499
  const router = createRouter(engine);
@@ -513,5 +517,4 @@ async function startReactPages(config) {
513
517
  engine.start();
514
518
  return { router };
515
519
  }
516
- //#endregion
517
520
  export { startReactPages };
@@ -1,6 +1,5 @@
1
1
  import { ComponentType } from "react";
2
2
  import { PageObject } from "void/pages-protocol";
3
- //#region src/runtime/pages-server.d.ts
4
3
  type ComponentModule = {
5
4
  default: ComponentType<any>;
6
5
  };
@@ -13,8 +12,8 @@ export type ReactPagesServerConfig = Readonly<{
13
12
  };
14
13
  components: Record<string, () => Promise<ComponentModule>>;
15
14
  layoutTree: Record<string, Array<string>>;
15
+ requestUrl?: string;
16
16
  preambleScript?: string;
17
17
  }>;
18
- export declare function renderReactPage({ pageObj, assetTags, components, layoutTree, preambleScript }: ReactPagesServerConfig): Promise<ReadableStream<Uint8Array>>;
19
- //#endregion
18
+ export declare function renderReactPage({ pageObj, assetTags, components, layoutTree, requestUrl, preambleScript }: ReactPagesServerConfig): Promise<ReadableStream<Uint8Array>>;
20
19
  export {};
@@ -1,11 +1,11 @@
1
- import { a as RouterContext, i as ParamsContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "../context-D2ctU4yT.mjs";
2
- import { n as DEFERRED_SHELL_END_ID, r as DEFERRED_SHELL_END_MARKER, t as DEFERRED_SHELL_CANCEL_REASON } from "../deferred-shell-DOuP2YAo.mjs";
1
+ import { a as RouterContext, i as ParamsContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "../context-BQpawTZc.mjs";
2
+ import { n as DEFERRED_SHELL_END_ID, r as DEFERRED_SHELL_END_MARKER, t as DEFERRED_SHELL_CANCEL_REASON } from "../deferred-shell-D5T32zXz.mjs";
3
3
  import React from "react";
4
4
  import { createSsrRouter, idleNavigationState } from "void/pages-client";
5
5
  import { renderToReadableStream } from "react-dom/server";
6
6
  import { renderBodyAttrs, renderHeadToString, renderHtmlAttrs } from "void/pages-head";
7
7
  import { serializePageData } from "void/pages-server";
8
- //#region src/runtime/page-streams.ts
8
+ // src/runtime/page-streams.ts
9
9
  function concatStreams(streams) {
10
10
  let index = 0;
11
11
  let reader;
@@ -94,8 +94,7 @@ function readDeferredShell(stream) {
94
94
  }
95
95
  }, { highWaterMark: 0 });
96
96
  }
97
- //#endregion
98
- //#region src/runtime/pages-server.ts
97
+ // src/runtime/pages-server.ts
99
98
  function createPendingDeferred() {
100
99
  return new Promise(() => {});
101
100
  }
@@ -112,14 +111,14 @@ function textStream(text) {
112
111
  controller.close();
113
112
  } });
114
113
  }
115
- async function renderReactPage({ pageObj, assetTags, components, layoutTree, preambleScript = "" }) {
114
+ async function renderReactPage({ pageObj, assetTags, components, layoutTree, requestUrl, preambleScript = "" }) {
116
115
  const PageComponent = (await components[pageObj.component]()).default;
117
116
  const layoutIds = layoutTree[pageObj.component] || [];
118
117
  const layoutComponents = await Promise.all(layoutIds.map(async (id) => (await components[id]()).default));
119
118
  const renderProps = propsForReactRender(pageObj);
120
119
  let element = React.createElement(PageComponent, renderProps);
121
120
  for (let i = layoutComponents.length - 1; i >= 0; i--) element = React.createElement(layoutComponents[i], null, element);
122
- element = React.createElement(RouterContext.Provider, { value: createSsrRouter(pageObj.url || "/", pageObj.params ?? {}) }, React.createElement(NavigationContext.Provider, { value: idleNavigationState() }, React.createElement(React.Suspense, { fallback: null }, React.createElement(SharedContext.Provider, { value: pageObj.shared || {} }, React.createElement(ParamsContext.Provider, { value: pageObj.params ?? {} }, React.createElement(ErrorsContext.Provider, { value: pageObj.errors || {} }, element))))));
121
+ element = React.createElement(RouterContext.Provider, { value: createSsrRouter(pageObj.url || "/", pageObj.params ?? {}, requestUrl) }, React.createElement(NavigationContext.Provider, { value: idleNavigationState() }, React.createElement(React.Suspense, { fallback: null }, React.createElement(SharedContext.Provider, { value: pageObj.shared || {} }, React.createElement(ParamsContext.Provider, { value: pageObj.params ?? {} }, React.createElement(ErrorsContext.Provider, { value: pageObj.errors || {} }, element))))));
123
122
  const renderElement = pageObj.deferredKeys ? React.createElement(React.Fragment, null, element, React.createElement("template", { id: DEFERRED_SHELL_END_ID })) : element;
124
123
  let shellError;
125
124
  let shellSent = false;
@@ -155,5 +154,4 @@ async function renderReactPage({ pageObj, assetTags, components, layoutTree, pre
155
154
  </html>`)
156
155
  ]);
157
156
  }
158
- //#endregion
159
157
  export { renderReactPage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@void/react",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "React pages, server rendering, forms, and navigation for Void.",
5
5
  "homepage": "https://void.cloud",
6
6
  "bugs": {
@@ -41,22 +41,22 @@
41
41
  "@vitejs/plugin-react": "^6.1.2"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/node": "^26.6.5",
44
+ "@types/node": "^26.6.6",
45
45
  "@types/react": "^19.3.0",
46
46
  "@types/react-dom": "^19.3.0",
47
47
  "happy-dom": "^21.0.4",
48
48
  "pathslash": "^0.1.0",
49
49
  "react": "^19.3.1",
50
50
  "react-dom": "^19.3.1",
51
- "vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
52
- "vite-plus": "1.3.0",
53
- "void": "1.4.0"
51
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0",
52
+ "vite-plus": "1.4.0",
53
+ "void": "1.6.0"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "react": "^19.0.0",
57
57
  "react-dom": "^19.0.0",
58
58
  "vite": "^8.0.0",
59
- "void": "1.4.0"
59
+ "void": "1.6.0"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "vp pack",