Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte: Svelte syntax Component Story Format (Reupload) #12367

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 49 additions & 47 deletions MAINTAINERS.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,56 @@
# Maintainers

This document will document some of the processes that members of the documentation team should adhere to.

# PR Process
## PR Process

1. Triage with the correct [label](#labels)
2. If there is a change related to it ensure it has been published and tested before closing

# Labels
## Labels

| label name | purpose |
|:--------------:|:------------|
| accessibility | |
| addon:(name) | |
| app:(name) | |
| api:(name) | |
| cleanup | Minor cleanup style change that won't show up in release changelog |
| bug | |
| cli | |
| good first review | |
| compatibility with other tools | |
| patch | Bugfix & documentation PR that need to be picked to release branch |
| picked | Patch PRs cherry-picked to master |
| compatibility with other tools | |
| components | |
| core | |
| decorators | |
| dependencies:update | |
| dependencies | |
| discussion | |
| do not merge | |
| documentation | |
| feature request | |
| good first issue | |
| has workaround | |
| help wanted | |
| high priority | |
| in progress | |
| inactive | |
| maintenance | |
| merged | |
| needs example | |
| needs more info | |
| needs rebase | |
| needs reproduction | |
| needs review | |
| performance issue | |
| presets | |
| question / support | |
| ready | |
| security | |
| todo | |
| typescript | |
| ui | |
| won't fix | |
| label name | purpose |
| :----------------------------: | :----------------------------------------------------------------- |
| accessibility | |
| addon:(name) | |
| app:(name) | |
| api:(name) | |
| cleanup | Minor cleanup style change that won't show up in release changelog |
| bug | |
| cli | |
| good first review | |
| compatibility with other tools | |
| patch | Bugfix & documentation PR that need to be picked to release branch |
| picked | Patch PRs cherry-picked to master |
| compatibility with other tools | |
| components | |
| core | |
| decorators | |
| dependencies:update | |
| dependencies | |
| discussion | |
| do not merge | |
| documentation | |
| feature request | |
| good first issue | |
| has workaround | |
| help wanted | |
| high priority | |
| in progress | |
| inactive | |
| maintenance | |
| merged | |
| needs example | |
| needs more info | |
| needs rebase | |
| needs reproduction | |
| needs review | |
| performance issue | |
| presets | |
| question / support | |
| ready | |
| security | |
| todo | |
| typescript | |
| ui | |
| won't fix | |
1 change: 0 additions & 1 deletion addons/docs/src/frameworks/svelte/extractArgTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export const createArgTypes = (docs: Docgen) => {
},
};
});

return results;
};

Expand Down
20 changes: 20 additions & 0 deletions app/svelte/src/client/components/Meta.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script>
import { getRegister } from './context';
export let title;
export let decorators;
export let parameters;
export let argTypes;
export let component;
const register = getRegister();
if (register) {
register.addMeta({
title,
component,
decorators,
parameters,
argTypes,
});
}
</script>

<slot />
8 changes: 8 additions & 0 deletions app/svelte/src/client/components/RegisterContext.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import { setRegister } from './context';
export let Stories;
export let register;
setRegister(register);
</script>

<svelte:component this={Stories} />
23 changes: 23 additions & 0 deletions app/svelte/src/client/components/Story.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script>
import { getRegister } from './context';
export let name;
export let decorators;
export let parameters;
export let argTypes;
export let component;
if (!name) {
throw new Error('Missing Story name');
}
const register = getRegister();
if (register) {
register.addStory({
name,
component,
decorators,
parameters,
argTypes,
});
}
</script>

<slot />
7 changes: 7 additions & 0 deletions app/svelte/src/client/components/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getContext, setContext } from 'svelte';

const REGISTER = '__STORYBOOK_register';

export const setRegister = (value: any) => setContext(REGISTER, value);

export const getRegister = () => getContext(REGISTER);
104 changes: 104 additions & 0 deletions app/svelte/src/client/extract-csf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* eslint-env browser */
import RegisterContext from './components/RegisterContext.svelte';

// This is the name that will be used for the story named 'default'.
//
// If the `_default` export is already taken (by a user's own named export), then
// a numeric index will be appended and increased until a free name is found.
//
// TODO What's the officially recommended default name?
//
const canonicalDefaultName = '_default';

const createFragment = document.createDocumentFragment
? () => document.createDocumentFragment()
: () => document.createElement('div');

const defaultStoryName = (xports: { [x: string]: any }) => {
if (!xports[canonicalDefaultName]) {
return canonicalDefaultName;
}
let lastDefaultIndex = 0;
let name;
do {
lastDefaultIndex += 1;
name = `${canonicalDefaultName}${lastDefaultIndex}`;
} while (xports[name] !== undefined);
return name;
};

// Extracts CSF from a Svelte component's `module.exports` object. The returned
// value is expected to be used to replace the component's `module.exports` in
// order to turn the component module into a proper CSF module.
export default (xports: { default?: any }) => {
const Stories = xports.default;
const result: {
default?: any;
[key: string]: any;
} = {};

const register = {
addMeta: (config: any) => {
if (result.default) {
throw new Error('Only one meta component is allowed per stories file');
}

result.default = config;
},
addStory: (story: {
name: any;
component: any;
parameters: any;
decorators: any;
argTypes: any;
}) => {
const { name, parameters, decorators, argTypes, component } = story;

const storyFn = (args: any) => {
return {
Component: component || result.default.component,
props: args,
};
};
if (name) {
storyFn.storyName = name;
}
if (parameters) {
storyFn.parameters = parameters;
}
if (decorators) {
storyFn.decorators = decorators;
}
if (argTypes) {
storyFn.argTypes = argTypes;
}

const prop = name === 'default' ? defaultStoryName(xports) : name;
result[prop] = storyFn;
},
};

// run a register phase to render Story and Meta components that will
// register themselves
const cmp = new RegisterContext({
target: createFragment(),
props: {
Stories,
register,
},
});
cmp.$destroy();

// goal: not having an error while a stories file is still empty (when it has
// just been created)
if (!result.default) {
return xports;
}
if (!result.default.title) {
throw new Error('Meta component with title is required');
}

result.default.excludeStories = Object.keys(xports).filter((name) => name !== 'default');

return { ...xports, ...result };
};
3 changes: 3 additions & 0 deletions app/svelte/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export {
raw,
} from './preview';

export { default as Meta } from './components/Meta.svelte';
export { default as Story } from './components/Story.svelte';

if (module && module.hot && module.hot.decline) {
module.hot.decline();
}
16 changes: 16 additions & 0 deletions app/svelte/src/server/document.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

# steps

yes before compile
you take Stories.svelte
you run all the preprocessors you need (or pass them to the parse, I don't remember exactly)
you still have some Svelte code
now you parse, you get AST
you remove every other story components
(like replacing everything with spaces, so source positions / maps stay the same)
that gives you a single story component
still Svelte code
now you compile that
gives you a compiled Svelte component, in the form of an ES module
you export that as export { default as my_story } from './my-virtual-story.svelte
mission complete
22 changes: 21 additions & 1 deletion app/svelte/src/server/framework-preset-svelte.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Configuration } from 'webpack'; // eslint-disable-line
import type { Configuration } from 'webpack';

export function webpack(config: Configuration) {
return {
Expand All @@ -7,11 +7,31 @@ export function webpack(config: Configuration) {
...config.module,
rules: [
...config.module.rules,

{
test: /\.(svelte|html)$/,
loader: require.resolve('svelte-loader'),
options: {},
},
{
test: /\.stories\.svelte$/,
enforce: 'post',
use: [
{
loader: require.resolve('./svelte-stories-loader'),
},
// svelte-stories-loader needs the stories component to be exported as
// CommonJS in order to be able to dynamically generate exports for CSF.
//
// TODO the babel loader could be merged into the main babel for perf
{
loader: require.resolve('babel-loader'),
options: {
plugins: ['transform-es2015-modules-commonjs'],
},
},
],
},
],
},
resolve: {
Expand Down
19 changes: 19 additions & 0 deletions app/svelte/src/server/svelte-stories-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const extractCsf = require.resolve('../client/extract-csf.js');

const post = `
{
const { default: extractCsf } = require('${posixify(extractCsf)}');
module.exports = extractCsf(exports)
}
`;

function posixify(file: string) {
return file.replace(/[/\\]/g, '/');
}

function svelteStoriesLoader(code: string, map: any) {
const transformedCode = code + post;
return transformedCode;
}

export default svelteStoriesLoader;
1 change: 1 addition & 0 deletions app/svelte/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
declare module '@storybook/core/*';
declare module 'global';
declare module '*.svelte';
8 changes: 2 additions & 6 deletions app/svelte/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
"types": ["webpack-env"],
"resolveJsonModule": true
},
"include": [
"src/**/*"
],
"exclude": [
"src/**/*.test.*"
]
"include": ["src/**/*"],
"exclude": ["src/**/*.test.*"]
}
Loading