@forgebook/sveltekit 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -2
  3. package/dist/src/app/env.d.ts +8 -0
  4. package/dist/src/app/env.js +15 -0
  5. package/dist/src/app/forms.d.ts +68 -0
  6. package/dist/src/app/forms.js +125 -0
  7. package/dist/src/app/manifest.d.ts +21 -0
  8. package/dist/src/app/manifest.js +17 -0
  9. package/dist/src/app/navigation.d.ts +97 -0
  10. package/dist/src/app/navigation.js +147 -0
  11. package/dist/src/app/paths.d.ts +32 -0
  12. package/dist/src/app/paths.js +56 -0
  13. package/dist/src/app/state.d.ts +27 -0
  14. package/dist/src/app/state.js +60 -0
  15. package/dist/src/app/stores.d.ts +31 -0
  16. package/dist/src/app/stores.js +36 -0
  17. package/dist/src/appSettings.d.ts +44 -0
  18. package/dist/src/appSettings.js +55 -0
  19. package/dist/src/kitParameters.d.ts +272 -0
  20. package/dist/src/kitParameters.js +291 -0
  21. package/dist/src/kitRenderer.d.ts +3 -0
  22. package/dist/src/kitRenderer.js +276 -0
  23. package/dist/src/kitStore.d.ts +90 -0
  24. package/dist/src/kitStore.js +301 -0
  25. package/dist/src/loadFetch.d.ts +33 -0
  26. package/dist/src/loadFetch.js +171 -0
  27. package/dist/src/mountFrame.d.ts +14 -0
  28. package/dist/src/mountFrame.js +15 -0
  29. package/dist/src/routeIds.d.ts +44 -0
  30. package/dist/src/routeIds.js +150 -0
  31. package/dist/src/routeOrder.d.ts +18 -0
  32. package/dist/src/routeOrder.js +187 -0
  33. package/dist/src/stories.d.ts +48 -0
  34. package/dist/src/stories.js +11 -0
  35. package/dist/src/storyCode.d.ts +3 -0
  36. package/dist/src/storyCode.js +9 -0
  37. package/dist/src/storyPage.d.ts +35 -0
  38. package/dist/src/storyPage.js +19 -0
  39. package/dist/src/vite/envModules.d.ts +67 -0
  40. package/dist/src/vite/envModules.js +181 -0
  41. package/dist/src/vite/extractDocs.d.ts +14 -0
  42. package/dist/src/vite/extractDocs.js +20 -0
  43. package/dist/src/vite/kitPlugin.d.ts +28 -0
  44. package/dist/src/vite/kitPlugin.js +241 -0
  45. package/dist/src/vite/kitProject.d.ts +27 -0
  46. package/dist/src/vite/kitProject.js +176 -0
  47. package/dist/src/vite/projectFiles.d.ts +14 -0
  48. package/dist/src/vite/projectFiles.js +70 -0
  49. package/dist/src/vite/sveltekit.d.ts +26 -0
  50. package/dist/src/vite/sveltekit.js +39 -0
  51. package/package.json +120 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ensiria
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,153 @@
1
- # Temporary Holding Version
1
+ # @forgebook/sveltekit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ SvelteKit for [Forgebook](https://www.npmjs.com/package/forgebook): a SvelteKit app's components and pages drawn in a
4
+ catalogue, with what they read of the app (`$app/state`, `$app/navigation`, `$app/forms`, `$app/paths`, `$app/env`,
5
+ the public environment, `$lib` and a page's `load`) given by each story. Built on
6
+ [`@forgebook/svelte`](https://www.npmjs.com/package/@forgebook/svelte), on Vite.
7
+
8
+ **Requirements:** SvelteKit 2 or 3 · Svelte 5.46 · `forgebook` · Vite 8 · React in the project, for the catalogue's own
9
+ interface (the frames that draw your components load none) ·
10
+ [MIT licence](https://github.com/ensiria/forgebook/blob/develop/packages/sveltekit/LICENSE)
11
+
12
+ ```sh
13
+ npm install --save-dev forgebook @forgebook/sveltekit react react-dom
14
+ ```
15
+
16
+ The catalogue's configuration names it as its framework, beside the app's `vite.config`:
17
+
18
+ ```ts
19
+ // forgebook.config.ts
20
+ import { sveltekit } from "@forgebook/sveltekit/vite";
21
+ import { defineConfig } from "forgebook";
22
+
23
+ export default defineConfig({ framework: sveltekit(), title: "My app", stories: ["src/**/*.stories.ts"] });
24
+ ```
25
+
26
+ It reads SvelteKit's options where SvelteKit keeps them (the `sveltekit()` plugin of `vite.config` in SvelteKit 3,
27
+ `svelte.config.js` in SvelteKit 2), Svelte's options with them, and keeps the app's other Vite plugins (Tailwind CSS, an
28
+ i18n compiler), so a component is drawn as the app draws it. `vite.config` is read as `vite dev` reads it, for a
29
+ catalogue's build too, so the app's plugins run there: `keepPlugin` leaves out one only an app's build needs (a
30
+ source-map upload, a service-worker generator). `sveltekit({ dir, viteConfig, keepPlugin })` names another folder or
31
+ configuration; `viteConfig: false` reads only `svelte.config.js`. A SvelteKit 3 project's `tsconfig.json` extends
32
+ `$app/tsconfig`, which `svelte-kit sync` writes: run it before the catalogue, as SvelteKit's templates do on install
33
+ (`"prepare": "svelte-kit sync"`); the catalogue says so when it has not run.
34
+
35
+ ## A story on a page
36
+
37
+ A story says which page its components are on, under `parameters.sveltekit`:
38
+
39
+ ```ts
40
+ import type { Meta, Story } from "@forgebook/sveltekit";
41
+
42
+ import SiteNav from "./SiteNav.svelte";
43
+
44
+ export default { title: "Layout/Site nav", component: SiteNav } satisfies Meta<typeof SiteNav>;
45
+
46
+ // `page.url` from $app/state, the route `/blog/[slug]` and `page.params.slug` read from src/routes
47
+ export const OnAPost: Story<typeof SiteNav> = { parameters: { sveltekit: { page: { url: "/blog/hello" } } } };
48
+ ```
49
+
50
+ A page is a story too, its data given or loaded as SvelteKit loads it:
51
+
52
+ ```ts
53
+ import { http, HttpResponse } from "msw";
54
+
55
+ import Post from "./+page.svelte";
56
+ import { load } from "./+page";
57
+
58
+ export default { title: "Pages/Post", component: Post } satisfies Meta<typeof Post>;
59
+
60
+ // the page's own load, run in the frame with the story's params; its fetch answered by the story's mock
61
+ export const Loaded: Story<typeof Post> = {
62
+ parameters: {
63
+ sveltekit: { page: { url: "/blog/hello" }, load },
64
+ msw: { handlers: [http.get("/api/posts/:slug", () => HttpResponse.json({ title: "Hello" }))] }
65
+ }
66
+ };
67
+
68
+ // or the data as it is, what a server load would have returned
69
+ export const Given: Story<typeof Post> = {
70
+ parameters: { sveltekit: { page: { url: "/blog/hello", data: { post: { title: "Hello" } } } } }
71
+ };
72
+ ```
73
+
74
+ | `parameters.sveltekit` | What it sets |
75
+ |---|---|
76
+ | `page.url` | The page's address, from the base path (`/blog/hello?tab=1`); the route and params are read from `src/routes`. `/` by default |
77
+ | `page.route`, `page.params` | The route id and params, over what the address gives; a route id with params and no `url` gives the address |
78
+ | `page.data`, `page.form`, `page.state`, `page.status`, `page.error` | The rest of `page` |
79
+ | `load` | The page's universal `load` (or a list, the layouts' first): run before the story is drawn, again after each move and on `invalidate` |
80
+ | `serverData` | What the page's server load returned: the `data` its `load` receives, or the page's data without one |
81
+ | `navigating`, `updated` | What `navigating` and `updated.current` hold |
82
+ | `navigation`, `forms.enhance`, `hrefs` | Callbacks, as Storybook's SvelteKit names them: called with `goto`'s (and the others') arguments; a link whose href `hrefs` entries match (by key, or as a regular expression with `asRegex`) calls each of them instead of moving |
83
+ | `forms.result` | What an enhanced form's action answers (`{ type: "failure", status: 400, data }`); a success by default |
84
+
85
+ `load` takes the page's own `load`, typed by its `./$types`; one written in the story types its event itself
86
+ (`satisfies PageLoad`). A story that gives page data (`page.data`, `serverData`, `load`) or an action's answer
87
+ (`forms.result`) is a page's: its
88
+ component gets `data`, `form` and `params` as SvelteKit gives a `+page.svelte` them, unless its args set them. Storybook's
89
+ `sveltekit_experimental` is read too (`state.page`, `stores.page`, `navigation`, `forms`, `hrefs`), so stories moved
90
+ with `forgebook init --from storybook` keep their pages.
91
+
92
+ ## What a story's page does
93
+
94
+ The page really moves, in SvelteKit's order: a link of the app clicked in a story, a GET form, `goto` and a redirect a
95
+ load throws run `beforeNavigate` (which may cancel), load the page's data, run `onNavigate`, change `page.url`, its route
96
+ and params, and run `afterNavigate`. A move a later one overtook is dropped; an error a load throws is the page's, shown
97
+ in place of the story. The frame's address never changes: every link (an SVG one and an `<area>` too) and every form is
98
+ caught, and one outside the app (another origin, or outside the base path) goes nowhere. One frame shows one page: a
99
+ story drawn several times at once (a matrix) shares it. Each move and each call
100
+ (`link`, `goto`, `invalidate`, `invalidateAll`, `refreshAll`, `pushState`, `preloadData`, `enhance`…) is listed in the
101
+ panel's Events. A play reads where the story went:
102
+
103
+ ```ts
104
+ import { storyPage } from "@forgebook/sveltekit/page";
105
+
106
+ export const GoesToAbout: Story<typeof SiteNav> = {
107
+ play: async ({ canvas, userEvent }) => {
108
+ await userEvent.click(canvas.getByRole("link", { name: "About" }));
109
+ // storyPage().pathname is "/about"; storyPage().calls lists the link
110
+ }
111
+ };
112
+ ```
113
+
114
+ An enhanced form (`use:enhance`) is sent to no server: the story's `forms.result` is the answer, and `page.form`, the
115
+ status and the form's `form` prop follow it as `applyAction` sets them, a success loads the page's data again; the
116
+ function `use:enhance` takes runs as in the app. A POST form without `use:enhance` is only listed among the events.
117
+
118
+ | Module | In a story |
119
+ |---|---|
120
+ | `$app/state`, `$app/stores` | The story's page, followed by Svelte; the stores for SvelteKit 2 |
121
+ | `$app/navigation` | `goto`, `invalidate`, `invalidateAll`, `refreshAll`, `preloadData`, `preloadCode`, `pushState`, `replaceState`, the three navigation callbacks; `disableScrollHandling` and `snapshot` do nothing |
122
+ | `$app/forms` | `enhance`, `applyAction`, `deserialize` (JSON) |
123
+ | `$app/paths` | `base`, `assets`, `asset`, `resolve`, `resolveRoute`, `match`, from the app's `paths` and routes |
124
+ | `$app/env`, `$app/environment` | `browser` (false in a server test), `dev`, `building` (false), `version` |
125
+ | `$app/manifest` | The routes and the static files |
126
+ | `$app/env/public` (SvelteKit 3) | The variables `src/env.ts` declares public, checked by their schema (one with none must be set) |
127
+ | `$env/static/public`, `$env/dynamic/public` (SvelteKit 2) | The variables with the public prefix, from the environment and the `.env` files, fixed when a static build is made |
128
+ | `$lib`, the `alias` option | As SvelteKit resolves them; SvelteKit 3's `#lib` is the app's own `imports` |
129
+ | `$app/env/private`, `$env/*/private`, `$app/server`, `$service-worker` | Refused: the story fails with why, and the value never reaches the page |
130
+ | The other SvelteKit's environment | Refused too: SvelteKit 3 has no `$env/*`, so no variable reaches its page by its prefix alone; SvelteKit 2 has no `$app/env/public` |
131
+
132
+ Generated server tests take `kitRenderer` from `@forgebook/sveltekit/renderer`: a page's `load` runs first, and a server
133
+ render never reaches the network for the page's own origin. A load's `fetch` of a path, or of an address on the story's
134
+ page's origin (`http://localhost` unless `page.url` names another), is answered by the story's `parameters.msw`
135
+ handlers, the ones the frame uses, run in Node by MSW's `getResponse` (MSW 2.11 or later, installed by the project): no
136
+ request is intercepted, so tests running at once keep their own mocks. A mocked redirect is followed through the
137
+ handlers and `HttpResponse.error()` rejects the fetch, as in the frame; `{ once: true }` handlers answer again in each
138
+ render. When no handler answers, or one answers `passthrough()`, the story fails with the address and what to give
139
+ instead: a handler, or the page's data (`serverData`, `page.data`); it fails even when the load catches the error. An
140
+ address on another origin, `127.0.0.1` beside a `localhost` page among them, is fetched as it is.
141
+
142
+ ## Not drawn
143
+
144
+ Remote functions (`*.remote.ts`, `query`, `form`, `command`) need SvelteKit's server and are not given. A page's layouts
145
+ (`+layout.svelte`) and `+error.svelte` are not drawn around it: a story draws its component, and a decorator adds a
146
+ layout. A param's matcher is not run (any value matches), the history is the story's own (`history.back()` is the
147
+ frame's), and `beforeNavigate` sees no `leave` navigation. The `tracing` field of a load's event is not given.
148
+
149
+ `@forgebook/sveltekit` exports the story types (`Meta`, `Story`, `Preview`, and `StorySveltekit`, `StoryPageParameters`,
150
+ `StoryKitLoad`, `StoryActionResult` for the parameters), `@forgebook/sveltekit/vite` the adapter, `@forgebook/sveltekit/page`
151
+ `storyPage()`. The rest of its exports (`./app/*`, `./frame`, `./code`, `./docs`, `./renderer`) are what the catalogue
152
+ loads itself, not for stories. Getting started, the catalogue's features and its commands:
153
+ [Forgebook's README](https://github.com/ensiria/forgebook/blob/develop/packages/forgebook/README.md).
@@ -0,0 +1,8 @@
1
+ /** Whether the code runs in the browser: `false` in a generated server test. */
2
+ export declare const browser: boolean;
3
+ /** Whether the catalogue's dev server runs, as SvelteKit's dev server would. */
4
+ export declare const dev: boolean;
5
+ /** Whether the app is being built or prerendered: a catalogue never runs it there. */
6
+ export declare const building = false;
7
+ /** The project's `version.name`. */
8
+ export declare const version: string;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `$app/env` (SvelteKit 3) and `$app/environment` (SvelteKit 2) in a catalogue: in the browser in a frame, on the
3
+ * server in a generated server test, in development under `forgebook dev`, never building.
4
+ *
5
+ * @module
6
+ */
7
+ import { appSettings } from "../appSettings.js";
8
+ /** Whether the code runs in the browser: `false` in a generated server test. */
9
+ export const browser = !import.meta.env.SSR;
10
+ /** Whether the catalogue's dev server runs, as SvelteKit's dev server would. */
11
+ export const dev = import.meta.env.DEV;
12
+ /** Whether the app is being built or prerendered: a catalogue never runs it there. */
13
+ export const building = false;
14
+ /** The project's `version.name`. */
15
+ export const version = appSettings().version;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * `$app/forms` in a catalogue: a form with `use:enhance` is submitted to no server. The submission is listed among the
3
+ * story's events, the story's `forms.result` (a success by default) is what the action answers, and the page's `form`,
4
+ * status or error follow it as SvelteKit's `applyAction` sets them.
5
+ *
6
+ * @module
7
+ */
8
+ import { type KitActionResult } from "../kitParameters.ts";
9
+ /** What `use:enhance`'s function receives as the form is submitted. */
10
+ export type SubmitInput = {
11
+ /** The action's address (`?/login`, from the page). */
12
+ readonly action: URL;
13
+ /** The form's values. */
14
+ readonly formData: FormData;
15
+ /** The form. */
16
+ readonly formElement: HTMLFormElement;
17
+ /** Aborts the submission. */
18
+ readonly controller: AbortController;
19
+ /** The button that submitted the form, or `null`. */
20
+ readonly submitter: HTMLElement | null;
21
+ /** Stops the submission. */
22
+ readonly cancel: () => void;
23
+ };
24
+ /** What the function `use:enhance`'s function returns receives, once the action answered. */
25
+ export type SubmitResultInput = Omit<SubmitInput, "controller" | "submitter" | "cancel"> & {
26
+ /** What the action answered. */
27
+ readonly result: KitActionResult;
28
+ /**
29
+ * Does what SvelteKit does without a function: after a success, resets the form and loads the page's data again;
30
+ * applies the result.
31
+ */
32
+ readonly update: (options?: UpdateOptions) => Promise<void>;
33
+ };
34
+ /** What `update` may leave out: the reset (`reset: false`), the new load (`invalidateAll` or `refreshAll: false`). */
35
+ export type UpdateOptions = {
36
+ /** Whether a success resets the form; `true` by default. */
37
+ readonly reset?: boolean;
38
+ /** Whether a success loads the page's data again (SvelteKit 2's name); `true` by default. */
39
+ readonly invalidateAll?: boolean;
40
+ /** Whether a success loads the page's data again (SvelteKit 3's name); `true` by default. */
41
+ readonly refreshAll?: boolean;
42
+ };
43
+ /** `use:enhance`'s function. */
44
+ export type SubmitFunction = (input: SubmitInput) => unknown;
45
+ /**
46
+ * Applies an action's result to the page, as SvelteKit's does: a success or failure sets `page.form` and the status,
47
+ * a redirect moves the page, an error sets `page.error`.
48
+ *
49
+ * @param result - the result.
50
+ */
51
+ export declare const applyAction: (result: KitActionResult) => Promise<void>;
52
+ /**
53
+ * An action's answer read from its text, as SvelteKit writes it: its data in JSON (SvelteKit writes it with
54
+ * `devalue`, which a value JSON can write reads the same with).
55
+ *
56
+ * @param text - the answer's text.
57
+ */
58
+ export declare const deserialize: (text: string) => KitActionResult;
59
+ /**
60
+ * Submits a form to no server: what `use:enhance` does in a story.
61
+ *
62
+ * @param form - the form.
63
+ * @param submit - the function called as it is submitted; what it returns is called with the result.
64
+ * @returns what removes the behaviour.
65
+ */
66
+ export declare const enhance: (form: HTMLFormElement, submit?: SubmitFunction) => {
67
+ readonly destroy: () => void;
68
+ };
@@ -0,0 +1,125 @@
1
+ /**
2
+ * `$app/forms` in a catalogue: a form with `use:enhance` is submitted to no server. The submission is listed among the
3
+ * story's events, the story's `forms.result` (a success by default) is what the action answers, and the page's `form`,
4
+ * status or error follow it as SvelteKit's `applyAction` sets them.
5
+ *
6
+ * @module
7
+ */
8
+ import { actionResultOf, errorOf } from "../kitParameters.js";
9
+ import { currentStore } from "../kitStore.js";
10
+ /**
11
+ * Applies an action's result to the story's page.
12
+ *
13
+ * @param store - the story's page.
14
+ * @param result - the result.
15
+ */
16
+ const applied = async (store, result) => {
17
+ switch (result.type) {
18
+ case "success":
19
+ case "failure":
20
+ store.setPage({ form: result.data ?? null, status: result.status });
21
+ return;
22
+ case "redirect":
23
+ await store.navigate("goto", result.location);
24
+ return;
25
+ case "error":
26
+ store.setPage({
27
+ error: errorOf(result.error) ?? { message: String(result.error) },
28
+ status: result.status ?? 500
29
+ });
30
+ }
31
+ };
32
+ /**
33
+ * Applies an action's result to the page, as SvelteKit's does: a success or failure sets `page.form` and the status,
34
+ * a redirect moves the page, an error sets `page.error`.
35
+ *
36
+ * @param result - the result.
37
+ */
38
+ export const applyAction = async (result) => {
39
+ const store = currentStore();
40
+ store.record("applyAction", [result]);
41
+ await applied(store, result);
42
+ };
43
+ /**
44
+ * An action's answer read from its text, as SvelteKit writes it: its data in JSON (SvelteKit writes it with
45
+ * `devalue`, which a value JSON can write reads the same with).
46
+ *
47
+ * @param text - the answer's text.
48
+ */
49
+ export const deserialize = (text) => {
50
+ const parsed = JSON.parse(text);
51
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
52
+ return { type: "error", error: new Error("The answer is not an action's result") };
53
+ const fields = Object.fromEntries(Object.entries(parsed));
54
+ const { data } = fields;
55
+ return actionResultOf({ ...fields, data: typeof data === "string" ? JSON.parse(data) : data });
56
+ };
57
+ /**
58
+ * A form's values, as the catalogue lists them: files by their name.
59
+ *
60
+ * @param formData - the values.
61
+ */
62
+ const listedValues = (formData) => Object.fromEntries([...formData].map(([name, value]) => [name, typeof value === "string" ? value : value.name]));
63
+ /**
64
+ * Submits a form to no server: what `use:enhance` does in a story.
65
+ *
66
+ * @param form - the form.
67
+ * @param submit - the function called as it is submitted; what it returns is called with the result.
68
+ * @returns what removes the behaviour.
69
+ */
70
+ export const enhance = (form, submit) => {
71
+ const onSubmit = async (event) => {
72
+ const store = currentStore();
73
+ // SvelteKit enhances a POST form only: another is the browser's (the story's frame keeps it, as for a link)
74
+ const method = (event.submitter?.getAttribute("formmethod") ?? form.method).toLowerCase();
75
+ if (method !== "post")
76
+ return;
77
+ event.preventDefault();
78
+ // only a button of this form adds its value to the form's: FormData refuses any other
79
+ const { submitter: sent } = event;
80
+ const submitter = (sent instanceof HTMLButtonElement || sent instanceof HTMLInputElement) && sent.form === form
81
+ ? sent
82
+ : null;
83
+ const target = submitter?.getAttribute("formaction") ?? form.getAttribute("action") ?? "";
84
+ const action = new URL(target, store.page().url);
85
+ const formData = new FormData(form, submitter);
86
+ store.record("enhance", [`${action.pathname}${action.search}`, listedValues(formData)]);
87
+ store.kit.forms.enhance?.();
88
+ let isCancelled = false;
89
+ const controller = new AbortController();
90
+ const after = await submit?.({
91
+ action,
92
+ formData,
93
+ formElement: form,
94
+ controller,
95
+ submitter,
96
+ cancel: () => {
97
+ isCancelled = true;
98
+ }
99
+ });
100
+ if (isCancelled)
101
+ return;
102
+ const result = store.kit.forms.result ?? { type: "success", status: 200 };
103
+ const update = async (options = {}) => {
104
+ if (result.type === "success") {
105
+ if (options.reset !== false)
106
+ form.reset();
107
+ // a success loads the page's data again, as SvelteKit's does, unless told not to
108
+ if (options.invalidateAll !== false && options.refreshAll !== false)
109
+ await store.reload();
110
+ }
111
+ await applied(store, result);
112
+ };
113
+ if (typeof after === "function")
114
+ await after({ action, formData, formElement: form, result, update });
115
+ else
116
+ await update();
117
+ };
118
+ const listener = (event) => {
119
+ void onSubmit(event);
120
+ };
121
+ form.addEventListener("submit", listener);
122
+ return {
123
+ destroy: () => form.removeEventListener("submit", listener)
124
+ };
125
+ };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `$app/manifest` in a catalogue (SvelteKit 3): the project's routes, from `src/routes`, and its static files, from
3
+ * `static`. A catalogue builds no app, so nothing is immutable or prerendered.
4
+ *
5
+ * @module
6
+ */
7
+ import { type AppRoute } from "../appSettings.ts";
8
+ /** The app's built files: none, as a catalogue builds no app. */
9
+ export declare const immutable: readonly {
10
+ readonly path: string;
11
+ }[];
12
+ /** The project's static files. */
13
+ export declare const assets: readonly {
14
+ readonly path: string;
15
+ }[];
16
+ /** The prerendered pages: none. */
17
+ export declare const prerendered: readonly {
18
+ readonly path: string;
19
+ }[];
20
+ /** The project's routes, with whether each has a page and an endpoint. */
21
+ export declare const routes: readonly AppRoute[];
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `$app/manifest` in a catalogue (SvelteKit 3): the project's routes, from `src/routes`, and its static files, from
3
+ * `static`. A catalogue builds no app, so nothing is immutable or prerendered.
4
+ *
5
+ * @module
6
+ */
7
+ import { appSettings } from "../appSettings.js";
8
+ /** The app's built files: none, as a catalogue builds no app. */
9
+ export const immutable = [];
10
+ /** The project's static files. */
11
+ export const assets = appSettings().staticFiles.map((path) => ({
12
+ path
13
+ }));
14
+ /** The prerendered pages: none. */
15
+ export const prerendered = [];
16
+ /** The project's routes, with whether each has a page and an endpoint. */
17
+ export const routes = appSettings().routes;
@@ -0,0 +1,97 @@
1
+ import type { KitNavigation } from "../kitParameters.ts";
2
+ import { type BeforeNavigation } from "../kitStore.ts";
3
+ /**
4
+ * `goto`'s options: the new page's state is read; the others (`replaceState`, `noScroll`, `keepFocus`…) are kept for
5
+ * the call's record, since a story's page has no history, scroll or focus of its own to keep.
6
+ */
7
+ export type GotoOptions = {
8
+ /** The new page's state. */
9
+ readonly state?: Readonly<Record<string, unknown>>;
10
+ /** Any of SvelteKit's other options. */
11
+ readonly [option: string]: unknown;
12
+ };
13
+ /** What `preloadData` resolves with: the data the story's loads give the href, or what they threw. */
14
+ export type PreloadResult = {
15
+ /** The loads ran, or there are none. */
16
+ readonly type: "loaded";
17
+ /** The status: 200. */
18
+ readonly status: number;
19
+ /** The data. */
20
+ readonly data: Readonly<Record<string, unknown>>;
21
+ } | {
22
+ /** A load threw. */
23
+ readonly type: "error";
24
+ /** What it threw. */
25
+ readonly error: unknown;
26
+ };
27
+ /**
28
+ * Goes to an address, as a story's page: its route, params and data follow, the navigation callbacks run.
29
+ *
30
+ * @param url - where to go, from the page's address.
31
+ * @param options - the new page's state; the page's data is loaded again at every move.
32
+ * @returns resolves once the page moved; rejects for an address outside the app, as SvelteKit does.
33
+ */
34
+ export declare const goto: (url: string | URL, options?: GotoOptions) => Promise<void>;
35
+ /**
36
+ * Loads the page's data again, as when something it depends on changed.
37
+ *
38
+ * @param resource - what changed: an address, a dependency's name, or a test of an address.
39
+ */
40
+ export declare const invalidate: (resource: string | URL | ((url: URL) => boolean)) => Promise<void>;
41
+ /** Loads the page's data again (SvelteKit 2). */
42
+ export declare const invalidateAll: () => Promise<void>;
43
+ /** Loads the page's data again, keeping its state (SvelteKit 3). */
44
+ export declare const refreshAll: () => Promise<void>;
45
+ /**
46
+ * Loads an address's data without going there.
47
+ *
48
+ * @param href - the address.
49
+ */
50
+ export declare const preloadData: (href: string) => Promise<PreloadResult>;
51
+ /**
52
+ * Loads a route's code: a story's code is loaded already.
53
+ *
54
+ * @param pathnames - the routes.
55
+ */
56
+ export declare const preloadCode: (...pathnames: readonly string[]) => Promise<void>;
57
+ /**
58
+ * Sets the page's state without a navigation (shallow routing).
59
+ *
60
+ * @param url - the address the state belongs to; recorded.
61
+ * @param state - the page's new state.
62
+ */
63
+ export declare const pushState: (url: string | URL, state: Readonly<Record<string, unknown>>) => void;
64
+ /**
65
+ * Replaces the page's state without a navigation (shallow routing).
66
+ *
67
+ * @param url - the address the state belongs to; recorded.
68
+ * @param state - the page's new state.
69
+ */
70
+ export declare const replaceState: (url: string | URL, state: Readonly<Record<string, unknown>>) => void;
71
+ /** Leaves the scroll as it is after a navigation: a story's page never scrolls on its own. */
72
+ export declare const disableScrollHandling: () => void;
73
+ /**
74
+ * Captures and restores a component's state across the history (SvelteKit 3): a story's history is its own, so there
75
+ * is nothing to restore.
76
+ */
77
+ export declare const snapshot: () => void;
78
+ /**
79
+ * Runs a callback when the component is drawn, with the page's first navigation, and after every navigation of the
80
+ * story's page. Called while a component is set up.
81
+ *
82
+ * @param callback - the callback.
83
+ */
84
+ export declare const afterNavigate: (callback: (navigation: KitNavigation) => void) => void;
85
+ /**
86
+ * Runs a callback before every navigation of the story's page, which it may cancel. Called while a component is set up.
87
+ *
88
+ * @param callback - the callback.
89
+ */
90
+ export declare const beforeNavigate: (callback: (navigation: BeforeNavigation) => void) => void;
91
+ /**
92
+ * Runs a callback as every navigation of the story's page starts; a function it returns runs once it is done. Called
93
+ * while a component is set up.
94
+ *
95
+ * @param callback - the callback.
96
+ */
97
+ export declare const onNavigate: (callback: (navigation: KitNavigation) => unknown) => void;