@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 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/main';
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,4 @@
1
+ export type MermaidMarkdownProps = {
2
+ readonly children: string;
3
+ };
4
+ export declare const MermaidMarkdown: ({ children }: MermaidMarkdownProps) => import("react/jsx-runtime").JSX.Element;
@@ -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.4",
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": "^16.0.8",
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.106.2"
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 ThemedDocsContainer = ({ children, context }) => {
6
- const isDark = useDarkMode();
7
- return (_jsx(DocsContainer, { context: context, theme: isDark ? themes.dark : themes.light, children: children }));
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: {