{"_id":"@azure-fluent-storybook/components","_rev":"5-a28a391a8c28c9214497d296c170b51f","name":"@azure-fluent-storybook/components","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.1":{"name":"@azure-fluent-storybook/components","version":"0.1.1","license":"MIT","_id":"@azure-fluent-storybook/components@0.1.1","maintainers":[{"name":"unthink","email":"alex@unthinkmedia.com"}],"dist":{"shasum":"642fcb5e72ad5a628105e85e719ec18d3363aac6","tarball":"https://registry.npmjs.org/@azure-fluent-storybook/components/-/components-0.1.1.tgz","fileCount":8,"integrity":"sha512-/E5r8tGp4eICEJ+xYBUsxMUlBZxyuEqCQTUplyIULwZaSM3jxhk2VjphY6JKzbRrddyIl4CAw7BGVxdosub7mA==","signatures":[{"sig":"MEUCIERK5Cv7M6u0cnQJyEAQYj3yn9Ls+vAtcM43hJrSWbRwAiEA23yvXTOfuZKjJL2ItSz8qptdjOuBozzWas4Df7RK+n0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":652729},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"19e05ac94445c24f7a202677af8590c7a41b606a","scripts":{"dev":"storybook dev -p 6006","lint":"eslint 'src/**/*.{ts,tsx}'","build":"storybook build -o storybook-static","format":"prettier --write 'src/**/*.{ts,tsx,json,md}'","lint:fix":"eslint 'src/**/*.{ts,tsx}' --fix","audit:llm":"tsx scripts/audit-llm-strength.ts","build:all":"npm run build:registry && npm run build:llm && npm run build","build:lib":"tsup","build:llm":"tsx scripts/generate-llm-bundle.ts","chromatic":"chromatic --exit-zero-on-changes","format:check":"prettier --check 'src/**/*.{ts,tsx,json,md}'","build:registry":"tsx scripts/generate-registry.ts","extract-tokens":"tsx scripts/extract-tokens.ts","prepublishOnly":"npm run build:lib","test:storybook":"test-storybook"},"_npmUser":{"name":"unthink","email":"alex@unthinkmedia.com"},"_npmVersion":"10.9.3","description":"Azure Portal–styled Fluent v9 components and themes","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.5.1","vite":"^6.0.0","react":"^18.3.1","eslint":"^9.16.0","prettier":"^3.4.0","chromatic":"^11.22.0","react-dom":"^18.3.1","scheduler":"^0.27.0","storybook":"^10.2.16","typescript":"^5.7.0","@types/react":"^18.3.12","@storybook/react":"^10.2.16","@types/react-dom":"^18.3.1","eslint-plugin-react":"^7.37.0","@vitejs/plugin-react":"^4.3.4","@fluentui/react-icons":"^2.0.260","@storybook/addon-a11y":"^10.2.16","@storybook/addon-docs":"^10.2.16","@storybook/react-vite":"^10.2.16","@storybook/test-runner":"^0.24.2","eslint-config-prettier":"^9.1.0","@storybook/addon-themes":"^10.2.16","eslint-plugin-storybook":"^10.2.16","@typescript-eslint/parser":"^8.18.0","@fluentui/react-components":"^9.56.0","@typescript-eslint/eslint-plugin":"^8.18.0"},"peerDependencies":{"react":">=17.0.0","react-dom":">=17.0.0","@fluentui/react-icons":">=2.0.200","@fluentui/react-components":">=9.46.0"},"peerDependenciesMeta":{"@fluentui/react-icons":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/components_0.1.1_1773117323674_0.5637873296075526","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@azure-fluent-storybook/components","version":"0.1.2","license":"MIT","_id":"@azure-fluent-storybook/components@0.1.2","maintainers":[{"name":"unthink","email":"alex@unthinkmedia.com"}],"dist":{"shasum":"669794ff15d950782e592b369a2099ad12d1a27d","tarball":"https://registry.npmjs.org/@azure-fluent-storybook/components/-/components-0.1.2.tgz","fileCount":8,"integrity":"sha512-BG0GQLCRz6P0etSvTptM/FmMFMiw4rOLRxmeBROW4/+ofjkvoZd4jrXM63Jcqr9oyIQ+atQOG332hyzFxd61Lw==","signatures":[{"sig":"MEQCIC5Vudmz2aQcv0WqtXaiD99zqCspzRLD+fl4oyvFmxLnAiAF9ptQxw1Xl2vhhojOn1igc/hpmaPcBXEtfakRDI5big==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":705025},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"d8fe2f7750380e9aaa6a6b0606b3b0d12106efd9","scripts":{"dev":"storybook dev -p 6006","lint":"eslint 'src/**/*.{ts,tsx}'","build":"storybook build -o storybook-static","format":"prettier --write 'src/**/*.{ts,tsx,json,md}'","lint:fix":"eslint 'src/**/*.{ts,tsx}' --fix","audit:llm":"tsx scripts/audit-llm-strength.ts","build:all":"npm run build:registry && npm run build:llm && npm run build","build:lib":"tsup","build:llm":"tsx scripts/generate-llm-bundle.ts","chromatic":"chromatic --exit-zero-on-changes","format:check":"prettier --check 'src/**/*.{ts,tsx,json,md}'","build:registry":"tsx scripts/generate-registry.ts","extract-tokens":"tsx scripts/extract-tokens.ts","prepublishOnly":"npm run build:lib","test:storybook":"test-storybook"},"_npmUser":{"name":"unthink","email":"alex@unthinkmedia.com"},"_npmVersion":"10.9.3","description":"Azure Portal–styled Fluent v9 components and themes","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.5.1","vite":"^6.0.0","react":"^18.3.1","eslint":"^9.16.0","prettier":"^3.4.0","chromatic":"^11.22.0","react-dom":"^18.3.1","scheduler":"^0.27.0","storybook":"^10.2.16","typescript":"^5.7.0","@types/react":"^18.3.12","@storybook/react":"^10.2.16","@types/react-dom":"^18.3.1","eslint-plugin-react":"^7.37.0","@vitejs/plugin-react":"^4.3.4","@fluentui/react-icons":"^2.0.260","@storybook/addon-a11y":"^10.2.16","@storybook/addon-docs":"^10.2.16","@storybook/react-vite":"^10.2.16","@storybook/test-runner":"^0.24.2","eslint-config-prettier":"^9.1.0","@storybook/addon-themes":"^10.2.16","eslint-plugin-storybook":"^10.2.16","@typescript-eslint/parser":"^8.18.0","@fluentui/react-components":"^9.56.0","@typescript-eslint/eslint-plugin":"^8.18.0"},"peerDependencies":{"react":">=17.0.0","react-dom":">=17.0.0","@fluentui/react-icons":">=2.0.200","@fluentui/react-components":">=9.46.0"},"peerDependenciesMeta":{"@fluentui/react-icons":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/components_0.1.2_1773172185341_0.7373909962622796","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@azure-fluent-storybook/components","version":"0.2.0","license":"MIT","_id":"@azure-fluent-storybook/components@0.2.0","maintainers":[{"name":"unthink","email":"alex@unthinkmedia.com"}],"dist":{"shasum":"5bd200d1a621ce5d24a777f174612727bf77f6cb","tarball":"https://registry.npmjs.org/@azure-fluent-storybook/components/-/components-0.2.0.tgz","fileCount":8,"integrity":"sha512-njCDcjyxeeeYA8i2fT1gn4yV/wJ/n7rexpo64Q1AsPlA4fXfE/5MpNVI/TpRliTHc96OCvTi7zmdGZsR4srCWQ==","signatures":[{"sig":"MEYCIQCvcNgeMBunrz3SItrXEbovOUtBYOAlyaYnBGHtOxAjxwIhAJ4VphNwLXtbvBb68m5fO6PDBCFI6MdKqwqpWcCRn0WX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":780642},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"6ce8b2fd4399f4b36102dd6451a43def8027e83c","scripts":{"dev":"storybook dev -p 6006","lint":"eslint 'src/**/*.{ts,tsx}'","build":"storybook build -o storybook-static","format":"prettier --write 'src/**/*.{ts,tsx,json,md}'","lint:fix":"eslint 'src/**/*.{ts,tsx}' --fix","audit:llm":"tsx scripts/audit-llm-strength.ts","build:all":"npm run build:registry && npm run build:llm && npm run build","build:lib":"tsup","build:llm":"tsx scripts/generate-llm-bundle.ts","chromatic":"chromatic --exit-zero-on-changes","format:check":"prettier --check 'src/**/*.{ts,tsx,json,md}'","build:registry":"tsx scripts/generate-registry.ts","extract-tokens":"tsx scripts/extract-tokens.ts","prepublishOnly":"npm run build:lib","test:storybook":"test-storybook"},"_npmUser":{"name":"unthink","email":"alex@unthinkmedia.com"},"_npmVersion":"10.9.3","description":"Azure Portal–styled Fluent v9 components and themes","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.5.1","vite":"^6.0.0","react":"^18.3.1","eslint":"^9.16.0","prettier":"^3.4.0","chromatic":"^11.22.0","react-dom":"^18.3.1","scheduler":"^0.27.0","storybook":"^10.2.16","typescript":"^5.7.0","@types/react":"^18.3.12","@storybook/react":"^10.2.16","@types/react-dom":"^18.3.1","eslint-plugin-react":"^7.37.0","@vitejs/plugin-react":"^4.3.4","@fluentui/react-icons":"^2.0.260","@storybook/addon-a11y":"^10.2.16","@storybook/addon-docs":"^10.2.16","@storybook/react-vite":"^10.2.16","@storybook/test-runner":"^0.24.2","eslint-config-prettier":"^9.1.0","@storybook/addon-themes":"^10.2.16","eslint-plugin-storybook":"^10.2.16","@typescript-eslint/parser":"^8.18.0","@fluentui/react-components":"^9.56.0","@typescript-eslint/eslint-plugin":"^8.18.0"},"peerDependencies":{"react":">=17.0.0","react-dom":">=17.0.0","@fluentui/react-icons":">=2.0.200","@fluentui/react-components":">=9.46.0"},"peerDependenciesMeta":{"@fluentui/react-icons":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/components_0.2.0_1773277942235_0.6043689159716379","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@azure-fluent-storybook/components","version":"0.3.0","license":"MIT","_id":"@azure-fluent-storybook/components@0.3.0","maintainers":[{"name":"unthink","email":"alex@unthinkmedia.com"}],"dist":{"shasum":"b4e7c971722dbd4b6509866fafa84982d9946586","tarball":"https://registry.npmjs.org/@azure-fluent-storybook/components/-/components-0.3.0.tgz","fileCount":8,"integrity":"sha512-fk+IzJPFT69IppeYl+H16OkFunZeGgj1TjMVCYlqMwLExqCb34vlJ+4kOPZjnrLsZf4ZSymx28LXrOMo1qP2Fg==","signatures":[{"sig":"MEUCIBjQap2uRXRFN2RU6gN7uGxqKkYNa+Aory9cdaZ0VIPXAiEAu56tDqia1i9WsaMy+8JEcJzdbIJVWMCxVrd9xxZ42xI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":954965},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"ee92f682b8ea796c834281857a19d15cf3a43b5b","scripts":{"dev":"storybook dev -p 6006","lint":"eslint 'src/**/*.{ts,tsx}'","test":"vitest run","build":"storybook build -o storybook-static","format":"prettier --write 'src/**/*.{ts,tsx,json,md}'","lint:fix":"eslint 'src/**/*.{ts,tsx}' --fix","audit:llm":"tsx scripts/audit-llm-strength.ts","build:all":"npm run build:registry && npm run build:llm && npm run build","build:lib":"tsup","build:llm":"tsx scripts/generate-llm-bundle.ts","chromatic":"chromatic --exit-zero-on-changes","test:watch":"vitest","format:check":"prettier --check 'src/**/*.{ts,tsx,json,md}'","build:registry":"tsx scripts/generate-registry.ts","extract-tokens":"tsx scripts/extract-tokens.ts","prepublishOnly":"npm run build:lib","test:storybook":"test-storybook"},"_npmUser":{"name":"unthink","email":"alex@unthinkmedia.com"},"_npmVersion":"10.9.3","description":"Azure Portal–styled Fluent v9 components and themes","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0","tsup":"^8.5.1","vite":"^6.0.0","react":"^18.3.1","eslint":"^9.16.0","vitest":"^4.1.0","prettier":"^3.4.0","chromatic":"^11.22.0","react-dom":"^18.3.1","scheduler":"^0.27.0","storybook":"^10.2.16","agentation":"^2.3.2","typescript":"^5.7.0","@types/react":"^18.3.12","@storybook/react":"^10.2.16","@types/react-dom":"^18.3.1","eslint-plugin-react":"^7.37.0","@vitejs/plugin-react":"^4.3.4","@fluentui/react-icons":"^2.0.260","@storybook/addon-a11y":"^10.2.16","@storybook/addon-docs":"^10.2.16","@storybook/react-vite":"^10.2.16","@storybook/test-runner":"^0.24.2","eslint-config-prettier":"^9.1.0","@storybook/addon-themes":"^10.2.16","eslint-plugin-storybook":"^10.2.16","@typescript-eslint/parser":"^8.18.0","@fluentui/react-components":"^9.56.0","@typescript-eslint/eslint-plugin":"^8.18.0"},"peerDependencies":{"react":">=17.0.0","react-dom":">=17.0.0","@fluentui/react-icons":">=2.0.200","@fluentui/react-components":">=9.46.0"},"peerDependenciesMeta":{"@fluentui/react-icons":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/components_0.3.0_1773772504688_0.6826924874592493","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@azure-fluent-storybook/components","version":"0.4.0","description":"Azure Portal–styled Fluent v9 components and themes","license":"MIT","type":"module","main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"publishConfig":{"access":"public"},"sideEffects":false,"scripts":{"dev":"storybook dev -p 6006","build":"storybook build -o storybook-static","build:registry":"tsx scripts/generate-registry.ts","build:llm":"tsx scripts/generate-llm-bundle.ts","build:all":"npm run build:registry && npm run build:llm && npm run build","audit:llm":"tsx scripts/audit-llm-strength.ts","extract-tokens":"tsx scripts/extract-tokens.ts","lint":"eslint 'src/**/*.{ts,tsx}'","lint:fix":"eslint 'src/**/*.{ts,tsx}' --fix","format":"prettier --write 'src/**/*.{ts,tsx,json,md}'","format:check":"prettier --check 'src/**/*.{ts,tsx,json,md}'","test:storybook":"test-storybook","test":"vitest run","test:watch":"vitest","chromatic":"chromatic --exit-zero-on-changes","build:lib":"tsup","prepublishOnly":"npm run build:lib"},"devDependencies":{"@fluentui/react-components":"^9.56.0","@fluentui/react-icons":"^2.0.260","@storybook/addon-a11y":"^10.2.16","@storybook/addon-docs":"^10.2.16","@storybook/addon-themes":"^10.2.16","@storybook/react":"^10.2.16","@storybook/react-vite":"^10.2.16","@storybook/test-runner":"^0.24.2","@types/react":"^18.3.12","@types/react-dom":"^18.3.1","@typescript-eslint/eslint-plugin":"^8.18.0","@typescript-eslint/parser":"^8.18.0","@vitejs/plugin-react":"^4.3.4","agentation":"^2.3.2","chromatic":"^11.22.0","eslint":"^9.16.0","eslint-config-prettier":"^9.1.0","eslint-plugin-react":"^7.37.0","eslint-plugin-storybook":"^10.2.16","prettier":"^3.4.0","react":"^18.3.1","react-dom":"^18.3.1","scheduler":"^0.27.0","storybook":"^10.2.16","tsup":"^8.5.1","tsx":"^4.19.0","typescript":"^5.7.0","vite":"^6.0.0","vitest":"^4.1.0"},"peerDependencies":{"@fluentui/react-components":">=9.46.0","@fluentui/react-icons":">=2.0.200","react":">=17.0.0","react-dom":">=17.0.0"},"peerDependenciesMeta":{"@fluentui/react-icons":{"optional":true}},"_id":"@azure-fluent-storybook/components@0.4.0","gitHead":"fa6ced18fd2222e069ea0a079dcaa81b4dc96029","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-JAfeIQnLvVQGrcp8J7zWKdo7Jh9ri5+v7EE5ExQYuBHNX0g9lFLO23W33RjjslsmVDcF4xo0kIlx3fpjtiuPNw==","shasum":"3fc96f0b3c51d59e74b89f18d975636d7c317b0e","tarball":"https://registry.npmjs.org/@azure-fluent-storybook/components/-/components-0.4.0.tgz","fileCount":8,"unpackedSize":1137729,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC1OT394RIn0y8wU6/VI/rT1wdZobAyJEyrRTjlvKC6GgIgLAfTOt0p3Yu8NuqYqIbQOTZCi1rQORHHS4/XhxCtyEw="}]},"_npmUser":{"name":"unthink","email":"alex@unthinkmedia.com"},"directories":{},"maintainers":[{"name":"unthink","email":"alex@unthinkmedia.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/components_0.4.0_1774502121237_0.6549750646657826"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-10T04:35:23.603Z","modified":"2026-03-26T05:15:21.523Z","0.1.1":"2026-03-10T04:35:23.882Z","0.1.2":"2026-03-10T19:49:45.530Z","0.2.0":"2026-03-12T01:12:22.507Z","0.3.0":"2026-03-17T18:35:04.838Z","0.4.0":"2026-03-26T05:15:21.386Z"},"license":"MIT","description":"Azure Portal–styled Fluent v9 components and themes","maintainers":[{"name":"unthink","email":"alex@unthinkmedia.com"}],"readme":"# Azure Storybook\n\nFluent UI React v9 component library themed as Azure Portal, built with Storybook 10.\n\n## Quick Start\n\n```bash\nnpm install\nnpm run dev        # Start Storybook dev server\n```\n\n\n## Scripts\n\n| Command                  | Description                             |\n| ------------------------ | --------------------------------------- |\n| `npm run dev`            | Start Storybook dev server on port 6006 |\n| `npm run build`          | Build static Storybook site             |\n| `npm run build:registry` | Generate component-registry.json        |\n| `npm run build:all`      | Build registry + Storybook              |\n| `npm run lint`           | Run ESLint                              |\n| `npm run format`         | Run Prettier                            |\n| `npm run chromatic`      | Push to Chromatic for visual testing    |\n\n## Structure\n\n```\nsrc/\n├── components/          # Azure-specific composed components\n│   ├── AzureBreadcrumb.tsx\n│   ├── CommandBar.tsx\n│   ├── FilterBar.tsx\n│   └── PageTitleBar.tsx\n├── stories/\n│   ├── foundations/     # Design tokens: Colors, Typography, Spacing, Shadows\n│   ├── components/      # Fluent v9 components: Button, Input, Card, etc.\n│   ├── composed/        # Composed component stories\n│   └── templates/       # Full page templates (ResourceListPage)\n├── themes/\n│   ├── azureThemes.ts   # Azure light/dark/HC themes\n│   ├── coherenceTokens.ts # Structured token reference\n│   └── index.ts\n└── component-registry.json  # Auto-generated LLM context\n\nllm-context/             # LLM-optimized documentation\n├── azure-theme.md       # Theme tokens quick reference\n├── component-patterns.md # Azure composition patterns\n└── styling-guide.md     # Griffel + token usage guide\n\nscripts/\n├── extract-tokens.ts    # One-time token extraction from Coherence CDN\n└── generate-registry.ts # Story metadata → registry JSON\n```\n\n## Theme System\n\nThree themes extracted from Azure Portal's Coherence design system:\n\n- **Azure Light** — default, white background with Azure blue (#0f6cbd) brand\n- **Azure Dark** — dark mode with matching brand ramp\n- **High Contrast** — WCAG AAA compliant\n\nToggle themes in the Storybook toolbar.\n\n### Using the Theme System in a Consuming App\n\nInstall the package:\n\n```bash\nnpm install @azure-fluent-storybook/components @fluentui/react-components\n```\n\nThe package exposes a **3-axis theming system** matching the Storybook toolbar:\n\n| Axis | API | What it controls |\n| --- | --- | --- |\n| **Product** | `getAllProductThemes()` | Brand ramp + product-specific token overrides (Azure, SRE Agent) |\n| **Appearance** | `AppearanceMode` type | Light / Dark / High Contrast base |\n| **Design System** | `getAllSkins()` | Skin-level token overrides (Fluent 2, Coherence, Ibiza, Fluent 1, Azure Fluent, CoreAI) |\n\n#### List available products, appearances, and design systems\n\n```tsx\nimport {\n  getAllProductThemes,\n  getAllSkins,\n  type AppearanceMode,\n} from '@azure-fluent-storybook/components';\n\nconst products = getAllProductThemes();\n// → [{ id: 'azure', displayName: 'Azure', ... }, { id: 'sre-agent', ... }]\n\nconst skins = getAllSkins();\n// → [{ id: 'fluent2', displayName: 'Fluent 2' }, { id: 'coherence', ... }, ...]\n\nconst appearances: AppearanceMode[] = ['light', 'dark', 'high-contrast'];\n```\n\n#### Resolve a theme and render\n\n```tsx\nimport { FluentProvider } from '@fluentui/react-components';\nimport { resolveTheme } from '@azure-fluent-storybook/components';\nimport type { AppearanceMode, DesignSystemId } from '@azure-fluent-storybook/components';\n\nfunction App() {\n  const [product, setProduct] = useState('azure');\n  const [appearance, setAppearance] = useState<AppearanceMode>('light');\n  const [designSystem, setDesignSystem] = useState<DesignSystemId>('fluent2');\n\n  const theme = resolveTheme(product, appearance, designSystem);\n\n  return (\n    <FluentProvider theme={theme}>\n      {/* your app */}\n    </FluentProvider>\n  );\n}\n```\n\n#### Build a theme switcher\n\n```tsx\nimport {\n  getAllProductThemes,\n  getAllSkins,\n  resolveTheme,\n  type AppearanceMode,\n  type DesignSystemId,\n} from '@azure-fluent-storybook/components';\n\nfunction ThemeSwitcher({ onThemeChange }) {\n  const products = getAllProductThemes();\n  const skins = getAllSkins();\n  const appearances: AppearanceMode[] = ['light', 'dark', 'high-contrast'];\n\n  const [productId, setProductId] = useState('azure');\n  const [appearance, setAppearance] = useState<AppearanceMode>('light');\n  const [skinId, setSkinId] = useState<DesignSystemId>('fluent2');\n\n  useEffect(() => {\n    onThemeChange(resolveTheme(productId, appearance, skinId));\n  }, [productId, appearance, skinId]);\n\n  return (\n    <div style={{ display: 'flex', gap: 12 }}>\n      <select value={productId} onChange={e => setProductId(e.target.value)}>\n        {products.map(p => <option key={p.id} value={p.id}>{p.displayName}</option>)}\n      </select>\n      <select value={appearance} onChange={e => setAppearance(e.target.value as AppearanceMode)}>\n        {appearances.map(a => <option key={a} value={a}>{a}</option>)}\n      </select>\n      <select value={skinId} onChange={e => setSkinId(e.target.value as DesignSystemId)}>\n        {skins.map(s => <option key={s.id} value={s.id}>{s.displayName}</option>)}\n      </select>\n    </div>\n  );\n}\n```\n\n#### Register custom products or design system skins\n\n```tsx\nimport { registerProductTheme, registerSkin } from '@azure-fluent-storybook/components';\n\nregisterProductTheme({\n  id: 'my-product',\n  displayName: 'My Product',\n  description: 'Custom product theme',\n  brand: myBrandRamp,\n  lightOverrides: { /* ... */ },\n});\n\nregisterSkin({\n  id: 'my-skin' as DesignSystemId,\n  displayName: 'My Skin',\n  description: 'Custom design system',\n  sections: { colors: {}, shape: {}, elevation: {}, density: {}, typography: {} },\n});\n```\n\n## Component Taxonomy\n\n| Category        | Description                                                                    |\n| --------------- | ------------------------------------------------------------------------------ |\n| **Foundations** | Color swatches, typography scale, spacing, shadows                             |\n| **Components**  | Stock Fluent v9: Button, Input, Card, Dialog, DataGrid, DataDisplay, Selection |\n| **Composed**    | Azure-specific: Breadcrumb, PageTitleBar, CommandBar, FilterBar                |\n| **Templates**   | Full pages: ResourceListPage (resource list with all composed components)      |\n\n## LLM Optimization\n\nThis Storybook is designed for LLM context:\n\n- `.copilot-instructions.md` — project conventions for Copilot\n- `llm-context/` — structured docs for theme, patterns, and styling\n- `component-registry.json` — machine-readable component index\n- CSF3 stories with autodocs for self-documenting APIs\n\n## Deployment\n\nDeployed to Azure Static Web Apps via GitHub Actions.\n\nRequired secrets:\n\n- `AZURE_STATIC_WEB_APPS_API_TOKEN` — SWA deployment token\n- `CHROMATIC_PROJECT_TOKEN` — Chromatic project token\n\n## Agentation Integration\n\n> Stakeholders can annotate UI issues directly in the deployed Storybook. Annotations automatically become GitHub Issues assigned to GitHub Copilot for automated fix PRs.\n\n### Architecture\n\n```\nBrowser (Storybook)\n  → POST /api/feedback  (SWA managed function)\n  → GitHub repository_dispatch\n  → GitHub Actions (.github/workflows/agentation-feedback.yml)\n  → GitHub Issue (assigned to Copilot)\n  → Copilot PR\n```\n\n### Environment Variables\n\nSet the following in **Azure Portal → Static Web App → Configuration → Application Settings**:\n\n| Variable | Required | Description |\n| --- | --- | --- |\n| `GITHUB_TOKEN` | ✅ Yes | GitHub token with `contents: write` scope. Used by the `/api/feedback` proxy to trigger `repository_dispatch`. |\n\n**Recommended token types** (in order of preference):\n1. **GitHub App installation token** — longest-lived, fine-grained permissions\n2. **Fine-grained PAT** — set expiry to 1 year, scope to `unthinkmedia/AzureStorybook`, permission: `Contents: Read and write`\n3. **Classic PAT** — `repo` scope (broader than needed but works)\n\n> ⚠️ Never commit the token. Set it only in Azure Portal or as a GitHub Actions secret.\n\n### How Stakeholders Use It\n\n1. Visit the deployed Storybook at the Azure SWA URL\n2. Click the **Agentation toolbar** icon in the story canvas\n3. Click on any UI element to annotate it — add a comment describing the issue\n4. Click **\"Send Annotations\"** to submit all annotations as a single GitHub Issue\n5. The issue is auto-assigned to Copilot, which will create a fix PR\n\n### Local Development\n\nTo run the API function locally alongside Storybook:\n\n**Option A: Azure Functions Core Tools**\n```bash\n# Terminal 1 — Storybook\nnpm run dev\n\n# Terminal 2 — API function\ncd api\nnpm install\n# Create local settings (not committed)\necho '{\"IsEncrypted\":false,\"Values\":{\"FUNCTIONS_WORKER_RUNTIME\":\"node\",\"GITHUB_TOKEN\":\"your-token-here\"}}' > local.settings.json\nnpx func start\n```\n\n**Option B: SWA CLI (proxies both together)**\n```bash\nnpm install -g @azure/static-web-apps-cli\nnpm run build\nswa start storybook-static --api-location api\n```\n\n> `api/local.settings.json` is already in `.gitignore` — safe to create locally.\n\n## Tech Stack\n\n- React 18 + TypeScript 5.7\n- Fluent UI React v9 (`@fluentui/react-components`)\n- Storybook 10 + Vite 6\n- Griffel CSS-in-JS\n- Chromatic visual regression\n- Azure Static Web Apps\n","readmeFilename":"README.md"}