storybook-addon-design-system-docs 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Storybook contributors
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 ADDED
@@ -0,0 +1,108 @@
1
+ # Storybook Addon Design System Docs
2
+
3
+ Automate your Design System documentation using your Tailwind CSS configuration and asset folders.
4
+
5
+ ![License](https://img.shields.io/npm/l/storybook-addon-design-system-docs)
6
+ ![Version](https://img.shields.io/npm/v/storybook-addon-design-system-docs)
7
+
8
+ ## Features
9
+
10
+ - 🎨 **Tailwind CSS Integration**: Automatically generates "Colors", "Typography", "Spacing", "Shadows", and more documentation pages directly from your `tailwind.config.js`.
11
+ - 🖼️ **Asset Gallery**: Auto-generates asset documentation (Icons, Illustrations) from your file system.
12
+ - ⚡ **Zero Config**: Works out of the box with sensible defaults.
13
+ - 🔧 **Customizable**: Override templates, customize the sidebar, and filter assets.
14
+ - 🖌️ **Theming**: Supports Light/Dark mode variants for assets.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install -D storybook-addon-design-system-docs
20
+ # or
21
+ yarn add -D storybook-addon-design-system-docs
22
+ # or
23
+ pnpm add -D storybook-addon-design-system-docs
24
+ # or
25
+ bun add -D storybook-addon-design-system-docs
26
+ ```
27
+
28
+ ## Setup
29
+
30
+ Add the addon to your `.storybook/main.ts` configuration:
31
+
32
+ ```ts
33
+ // .storybook/main.ts
34
+ import type { StorybookConfig } from '@storybook/react-vite';
35
+
36
+ const config: StorybookConfig = {
37
+ addons: [
38
+ {
39
+ name: 'storybook-addon-design-system-docs',
40
+ options: {
41
+ // REQUIRED: Path to your tailwind config
42
+ tailwindConfig: '../tailwind.config.js',
43
+
44
+ // Optional: Customize sidebar group name
45
+ sidebarGroup: 'Design System',
46
+
47
+ // Optional: Configure asset galleries
48
+ assets: [
49
+ {
50
+ name: 'Icons',
51
+ source: './src/assets/icons',
52
+ staticPath: '/assets/icons', // URL path to serve assets from
53
+ },
54
+ ],
55
+ },
56
+ },
57
+ // ... other addons
58
+ ],
59
+ };
60
+ export default config;
61
+ ```
62
+
63
+ ## Configuration
64
+
65
+ ### Options
66
+
67
+ | Option | Type | Required | Default | Description |
68
+ | ---------------- | -------------- | -------- | ------------------ | ------------------------------------------ |
69
+ | `tailwindConfig` | `string` | **Yes** | - | Path to `tailwind.config.js` |
70
+ | `sidebarGroup` | `string` | No | `'Design System/'` | Sidebar group name for generated docs |
71
+ | `assets` | `AssetGroup[]` | No | `[]` | List of asset groups to generate |
72
+ | `showOnlyCustom` | `boolean` | No | `false` | If true, only shows custom Tailwind values |
73
+
74
+ ### Asset Configuration
75
+
76
+ ```ts
77
+ assets: [
78
+ {
79
+ name: 'Icons', // Display name
80
+ source: './src/icons', // Source directory (relative to project root)
81
+ staticPath: '/icons', // URL path (must match where you serve static files or let addon handle it)
82
+ variants: {
83
+ // Optional variants
84
+ enabled: true,
85
+ suffixes: ['.light', '.dark'],
86
+ },
87
+ display: {
88
+ // Optional display settings
89
+ layout: 'grid',
90
+ showFilename: true,
91
+ },
92
+ },
93
+ ];
94
+ ```
95
+
96
+ ## Contributing
97
+
98
+ We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
99
+
100
+ ## Credits
101
+
102
+ This project is a fork of [storybook-addon-tailwind-autodocs](https://github.com/matanio/storybook-addon-tailwind-autodocs) by [Matan Yosef](https://github.com/matanio).
103
+
104
+ > Thank you Matan for the initial implementation!
105
+
106
+ ## License
107
+
108
+ MIT © [Saulo Vallory](https://saulo.engineer) and [Matan Yosef](https://github.com/matanio)
@@ -0,0 +1,15 @@
1
+ import type { AssetGroupConfig, NormalizedAssetGroup } from "@/types";
2
+ /**
3
+ * Validates that the provided configurations meet minimum requirements.
4
+ * Throws an error if any configuration is invalid.
5
+ */
6
+ export declare function validateAssetConfig(configs: AssetGroupConfig[]): void;
7
+ /**
8
+ * Converts a single raw `AssetGroupConfig` into a `NormalizedAssetGroup`.
9
+ * Applies defaults for all optional fields and resolves paths.
10
+ */
11
+ export declare function normalizeAssetGroup(config: AssetGroupConfig, sidebarGroup?: string, configDir?: string): NormalizedAssetGroup;
12
+ /**
13
+ * Batch normalizes a list of asset configurations.
14
+ */
15
+ export declare function normalizeAssetConfigs(assetConfigs?: AssetGroupConfig[], sidebarGroup?: string, configDir?: string): NormalizedAssetGroup[];
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeAssetConfigs = exports.normalizeAssetGroup = exports.validateAssetConfig = void 0;
4
+ const path_1 = require("path");
5
+ const DEFAULT_VARIANT_CONFIG = {
6
+ enabled: true,
7
+ suffixes: ["-light", "-dark"],
8
+ defaultVariant: "light",
9
+ };
10
+ const DEFAULT_DISPLAY_CONFIG = {
11
+ layout: "grid",
12
+ columns: 4,
13
+ showFilename: true,
14
+ showPath: false,
15
+ previewSize: 128,
16
+ background: "checkerboard",
17
+ };
18
+ const DEFAULT_FILTER_CONFIG = {
19
+ include: ["**/*.svg"],
20
+ exclude: [],
21
+ };
22
+ /**
23
+ * Validates that the provided configurations meet minimum requirements.
24
+ * Throws an error if any configuration is invalid.
25
+ */
26
+ function validateAssetConfig(configs) {
27
+ if (!Array.isArray(configs)) {
28
+ throw new Error("assets must be an array");
29
+ }
30
+ for (const config of configs) {
31
+ if (!config.name || typeof config.name !== "string") {
32
+ throw new Error("Each asset group must have a name");
33
+ }
34
+ if (!config.source || typeof config.source !== "string") {
35
+ throw new Error(`Asset group "${config.name}" must have a source directory`);
36
+ }
37
+ }
38
+ }
39
+ exports.validateAssetConfig = validateAssetConfig;
40
+ /**
41
+ * Converts a single raw `AssetGroupConfig` into a `NormalizedAssetGroup`.
42
+ * Applies defaults for all optional fields and resolves paths.
43
+ */
44
+ function normalizeAssetGroup(config, sidebarGroup = "Assets/", configDir) {
45
+ // Normalize path
46
+ let storyPath = config.path ?? sidebarGroup;
47
+ if (storyPath.endsWith("/")) {
48
+ storyPath = `${storyPath}${config.name}`;
49
+ }
50
+ // Resolve source path relative to configDir
51
+ const source = path_1.default.isAbsolute(config.source)
52
+ ? config.source
53
+ : configDir
54
+ ? path_1.default.resolve(configDir, config.source)
55
+ : config.source;
56
+ // Normalize variants config
57
+ const variants = {
58
+ ...DEFAULT_VARIANT_CONFIG,
59
+ ...config.variants,
60
+ };
61
+ if (config.variants?.suffixes) {
62
+ variants.suffixes = config.variants.suffixes;
63
+ }
64
+ // Normalize display config
65
+ const display = {
66
+ ...DEFAULT_DISPLAY_CONFIG,
67
+ ...config.display,
68
+ };
69
+ // Normalize filter config
70
+ const filter = {
71
+ include: config.filter?.include ?? DEFAULT_FILTER_CONFIG.include,
72
+ exclude: config.filter?.exclude ?? DEFAULT_FILTER_CONFIG.exclude,
73
+ };
74
+ // Normalize copy config
75
+ const copy = config.copy ?? {};
76
+ // Determine static path: user-provided or fallback to addon-assets
77
+ const staticPath = config.staticPath ?? `/addon-assets/${config.name}`;
78
+ return {
79
+ name: config.name,
80
+ path: storyPath,
81
+ source,
82
+ staticPath,
83
+ title: config.title ?? config.name,
84
+ description: config.description,
85
+ variants,
86
+ display,
87
+ copy,
88
+ filter,
89
+ groupByFolder: config.groupByFolder ?? false,
90
+ };
91
+ }
92
+ exports.normalizeAssetGroup = normalizeAssetGroup;
93
+ /**
94
+ * Batch normalizes a list of asset configurations.
95
+ */
96
+ function normalizeAssetConfigs(assetConfigs = [], sidebarGroup = "Assets/", configDir) {
97
+ validateAssetConfig(assetConfigs);
98
+ return assetConfigs.map((config) => normalizeAssetGroup(config, sidebarGroup, configDir));
99
+ }
100
+ exports.normalizeAssetConfigs = normalizeAssetConfigs;
@@ -0,0 +1,11 @@
1
+ import type { NormalizedAddonOptions } from "@/core/primitives/types";
2
+ export interface GenerateAssetsOptions {
3
+ configDir: string;
4
+ assets: any[];
5
+ addonOptions: NormalizedAddonOptions;
6
+ }
7
+ /**
8
+ * Generates physical MDX files for each configured asset group.
9
+ * These files are written to .storybook/design-system/assets/ and added to stories.
10
+ */
11
+ export declare function generateAssetStories(options: GenerateAssetsOptions): string[];
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateAssetStories = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const Logger_1 = require("@/util/Logger");
7
+ const resolveTemplate_1 = require("@/util/resolveTemplate");
8
+ const logger = new Logger_1.Logger("AssetGenerator");
9
+ /**
10
+ * Generates physical MDX files for each configured asset group.
11
+ * These files are written to .storybook/design-system/assets/ and added to stories.
12
+ */
13
+ function generateAssetStories(options) {
14
+ const { configDir, assets, addonOptions } = options;
15
+ const generatedStories = [];
16
+ if (!assets || !Array.isArray(assets) || assets.length === 0) {
17
+ return [];
18
+ }
19
+ const assetsDir = path_1.default.resolve(configDir, "design-system/assets");
20
+ // Ensure directory exists
21
+ if (!fs_1.default.existsSync(assetsDir)) {
22
+ fs_1.default.mkdirSync(assetsDir, { recursive: true });
23
+ }
24
+ // Load template
25
+ let templateContent = "";
26
+ const templatePath = (0, resolveTemplate_1.resolveTemplate)("assets", addonOptions);
27
+ if (fs_1.default.existsSync(templatePath)) {
28
+ try {
29
+ templateContent = fs_1.default.readFileSync(templatePath, "utf-8");
30
+ }
31
+ catch (e) {
32
+ logger.error(`Failed to read assets template at ${templatePath}`, e);
33
+ }
34
+ }
35
+ if (!templateContent) {
36
+ logger.warn("Could not find assets.mdx template");
37
+ return [];
38
+ }
39
+ // Generate files for each group
40
+ const validFiles = new Set();
41
+ assets.forEach((group) => {
42
+ const groupName = group.name;
43
+ const groupTitle = group.title || groupName;
44
+ // Sanitize filename
45
+ const cleanName = groupName.replace(/[^a-zA-Z0-9]/g, "");
46
+ const filename = `${cleanName}.mdx`;
47
+ const filePath = path_1.default.join(assetsDir, filename);
48
+ // Interpolate template
49
+ const fileContent = templateContent
50
+ .replace(/\{\{group\.name\}\}/g, groupName)
51
+ .replace(/\{\{group\.title\}\}/g, groupTitle);
52
+ try {
53
+ fs_1.default.writeFileSync(filePath, fileContent);
54
+ validFiles.add(filename);
55
+ generatedStories.push(filePath);
56
+ }
57
+ catch (e) {
58
+ logger.error(`Failed to write asset MDX for group ${groupName}`, e);
59
+ }
60
+ });
61
+ // Cleanup orphaned files
62
+ if (fs_1.default.existsSync(assetsDir)) {
63
+ try {
64
+ const files = fs_1.default.readdirSync(assetsDir);
65
+ files.forEach((file) => {
66
+ if (file.endsWith(".mdx") && !validFiles.has(file)) {
67
+ fs_1.default.unlinkSync(path_1.default.join(assetsDir, file));
68
+ }
69
+ });
70
+ }
71
+ catch (e) {
72
+ logger.warn("Failed to cleanup orphaned asset files", e);
73
+ }
74
+ }
75
+ return generatedStories;
76
+ }
77
+ exports.generateAssetStories = generateAssetStories;
@@ -0,0 +1,7 @@
1
+ export * from "@/core/primitives/config";
2
+ export * from "@/core/primitives/data";
3
+ export * from "@/core/primitives/load";
4
+ export * from "@/core/primitives/loaders/tw-config";
5
+ export * from "@/core/primitives/loaders/tw-css";
6
+ export * from "@/core/primitives/parsers/theme-css";
7
+ export * from "@/core/primitives/types";
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("@/core/primitives/config"), exports);
18
+ __exportStar(require("@/core/primitives/data"), exports);
19
+ __exportStar(require("@/core/primitives/load"), exports);
20
+ __exportStar(require("@/core/primitives/loaders/tw-config"), exports);
21
+ __exportStar(require("@/core/primitives/loaders/tw-css"), exports);
22
+ __exportStar(require("@/core/primitives/parsers/theme-css"), exports);
23
+ __exportStar(require("@/core/primitives/types"), exports);
@@ -0,0 +1,130 @@
1
+ import type { NormalizedSection, TemplateConfig } from "@/types";
2
+ /**
3
+ * Normalized configuration for the Design System Addon.
4
+ * This is the internal representation of the options after validation and defaults.
5
+ */
6
+ export interface NormalizedAddonOptions {
7
+ /** The validated Tailwind config path */
8
+ tailwindConfig: string;
9
+ /** The base sidebar group name (e.g., "Design System/") */
10
+ sidebarGroup: string;
11
+ /** The list of enabled and normalized primitive sections */
12
+ sections: NormalizedSection[];
13
+ /** Optional configuration for forcing all primitives into a single document */
14
+ forceSingleDoc?: NormalizedSection;
15
+ /** Whether to hide default Tailwind values */
16
+ showOnlyCustom: boolean;
17
+ /** Typography configuration */
18
+ typography?: {
19
+ example?: string;
20
+ };
21
+ /** Template engine configuration */
22
+ templates?: TemplateConfig;
23
+ }
24
+ /**
25
+ * Represents a single color definition in the theme.
26
+ */
27
+ export interface ColorData {
28
+ /** The base name of the color (e.g., 'blue') */
29
+ baseName: string;
30
+ /** A record of shades where key is the shade level (e.g., '500') and value is the hex code */
31
+ shades: Record<string, string>;
32
+ /** A descriptive subtitle for the color group */
33
+ subtitle: string;
34
+ /** Whether this color is a custom definition (not in base Tailwind) */
35
+ isCustom: boolean;
36
+ /** Whether this color extends an existing Tailwind color */
37
+ isExtended: boolean;
38
+ /** Whether this is a default Tailwind color */
39
+ isDefault: boolean;
40
+ }
41
+ /**
42
+ * Context data for rendering the colors section.
43
+ */
44
+ export interface ColorsContext {
45
+ /** All color definitions */
46
+ colors: ColorData[];
47
+ /** Colors marked as custom/extended */
48
+ customColors: ColorData[];
49
+ /** Colors from Tailwind defaults */
50
+ builtInColors: ColorData[];
51
+ /** Whether there are any colors to display */
52
+ hasColors: boolean;
53
+ }
54
+ /**
55
+ * Context data for rendering the typography section.
56
+ */
57
+ export interface TypographyContext {
58
+ /** Font family definitions as pairs of [label, fontFamily] */
59
+ fontFamilies: [string, string][];
60
+ /** Custom font families defined in the theme */
61
+ customFamilies: [string, string][];
62
+ /** Standard Tailwind built-in font families (sans, serif, mono) */
63
+ builtInFamilies: [string, string][];
64
+ /** Font weight definitions as pairs of [label, value] */
65
+ fontWeights: [string, string][];
66
+ /** Font size definitions as pairs of [label, value] */
67
+ fontSizes: [string, string][];
68
+ /** Whether there are any font families to display */
69
+ hasFontFamily: boolean;
70
+ /** All weight keys available for filter state initialization */
71
+ allWeightKeys: string[];
72
+ /** All size keys available for filter state initialization */
73
+ allSizeKeys: string[];
74
+ }
75
+ /**
76
+ * Context data for rendering the spacing section.
77
+ */
78
+ export interface SpacingContext {
79
+ /** Spacing value entries as pairs of [label, value] */
80
+ entries: [string, string][];
81
+ /** Whether there are any spacing values to display */
82
+ hasSpacing: boolean;
83
+ /** The maximum numeric value in the entries, used for bar chart scaling */
84
+ maxValue: number;
85
+ }
86
+ /**
87
+ * Context data for rendering the shadows section.
88
+ */
89
+ export interface ShadowsContext {
90
+ /** Shadow value entries as pairs of [label, value] */
91
+ entries: [string, string][];
92
+ /** Whether there are any shadow values to display */
93
+ hasShadows: boolean;
94
+ }
95
+ /**
96
+ * Context data for rendering the border radius section.
97
+ */
98
+ export interface RadiusContext {
99
+ /** Border radius entries as pairs of [label, value] */
100
+ entries: [string, string][];
101
+ /** Whether there are any border radius values to display */
102
+ hasRadius: boolean;
103
+ }
104
+ /**
105
+ * Main context for theme template rendering, combining all section contexts and global settings.
106
+ */
107
+ export interface DesignSystemData {
108
+ /** List of section names that are currently enabled */
109
+ enabledSections: string[];
110
+ /** Whether to show only custom values, hiding default Tailwind tokens */
111
+ showOnlyCustom: boolean;
112
+ /** Default text to use for typography samples */
113
+ defaultSampleText: string;
114
+ /** Whether to use optimized React components for rendering */
115
+ useReactComponents: boolean;
116
+ /** Whether to force generation of a single documentation story instead of individual ones */
117
+ forceSingleDoc: boolean;
118
+ /** The sanitized export name when in single-story mode */
119
+ exportName?: string;
120
+ /** Context for the colors documentation section */
121
+ colors: ColorsContext;
122
+ /** Context for the typography documentation section */
123
+ typography: TypographyContext;
124
+ /** Optional context for the spacing documentation section */
125
+ spacing?: SpacingContext;
126
+ /** Optional context for the shadows documentation section */
127
+ shadows?: ShadowsContext;
128
+ /** Optional context for the border radius documentation section */
129
+ borderRadius?: RadiusContext;
130
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ // Minimal manager entry point
2
+ console.log('[MANAGER] Manager loaded');