@void/vue 1.3.0 → 1.5.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.
package/dist/index.d.mts CHANGED
@@ -2,22 +2,11 @@ import { ActionClient, FormResetOptions, NavigationState, VisitOptions, VoidActi
2
2
  import { Component } from "vue";
3
3
  import { CloudContextVariables, DeferredState as Deferred, InferProps } from "void";
4
4
  import { ActionFormOptions, ActionUrl, ResolveActionBody } from "void/routes";
5
- //#region src/runtime/form.d.ts
6
5
  export declare const Form: Component;
7
- //#endregion
8
- //#region src/runtime/link.d.ts
9
6
  export declare const Link: Component;
10
- //#endregion
11
- //#region src/runtime/use-router.d.ts
12
7
  export declare function useRouter(): VoidRouter;
13
- //#endregion
14
- //#region src/runtime/use-params.d.ts
15
8
  export declare function useParams<T extends Record<string, string> = Record<string, string>>(): T;
16
- //#endregion
17
- //#region src/runtime/use-shared.d.ts
18
9
  export declare function useShared<T = CloudContextVariables["shared"]>(): T;
19
- //#endregion
20
- //#region src/runtime/use-form.d.ts
21
10
  type FormSubmitOptions = Omit<VisitOptions, "method" | "data"> & {
22
11
  data?: Record<string, unknown>;
23
12
  };
@@ -39,11 +28,7 @@ export declare function useForm<U extends ActionUrl & string>(url: U, defaults:
39
28
  clearErrors(...fields: ReadonlyArray<keyof ResolveActionBody<U> & string>): void;
40
29
  clearError(): void;
41
30
  };
42
- //#endregion
43
- //#region src/runtime/use-navigation.d.ts
44
31
  export declare function useNavigation(): NavigationState;
45
- //#endregion
46
- //#region src/runtime/use-island-form.d.ts
47
32
  type IslandFormReturn<T extends Record<string, unknown>> = Readonly<{
48
33
  data: T;
49
34
  errors: Record<string, string>;
@@ -66,9 +51,6 @@ type IslandFormReturn<T extends Record<string, unknown>> = Readonly<{
66
51
  * Void Router (which is not available in island mode).
67
52
  */
68
53
  export declare function useIslandForm<T extends Record<string, unknown>>(defaults: T): IslandFormReturn<T>;
69
- //#endregion
70
- //#region src/runtime/action.d.ts
71
54
  export declare const action: ActionClient["action"];
72
55
  export declare const setActionRouter: ActionClient["setActionRouter"];
73
- //#endregion
74
56
  export type { Deferred, InferProps };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { VoidActionError, categorizeActionError, cloneFormValue, createActionClient, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, idleNavigationState, interpolateRouteParams, isAbortError, isEqualFormValue, isModifiedEvent, mergeDataIntoHref, parseFormResetArgs, scheduleFormRetry, ssrProxy, submitAction } from "void/pages-client";
1
+ import { cloneFormValue, createActionClient, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, idleNavigationState, interpolateRouteParams, isAbortError, isEqualFormValue, isModifiedEvent, mergeDataIntoHref, parseFormResetArgs, scheduleFormRetry, ssrProxy, submitAction, submitIslandAction } from "void/pages-client";
2
2
  import { computed, defineComponent, h, inject, onMounted, onUnmounted, reactive, ref, shallowRef, watch } from "vue";
3
- //#region src/runtime/form.ts
3
+ // src/runtime/form.ts
4
4
  const Form = defineComponent({
5
5
  name: "VoidForm",
6
6
  inheritAttrs: false,
@@ -42,8 +42,7 @@ const Form = defineComponent({
42
42
  };
43
43
  }
44
44
  });
45
- //#endregion
46
- //#region src/runtime/link.ts
45
+ // src/runtime/link.ts
47
46
  function callHandler(handler, event) {
48
47
  if (Array.isArray(handler)) {
49
48
  for (const fn of handler) if (typeof fn === "function") fn(event);
@@ -219,27 +218,23 @@ const Link = defineComponent({
219
218
  };
220
219
  }
221
220
  });
222
- //#endregion
223
- //#region src/runtime/use-router.ts
221
+ // src/runtime/use-router.ts
224
222
  function useRouter() {
225
223
  return inject("__void_router", null) ?? ssrProxy;
226
224
  }
227
- //#endregion
228
- //#region src/runtime/use-params.ts
225
+ // src/runtime/use-params.ts
229
226
  function useParams() {
230
227
  const params = inject("__void_params");
231
228
  if (!params) throw new Error("useParams(): must be used inside a Void page.");
232
229
  return params;
233
230
  }
234
- //#endregion
235
- //#region src/runtime/use-shared.ts
231
+ // src/runtime/use-shared.ts
236
232
  function useShared() {
237
233
  const shared = inject("__void_shared");
238
234
  if (!shared) throw new Error("useShared(): must be used inside a Void page.");
239
235
  return shared;
240
236
  }
241
- //#endregion
242
- //#region src/runtime/use-form.ts
237
+ // src/runtime/use-form.ts
243
238
  function useForm(url, defaults, options) {
244
239
  const initialDefaults = cloneFormValue(defaults);
245
240
  const router = inject("__void_router", null);
@@ -328,22 +323,11 @@ function useForm(url, defaults, options) {
328
323
  delete: (opts) => submit("DELETE", opts)
329
324
  });
330
325
  }
331
- //#endregion
332
- //#region src/runtime/use-navigation.ts
326
+ // src/runtime/use-navigation.ts
333
327
  function useNavigation() {
334
328
  return inject("__void_navigation", null) ?? idleNavigationState();
335
329
  }
336
- //#endregion
337
- //#region src/runtime/use-island-form.ts
338
- async function readActionErrorBody(response) {
339
- const contentType = response.headers.get("content-type") || "";
340
- try {
341
- if (contentType.includes("application/json")) return await response.json();
342
- return await response.text() || null;
343
- } catch {
344
- return null;
345
- }
346
- }
330
+ // src/runtime/use-island-form.ts
347
331
  /**
348
332
  * Form composable for island pages. Uses fetch + page reload instead of the
349
333
  * Void Router (which is not available in island mode).
@@ -380,16 +364,12 @@ function useIslandForm(defaults) {
380
364
  clearErrors();
381
365
  clearError();
382
366
  try {
383
- const response = await fetch(url, {
384
- method,
385
- headers: { "Content-Type": "application/json" },
386
- body: JSON.stringify(data)
387
- });
388
- if (response.redirected) {
389
- window.location.href = response.url;
367
+ const result = await submitIslandAction(url, method, data);
368
+ if (result.kind === "redirect") {
369
+ window.location.href = result.url;
390
370
  return;
391
371
  }
392
- if (response.ok) {
372
+ if (result.kind === "success") {
393
373
  wasSuccessful.value = true;
394
374
  recentlySuccessful.value = true;
395
375
  defaults_ = { ...data };
@@ -397,22 +377,8 @@ function useIslandForm(defaults) {
397
377
  recentlySuccessful.value = false;
398
378
  }, 2e3);
399
379
  window.location.reload();
400
- } else {
401
- const body = await readActionErrorBody(response);
402
- const actionError = new VoidActionError({
403
- body,
404
- status: response.status,
405
- statusText: response.statusText,
406
- url
407
- });
408
- const validationErrors = response.status === 422 ? getValidationErrors(body) : null;
409
- if (validationErrors) {
410
- Object.assign(errors, validationErrors);
411
- return;
412
- }
413
- if (categorizeActionError(response.status) === "boundary") throw actionError;
414
- error.value = actionError;
415
- }
380
+ } else if (result.kind === "validation") Object.assign(errors, result.errors);
381
+ else error.value = result.error;
416
382
  } finally {
417
383
  pending.value = false;
418
384
  }
@@ -435,10 +401,8 @@ function useIslandForm(defaults) {
435
401
  delete: (url) => submit(url, "DELETE")
436
402
  });
437
403
  }
438
- //#endregion
439
- //#region src/runtime/action.ts
404
+ // src/runtime/action.ts
440
405
  const client = createActionClient();
441
406
  const action = client.action;
442
407
  const setActionRouter = client.setActionRouter;
443
- //#endregion
444
408
  export { Form, Link, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
package/dist/plugin.d.mts CHANGED
@@ -1,17 +1,13 @@
1
1
  import vue from "@vitejs/plugin-vue";
2
2
  import { Plugin } from "vite";
3
- //#region src/plugin-pages.d.ts
4
3
  type PrefetchConfig = {
5
4
  hoverDelay?: number;
6
5
  cacheFor?: number | string | [string, string];
7
6
  };
8
- //#endregion
9
- //#region src/plugin.d.ts
10
7
  export type VoidVueOptions = Readonly<{
11
8
  vue?: Parameters<typeof vue>[0];
12
9
  viewTransitions?: boolean;
13
10
  prefetch?: PrefetchConfig;
14
11
  }>;
15
12
  export declare function voidVue(options?: VoidVueOptions): Array<Plugin>;
16
- //#endregion
17
13
  export {};
package/dist/plugin.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import vue from "@vitejs/plugin-vue";
2
- import { generateComponentManifest, resolveEffectiveLayoutChain, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages } from "void/pages";
2
+ import { createPagesPlugin, generateComponentManifest, resolveEffectiveLayoutChain, resolvePagesDir, scanPages } from "void/pages";
3
3
  import { existsSync, readFileSync, readdirSync } from "node:fs";
4
4
  import nodePath from "node:path";
5
5
  import { normalizePath } from "vite";
6
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
7
+ // ../../node_modules/.pnpm/pathslash@0.1.0/node_modules/pathslash/dist/index.mjs
8
8
  const BACKSLASH_RE = /\\/g;
9
9
  const isWindows = process.platform === "win32";
10
10
  /**
@@ -42,8 +42,7 @@ const posix = { ...nodePath.posix };
42
42
  posix.posix = win32.posix = posix;
43
43
  posix.win32 = win32.win32 = win32;
44
44
  const { basename, delimiter, dirname, extname, format, isAbsolute, join, matchesGlob, normalize, parse, relative, resolve, sep, toNamespacedPath } = isWindows ? win32 : posix;
45
- //#endregion
46
- //#region src/plugin-islands.ts
45
+ // src/plugin-islands.ts
47
46
  const COMPONENT_EXTENSIONS = [
48
47
  ".vue",
49
48
  ".tsx",
@@ -311,9 +310,7 @@ initIslands(islands, hydrateIsland);
311
310
  `);
312
311
  return lines.join("\n");
313
312
  }
314
- //#endregion
315
- //#region src/plugin-pages.ts
316
- const RENDERER_ID = "virtual:void-pages-renderer";
313
+ // src/plugin-pages.ts
317
314
  const CLIENT_ENTRY_ID = "virtual:void-pages-client";
318
315
  /** Runtime helper injected into generated SSR and client page bundles. */
319
316
  const PATCH_PROPS_RUNTIME = `
@@ -389,30 +386,7 @@ function hasNonIslandPages(dir) {
389
386
  return false;
390
387
  }
391
388
  function pagesPlugin(pagesDir, options) {
392
- let pageScan = null;
393
- let isDev = false;
394
- let viteConfig;
395
- const root = options?.root ?? dirname(pagesDir);
396
389
  const normalizedPagesDir = normalizePath(pagesDir);
397
- let pendingRescan = null;
398
- const rescanPages = async () => {
399
- pageScan = existsSync(pagesDir) ? await scanPages(root, {
400
- pagesDir,
401
- environment: isDev ? "dev" : "prod"
402
- }) : null;
403
- };
404
- const runRescan = () => {
405
- pendingRescan ??= rescanPages().finally(() => {
406
- pendingRescan = null;
407
- });
408
- return pendingRescan;
409
- };
410
- const invalidatePageModules = (server) => {
411
- for (const env of Object.values(server.environments)) for (const id of ["\0" + RENDERER_ID, "\0" + CLIENT_ENTRY_ID]) {
412
- const mod = env.moduleGraph.getModuleById(id);
413
- if (mod) env.moduleGraph.invalidateModule(mod);
414
- }
415
- };
416
390
  return [{
417
391
  name: "void-vue:pages-transform",
418
392
  enforce: "pre",
@@ -439,58 +413,16 @@ function pagesPlugin(pagesDir, options) {
439
413
  };
440
414
  }
441
415
  }
442
- }, {
416
+ }, createPagesPlugin(pagesDir, {
443
417
  name: "void-vue:pages",
444
- async buildStart() {
445
- await runRescan();
446
- },
447
- resolveId: {
448
- filter: { id: /^virtual:void-pages-(renderer|client)$/ },
449
- handler(id) {
450
- return "\0" + id;
451
- }
452
- },
453
- load: {
454
- filter: { id: /^\0virtual:void-pages-(renderer|client)$/ },
455
- async handler(id) {
456
- if (isDev && pendingRescan) await pendingRescan;
457
- if (!pageScan && existsSync(pagesDir)) await runRescan();
458
- if (id === "\0" + RENDERER_ID) {
459
- if (!pageScan) return "export function renderPage() { throw new Error('No pages found'); }";
460
- return generateRendererModule(pageScan, pagesDir);
461
- }
462
- if (id === "\0" + CLIENT_ENTRY_ID) {
463
- if (!pageScan) return "";
464
- return generateClientEntry(pageScan, pagesDir, options?.viewTransitions, options?.prefetch, resolveStaticPageDataBuildOptions(root, { publicDir: viteConfig?.publicDir }));
465
- }
466
- }
418
+ root: options?.root,
419
+ generateRenderer(scan) {
420
+ return generateRendererModule(scan, pagesDir);
467
421
  },
468
- configureServer(server) {
469
- const handlePagesChange = async (path, event) => {
470
- const normalizedPath = normalizePath(path);
471
- if (normalizedPath !== normalizedPagesDir && !normalizedPath.startsWith(normalizedPagesDir + "/")) return;
472
- if (event === "change" && !normalizedPath.endsWith(".md")) return;
473
- try {
474
- await runRescan();
475
- } catch (error) {
476
- server.config.logger.error(error instanceof Error ? error.message : String(error), {
477
- error: error instanceof Error ? error : void 0,
478
- timestamp: true
479
- });
480
- return;
481
- }
482
- invalidatePageModules(server);
483
- };
484
- server.watcher.on("add", (path) => handlePagesChange(path, "add"));
485
- server.watcher.on("change", (path) => handlePagesChange(path, "change"));
486
- server.watcher.on("unlink", (path) => handlePagesChange(path, "unlink"));
422
+ generateClient(scan, staticPageData) {
423
+ return generateClientEntry(scan, pagesDir, options?.viewTransitions, options?.prefetch, staticPageData);
487
424
  },
488
- configResolved(config) {
489
- viteConfig = config;
490
- },
491
- config(_, env) {
492
- isDev = env.command === "serve";
493
- if (!existsSync(pagesDir)) return;
425
+ config({ isDev }) {
494
426
  if (isDev) return { optimizeDeps: { include: ["vue"] } };
495
427
  if (!hasNonIslandPages(pagesDir)) return;
496
428
  return { environments: { client: { build: {
@@ -498,7 +430,7 @@ function pagesPlugin(pagesDir, options) {
498
430
  rollupOptions: { input: { "pages-client": CLIENT_ENTRY_ID } }
499
431
  } } } };
500
432
  }
501
- }];
433
+ })];
502
434
  }
503
435
  function generateRendererModule(scan, pagesDir) {
504
436
  return `
@@ -654,8 +586,7 @@ start();
654
586
  commitInitialRender();
655
587
  `;
656
588
  }
657
- //#endregion
658
- //#region src/plugin.ts
589
+ // src/plugin.ts
659
590
  function voidVue(options) {
660
591
  const root = process.cwd();
661
592
  const pagesDir = resolvePagesDir(root);
@@ -669,5 +600,4 @@ function voidVue(options) {
669
600
  ...islandsPlugin(pagesDir, { root })
670
601
  ];
671
602
  }
672
- //#endregion
673
603
  export { voidVue };
@@ -1,4 +1,3 @@
1
- //#region src/runtime/use-deferred.d.ts
2
1
  export type DeferredRef<T = unknown> = {
3
2
  value: null;
4
3
  loading: true;
@@ -14,5 +13,4 @@ export type DeferredRef<T = unknown> = {
14
13
  };
15
14
  export declare function createDeferred<T = unknown>(): DeferredRef<T>;
16
15
  export declare function resolveDeferred(ref: DeferredRef, data: unknown): void;
17
- export declare function rejectDeferred(ref: DeferredRef, error: string): void;
18
- //#endregion
16
+ export declare function rejectDeferred(ref: DeferredRef, error: string): void;
@@ -1,5 +1,5 @@
1
1
  import { reactive } from "vue";
2
- //#region src/runtime/use-deferred.ts
2
+ // src/runtime/use-deferred.ts
3
3
  function createDeferred() {
4
4
  return reactive({
5
5
  value: null,
@@ -17,5 +17,4 @@ function rejectDeferred(ref, error) {
17
17
  r.error = new Error(error);
18
18
  r.loading = false;
19
19
  }
20
- //#endregion
21
20
  export { createDeferred, rejectDeferred, resolveDeferred };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@void/vue",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Vue pages, server rendering, forms, and navigation for Void.",
5
5
  "homepage": "https://void.cloud",
6
6
  "bugs": {
@@ -37,16 +37,16 @@
37
37
  "@vitejs/plugin-vue": "^6.0.10"
38
38
  },
39
39
  "devDependencies": {
40
- "@types/node": "^26.6.5",
40
+ "@types/node": "^26.6.6",
41
41
  "pathslash": "^0.1.0",
42
- "vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
43
- "vite-plus": "1.3.0",
44
- "void": "1.3.0",
42
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0",
43
+ "vite-plus": "1.4.0",
44
+ "void": "1.5.0",
45
45
  "vue": "^3.5.44"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "vite": "^8.0.0",
49
- "void": "1.3.0",
49
+ "void": "1.5.0",
50
50
  "vue": "^3.5.0"
51
51
  },
52
52
  "scripts": {