├── .gitignore ├── .prettierrc ├── README.md ├── apps ├── storybook │ ├── .storybook │ │ ├── main.js │ │ └── preview.js │ ├── package.json │ ├── panda.config.ts │ ├── panda.css │ ├── postcss.config.cjs │ ├── stories │ │ ├── Button.stories.js │ │ ├── Button.tsx │ │ ├── Header.stories.js │ │ ├── Header.tsx │ │ ├── Introduction.mdx │ │ ├── Page.stories.js │ │ ├── Page.tsx │ │ └── assets │ │ │ ├── code-brackets.svg │ │ │ ├── colors.svg │ │ │ ├── comments.svg │ │ │ ├── direction.svg │ │ │ ├── flow.svg │ │ │ ├── plugin.svg │ │ │ ├── repo.svg │ │ │ └── stackalt.svg │ └── tsconfig.json └── web │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .storybook │ ├── main.ts │ └── preview.ts │ ├── index.html │ ├── package.json │ ├── panda.config.ts │ ├── postcss.config.cjs │ ├── public │ └── vite.svg │ ├── src │ ├── App.css │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── index.css │ ├── main.tsx │ ├── panda.css │ ├── stories │ │ ├── Button.stories.js │ │ ├── Button.tsx │ │ ├── Header.stories.js │ │ ├── Header.tsx │ │ ├── Introduction.mdx │ │ ├── Page.stories.js │ │ ├── Page.tsx │ │ └── assets │ │ │ ├── code-brackets.svg │ │ │ ├── colors.svg │ │ │ ├── comments.svg │ │ │ ├── direction.svg │ │ │ ├── flow.svg │ │ │ ├── plugin.svg │ │ │ ├── repo.svg │ │ │ └── stackalt.svg │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── package.json ├── packages ├── button │ ├── demo │ │ ├── app.tsx │ │ ├── demo-container.tsx │ │ ├── icons.tsx │ │ ├── main.tsx │ │ ├── panda.css │ │ └── theme-toggle.tsx │ ├── index.html │ ├── package.json │ ├── panda.config.ts │ ├── postcss.config.cjs │ ├── src │ │ ├── button.recipe.ts │ │ ├── button.tsx │ │ ├── index.ts │ │ └── preset.ts │ ├── tsconfig.json │ └── tsconfig.node.json ├── preset │ ├── package.json │ ├── panda.config.ts │ ├── postcss.config.cjs │ └── src │ │ ├── index.ts │ │ └── semantic-tokens.ts └── some-component │ ├── package.json │ ├── panda.config.ts │ ├── src │ ├── index.ts │ └── some-component.tsx │ ├── tsconfig.json │ └── tsconfig.node.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Dependency directory 7 | **/node_modules/** 8 | node_modules 9 | 10 | dist 11 | dist-ssr 12 | out 13 | build 14 | **/buil 15 | tsconfig.tsbuildinfo 16 | .DS_Store 17 | __generated__ 18 | *.env 19 | .idea 20 | *.vsix 21 | 22 | ## Panda 23 | styled-system 24 | styled-system-static 25 | panda 26 | panda-static 27 | 28 | !packages/studio/styled-system 29 | packages/studio/src/lib/analysis.json 30 | storybook-static 31 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 120, 4 | "bracketSpacing": true, 5 | "jsxSingleQuote": false, 6 | "proseWrap": "always", 7 | "semi": false, 8 | "tabWidth": 2, 9 | "trailingComma": "all" 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | a new example repository with more use-cases: https://github.com/astahmer/panda-monorepo-setup 2 | 3 | 4 | example of a panda monorepo usage with a consuming app and multiple ui-lib providers 5 | 6 | was asked here https://discord.com/channels/1118988919804010566/1118988920533823540/1120270002352836648 7 | 8 | ```md 9 | my-monorepo 10 | ├─ apps 11 | │ ├─ web <-- consuming the `preset`, `button`, `some-component`, etc packages 12 | │ ├─ storybook 13 | ├─ packages 14 | │ ├─ preset <-- using definePreset(), contains the theme base (tokens.colors, semantic tokens, etc) 15 | │ └─ button <-- consuming the preset, provides a button recipe (in a buttonPreset) + a ShadcnButton component 16 | │ └─ some-component <-- consuming the preset, provides a component using internal `css` calls, ships a panda.json extract result 17 | ``` 18 | 19 | for storybook, you can run `pnpm storybook build && npx serve storybook-static` 20 | -------------------------------------------------------------------------------- /apps/storybook/.storybook/main.js: -------------------------------------------------------------------------------- 1 | /** @type { import('@storybook/react-vite').StorybookConfig } */ 2 | const config = { 3 | stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], 4 | addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'], 5 | framework: { 6 | name: '@storybook/react-vite', 7 | options: {}, 8 | }, 9 | docs: { 10 | autodocs: 'tag', 11 | }, 12 | } 13 | export default config 14 | -------------------------------------------------------------------------------- /apps/storybook/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import '../panda.css' 2 | 3 | /** @type { import('@storybook/react').Preview } */ 4 | const preview = { 5 | parameters: { 6 | actions: { argTypesRegex: '^on[A-Z].*' }, 7 | controls: { 8 | matchers: { 9 | color: /(background|color)$/i, 10 | date: /Date$/, 11 | }, 12 | }, 13 | }, 14 | } 15 | 16 | export default preview 17 | -------------------------------------------------------------------------------- /apps/storybook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apps", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "prepare": "panda codegen", 8 | "storybook": "storybook dev -p 6006", 9 | "build-storybook": "storybook build", 10 | "dev": "pnpm storybook", 11 | "build": "pnpm build-storybook" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "@pandacss/dev": "^0.3.2", 18 | "@storybook/addon-essentials": "^7.0.24", 19 | "@storybook/addon-interactions": "^7.0.24", 20 | "@storybook/addon-links": "^7.0.24", 21 | "@storybook/blocks": "^7.0.24", 22 | "@storybook/react": "^7.0.24", 23 | "@storybook/react-vite": "^7.0.24", 24 | "@storybook/testing-library": "^0.0.14-next.2", 25 | "@types/react": "^18.0.37", 26 | "@types/react-dom": "^18.0.11", 27 | "prop-types": "^15.8.1", 28 | "react": "^18.2.0", 29 | "react-dom": "^18.2.0", 30 | "storybook": "^7.0.24" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/storybook/panda.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@pandacss/dev' 2 | 3 | export default defineConfig({ 4 | // Whether to use css reset 5 | preflight: true, 6 | 7 | // Where to look for your css declarations 8 | include: ['./stories/**/*.{js,jsx,ts,tsx}'], 9 | 10 | // Files to exclude 11 | exclude: [], 12 | 13 | // Useful for theme customization 14 | theme: { 15 | extend: {}, 16 | }, 17 | 18 | // The output directory for your css system 19 | outdir: 'styled-system', 20 | 21 | // The JSX framework to use 22 | jsxFramework: 'react', 23 | }) 24 | -------------------------------------------------------------------------------- /apps/storybook/panda.css: -------------------------------------------------------------------------------- 1 | @layer reset, base, tokens, recipes, utilities; 2 | -------------------------------------------------------------------------------- /apps/storybook/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@pandacss/dev/postcss': {}, 4 | }, 5 | } -------------------------------------------------------------------------------- /apps/storybook/stories/Button.stories.js: -------------------------------------------------------------------------------- 1 | import { Button } from './Button' 2 | 3 | // More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction 4 | export default { 5 | title: 'Example/Button', 6 | component: Button, 7 | tags: ['autodocs'], 8 | argTypes: { 9 | backgroundColor: { control: 'color' }, 10 | }, 11 | } 12 | 13 | // More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args 14 | export const Primary = { 15 | args: { 16 | variant: 'primary', 17 | label: 'Button', 18 | }, 19 | } 20 | 21 | export const Secondary = { 22 | args: { 23 | label: 'Button', 24 | }, 25 | } 26 | 27 | export const Large = { 28 | args: { 29 | size: 'large', 30 | label: 'Button', 31 | }, 32 | } 33 | 34 | export const Small = { 35 | args: { 36 | size: 'small', 37 | label: 'Button', 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /apps/storybook/stories/Button.tsx: -------------------------------------------------------------------------------- 1 | import { RecipeVariantProps, cva, cx } from '../styled-system/css' 2 | import { HTMLStyledProps, styled } from '../styled-system/jsx' 3 | 4 | // I just took the original storybook sample & pasted it here, then adapted it to CVA :) 5 | // https://transform.tools/css-to-js 6 | 7 | const button = cva({ 8 | base: { 9 | fontFamily: "'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif", 10 | fontWeight: 700, 11 | border: '0', 12 | borderRadius: '3em', 13 | cursor: 'pointer', 14 | display: 'inline-block', 15 | lineHeight: 1, 16 | }, 17 | variants: { 18 | variant: { 19 | primary: { 20 | color: 'white', 21 | backgroundColor: '#1ea7fd', 22 | }, 23 | secondary: { 24 | color: '#333', 25 | backgroundColor: 'transparent', 26 | boxShadow: 'rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset', 27 | }, 28 | }, 29 | size: { 30 | small: { fontSize: '12px', padding: '10px 16px' }, 31 | medium: { fontSize: '14px', padding: '11px 20px' }, 32 | large: { fontSize: '16px', padding: '12px 24px' }, 33 | }, 34 | }, 35 | defaultVariants: { 36 | variant: 'primary', 37 | size: 'medium', 38 | }, 39 | }) 40 | 41 | type ButtonProps = HTMLStyledProps<'button'> & RecipeVariantProps 42 | 43 | /** 44 | * Primary UI component for user interaction 45 | */ 46 | export const Button = ({ 47 | variant, 48 | size, 49 | className, 50 | label, 51 | ...props 52 | }: ButtonProps & { 53 | label: string 54 | }) => { 55 | return ( 56 | 57 | {label} 58 | 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /apps/storybook/stories/Header.stories.js: -------------------------------------------------------------------------------- 1 | import { Header } from './Header'; 2 | 3 | export default { 4 | title: 'Example/Header', 5 | component: Header, 6 | // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs 7 | tags: ['autodocs'], 8 | parameters: { 9 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout 10 | layout: 'fullscreen', 11 | }, 12 | }; 13 | 14 | export const LoggedIn = { 15 | args: { 16 | user: { 17 | name: 'Jane Doe', 18 | }, 19 | }, 20 | }; 21 | 22 | export const LoggedOut = {}; 23 | -------------------------------------------------------------------------------- /apps/storybook/stories/Header.tsx: -------------------------------------------------------------------------------- 1 | import { css } from '../styled-system/css' 2 | import { Button } from './Button' 3 | 4 | export type User = { name: string } 5 | 6 | export const Header = ({ 7 | user, 8 | onLogin, 9 | onLogout, 10 | onCreateAccount, 11 | }: { 12 | user: User | undefined 13 | onLogin: () => void 14 | onLogout: () => void 15 | onCreateAccount: () => void 16 | }) => ( 17 |
18 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |

Acme

47 |
48 |
49 | {user ? ( 50 | <> 51 | 58 | Welcome, {user.name}! 59 | 60 |
69 |
70 |
71 | ) 72 | -------------------------------------------------------------------------------- /apps/storybook/stories/Introduction.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/blocks'; 2 | import Code from './assets/code-brackets.svg'; 3 | import Colors from './assets/colors.svg'; 4 | import Comments from './assets/comments.svg'; 5 | import Direction from './assets/direction.svg'; 6 | import Flow from './assets/flow.svg'; 7 | import Plugin from './assets/plugin.svg'; 8 | import Repo from './assets/repo.svg'; 9 | import StackAlt from './assets/stackalt.svg'; 10 | 11 | 12 | 13 | 118 | 119 | # Welcome to Storybook 120 | 121 | Storybook helps you build UI components in isolation from your app's business logic, data, and context. 122 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA. 123 | 124 | Browse example stories now by navigating to them in the sidebar. 125 | View their code in the `stories` directory to learn how they work. 126 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages. 127 | 128 |
Configure
129 | 130 |
131 | 136 | plugin 137 | 138 | Presets for popular tools 139 | Easy setup for TypeScript, SCSS and more. 140 | 141 | 142 | 147 | Build 148 | 149 | Build configuration 150 | How to customize webpack and Babel 151 | 152 | 153 | 158 | colors 159 | 160 | Styling 161 | How to load and configure CSS libraries 162 | 163 | 164 | 169 | flow 170 | 171 | Data 172 | Providers and mocking for data libraries 173 | 174 | 175 |
176 | 177 |
Learn
178 | 179 |
180 | 181 | repo 182 | 183 | Storybook documentation 184 | Configure, customize, and extend 185 | 186 | 187 | 188 | direction 189 | 190 | In-depth guides 191 | Best practices from leading teams 192 | 193 | 194 | 195 | code 196 | 197 | GitHub project 198 | View the source and add issues 199 | 200 | 201 | 202 | comments 203 | 204 | Discord chat 205 | Chat with maintainers and the community 206 | 207 | 208 |
209 | 210 |
211 | TipEdit the Markdown in{' '} 212 | stories/Introduction.stories.mdx 213 |
214 | -------------------------------------------------------------------------------- /apps/storybook/stories/Page.stories.js: -------------------------------------------------------------------------------- 1 | import { within, userEvent } from '@storybook/testing-library'; 2 | 3 | import { Page } from './Page'; 4 | 5 | export default { 6 | title: 'Example/Page', 7 | component: Page, 8 | parameters: { 9 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout 10 | layout: 'fullscreen', 11 | }, 12 | }; 13 | 14 | export const LoggedOut = {}; 15 | 16 | // More on interaction testing: https://storybook.js.org/docs/react/writing-tests/interaction-testing 17 | export const LoggedIn = { 18 | play: async ({ canvasElement }) => { 19 | const canvas = within(canvasElement); 20 | const loginButton = await canvas.getByRole('button', { 21 | name: /Log in/i, 22 | }); 23 | await userEvent.click(loginButton); 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /apps/storybook/stories/Page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Header, User } from './Header' 3 | import { css } from '../styled-system/css' 4 | 5 | export const Page = () => { 6 | const [user, setUser] = React.useState() 7 | 8 | return ( 9 |
10 |
setUser({ name: 'Jane Doe' })} 13 | onLogout={() => setUser(undefined)} 14 | onCreateAccount={() => setUser({ name: 'Jane Doe' })} 15 | /> 16 | 17 |
40 |

Pages in Storybook

41 |

42 | We recommend building UIs with a{' '} 43 | 44 | component-driven 45 | {' '} 46 | process starting with atomic components and ending with pages. 47 |

48 |

49 | Render pages with mock data. This makes it easy to build and review page states without needing to navigate to 50 | them in your app. Here are some handy patterns for managing page data in Storybook: 51 |

52 |
    53 |
  • 54 | Use a higher-level connected component. Storybook helps you compose such data from the "args" of child 55 | component stories 56 |
  • 57 |
  • 58 | Assemble data in the page component from your services. You can mock these services out using Storybook. 59 |
  • 60 |
61 |

62 | Get a guided tutorial on component-driven development at{' '} 63 | 64 | Storybook tutorials 65 | 66 | . Read more in the{' '} 67 | 68 | docs 69 | 70 | . 71 |

72 |
80 | 94 | Tip 95 | {' '} 96 | Adjust the width of the canvas with the{' '} 97 | 112 | 113 | 118 | 119 | 120 | Viewports addon in the toolbar 121 |
122 |
123 |
124 | ) 125 | } 126 | -------------------------------------------------------------------------------- /apps/storybook/stories/assets/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /apps/storybook/stories/assets/colors.svg: -------------------------------------------------------------------------------- 1 | illustration/colors -------------------------------------------------------------------------------- /apps/storybook/stories/assets/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /apps/storybook/stories/assets/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /apps/storybook/stories/assets/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /apps/storybook/stories/assets/plugin.svg: -------------------------------------------------------------------------------- 1 | illustration/plugin -------------------------------------------------------------------------------- /apps/storybook/stories/assets/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /apps/storybook/stories/assets/stackalt.svg: -------------------------------------------------------------------------------- 1 | illustration/stackalt -------------------------------------------------------------------------------- /apps/storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/web/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { browser: true, es2020: true }, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:react-hooks/recommended', 7 | ], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 10 | plugins: ['react-refresh'], 11 | rules: { 12 | 'react-refresh/only-export-components': 'warn', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /apps/web/.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from '@storybook/react-vite' 2 | const config: StorybookConfig = { 3 | stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], 4 | addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'], 5 | framework: { 6 | name: '@storybook/react-vite', 7 | options: {}, 8 | }, 9 | docs: { 10 | autodocs: 'tag', 11 | }, 12 | } 13 | export default config 14 | -------------------------------------------------------------------------------- /apps/web/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from '@storybook/react' 2 | import '../src/panda.css' 3 | 4 | const preview: Preview = { 5 | parameters: { 6 | actions: { argTypesRegex: '^on[A-Z].*' }, 7 | controls: { 8 | matchers: { 9 | color: /(background|color)$/i, 10 | date: /Date$/, 11 | }, 12 | }, 13 | }, 14 | } 15 | 16 | export default preview 17 | -------------------------------------------------------------------------------- /apps/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@my-monorepo/web", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview", 11 | "storybook": "storybook dev -p 6006", 12 | "build-storybook": "storybook build" 13 | }, 14 | "dependencies": { 15 | "@my-monorepo/button": "workspace:^", 16 | "@my-monorepo/preset": "workspace:^", 17 | "@my-monorepo/some-component": "workspace:^", 18 | "react": "^18.2.0", 19 | "react-dom": "^18.2.0" 20 | }, 21 | "devDependencies": { 22 | "@pandacss/dev": "^0.3.2", 23 | "@pandacss/preset-panda": "^0.3.2", 24 | "@storybook/addon-essentials": "^7.0.24", 25 | "@storybook/addon-interactions": "^7.0.24", 26 | "@storybook/addon-links": "^7.0.24", 27 | "@storybook/blocks": "^7.0.24", 28 | "@storybook/react": "^7.0.24", 29 | "@storybook/react-vite": "^7.0.24", 30 | "@storybook/testing-library": "^0.0.14-next.2", 31 | "@types/react": "^18.0.37", 32 | "@types/react-dom": "^18.0.11", 33 | "@typescript-eslint/eslint-plugin": "^5.59.0", 34 | "@typescript-eslint/parser": "^5.59.0", 35 | "@vitejs/plugin-react-swc": "^3.0.0", 36 | "eslint": "^8.38.0", 37 | "eslint-plugin-react-hooks": "^4.6.0", 38 | "eslint-plugin-react-refresh": "^0.3.4", 39 | "storybook": "^7.0.24", 40 | "typescript": "^5.0.2", 41 | "vite": "^4.3.9" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /apps/web/panda.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@pandacss/dev' 2 | import presetPanda from '@pandacss/preset-panda' 3 | import { myMonorepoPreset } from '@my-monorepo/preset' 4 | import { buttonPreset } from '@my-monorepo/button/preset' 5 | 6 | export default defineConfig({ 7 | presets: [presetPanda, myMonorepoPreset, buttonPreset], 8 | // Whether to use css reset 9 | preflight: true, 10 | // Where to look for your css declarations 11 | include: [ 12 | './src/**/*.{js,jsx,ts,tsx}', 13 | './pages/**/*.{js,jsx,ts,tsx}', 14 | './stories/**/*.{js,jsx,ts,tsx}', 15 | // if you remove this one, the `SomeComponent` styles will be missing in the final css 16 | './node_modules/@my-monorepo/some-component/dist/panda.json', 17 | // this one is unnecessary since no `css` function (or style props etc) is directly used in this package 18 | // but including it should not hurt and would make it future-proof 19 | './node_modules/@my-monorepo/button/dist/panda.json', 20 | ], 21 | 22 | // Files to exclude 23 | exclude: [], 24 | 25 | // Useful for theme customization 26 | theme: { 27 | extend: { 28 | tokens: { 29 | colors: { 30 | specificColorFromWebApp: { value: '#262626' }, 31 | }, 32 | }, 33 | }, 34 | }, 35 | 36 | // The output directory for your css system 37 | outdir: '@my-monorepo/ui-lib', 38 | emitPackage: true, 39 | jsxFramework: 'react', 40 | }) 41 | -------------------------------------------------------------------------------- /apps/web/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@pandacss/dev/postcss': {}, 4 | }, 5 | } -------------------------------------------------------------------------------- /apps/web/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/web/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/web/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { css, cx } from '@my-monorepo/ui-lib/css' 3 | import { styled } from '@my-monorepo/ui-lib/jsx' 4 | import { ShadcnButton } from '@my-monorepo/button' 5 | 6 | import './App.css' 7 | import './panda.css' 8 | import { SomeComponent } from '@my-monorepo/some-component' 9 | 10 | function App() { 11 | const [count, setCount] = useState(0) 12 | 13 | return ( 14 | <> 15 |

Panda CSS monorepo example

16 |
17 | [light] Using UI-lib button 18 |
19 |
20 | [dark] Using UI-lib button 21 |
22 | 23 | 24 | A component using internal `css` function calls, that needs to ship its own extract result 25 | 26 | 27 |
Hello 🐼!
28 |
29 | 32 |

33 | Edit src/App.tsx and save to test HMR 34 |

35 |
36 | 37 | ) 38 | } 39 | 40 | export default App 41 | -------------------------------------------------------------------------------- /apps/web/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/web/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | font-weight: 500; 19 | color: #646cff; 20 | text-decoration: inherit; 21 | } 22 | a:hover { 23 | color: #535bf2; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | display: flex; 29 | place-items: center; 30 | min-width: 320px; 31 | min-height: 100vh; 32 | } 33 | 34 | h1 { 35 | font-size: 3.2em; 36 | line-height: 1.1; 37 | } 38 | 39 | .vite-button { 40 | border-radius: 8px; 41 | border: 1px solid transparent; 42 | padding: 0.6em 1.2em; 43 | font-size: 1em; 44 | font-weight: 500; 45 | font-family: inherit; 46 | background-color: #1a1a1a; 47 | cursor: pointer; 48 | transition: border-color 0.25s; 49 | } 50 | .vite-button:hover { 51 | border-color: #646cff; 52 | } 53 | .vite-button:focus, 54 | .vite-button:focus-visible { 55 | outline: 4px auto -webkit-focus-ring-color; 56 | } 57 | 58 | @media (prefers-color-scheme: light) { 59 | :root { 60 | color: #213547; 61 | background-color: #ffffff; 62 | } 63 | a:hover { 64 | color: #747bff; 65 | } 66 | button { 67 | background-color: #f9f9f9; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /apps/web/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /apps/web/src/panda.css: -------------------------------------------------------------------------------- 1 | @layer reset, base, tokens, recipes, utilities; 2 | -------------------------------------------------------------------------------- /apps/web/src/stories/Button.stories.js: -------------------------------------------------------------------------------- 1 | import { Button } from './Button' 2 | 3 | // More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction 4 | export default { 5 | title: 'Example/Button', 6 | component: Button, 7 | tags: ['autodocs'], 8 | argTypes: { 9 | backgroundColor: { control: 'color' }, 10 | }, 11 | } 12 | 13 | // More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args 14 | export const Primary = { 15 | args: { 16 | variant: 'primary', 17 | label: 'Button', 18 | }, 19 | } 20 | 21 | export const Secondary = { 22 | args: { 23 | label: 'Button', 24 | }, 25 | } 26 | 27 | export const Large = { 28 | args: { 29 | size: 'large', 30 | label: 'Button', 31 | }, 32 | } 33 | 34 | export const Small = { 35 | args: { 36 | size: 'small', 37 | label: 'Button', 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /apps/web/src/stories/Button.tsx: -------------------------------------------------------------------------------- 1 | import { RecipeVariantProps, cva, cx } from '@my-monorepo/ui-lib/css' 2 | import { HTMLStyledProps, styled } from '@my-monorepo/ui-lib/jsx' 3 | 4 | // I just took the original storybook sample & pasted it here, then adapted it to CVA :) 5 | // https://transform.tools/css-to-js 6 | 7 | const button = cva({ 8 | base: { 9 | fontFamily: "'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif", 10 | fontWeight: 700, 11 | border: '0', 12 | borderRadius: '3em', 13 | cursor: 'pointer', 14 | display: 'inline-block', 15 | lineHeight: 1, 16 | }, 17 | variants: { 18 | variant: { 19 | primary: { 20 | color: 'white', 21 | backgroundColor: '#1ea7fd', 22 | }, 23 | secondary: { 24 | color: '#333', 25 | backgroundColor: 'transparent', 26 | boxShadow: 'rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset', 27 | }, 28 | }, 29 | size: { 30 | small: { fontSize: '12px', padding: '10px 16px' }, 31 | medium: { fontSize: '14px', padding: '11px 20px' }, 32 | large: { fontSize: '16px', padding: '12px 24px' }, 33 | }, 34 | }, 35 | defaultVariants: { 36 | variant: 'primary', 37 | size: 'medium', 38 | }, 39 | }) 40 | 41 | type ButtonProps = HTMLStyledProps<'button'> & RecipeVariantProps 42 | 43 | /** 44 | * Primary UI component for user interaction 45 | */ 46 | export const Button = ({ 47 | variant, 48 | size, 49 | className, 50 | label, 51 | ...props 52 | }: ButtonProps & { 53 | label: string 54 | }) => { 55 | return ( 56 | 57 | {label} 58 | 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /apps/web/src/stories/Header.stories.js: -------------------------------------------------------------------------------- 1 | import { Header } from './Header'; 2 | 3 | export default { 4 | title: 'Example/Header', 5 | component: Header, 6 | // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs 7 | tags: ['autodocs'], 8 | parameters: { 9 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout 10 | layout: 'fullscreen', 11 | }, 12 | }; 13 | 14 | export const LoggedIn = { 15 | args: { 16 | user: { 17 | name: 'Jane Doe', 18 | }, 19 | }, 20 | }; 21 | 22 | export const LoggedOut = {}; 23 | -------------------------------------------------------------------------------- /apps/web/src/stories/Header.tsx: -------------------------------------------------------------------------------- 1 | import { css } from '@my-monorepo/ui-lib/css' 2 | import { Button } from './Button' 3 | 4 | export type User = { name: string } 5 | 6 | export const Header = ({ 7 | user, 8 | onLogin, 9 | onLogout, 10 | onCreateAccount, 11 | }: { 12 | user: User | undefined 13 | onLogin: () => void 14 | onLogout: () => void 15 | onCreateAccount: () => void 16 | }) => ( 17 |
18 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |

Acme

47 |
48 |
49 | {user ? ( 50 | <> 51 | 58 | Welcome, {user.name}! 59 | 60 |
69 |
70 |
71 | ) 72 | -------------------------------------------------------------------------------- /apps/web/src/stories/Introduction.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/blocks'; 2 | import Code from './assets/code-brackets.svg'; 3 | import Colors from './assets/colors.svg'; 4 | import Comments from './assets/comments.svg'; 5 | import Direction from './assets/direction.svg'; 6 | import Flow from './assets/flow.svg'; 7 | import Plugin from './assets/plugin.svg'; 8 | import Repo from './assets/repo.svg'; 9 | import StackAlt from './assets/stackalt.svg'; 10 | 11 | 12 | 13 | 118 | 119 | # Welcome to Storybook 120 | 121 | Storybook helps you build UI components in isolation from your app's business logic, data, and context. 122 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA. 123 | 124 | Browse example stories now by navigating to them in the sidebar. 125 | View their code in the `stories` directory to learn how they work. 126 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages. 127 | 128 |
Configure
129 | 130 |
131 | 136 | plugin 137 | 138 | Presets for popular tools 139 | Easy setup for TypeScript, SCSS and more. 140 | 141 | 142 | 147 | Build 148 | 149 | Build configuration 150 | How to customize webpack and Babel 151 | 152 | 153 | 158 | colors 159 | 160 | Styling 161 | How to load and configure CSS libraries 162 | 163 | 164 | 169 | flow 170 | 171 | Data 172 | Providers and mocking for data libraries 173 | 174 | 175 |
176 | 177 |
Learn
178 | 179 |
180 | 181 | repo 182 | 183 | Storybook documentation 184 | Configure, customize, and extend 185 | 186 | 187 | 188 | direction 189 | 190 | In-depth guides 191 | Best practices from leading teams 192 | 193 | 194 | 195 | code 196 | 197 | GitHub project 198 | View the source and add issues 199 | 200 | 201 | 202 | comments 203 | 204 | Discord chat 205 | Chat with maintainers and the community 206 | 207 | 208 |
209 | 210 |
211 | TipEdit the Markdown in{' '} 212 | stories/Introduction.stories.mdx 213 |
214 | -------------------------------------------------------------------------------- /apps/web/src/stories/Page.stories.js: -------------------------------------------------------------------------------- 1 | import { within, userEvent } from '@storybook/testing-library'; 2 | 3 | import { Page } from './Page'; 4 | 5 | export default { 6 | title: 'Example/Page', 7 | component: Page, 8 | parameters: { 9 | // More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout 10 | layout: 'fullscreen', 11 | }, 12 | }; 13 | 14 | export const LoggedOut = {}; 15 | 16 | // More on interaction testing: https://storybook.js.org/docs/react/writing-tests/interaction-testing 17 | export const LoggedIn = { 18 | play: async ({ canvasElement }) => { 19 | const canvas = within(canvasElement); 20 | const loginButton = await canvas.getByRole('button', { 21 | name: /Log in/i, 22 | }); 23 | await userEvent.click(loginButton); 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /apps/web/src/stories/Page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Header, User } from './Header' 3 | import { css } from '@my-monorepo/ui-lib/css' 4 | 5 | export const Page = () => { 6 | const [user, setUser] = React.useState() 7 | 8 | return ( 9 |
10 |
setUser({ name: 'Jane Doe' })} 13 | onLogout={() => setUser(undefined)} 14 | onCreateAccount={() => setUser({ name: 'Jane Doe' })} 15 | /> 16 | 17 |
40 |

Pages in Storybook

41 |

42 | We recommend building UIs with a{' '} 43 | 44 | component-driven 45 | {' '} 46 | process starting with atomic components and ending with pages. 47 |

48 |

49 | Render pages with mock data. This makes it easy to build and review page states without needing to navigate to 50 | them in your app. Here are some handy patterns for managing page data in Storybook: 51 |

52 |
    53 |
  • 54 | Use a higher-level connected component. Storybook helps you compose such data from the "args" of child 55 | component stories 56 |
  • 57 |
  • 58 | Assemble data in the page component from your services. You can mock these services out using Storybook. 59 |
  • 60 |
61 |

62 | Get a guided tutorial on component-driven development at{' '} 63 | 64 | Storybook tutorials 65 | 66 | . Read more in the{' '} 67 | 68 | docs 69 | 70 | . 71 |

72 |
80 | 94 | Tip 95 | {' '} 96 | Adjust the width of the canvas with the{' '} 97 | 112 | 113 | 118 | 119 | 120 | Viewports addon in the toolbar 121 |
122 |
123 |
124 | ) 125 | } 126 | -------------------------------------------------------------------------------- /apps/web/src/stories/assets/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /apps/web/src/stories/assets/colors.svg: -------------------------------------------------------------------------------- 1 | illustration/colors -------------------------------------------------------------------------------- /apps/web/src/stories/assets/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /apps/web/src/stories/assets/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /apps/web/src/stories/assets/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /apps/web/src/stories/assets/plugin.svg: -------------------------------------------------------------------------------- 1 | illustration/plugin -------------------------------------------------------------------------------- /apps/web/src/stories/assets/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /apps/web/src/stories/assets/stackalt.svg: -------------------------------------------------------------------------------- 1 | illustration/stackalt -------------------------------------------------------------------------------- /apps/web/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /apps/web/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react-swc' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | optimizeDeps: { 8 | exclude: ['@my-monorepo/ui-lib'], 9 | }, 10 | }) 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "publint": "^0.1.12", 4 | "rimraf": "^5.0.1", 5 | "tsup": "^7.0.0", 6 | "typescript": "^5.0.2" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/button/demo/app.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Stack, styled } from '@my-monorepo/ui-lib/jsx' 2 | import { ShadcnButton } from '../src/button' 3 | import { ThemeToggle } from './theme-toggle' 4 | 5 | export const App = () => { 6 | return ( 7 |
8 | 9 | 10 | 11 | 12 | Click me ! 13 | 14 |
15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /packages/button/demo/demo-container.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from 'react' 2 | import { styled, Center, Stack, StackProps } from '@my-monorepo/ui-lib/jsx' 3 | 4 | export const DemoContainer = ({ 5 | children, 6 | direction = 'row', 7 | }: PropsWithChildren<{ 8 | direction?: StackProps['direction'] 9 | preset?: 'chakra' | 'shadcn' 10 | }>) => { 11 | return ( 12 |
13 | 14 | 15 | 16 | {children} 17 | 18 | 19 | 20 | 21 | 22 | {children} 23 | 24 | 25 | 26 |
27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /packages/button/demo/icons.tsx: -------------------------------------------------------------------------------- 1 | import { Moon, SunMedium, type Icon as LucideIcon } from 'lucide-react' 2 | 3 | export type Icon = LucideIcon 4 | 5 | export const Icons = { 6 | sun: SunMedium, 7 | moon: Moon, 8 | } 9 | -------------------------------------------------------------------------------- /packages/button/demo/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import './panda.css' 4 | 5 | import { App } from './app' 6 | 7 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 8 | 9 | 10 | , 11 | ) 12 | -------------------------------------------------------------------------------- /packages/button/demo/panda.css: -------------------------------------------------------------------------------- 1 | @layer reset, base, tokens, recipes, utilities; 2 | 3 | :root { 4 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 5 | line-height: 1.5; 6 | font-weight: 400; 7 | 8 | font-synthesis: none; 9 | text-rendering: optimizeLegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | -webkit-text-size-adjust: 100%; 13 | } 14 | 15 | #root { 16 | margin: 0; 17 | display: flex; 18 | place-items: center; 19 | min-width: 320px; 20 | min-height: 100vh; 21 | } 22 | -------------------------------------------------------------------------------- /packages/button/demo/theme-toggle.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { css } from '@my-monorepo/ui-lib/css' 4 | import { ShadcnButton } from '../src/button' 5 | import { Icons } from './icons' 6 | 7 | export function ThemeToggle() { 8 | return ( 9 | document.documentElement.classList.toggle('dark')} 13 | > 14 | 24 | 34 | Toggle theme 35 | 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /packages/button/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/button/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@my-monorepo/button", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "exports": { 8 | ".": { 9 | "types": "./dist/index.d.ts", 10 | "import": "./dist/index.mjs", 11 | "require": "./dist/index.js" 12 | }, 13 | "./preset": { 14 | "types": "./dist/preset.d.ts", 15 | "import": "./dist/preset.mjs", 16 | "require": "./dist/preset.js" 17 | } 18 | }, 19 | "keywords": [], 20 | "author": "", 21 | "license": "ISC", 22 | "scripts": { 23 | "reset": "rimraf node_modules && rimraf dist", 24 | "codegen": "panda codegen --clean", 25 | "build": "tsup src/index.ts src/preset.ts --dts --format=esm,cjs --clean --dts --external @pandacss/dev --external @my-monorepo/ui-lib", 26 | "dev": "pnpm build --watch", 27 | "preview": "vite", 28 | "ship": "panda ship src/**/*.tsx --outfile dist/panda.json", 29 | "build-ship": "pnpm build && pnpm ship" 30 | }, 31 | "dependencies": { 32 | "@ark-ui/react": "^0.6.0", 33 | "@my-monorepo/preset": "workspace:^", 34 | "react": "^18.2.0", 35 | "react-dom": "^18.2.0" 36 | }, 37 | "devDependencies": { 38 | "@pandacss/dev": "^0.3.2", 39 | "@pandacss/preset-panda": "^0.3.2", 40 | "@pandacss/types": "^0.3.2", 41 | "@types/react": "^18.0.37", 42 | "@types/react-dom": "^18.0.11", 43 | "lucide-react": "^0.246.0", 44 | "vite": "^4.3.9", 45 | "vite-plugin-dts": "^2.3.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/button/panda.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@pandacss/dev' 2 | import presetPanda from '@pandacss/preset-panda' 3 | import { myMonorepoPreset } from '@my-monorepo/preset' 4 | import { shadcnButton } from './src/button.recipe' 5 | 6 | export default defineConfig({ 7 | presets: [myMonorepoPreset, presetPanda], 8 | // Whether to use css reset 9 | preflight: true, 10 | 11 | // Where to look for your css declarations 12 | include: ['./src/**/*.{js,jsx,ts,tsx}', './demo/**/*.{js,jsx,ts,tsx}'], 13 | 14 | // Files to exclude 15 | exclude: [], 16 | 17 | // Useful for theme customization 18 | theme: { 19 | extend: { 20 | recipes: { shadcnButton }, 21 | }, 22 | }, 23 | 24 | // The output directory for your css system 25 | outdir: '@my-monorepo/ui-lib', 26 | emitPackage: true, 27 | jsxFramework: 'react', 28 | }) 29 | -------------------------------------------------------------------------------- /packages/button/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@pandacss/dev/postcss': {}, 4 | }, 5 | } -------------------------------------------------------------------------------- /packages/button/src/button.recipe.ts: -------------------------------------------------------------------------------- 1 | import { createAnatomy } from '@ark-ui/react' 2 | 3 | import { defineParts, defineRecipe } from '@pandacss/dev' 4 | 5 | const buttonAnatomy = createAnatomy('shadcnButton', ['root']) 6 | const parts = defineParts(buttonAnatomy.build()) 7 | 8 | export const shadcnButton = defineRecipe({ 9 | name: 'shadcnButton', 10 | jsx: ['ShadcnButton'], 11 | base: parts({ 12 | root: { 13 | cursor: 'pointer', 14 | display: 'inline-flex', 15 | alignItems: 'center', 16 | justifyContent: 'center', 17 | borderRadius: 'md', 18 | fontSize: 'sm', 19 | fontWeight: 'medium', 20 | transitionProperty: 'colors', 21 | ringColor: 'shadcn.background', 22 | _focusVisible: { outline: 'none', ring: 2, ringOffset: 2 }, 23 | _disabled: { opacity: 0.5, pointerEvents: 'none' }, 24 | }, 25 | }), 26 | variants: { 27 | variant: { 28 | default: { 29 | bg: 'shadcn.primary', 30 | color: 'shadcn.primaryForeground', 31 | _hover: { 32 | bg: { 33 | base: 'hsl(222.2 47.4% 11.2% / 0.9)', 34 | _dark: 'hsl(210 40% 98% / 0.9)', 35 | }, 36 | }, 37 | }, 38 | destructive: { 39 | bg: 'shadcn.destructive', 40 | color: 'shadcn.destructiveForeground', 41 | _hover: { bg: 'shadcn.destructiveHover' }, 42 | }, 43 | outline: { 44 | border: '1px solid token(colors.shadcn.input)', 45 | _hover: { bg: 'shadcn.accentForeground', color: 'shadcn.accent' }, 46 | }, 47 | secondary: { 48 | bg: 'shadcn.secondary', 49 | color: 'shadcn.secondaryForeground', 50 | _hover: { bg: 'shadcn.secondary' }, 51 | }, 52 | ghost: { 53 | _hover: { bg: 'shadcn.accent', color: 'shadcn.accentForeground' }, 54 | }, 55 | link: { 56 | color: 'shadcn.primary', 57 | textUnderlineOffset: '4px', 58 | _hover: { textDecoration: 'underline' }, 59 | }, 60 | }, 61 | size: { 62 | default: { h: 10, py: 2, px: 4 }, 63 | sm: { h: 9, px: 3, borderRadius: 'md' }, 64 | lg: { h: 11, px: 8, borderRadius: 'md' }, 65 | }, 66 | }, 67 | defaultVariants: { 68 | variant: 'default', 69 | size: 'default', 70 | }, 71 | }) 72 | -------------------------------------------------------------------------------- /packages/button/src/button.tsx: -------------------------------------------------------------------------------- 1 | import { cx } from '@my-monorepo/ui-lib/css' 2 | import { ShadcnButtonVariantProps, shadcnButton } from '@my-monorepo/ui-lib/recipes' 3 | import { type HTMLStyledProps, styled } from '@my-monorepo/ui-lib/jsx' 4 | import { forwardRef } from 'react' 5 | 6 | interface ShadcnButtonProps extends HTMLStyledProps<'button'>, ShadcnButtonVariantProps {} 7 | 8 | export const ShadcnButton = forwardRef( 9 | ({ className, variant, size, ...props }, ref) => { 10 | return ( 11 | 18 | ) 19 | }, 20 | ) 21 | ShadcnButton.displayName = 'ShadcnButton' 22 | -------------------------------------------------------------------------------- /packages/button/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button' 2 | -------------------------------------------------------------------------------- /packages/button/src/preset.ts: -------------------------------------------------------------------------------- 1 | import { definePreset } from '@pandacss/dev' 2 | import type { Preset } from '@pandacss/types' 3 | import { shadcnButton } from './button.recipe' 4 | 5 | export const buttonPreset = definePreset({ 6 | theme: { 7 | extend: { 8 | recipes: { shadcnButton }, 9 | }, 10 | }, 11 | }) as Preset 12 | -------------------------------------------------------------------------------- /packages/button/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src", "demo"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /packages/button/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/preset/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@my-monorepo/preset", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "keywords": [], 7 | "author": "", 8 | "license": "ISC", 9 | "scripts": { 10 | "reset": "rimraf node_modules && rimraf dist", 11 | "codegen": "panda codegen --clean", 12 | "build": "tsup src/index.ts --dts --format=esm,cjs --clean --dts --external @pandacss/dev", 13 | "dev": "pnpm build --watch" 14 | }, 15 | "dependencies": { 16 | "@pandacss/dev": "^0.3.2" 17 | }, 18 | "devDependencies": { 19 | "@pandacss/types": "^0.3.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/preset/panda.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@pandacss/dev" 2 | 3 | export default defineConfig({ 4 | // Whether to use css reset 5 | preflight: true, 6 | 7 | // Where to look for your css declarations 8 | include: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"], 9 | 10 | // Files to exclude 11 | exclude: [], 12 | 13 | // Useful for theme customization 14 | theme: { 15 | extend: {} 16 | }, 17 | 18 | // The output directory for your css system 19 | outdir: "styled-system", 20 | 21 | }) -------------------------------------------------------------------------------- /packages/preset/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@pandacss/dev/postcss': {}, 4 | }, 5 | } -------------------------------------------------------------------------------- /packages/preset/src/index.ts: -------------------------------------------------------------------------------- 1 | import { definePreset } from '@pandacss/dev' 2 | import type { Preset } from '@pandacss/types' 3 | import { semanticTokens } from './semantic-tokens' 4 | 5 | export const myMonorepoPreset = definePreset({ 6 | theme: { 7 | extend: { 8 | tokens: { 9 | colors: { 10 | 'nice-yellow': { value: '#facc15' }, 11 | }, 12 | }, 13 | semanticTokens: { 14 | colors: { 15 | ...semanticTokens.colors, 16 | 'my-monorepo': { 17 | 'nice-yellow': { value: '{colors.nice-yellow}' }, 18 | }, 19 | }, 20 | }, 21 | }, 22 | }, 23 | }) as Preset 24 | -------------------------------------------------------------------------------- /packages/preset/src/semantic-tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from '@pandacss/dev' 2 | 3 | /** @see https://ui.shadcn.com/docs/theming */ 4 | export const semanticTokens = defineSemanticTokens({ 5 | colors: { 6 | shadcn: { 7 | background: { 8 | value: { base: 'hsl(0 0% 100%)', _dark: 'hsl(224 71% 4%)' }, 9 | }, 10 | foreground: { 11 | value: { 12 | base: 'hsl(222.2 47.4% 11.2%)', 13 | _dark: 'hsl(213 31% 91%)', 14 | }, 15 | }, 16 | muted: { 17 | value: { base: 'hsl(210 40% 96.1%)', _dark: 'hsl(223 47% 11%)' }, 18 | }, 19 | mutedForeground: { 20 | value: { 21 | base: 'hsl(215.4 16.3% 46.9%)', 22 | _dark: 'hsl(215.4 16.3% 56.9%)', 23 | }, 24 | }, 25 | popover: { 26 | value: { base: 'hsl(0 0% 100%)', _dark: 'hsl(224 71% 4%)' }, 27 | }, 28 | popoverForeground: { 29 | value: { 30 | base: 'hsl(222.2 47.4% 11.2%)', 31 | _dark: 'hsl(215 20.2% 65.1%)', 32 | }, 33 | }, 34 | card: { 35 | value: { base: 'hsl(0 0% 100%)', _dark: 'hsl(224 71% 4%)' }, 36 | }, 37 | cardForeground: { 38 | value: { 39 | base: 'hsl(222.2 47.4% 11.2%)', 40 | _dark: 'hsl(213 31% 91%)', 41 | }, 42 | }, 43 | border: { 44 | value: { 45 | base: 'hsl(214.3 31.8% 91.4%)', 46 | _dark: 'hsl(216 34% 17%)', 47 | }, 48 | }, 49 | input: { 50 | value: { 51 | base: 'hsl(214.3 31.8% 91.4%)', 52 | _dark: 'hsl(216 34% 17%)', 53 | }, 54 | }, 55 | primary: { 56 | value: { 57 | base: 'hsl(222.2 47.4% 11.2%)', 58 | _dark: 'hsl(210 40% 98%)', 59 | }, 60 | }, 61 | primaryForeground: { 62 | value: { 63 | base: 'hsl(210 40% 98%)', 64 | _dark: 'hsl(222.2 47.4% 1.2%)', 65 | }, 66 | }, 67 | secondary: { 68 | value: { 69 | base: 'hsl(210 40% 96.1%)', 70 | _dark: 'hsl(222.2 47.4% 11.2%)', 71 | }, 72 | }, 73 | secondaryForeground: { 74 | value: { 75 | base: 'hsl(222.2 47.4% 11.2%)', 76 | _dark: 'hsl(210 40% 98%)', 77 | }, 78 | }, 79 | accent: { 80 | value: { base: 'hsl(210 40% 96.1%)', _dark: 'hsl(216 34% 17%)' }, 81 | }, 82 | accentForeground: { 83 | value: { 84 | base: 'hsl(222.2 47.4% 11.2%)', 85 | _dark: 'hsl(210 40% 98%)', 86 | }, 87 | }, 88 | destructive: { 89 | value: { base: 'hsl(0 100% 50%)', _dark: 'hsl(0 63% 31%)' }, 90 | }, 91 | destructiveForeground: { 92 | value: { base: 'hsl(210 40% 98%)', _dark: 'hsl(210 40% 98%)' }, 93 | }, 94 | ring: { 95 | value: { 96 | base: 'hsl(215 20.2% 65.1%)', 97 | _dark: 'hsl(216 34% 17%)', 98 | }, 99 | }, 100 | radius: { value: { base: '0.5rem', _dark: '0.5rem' } }, 101 | }, 102 | }, 103 | }) 104 | -------------------------------------------------------------------------------- /packages/some-component/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@my-monorepo/some-component", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.mjs", 6 | "types": "dist/index.d.ts", 7 | "keywords": [], 8 | "author": "", 9 | "license": "ISC", 10 | "scripts": { 11 | "reset": "rimraf node_modules && rimraf dist", 12 | "codegen": "panda codegen --clean", 13 | "build": "tsup src/index.ts --dts --format=esm,cjs --clean --dts --external @pandacss/dev --external @my-monorepo/ui-lib", 14 | "dev": "pnpm build --watch", 15 | "preview": "vite", 16 | "ship": "panda ship src/**/*.tsx --outfile dist/panda.json", 17 | "build-ship": "pnpm build && pnpm ship" 18 | }, 19 | "dependencies": { 20 | "@ark-ui/react": "^0.6.0", 21 | "@my-monorepo/preset": "workspace:^", 22 | "react": "^18.2.0", 23 | "react-dom": "^18.2.0" 24 | }, 25 | "devDependencies": { 26 | "@pandacss/dev": "^0.3.2", 27 | "@pandacss/preset-panda": "^0.3.2", 28 | "@pandacss/types": "^0.3.2", 29 | "@types/react": "^18.0.37", 30 | "@types/react-dom": "^18.0.11", 31 | "lucide-react": "^0.246.0", 32 | "vite": "^4.3.9", 33 | "vite-plugin-dts": "^2.3.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/some-component/panda.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@pandacss/dev' 2 | import presetPanda from '@pandacss/preset-panda' 3 | import { myMonorepoPreset } from '@my-monorepo/preset' 4 | 5 | export default defineConfig({ 6 | presets: [myMonorepoPreset, presetPanda], 7 | // Whether to use css reset 8 | preflight: true, 9 | 10 | // Where to look for your css declarations 11 | include: ['./src/**/*.{js,jsx,ts,tsx}'], 12 | 13 | // Files to exclude 14 | exclude: [], 15 | 16 | // Useful for theme customization 17 | theme: { 18 | extend: {}, 19 | }, 20 | 21 | // The output directory for your css system 22 | outdir: '@my-monorepo/ui-lib', 23 | emitPackage: true, 24 | jsxFramework: 'react', 25 | }) 26 | -------------------------------------------------------------------------------- /packages/some-component/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './some-component' 2 | -------------------------------------------------------------------------------- /packages/some-component/src/some-component.tsx: -------------------------------------------------------------------------------- 1 | import { SystemStyleObject } from '@my-monorepo/preset/styled-system/types' 2 | import { cx, css } from '@my-monorepo/ui-lib/css' 3 | 4 | import { PropsWithChildren } from 'react' 5 | 6 | export const SomeComponent = ({ 7 | children, 8 | className, 9 | }: PropsWithChildren>>) => { 10 | return ( 11 |
17 |

18 | Using the `panda ship` command, we can generate a file that contains the extraction result (from your library 19 | component internal styles) so that you can include it as just another source of files to extract styles from. 20 |
21 | 22 | You can try removing the `'./node_modules/@my-monorepo/some-component/dist/panda.json',` line from the 23 | `app/web/panda.config.ts` and see that the styles from this component will be missing. 24 | 25 |

26 | {children} 27 |
28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /packages/some-component/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /packages/some-component/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | - apps/** 2 | - packages/** 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | } 19 | } 20 | --------------------------------------------------------------------------------