@vyriy/storybook-config 0.3.4 → 0.3.8
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/README.md +33 -1
- package/mermaid-markdown.d.ts +4 -0
- package/mermaid-markdown.js +80 -0
- package/package.json +15 -3
- package/preview.d.ts +8 -0
- package/preview.js +17 -3
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ export { default } from '@vyriy/storybook-config/preview';
|
|
|
56
56
|
If you customize preview locally, the preview module also exposes `Preview`.
|
|
57
57
|
|
|
58
58
|
```ts
|
|
59
|
-
import config, { type Preview } from '@vyriy/storybook-config/
|
|
59
|
+
import config, { type Preview } from '@vyriy/storybook-config/preview';
|
|
60
60
|
|
|
61
61
|
const preview: Preview = {
|
|
62
62
|
...config,
|
|
@@ -64,6 +64,38 @@ const preview: Preview = {
|
|
|
64
64
|
};
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
When a project needs custom docs themes, use `createThemedDocsContainer` so shared Markdown behavior stays enabled.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import config, { createThemedDocsContainer, type Preview } from '@vyriy/storybook-config/preview';
|
|
71
|
+
import themeDark from './theme-dark';
|
|
72
|
+
import themeLight from './theme-light';
|
|
73
|
+
|
|
74
|
+
const preview: Preview = {
|
|
75
|
+
...config,
|
|
76
|
+
parameters: {
|
|
77
|
+
...config.parameters,
|
|
78
|
+
docs: {
|
|
79
|
+
container: createThemedDocsContainer({
|
|
80
|
+
dark: themeDark,
|
|
81
|
+
light: themeLight,
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The shared preview container configures Storybook `Markdown` blocks to render Mermaid fenced code blocks.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import Structure from './STRUCTURE.md?raw';
|
|
92
|
+
import { Markdown } from '@storybook/addon-docs/blocks';
|
|
93
|
+
|
|
94
|
+
<Markdown>{Structure}</Markdown>;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The underlying renderer is also available as `@vyriy/storybook-config/mermaid-markdown` for custom docs surfaces outside the shared preview container.
|
|
98
|
+
|
|
67
99
|
## Current Vyriy Usage
|
|
68
100
|
|
|
69
101
|
In this repository:
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Markdown } from '@storybook/addon-docs/blocks';
|
|
3
|
+
import { useDarkMode } from '@vueless/storybook-dark-mode';
|
|
4
|
+
import mermaid from 'mermaid';
|
|
5
|
+
import { useEffect, useId, useMemo, useState } from 'react';
|
|
6
|
+
const mermaidBlockPattern = /```mermaid\s*\n([\s\S]*?)```/g;
|
|
7
|
+
const parseMarkdownParts = (markdown) => {
|
|
8
|
+
const parts = [];
|
|
9
|
+
let cursor = 0;
|
|
10
|
+
for (const match of markdown.matchAll(mermaidBlockPattern)) {
|
|
11
|
+
const [block, diagram] = match;
|
|
12
|
+
const { index } = match;
|
|
13
|
+
if (index > cursor) {
|
|
14
|
+
parts.push({
|
|
15
|
+
content: markdown.slice(cursor, index),
|
|
16
|
+
key: `markdown-${cursor}-${index}`,
|
|
17
|
+
type: 'markdown',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
parts.push({
|
|
21
|
+
content: diagram.trim(),
|
|
22
|
+
key: `mermaid-${index}`,
|
|
23
|
+
type: 'mermaid',
|
|
24
|
+
});
|
|
25
|
+
cursor = index + block.length;
|
|
26
|
+
}
|
|
27
|
+
if (cursor < markdown.length) {
|
|
28
|
+
parts.push({
|
|
29
|
+
content: markdown.slice(cursor),
|
|
30
|
+
key: `markdown-${cursor}-${markdown.length}`,
|
|
31
|
+
type: 'markdown',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return parts;
|
|
35
|
+
};
|
|
36
|
+
const MermaidDiagram = ({ chart }) => {
|
|
37
|
+
const id = `mermaid-${useId().replaceAll(':', '')}`;
|
|
38
|
+
const isDark = useDarkMode();
|
|
39
|
+
const [svg, setSvg] = useState('');
|
|
40
|
+
const [error, setError] = useState();
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
let mounted = true;
|
|
43
|
+
mermaid.initialize({
|
|
44
|
+
securityLevel: 'strict',
|
|
45
|
+
startOnLoad: false,
|
|
46
|
+
theme: isDark ? 'dark' : 'default',
|
|
47
|
+
});
|
|
48
|
+
void mermaid
|
|
49
|
+
.render(id, chart)
|
|
50
|
+
.then(({ svg: renderedSvg }) => {
|
|
51
|
+
if (!mounted) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setError(undefined);
|
|
55
|
+
setSvg(renderedSvg);
|
|
56
|
+
})
|
|
57
|
+
.catch((unknownError) => {
|
|
58
|
+
if (!mounted) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
setSvg('');
|
|
62
|
+
setError(unknownError instanceof Error ? unknownError.message : 'Unable to render Mermaid diagram.');
|
|
63
|
+
});
|
|
64
|
+
return () => {
|
|
65
|
+
mounted = false;
|
|
66
|
+
};
|
|
67
|
+
}, [
|
|
68
|
+
chart,
|
|
69
|
+
id,
|
|
70
|
+
isDark,
|
|
71
|
+
]);
|
|
72
|
+
if (error) {
|
|
73
|
+
return (_jsx("pre", { children: _jsx("code", { children: error }) }));
|
|
74
|
+
}
|
|
75
|
+
return (_jsx("div", { className: "vyriy-mermaid", dangerouslySetInnerHTML: { __html: svg } }));
|
|
76
|
+
};
|
|
77
|
+
export const MermaidMarkdown = ({ children }) => {
|
|
78
|
+
const parts = useMemo(() => parseMarkdownParts(children), [children]);
|
|
79
|
+
return (_jsx(_Fragment, { children: parts.map((part) => part.type === 'mermaid' ? (_jsx(MermaidDiagram, { chart: part.content }, part.key)) : (_jsx(Markdown, { children: part.content }, part.key))) }));
|
|
80
|
+
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vyriy/storybook-config",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Shared Storybook config for Vyriy projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
7
7
|
"dependencies": {
|
|
8
|
+
"@mdx-js/react": "^3.1.1",
|
|
8
9
|
"@storybook/addon-a11y": "^10.4.0",
|
|
9
10
|
"@storybook/addon-docs": "^10.4.0",
|
|
10
11
|
"@storybook/addon-themes": "^10.4.0",
|
|
@@ -12,16 +13,17 @@
|
|
|
12
13
|
"@storybook/react-webpack5": "^10.4.0",
|
|
13
14
|
"@vueless/storybook-dark-mode": "^10.0.8",
|
|
14
15
|
"css-loader": "^7.1.4",
|
|
16
|
+
"mermaid": "^11.15.0",
|
|
15
17
|
"react": "^19.2.6",
|
|
16
18
|
"react-dom": "^19.2.6",
|
|
17
19
|
"sass": "^1.99.0",
|
|
18
|
-
"sass-loader": "^
|
|
20
|
+
"sass-loader": "^17.0.0",
|
|
19
21
|
"storybook": "^10.4.0",
|
|
20
22
|
"storybook-addon-pseudo-states": "^10.4.0",
|
|
21
23
|
"storybook-addon-tag-badges": "^3.1.0",
|
|
22
24
|
"style-loader": "^4.0.0",
|
|
23
25
|
"typescript": "^6.0.3",
|
|
24
|
-
"webpack": "^5.
|
|
26
|
+
"webpack": "^5.107.0"
|
|
25
27
|
},
|
|
26
28
|
"agents": "./AGENTS.md",
|
|
27
29
|
"license": "MIT",
|
|
@@ -47,6 +49,16 @@
|
|
|
47
49
|
"import": "./main.js",
|
|
48
50
|
"default": "./main.js"
|
|
49
51
|
},
|
|
52
|
+
"./mermaid-markdown": {
|
|
53
|
+
"types": "./mermaid-markdown.d.ts",
|
|
54
|
+
"import": "./mermaid-markdown.js",
|
|
55
|
+
"default": "./mermaid-markdown.js"
|
|
56
|
+
},
|
|
57
|
+
"./mermaid-markdown.js": {
|
|
58
|
+
"types": "./mermaid-markdown.d.ts",
|
|
59
|
+
"import": "./mermaid-markdown.js",
|
|
60
|
+
"default": "./mermaid-markdown.js"
|
|
61
|
+
},
|
|
50
62
|
"./preview": {
|
|
51
63
|
"types": "./preview.d.ts",
|
|
52
64
|
"import": "./preview.js",
|
package/preview.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { Preview as ReactWebpackPreview } from '@storybook/react-webpack5';
|
|
2
|
+
import { type DocsContainerProps } from '@storybook/addon-docs/blocks';
|
|
3
|
+
import { type PropsWithChildren } from 'react';
|
|
4
|
+
import { type ThemeVars } from 'storybook/theming';
|
|
2
5
|
export type { Preview } from '@storybook/react-webpack5';
|
|
6
|
+
export type DocsThemes = {
|
|
7
|
+
readonly dark: ThemeVars;
|
|
8
|
+
readonly light: ThemeVars;
|
|
9
|
+
};
|
|
10
|
+
export declare const createThemedDocsContainer: (docsThemes: DocsThemes) => ({ children, context }: PropsWithChildren<DocsContainerProps>) => import("react/jsx-runtime").JSX.Element;
|
|
3
11
|
declare const preview: ReactWebpackPreview;
|
|
4
12
|
export default preview;
|
package/preview.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { MDXProvider } from '@mdx-js/react';
|
|
2
3
|
import { DocsContainer } from '@storybook/addon-docs/blocks';
|
|
4
|
+
import { lazy, Suspense } from 'react';
|
|
3
5
|
import { themes } from 'storybook/theming';
|
|
4
6
|
import { useDarkMode } from '@vueless/storybook-dark-mode';
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
return
|
|
7
|
+
const LazyMermaidMarkdown = lazy(async () => {
|
|
8
|
+
const { MermaidMarkdown } = await import('./mermaid-markdown.js');
|
|
9
|
+
return { default: MermaidMarkdown };
|
|
10
|
+
});
|
|
11
|
+
const MermaidMarkdownOverride = ({ children }) => (_jsx(Suspense, { fallback: null, children: _jsx(LazyMermaidMarkdown, { children: children }) }));
|
|
12
|
+
export const createThemedDocsContainer = (docsThemes) => {
|
|
13
|
+
const ThemedDocsContainer = ({ children, context }) => {
|
|
14
|
+
const isDark = useDarkMode();
|
|
15
|
+
return (_jsx(DocsContainer, { context: context, theme: isDark ? docsThemes.dark : docsThemes.light, children: _jsx(MDXProvider, { components: { Markdown: MermaidMarkdownOverride }, children: children }) }));
|
|
16
|
+
};
|
|
17
|
+
return ThemedDocsContainer;
|
|
8
18
|
};
|
|
19
|
+
const ThemedDocsContainer = createThemedDocsContainer({
|
|
20
|
+
dark: themes.dark,
|
|
21
|
+
light: themes.light,
|
|
22
|
+
});
|
|
9
23
|
const preview = {
|
|
10
24
|
tags: ['autodocs'],
|
|
11
25
|
argTypes: {
|