{"id":31718679,"url":"https://github.com/speakeasy-api/moonshine","last_synced_at":"2025-10-09T02:54:53.967Z","repository":{"id":314492924,"uuid":"874686981","full_name":"speakeasy-api/moonshine","owner":"speakeasy-api","description":"Speakeasy's design system 💅","archived":false,"fork":false,"pushed_at":"2025-10-06T12:32:15.000Z","size":4528,"stargazers_count":3,"open_issues_count":7,"forks_count":1,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-10-06T12:34:18.976Z","etag":null,"topics":["design","mcp","openapi","sdks"],"latest_commit_sha":null,"homepage":"https://moonshine.speakeasy.com","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/speakeasy-api.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-10-18T09:26:18.000Z","updated_at":"2025-10-06T11:51:30.000Z","dependencies_parsed_at":"2025-09-12T20:53:56.286Z","dependency_job_id":"f538d02d-f5fb-4731-af1c-f956a77d290d","html_url":"https://github.com/speakeasy-api/moonshine","commit_stats":null,"previous_names":["speakeasy-api/moonshine"],"tags_count":292,"template":false,"template_full_name":null,"purl":"pkg:github/speakeasy-api/moonshine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fmoonshine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fmoonshine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fmoonshine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fmoonshine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/speakeasy-api","download_url":"https://codeload.github.com/speakeasy-api/moonshine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fmoonshine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278621852,"owners_count":26017254,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["design","mcp","openapi","sdks"],"created_at":"2025-10-09T02:54:49.396Z","updated_at":"2025-10-09T02:54:53.955Z","avatar_url":"https://github.com/speakeasy-api.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🥃 Moonshine 🥃\n\n[![NPM](https://img.shields.io/badge/npm-moonshine@latest-blue)](https://www.npmjs.com/package/@speakeasy-api/moonshine)\n\u003ca href=\"https://moonshine.speakeasy.com/\" target=\"_blank\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/storybooks/brand/master/badge/badge-storybook.svg\"\u003e\u003c/a\u003e\n\nSpeakeasy's design system.\n\n## Installation \u0026 Setup\n\n### 1. Install the package and dependencies\n\n```bash\npnpm add @speakeasy-api/moonshine\n```\n\nMake sure you install Lucide as it is a peer dependency of this package:\n\n```\npnpm add lucide-react\n```\n\n### 2. Configure Tailwind CSS\n\nAdd this to the top of your project's CSS file where you configure Tailwind:\n\n```css\n/* This must come BEFORE your Tailwind imports */\n@reference \"../node_modules/@speakeasy-api/moonshine/src/global.css\";\n\n/* Your Tailwind setup */\n@import 'tailwindcss';\n```\n\n**Note:** The `@reference` directive is required for Tailwind v4 to recognize Moonshine's custom utilities and make them available in your project.\n\n### 3. Import Moonshine's Compiled CSS\n\nIn your main app file (or root layout):\n\n```ts\nimport '@speakeasy-api/moonshine/moonshine.css'\n```\n\n### 4. Set up the Provider\n\nWrap your application in the `MoonshineConfigProvider` component:\n\n```tsx\nimport { MoonshineConfigProvider } from '@speakeasy-api/moonshine'\n;\u003cMoonshineConfigProvider themeElement={document.documentElement}\u003e\n  \u003cApp /\u003e\n\u003c/MoonshineConfigProvider\u003e\n```\n\n### 5. Configure Custom Fonts (Optional)\n\nMoonshine uses custom fonts (Diatype, Tobias). If you have licenses for these fonts, add them to your project:\n\n```css\n/* In your global CSS */\n@font-face {\n  font-family: 'Diatype';\n  src: url('/fonts/diatype/ABCDiatype-Regular.woff2') format('woff2');\n  font-weight: 400;\n  font-style: normal;\n  font-display: block;\n}\n\n@font-face {\n  font-family: 'Diatype';\n  src: url('/fonts/diatype/ABCDiatype-Light.woff2') format('woff2');\n  font-weight: 300;\n  font-style: normal;\n  font-display: block;\n}\n\n/* Add other font weights and Tobias font-face declarations as needed */\n```\n\nIf you don't have these fonts, the design system will fall back to system fonts.\n\n### 6. Use Components and Utilities\n\n```tsx\nimport { Grid } from '@speakeasy-api/moonshine'\n\n// Use semantic utility classes\n;\u003cdiv className=\"text-heading-lg bg-surface-primary\"\u003eHello Moonshine!\u003c/div\u003e\n```\n\n### TypeScript Support for Utility Classes\n\nMoonshine provides TypeScript types for all available utility classes to improve your development experience:\n\n```tsx\nimport type { MoonshineClasses } from '@speakeasy-api/moonshine/types/utilities'\n\n// Use for type-safe className props\ninterface MyComponentProps {\n  className?: MoonshineClasses\n}\n\n// Get autocomplete for all available utilities\nconst styles: MoonshineClasses = 'text-heading-lg' // ✅ Autocompletes!\n```\n\nThe types are automatically generated during the build process and include:\n\n- All custom utilities (`text-heading-xl`, `bg-surface-primary`, etc.)\n- All semantic color utilities (`bg-warning`, `text-success`, etc.)\n- Full IntelliSense support in your IDE\n\n💡 **Tip**: This prevents typos and helps you discover available utilities without leaving your editor!\n\nThe package is built with [vite](https://vitejs.dev/), and is distributed in both [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) and [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs) formats.\n\n### Using Tailwind Merge\n\nMoonshine exports a custom wrapper for Tailwind Merge to avoid unexpected clashes between semantic class names. This version should be used in favour of using tailwind merge directly.\n\n```tsx\nimport { cn } from '@speakeasy-api/moonshine'\n\nreturn (\n  \u003cspan\n    className={cn('text-body-md', props.muted ? 'text-muted' : 'text-default')}\n  \u003e\n    Lorem Ipsum\n  \u003c/span\u003e\n)\n```\n\n## Design System Architecture\n\nMoonshine is a utility-first design system built on top of [Tailwind CSS v4](https://tailwindcss.com/). It provides a curated set of design tokens and utilities that enforce consistency while preventing common pitfalls.\n\n### CSS Architecture\n\nOur CSS is organized into three main files:\n\n1. **`base.css`** - Primitive design tokens (colors, fonts, spacing scales)\n\n   - Contains raw values that should **not** be used directly in components\n   - Defines theme-aware semantic tokens that adapt to light/dark mode\n   - Houses base element styles and resets\n\n2. **`utilities.css`** - The public API of our design system\n\n   - Exposes carefully crafted utility classes like `text-heading-xl`, `bg-surface-primary`\n   - Enforces typography combinations to prevent arbitrary text styling\n   - Provides semantic color utilities that automatically handle theming\n\n3. **`global.css`** - Orchestration and configuration\n   - Imports Tailwind and configures plugins\n   - Defines custom variants (dark mode, interaction states)\n   - Sets up responsive utility generation\n\n### Design Principles\n\n- **Constrained, not restrictive**: We provide a curated set of utilities that make the right thing easy\n- **Semantic, not arbitrary**: Use `text-heading-lg` not `text-[29px] leading-[1.5]`\n- **Theme-aware by default**: Colors and styles automatically adapt to light/dark mode\n- **Type-safe when possible**: Utilities are designed to work with TypeScript autocomplete\n\n### Usage Guidelines\n\n✅ **Do:**\n\n- Use semantic utilities: `bg-warning`, `text-body`, `border-error`\n- Leverage pre-defined typography scales: `text-heading-xl`, `text-body-sm`\n- Stick to the exposed utility classes in `utilities.css`\n\n❌ **Don't:**\n\n- Access raw color values: `bg-[var(--color-neutral-200)]`\n- Create arbitrary combinations: `text-[1.813rem] leading-[1.5]`\n- Override the design system without discussing with the team\n\nFor more technical details about the CSS architecture, see [CLAUDE.md](./CLAUDE.md).\n\n## Troubleshooting\n\n### Utilities not working\n\nMake sure you've added the `@reference` directive to your global CSS file. This is required for Tailwind v4 to pick up Moonshine's utility classes.\n\n### Fonts not loading\n\nThe custom fonts (Diatype, Tobias) require licenses. If you don't have them, the system will use fallback fonts. Ensure your font files are in the correct path if you do have licenses.\n\n### Dark mode not working\n\nEnsure the `themeElement` prop in `MoonshineConfigProvider` points to the element where your `dark` class is applied (usually `document.documentElement`).\n\n### TypeScript types not found\n\nMake sure you're importing from the correct path:\n\n```tsx\nimport type { MoonshineClasses } from '@speakeasy-api/moonshine/types/utilities'\n```\n\n## Contributing\n\n### Setup\n\n1. Clone the repository\n2. Run `pnpm install` to install the dependencies\n3. Run `pnpm build` to build the package\n4. Run `pnpm storybook` to start the storybook server\n\nIf you'd like to develop Moonshine in tandem with another app, you can follow the steps outlined below in the **Linking the library locally** section.\n\n### Guidelines\n\n- We're using [Storybook](https://storybook.js.org/) to develop the components.\n- Components should be added to the `src/components` directory.\n- Each component should have its own directory. e.g `src/components/Box`, `src/components/Button` etc.\n- Each component should have a corresponding Storybook story file located at `src/components/{Your Component}/index.stories.tsx`, with several stories for different use cases.\n- Shadcn components **should not** be exported directly from `src/index.ts`.\n\n### Workflow\n\nWe use [Semantic Release](https://semantic-release.gitbook.io/semantic-release/) to handle versioning and changelog generation.\n\nThe release workflow is as follows:\n\n1. Create a new branch for your changes\n2. Make your changes\n3. Add a commit with the conventional changelog message format (e.g `feat(component-name): what the commit does`)\n4. Push your changes to GitHub\n5. Merge the PR into the `main` branch\n6. A new version is released to NPM\n\n#### Conventional changelog reference\n\nOnly certain commit types will trigger a release (noted below in **bold**).\n\n- **`feat`:** A new feature (triggers a minor release)\n- **`fix`:** A bug fix (triggers a patch release)\n- **`perf`:** A code change that improves performance (triggers a patch release)\n- `refactor`: A code change that neither fixes a bug nor adds a feature (no release)\n- `docs`: Documentation only changes (no release)\n- `style`: Changes that do not affect the meaning of the code (no release)\n- `test`: Adding missing tests (no release)\n- `ci`: Changes to CI configuration files and scripts (no release)\n- `build`: Changes that affect the build system or external dependencies (no release)\n- `chore`: Other changes that don't modify src or test files (no release)\n\n##### Breaking changes\n\nIf a PR is a breaking change for consumers, then the commit message should use a bang (`!`) to signify a breaking change, which will trigger a major release:\n\n```\nfeat(component-name)!: breaking change description\nfix(component-name)!: breaking change description\n```\n\n### Testing\n\nWe're using [Vitest](https://vitest.dev/) and [@testing-library/react](https://testing-library.com/react/) for testing components when necessary.\n\nRun `pnpm test` to run the tests.\n\n### Linking the library locally\n\nRun `pnpm build:watch` within Moonshine to build the library and watch for changes.\n\nThen run `pnpm link ../path/to/moonshine` within the app that will use the library. For the registry `webapp` directory (assuming a standard cloning setup where `moonshine` is a sibling of the registry repo), it would be:\n\n```bash\npnpm link ../path/to/moonshine\n```\n\nThe lockfile file within your app should referenced the linked copy:\n\n```yaml\n'@speakeasy-api/moonshine':\n  specifier: ^0.43.1\n  version: link:../../../../moonshine\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspeakeasy-api%2Fmoonshine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspeakeasy-api%2Fmoonshine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspeakeasy-api%2Fmoonshine/lists"}