Storybook Design System Workflow
Overview
AzmX maintains two Storybook repositories for React applications and cross-platform UI components.
Repositories:
- dga-react-storybook-design-system - React-based design system (Vite + Storybook)
- platform-code-cross-platform-storybook - Stencil-based monorepo (React, Angular, HTML)
Technology Stack
DGA React Storybook
- React 18.3.1 + TypeScript 5.5.3
- Vite 5.4.1 + Storybook 7.6.17
- Package:
platformscode-new-reactv0.0.83
Cross-Platform Storybook
- Stencil 4.7.0 (Web Components)
- Targets: React, Angular, HTML
- Package Manager: pnpm workspace
- Package:
@platformscode/corev0.0.1
Repository Structure
DGA React Storybook
dga-react-storybook-design-system/
├── .storybook/ # Storybook config
├── src/stories/Components/ # Component stories
│ ├── Button/
│ ├── FileUpload/
│ └── Dropdown/
├── package.json
└── vite.config.ts
Cross-Platform Storybook
platform-code-cross-platform-storybook/
├── packages/
│ ├── core/ # Stencil components (source)
│ │ ├── src/components/
│ │ └── stencil.config.ts
│ ├── react/ # Auto-generated React wrappers
│ └── angular-workspace/
├── apps/
│ ├── react/ # React demo
│ └── demo-angular/ # Angular demo
└── pnpm-workspace.yaml
Component Development Workflow
graph TD
A[Identify Component Need] --> B{Which Repo?}
B -->|React Only| C[DGA React Storybook]
B -->|Cross-Platform| D[Platform Code Core]
C --> E[Create Component Story]
D --> F[Create Stencil Component]
F --> G[Build React Wrappers]
G --> E
E --> I[Write Story Variants]
I --> J[Add Documentation]
J --> K[Local Testing]
K --> L[Code Review]
L --> M[Merge to Main]
M --> N[Version & Publish]
N --> O[Update Main Projects]
Creating New Components
DGA React Storybook (React-Only)
1. Create Component Story
// src/stories/Components/MyComponent/MyComponent.stories.tsx
import { Meta, StoryObj } from "@storybook/react";
import { DgaMyComponent } from "platformscode-new-react";
const meta: Meta<typeof DgaMyComponent> = {
title: "Components/MyComponent",
component: DgaMyComponent,
tags: ["autodocs"],
argTypes: {
variant: {
control: "select",
options: ["primary", "secondary"],
},
disabled: { control: "boolean" },
onClick: { action: "onClick" },
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: { variant: "primary", label: "Click me" }
};
export const Disabled: Story = {
args: { variant: "primary", label: "Disabled", disabled: true }
};
2. Run Storybook
Cross-Platform Components (Stencil)
1. Generate Component
2. Create Stencil Component
// packages/core/src/components/dga-my-component/dga-my-component.tsx
import { Component, Prop, h, Event, EventEmitter } from '@stencil/core';
@Component({
tag: 'dga-my-component',
styleUrl: 'dga-my-component.scss',
shadow: false
})
export class DgaMyComponent {
@Prop() variant?: 'primary' | 'secondary' = 'primary';
@Prop() label?: string;
@Prop() disabled?: boolean = false;
@Event() onClick?: EventEmitter<MouseEvent>;
private handleClick(event: MouseEvent) {
if (!this.disabled) this.onClick.emit(event);
}
render() {
return (
<div
class={`component component--${this.variant}`}
onClick={(e: any) => this.handleClick(e)}
>
{this.label}
</div>
);
}
}
3. Build React Wrappers
Storybook Best Practices
Story Organization
// Use hierarchical naming
title: "Components/Forms/Input" // ✅ Good
title: "Input" // ❌ Too generic
// Enable autodocs
tags: ["autodocs"]
// Provide arg descriptions
argTypes: {
variant: {
description: "Visual style variant",
control: "select",
options: ["primary", "secondary"]
}
}
Story Variants
export const Default: Story = {};
export const WithIcon: Story = {
args: { leadIcon: true, leadIconType: "arrow-right" }
};
export const KitchenSink: Story = {
render: () => (
<div style={{ display: 'flex', gap: '16px' }}>
<DgaMyComponent variant="primary" label="Primary" />
<DgaMyComponent variant="secondary" label="Secondary" />
</div>
)
};
Interactive Controls
argTypes: {
onClick: { action: "onClick" },
variant: { control: "select" },
disabled: { control: "boolean" },
bgColor: { control: "color" },
}
Component Documentation
Each component should include a README:
# dga-my-component
Brief component description.
## Usage
### React
\`\`\`tsx
import { DgaMyComponent } from 'platformscode-new-react';
<DgaMyComponent variant="primary" label="Click me" />
\`\`\`
## Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| variant | 'primary' \| 'secondary' | 'primary' | Style variant |
| label | string | - | Button label |
| disabled | boolean | false | Disabled state |
## Events
| Event | Description |
|-------|-------------|
| onClick | Emitted when clicked |
Publishing and Versioning
Build and Publish Process
1. Build Components
2. Update Version (Semantic Versioning) - Patch (0.0.x): Bug fixes - Minor (0.x.0): New features, non-breaking changes - Major (x.0.0): Breaking API changes
3. Publish to NPM
Integration with Projects
React/Next.js Installation
// app/layout.tsx
import 'platformscode-new-react/dist/style.css';
import { DgaButton, DgaFileUpload } from 'platformscode-new-react';
export default function MyPage() {
return (
<DgaButton
variant="primary-brand"
label="Click me"
onClick={(e) => console.log('Clicked')}
/>
);
}
HTML Projects (Web Components)
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="node_modules/@platformscode/core/dist/platformscode/platformscode.css" />
<script type="module" src="node_modules/@platformscode/core/dist/platformscode/platformscode.esm.js"></script>
</head>
<body>
<dga-button variant="primary-neutral" label="Click Me"></dga-button>
<script>
document.querySelector('dga-button')
.addEventListener('onClick', (e) => console.log('Clicked', e));
</script>
</body>
</html>
Update to Latest Version
npm update platformscode-new-react
# Or specific version
npm install [email protected]
Cross-Platform Considerations
Framework-Specific Props
React (camelCase)
HTML (kebab-case)
<dga-button lead-icon="true"></dga-button>
<script>
el.addEventListener('onClick', (e) => console.log(e));
</script>
Common Patterns
Form Component with State
export const FileUploadForm: Story = {
render: () => {
const [files, setFiles] = React.useState([]);
return (
<DgaFileUpload
multiple={true}
accept="image/*,.pdf"
maximumFilesSize={5000000}
getUploadedFile={(e) => setFiles([...files, e.detail])}
/>
);
}
};
Troubleshooting
Component not appearing in Storybook
# Check .storybook/main.ts stories path
stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"]
# Restart Storybook
npm run storybook
Styles not loading in React
Cross-platform build fails
# Clean and rebuild
rm -rf packages/core/dist packages/react/dist
cd packages/core && npm run build
cd ../react && npm run build
Types not available
// package.json
{
"types": "dist/types/index.d.ts",
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"import": "./dist/index.js"
}
}
}
Quick Commands
# DGA React Storybook
npm run storybook # Dev server
npm run build-storybook # Build static
npm run build # Build library
# Cross-Platform Storybook
cd packages/core
npm run build # Build Stencil
npm run start # Watch mode
cd packages/react
npm run build # Build React
npm publish --access public # Publish NPM