Skip to content

Commit

Permalink
feat: tighter integration with sveltekit
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloricciuti committed Nov 9, 2023
1 parent 4f527a8 commit dca97a1
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 9 deletions.
15 changes: 14 additions & 1 deletion code/frameworks/sveltekit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./src/components/LinkListener.svelte": "./src/components/LinkListener.svelte",
"./preview": {
"types": "./dist/preview.d.ts",
"require": "./dist/preview.js",
"import": "./dist/preview.mjs"
},
"./dist/preview.js": {
"types": "./dist/preview.d.ts",
"require": "./dist/preview.js",
"import": "./dist/preview.mjs"
},
"./preset": {
"types": "./dist/preset.d.ts",
"require": "./dist/preset.js"
Expand All @@ -43,7 +54,8 @@
"README.md",
"*.js",
"*.d.ts",
"!src/**/*"
"!src/**/*",
"src/components/**/*"
],
"scripts": {
"check": "../../../scripts/prepare/check.ts",
Expand Down Expand Up @@ -72,6 +84,7 @@
"bundler": {
"entries": [
"./src/index.ts",
"./src/preview.ts",
"./src/preset.ts"
],
"platform": "node"
Expand Down
43 changes: 43 additions & 0 deletions code/frameworks/sveltekit/src/components/LinkListener.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script>
import { onMount } from 'svelte';
/**
* @type {Parameters<(import("@storybook/svelte").Preview["decorators"] & {})[number]>[1]}
*/
export let ctx;
onMount(() => {
const listener = (/**@type {Event}*/ e) => {
const path = e.composedPath();
const has_link = path.findLast((el) => el instanceof HTMLElement && el.tagName === 'A');
if (has_link && has_link instanceof HTMLAnchorElement) {
const to = has_link.getAttribute('href');
let override_called = false;
if (ctx?.parameters?.sveltekit?.linkOverrides && to) {
for (const [link, override] of Object.entries(ctx.parameters.sveltekit.linkOverrides)) {
if (override instanceof Function) {
const regex = new RegExp(link);
if (regex.test(to)) {
override();
override_called = true;
}
}
}
}
if (!override_called) {
// import('@storybook/addon-actions')
// .then(({ action }) => {
// action('sveltekit.navigation')();
// })
// .catch(console.log);
}
e.preventDefault();
}
};
window.addEventListener('click', listener);
return () => {
window.removeEventListener('click', listener);
};
});
</script>
<slot />
19 changes: 19 additions & 0 deletions code/frameworks/sveltekit/src/mocks/app/forms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function enhance(form: HTMLFormElement) {
// import('@storybook/addon-actions')
// .then(({ action }) => {
// action('sveltekit.enhance')();
// })
// .catch(console.log);
}

export function applyAction() {}

export function deserialize() {
return deserializeResponse;
}

let deserializeResponse: any;

export function setDeserializeResponse(answer: any) {
deserializeResponse = answer;
}
49 changes: 49 additions & 0 deletions code/frameworks/sveltekit/src/mocks/app/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { getContext, onMount, setContext } from 'svelte';

export async function goto(...args: any[]) {
// try {
// const { action } = await import('@storybook/addon-actions');
// action('sveltekit.goto')(...args);
// } catch (e) {
// console.log(e);
// }
}

export function setAfterNavigateArgument(afterNavigateArgs: any) {
setContext('after-navigate-args', afterNavigateArgs);
}

export function afterNavigate(cb: any) {
const argument = getContext('after-navigate-args');
onMount(() => {
cb(argument);
});
}

export function onNavigate() {}

export function beforeNavigate() {}

export function disableScrollHandling() {}

export async function invalidate(...args: any[]) {
// try {
// const { action } = await import('@storybook/addon-actions');
// action('sveltekit.invalidate')(...args);
// } catch (e) {
// console.log(e);
// }
}

export async function invalidateAll() {
// try {
// const { action } = await import('@storybook/addon-actions');
// action('sveltekit.invalidateAll')();
// } catch (e) {
// console.log(e);
// }
}

export function preloadCode() {}

export function preloadData() {}
20 changes: 20 additions & 0 deletions code/frameworks/sveltekit/src/mocks/app/stores.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { getContext, setContext } from 'svelte';

function createMockedStore(contextName: string) {
return [
{
subscribe(runner: any) {
const page = getContext(contextName);
runner(page);
return () => {};
},
},
(value: unknown) => {
setContext(contextName, value);
},
] as const;
}

export const [page, setPage] = createMockedStore('page-ctx');
export const [navigating, setNavigating] = createMockedStore('navigating-ctx');
export const [updated, setUpdated] = createMockedStore('updated-ctx');
31 changes: 23 additions & 8 deletions code/frameworks/sveltekit/src/plugins/config-overrides.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
import type { Plugin } from 'vite';
import { resolve } from 'node:path';
import { mergeConfig, type Plugin } from 'vite';

export function configOverrides() {
return {
// SvelteKit sets SSR, we need it to be false when building
name: 'storybook:sveltekit-overrides',
apply: 'build',
config: () => {
return { build: { ssr: false } };
return [
{
// SvelteKit sets SSR, we need it to be false when building
name: 'storybook:sveltekit-overrides',
apply: 'build',
config: () => {
return { build: { ssr: false } };
},
},
} satisfies Plugin;
{
name: 'storybook:sveltekit-mock-stores',
enforce: 'post',
config: (config) =>
mergeConfig(config, {
resolve: {
alias: {
$app: resolve(__dirname, '../src/mocks/app/'),
},
},
}),
},
] satisfies Plugin[];
}
4 changes: 4 additions & 0 deletions code/frameworks/sveltekit/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export const core: PresetProperty<'core', StorybookConfig> = {
builder: getAbsolutePath('@storybook/builder-vite'),
renderer: getAbsolutePath('@storybook/svelte'),
};
export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => [
...entry,
require.resolve('@storybook/sveltekit/preview'),
];

export const viteFinal: NonNullable<StorybookConfig['viteFinal']> = async (config, options) => {
const baseConfig = await svelteViteFinal(config, options);
Expand Down
19 changes: 19 additions & 0 deletions code/frameworks/sveltekit/src/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Decorator } from '@storybook/svelte';

// eslint-disable-next-line import/no-extraneous-dependencies
import LinkListener from '@storybook/sveltekit/src/components/LinkListener.svelte';
import { setDeserializeResponse } from './mocks/app/forms';
import { setAfterNavigateArgument } from './mocks/app/navigation';
import { setNavigating, setPage, setUpdated } from './mocks/app/stores';

export const decorators: Decorator[] = [
(Story, ctx) => {
setPage(ctx.parameters?.sveltekit?.stores?.page);
setUpdated(ctx.parameters?.sveltekit?.stores?.updated);
setNavigating(ctx.parameters?.sveltekit?.stores?.navigating);
setDeserializeResponse(ctx.parameters?.sveltekit?.forms?.deserializeResponse);
setAfterNavigateArgument(ctx.parameters?.sveltekit?.navigation?.afterNavigate);
return Story();
},
(_, ctx) => ({ Component: LinkListener, props: { ctx } }),
];

0 comments on commit dca97a1

Please sign in to comment.