Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
2783a68
feat(types): add LibManifest type
Adebesin-Cell May 5, 2026
0401d48
refactor(types): alphabetize lib-manifest export
Adebesin-Cell May 5, 2026
f5a4128
test(node): add lib-manifest fixtures
Adebesin-Cell May 5, 2026
ebb8e7b
feat(node): add readLibManifest
Adebesin-Cell May 5, 2026
5c62b6d
fix(node): only swallow EEXIST in lib-manifest test setup
Adebesin-Cell May 5, 2026
5844446
feat(node): export readLibManifest
Adebesin-Cell May 5, 2026
23d07ed
test(fixture): hand-write panda.lib.json for smoke test
Adebesin-Cell May 5, 2026
7686b63
refactor(node): isolate lib-manifest test symlinks in tmpdir
Adebesin-Cell May 5, 2026
2435865
refactor(node): reuse isObject from @pandacss/shared
Adebesin-Cell May 5, 2026
3ecaa85
refactor(config): move lib-manifest reader from node to config
Adebesin-Cell May 5, 2026
f1fa60e
feat(types): add designSystem field to Config
Adebesin-Cell May 5, 2026
e3c0a20
feat(config): wire designSystem into getResolvedConfig
Adebesin-Cell May 5, 2026
c88571b
test(config): tighten designSystem getResolvedConfig assertions
Adebesin-Cell May 5, 2026
98d3c9d
feat(node): hydrate encoder from designSystem manifest buildinfo
Adebesin-Cell May 5, 2026
a4ebc1c
fix(node): guard designSystem manifest read against throw
Adebesin-Cell May 5, 2026
d3d16a0
fix(config): extract named-export preset from bundled module in desig…
Adebesin-Cell May 5, 2026
fdbaf64
test(fixture): use designSystem in app config
Adebesin-Cell May 5, 2026
323607b
fix(config): expand preset key heuristic and relocate designSystem field
Adebesin-Cell May 5, 2026
8563d78
perf(config): memoize readLibManifest to skip duplicate disk reads
Adebesin-Cell May 6, 2026
970e78f
docs(node): note cross-package fixture path coupling
Adebesin-Cell May 6, 2026
03cda90
docs(types): clarify LibManifest schemaVersion vs buildinfo schemaVer…
Adebesin-Cell May 6, 2026
6bf030f
test(sandbox): add minimal designSystem example
Adebesin-Cell May 6, 2026
9994274
feat(types): add internal libraryMode field for panda lib
Adebesin-Cell May 6, 2026
294f321
feat(node): gate designSystem hydration on libraryMode flag
Adebesin-Cell May 6, 2026
335252f
feat(node): smart include resolves bare specifiers
Adebesin-Cell May 6, 2026
9da793d
fix(node): tighten smart-include β€” cwd, logger context, file-path ent…
Adebesin-Cell May 6, 2026
51628b5
fix(node): add dist fixture for file-path-style package.json entries …
Adebesin-Cell May 6, 2026
985d143
test(sandbox): demonstrate smart include in example app
Adebesin-Cell May 6, 2026
c5c4c76
fix(sandbox): emit recipes from styled-system package in v2-ds-example
Adebesin-Cell May 6, 2026
77e7226
fix(sandbox): emit recipes from styled-system package in v2-ds-fixture
Adebesin-Cell May 6, 2026
016586f
feat(node): add writeLibManifest
Adebesin-Cell May 6, 2026
49b00a2
fix(node): guard installedVersion + accept pandaVersion option
Adebesin-Cell May 6, 2026
66af8a7
feat(node): add buildLib orchestrator
Adebesin-Cell May 6, 2026
bd6d986
refactor(node): tighten buildLib types β€” drop any cast, thread pandaV…
Adebesin-Cell May 6, 2026
93d57b3
feat(cli): add panda lib command
Adebesin-Cell May 6, 2026
73232a5
refactor(cli): type the panda lib command flags
Adebesin-Cell May 6, 2026
6eb1a50
feat(cli): add --watch to panda lib
Adebesin-Cell May 6, 2026
2577133
test(sandbox): regenerate v2-ds-example lib manifest via panda lib
Adebesin-Cell May 6, 2026
ccd0654
test(sandbox): regenerate v2-ds-fixture lib-leaf manifest via panda lib
Adebesin-Cell May 6, 2026
1018003
feat(cli)!: remove panda ship β€” folded into panda lib
Adebesin-Cell May 6, 2026
4abfb7b
feat(cli)!: remove panda emit-pkg β€” folded into panda lib
Adebesin-Cell May 6, 2026
606ae30
docs(changeset): document panda lib migration
Adebesin-Cell May 6, 2026
44afb36
test(cli): skip ship and emit-pkg tests removed
Adebesin-Cell May 6, 2026
deeea15
refactor(node): dedupe package.json read in buildLib
Adebesin-Cell May 6, 2026
920e733
test(sandbox): replace css:ship scripts with lib in v2-ds-fixture
Adebesin-Cell May 6, 2026
dea516b
fix(node): smart-include falls back to main-entry walkup when package…
Adebesin-Cell May 6, 2026
c9c5d67
test(sandbox): add @v2-ds-example/charts non-panda lib for smart-incl…
Adebesin-Cell May 6, 2026
43925ef
feat(types): add LibManifest.presetExport
Adebesin-Cell May 6, 2026
603081d
feat(node): panda lib detects + writes presetExport
Adebesin-Cell May 6, 2026
46e2773
fix(node): warn on preset detect failure + cover default-export branch
Adebesin-Cell May 6, 2026
bcf58d4
refactor(config): drop preset heuristic β€” use manifest.presetExport
Adebesin-Cell May 6, 2026
e454468
fix(node): resolve preset path against manifest dir in detectPresetEx…
Adebesin-Cell May 6, 2026
5f99b79
test(sandbox): regenerate fixture manifests with presetExport
Adebesin-Cell May 6, 2026
af5a357
fix(config): revert valid-pkg manifest β€” fallback handles omitted pre…
Adebesin-Cell May 6, 2026
dff5ab0
test(sandbox): add v2-ds-fixture depth-3 chain sources
Adebesin-Cell May 6, 2026
3ead9f1
chore: extend smart-include fixture + lockfile
Adebesin-Cell May 6, 2026
3671f41
fix(config): type designSystemPreset as Preset (matches presets array…
Adebesin-Cell May 6, 2026
81b7699
refactor(config): strip noisy comments in designSystem block
Adebesin-Cell May 6, 2026
13624d7
refactor: strip noisy comments across new code
Adebesin-Cell May 6, 2026
8ebb133
refactor: drop remaining inline comments from new code
Adebesin-Cell May 6, 2026
fb8c8a7
refactor(node): drop unused error bindings in create-context catches
Adebesin-Cell May 7, 2026
e2c4ba2
chore(sandbox): untrack generated styled-system + dist artifacts
Adebesin-Cell May 7, 2026
2fb66c9
feat(node): panda lib compiles preset.ts β†’ dist/preset.mjs
Adebesin-Cell May 7, 2026
d1bc0f1
test(node): cover panda lib preset compilation edges
Adebesin-Cell May 7, 2026
4dd9e63
feat(node): make designSystem hydration unconditional
Adebesin-Cell May 7, 2026
5167db5
test(node): cover panda lib edges β€” preset compile + chain composition
Adebesin-Cell May 7, 2026
096016e
test(config): cover forward-compat manifest + presetExport extraction
Adebesin-Cell May 7, 2026
6e1d7e3
feat(config): cycle-detect preset chains in getResolvedConfig
Adebesin-Cell May 7, 2026
5d22dd1
fix(config,node): correctness + portability cleanups in design-system…
Adebesin-Cell May 7, 2026
25852f7
fix(config): cast preset through unknown to satisfy preset:resolved h…
Adebesin-Cell May 7, 2026
2dd0b95
chore(changeset): consolidate design-system changesets
Adebesin-Cell May 8, 2026
d8d43ef
chore: tighten comment wording
Adebesin-Cell May 8, 2026
399da71
chore: drop create-recipe-context codegen β€” belongs to feat/create-re…
Adebesin-Cell May 8, 2026
c2c74ee
chore: tighten test/doc wording
Adebesin-Cell May 8, 2026
0f41f47
fix(config,node): drop manifest cache, fail loud on missing preset
Adebesin-Cell May 8, 2026
13194c9
fix(sandbox): add missing src/index.ts barrels in v2-ds-fixture libs
Adebesin-Cell May 12, 2026
7d30a08
refactor(sandbox): lib generates own local styled-system in v2-ds-fix…
Adebesin-Cell May 12, 2026
d24cb0b
refactor(sandbox): lib-mid generates own local styled-system, drops d…
Adebesin-Cell May 12, 2026
53517a1
refactor(sandbox): lib-leaf generates own local styled-system, drops …
Adebesin-Cell May 12, 2026
2ab8ed0
refactor(sandbox): app generates own local styled-system with strictT…
Adebesin-Cell May 12, 2026
cc29280
refactor(sandbox): drop shared styled-system workspace package from v…
Adebesin-Cell May 12, 2026
a3bee40
feat(config,node,types): transitive designSystem chain via lib manifest
Adebesin-Cell May 12, 2026
951ae73
refactor(sandbox): v2-ds-fixture chain via manifest designSystem, not…
Adebesin-Cell May 12, 2026
9c4396d
fix(config): walk manifest chain from each level's own dir, not initi…
Adebesin-Cell May 12, 2026
acd5d9c
test(sandbox): add chain-3-alt sibling branch to v2-ds-stress
Adebesin-Cell May 12, 2026
6012d14
fix(node,config): address review on designSystem chain
Adebesin-Cell May 13, 2026
2d3c554
Merge branch 'v2' into v2-designsystem-all-levels
Adebesin-Cell May 18, 2026
d33413a
Merge branch 'v2' into v2-designsystem-all-levels
Adebesin-Cell May 21, 2026
89ca896
feat(node,config,types): design-system dx β€” propagation, drift, guards
Adebesin-Cell May 21, 2026
9350a27
chore: prettier formatting cleanup
Adebesin-Cell May 21, 2026
0f66e9d
feat(sandbox): make v2-ds-example a runnable next 15 app
Adebesin-Cell May 21, 2026
45f3910
fix(sandbox): restore brand2 borderColor in panel demo
Adebesin-Cell May 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .changeset/first-class-design-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
'@pandacss/dev': major
'@pandacss/node': major
'@pandacss/types': major
'@pandacss/config': major
---

First-class design system support. One config field for consumers (`designSystem`), one CLI command for lib authors (`panda lib`). Works at every level of a chain composition.

**Lib author flow.** `panda lib` produces a complete `dist/`:

- `panda.buildinfo.json` (replaces `panda ship`)
- `panda.lib.json` (new β€” design-system manifest)
- `preset.mjs` (new β€” compiled preset; consumers no longer need source `.ts` shipped)
- patched `package.json` exports including `./preset` β†’ `./dist/preset.mjs`

`panda lib --watch` rebuilds on `src/` changes.

**Migration:**

```bash
# v1
panda codegen && panda ship && panda emit-pkg

# v2
panda lib
```

`panda ship` and `panda emit-pkg` are removed.

**Consumer flow.** Point at the lib via:

```ts
designSystem: '@acme/ds'
```

One field replaces the prior `presets` + `importMap` + `outdir` + `include`-with-buildinfo coordination.

**Smart include.** Bare specifiers in `include` resolve via Node module resolution. Libs with a `panda.lib.json` are skipped (manifest carries the buildinfo path); libs without a manifest get auto-globbed via their `package.json#files`.

**Chain composition.** Intermediate libs in a chain use the same `designSystem: '@parent'` declaration β€” same shape at depth 1 as at depth N.
27 changes: 0 additions & 27 deletions packages/cli/__tests__/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,31 +190,4 @@ describe('CLI', () => {
const debugConfigExists = await fs.access(path.resolve(paths.styledSystem, 'debug/config.json'))
expect(debugConfigExists).toBeUndefined()
})

test('ship', async () => {
const cmd = `node ${binPath} ship --cwd="${testsCwd}"`

// ship
const output = runCommand(cmd, { cwd: testsCwd })
expect(output.includes('files using Panda')).toBe(true)

// Check that the `styled-system/panda.buildinfo.json` file was created
const buildInfoExists = await fs.access(path.resolve(paths.styledSystem, 'panda.buildinfo.json'))
expect(buildInfoExists).toBeUndefined()
})

test('emit-pkg', async () => {
const cmd = `node ${binPath} emit-pkg --cwd="${testsCwd}"`

// emit-pkg
const output = runCommand(cmd, { cwd: testsCwd })
expect(output.includes('Emit package.json')).toBe(true)

// Check that the `package.json` file was created
const pkgExists = await fs.access(paths.pkgJson)
expect(pkgExists).toBeUndefined()

// Clean up
await fs.unlink(paths.pkgJson)
})
})
137 changes: 16 additions & 121 deletions packages/cli/src/cli-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { colors, logger } from '@pandacss/logger'
import {
PandaContext,
analyze,
buildInfo,
buildLib,
codegen,
cssgen,
debug,
Expand All @@ -28,12 +28,11 @@ import type {
CodegenCommandFlags,
CssGenCommandFlags,
DebugCommandFlags,
EmitPackageCommandFlags,
InitCommandFlags,
LibCommandFlags,
MainCommandFlags,
McpCommandFlags,
McpInitCommandFlags,
ShipCommandFlags,
SpecCommandFlags,
StudioCommandFlags,
} from './types'
Expand Down Expand Up @@ -478,39 +477,29 @@ export async function main() {
})

cli
.command('ship [glob]', 'Ship extract result from files in glob')
.command('lib', 'Build a panda design-system library β€” buildinfo + manifest + package exports')
.option('--outdir <dir>', 'Output directory for dist artifacts', { default: 'dist' })
.option('--preset <path>', 'Path to preset file relative to manifest', { default: '../preset.ts' })
.option('--silent', "Don't print any logs")
.option(
'--o, --outfile [file]',
"Output path for the build info file, default to './styled-system/panda.buildinfo.json'",
)
.option('-m, --minify', 'Minify generated JSON file')
.option('-w, --watch', 'Watch src/ and rebuild')
.option('-p, --poll', 'Use polling instead of filesystem events when watching')
.option('-c, --config <path>', 'Path to panda config file')
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
.option('-w, --watch', 'Watch files and rebuild')
.option('-p, --poll', 'Use polling instead of filesystem events when watching')
.action(async (maybeGlob?: string, flags: ShipCommandFlags = {}) => {
const { silent, outfile: outfileFlag, minify, config: configPath, watch, poll } = flags

const cwd = resolve(flags.cwd!)
.action(async (flags: LibCommandFlags = {}) => {
const { silent, outdir, preset, watch, poll, config: configPath } = flags

if (silent) {
logger.level = 'silent'
}

const cwd = resolve(flags.cwd!)

let ctx = await loadConfigAndCreateContext({
cwd,
config: maybeGlob ? { include: [maybeGlob] } : undefined,
configPath,
})

const outfile = outfileFlag ?? join(...ctx.paths.root, 'panda.buildinfo.json')

if (minify) {
ctx.config.minify = true
}

await buildInfo(ctx, outfile)
await buildLib(ctx, { outdir, preset })

if (watch) {
ctx.watchConfig(
Expand All @@ -520,8 +509,8 @@ export async function main() {
})

await ctx.hooks['config:change']?.({ config: ctx.config, changes: affecteds })
await buildInfo(ctx, outfile)
logger.info('ctx:updated', 'config rebuilt βœ…')
await buildLib(ctx, { outdir, preset })
logger.info('ctx:updated', 'lib rebuilt βœ…')
},
{ cwd, poll },
)
Expand All @@ -531,109 +520,15 @@ export async function main() {
ctx.project.removeSourceFile(ctx.runtime.path.abs(cwd, file))
} else if (event === 'change') {
ctx.project.reloadSourceFile(file)
await buildInfo(ctx, outfile)
await buildLib(ctx, { outdir, preset })
} else if (event === 'add') {
ctx.project.createSourceFile(file)
await buildInfo(ctx, outfile)
await buildLib(ctx, { outdir, preset })
}
})
}
})

cli
.command('emit-pkg', 'Emit package.json with entrypoints')
.option('--outdir <dir>', 'Output directory', { default: '.' })
.option('--base <source>', 'The base directory of the package.json entrypoints')
.option('--silent', "Don't print any logs")
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
.action(async (flags: EmitPackageCommandFlags) => {
const { outdir, silent, base } = flags

if (silent) {
logger.level = 'silent'
}

const cwd = resolve(flags.cwd!)

const ctx = await loadConfigAndCreateContext({
cwd,
config: { cwd },
})

const pkgPath = resolve(cwd, outdir, 'package.json')
const exists = ctx.runtime.fs.existsSync(pkgPath)

const exports = [] as any[]

const createDir = (...dir: string[]) => {
return ['.', base, ...dir].filter(Boolean).join('/')
}

const createEntry = (dir: string) => ({
types: ctx.file.extDts(createDir(dir, 'index')),
require: ctx.file.ext(createDir(dir, 'index')),
import: ctx.file.ext(createDir(dir, 'index')),
})

exports.push(
['./css', createEntry('css')],
['./tokens', createEntry('tokens')],
['./types', createEntry('types')],
)

if (!ctx.patterns.isEmpty()) {
exports.push(['./patterns', createEntry('patterns')])
}

if (!ctx.recipes.isEmpty()) {
exports.push(['./recipes', createEntry('recipes')])
}

if (!ctx.patterns.isEmpty()) {
exports.push(['./jsx', createEntry('jsx')])
}

if (ctx.config.themes) {
exports.push(['./themes', createEntry('themes')])
}

const stylesDir = createDir('styles.css')

if (!exists) {
//
const content = {
name: outdir,
description: 'This package is auto-generated by Panda CSS',
version: '0.1.0',
type: 'module',
keywords: ['pandacss', 'styled-system', 'codegen'],
license: 'ISC',
exports: {
...Object.fromEntries(exports),
'./styles.css': stylesDir,
},
scripts: {
prepare: 'panda codegen --clean',
},
}

await ctx.runtime.fs.writeFile(pkgPath, JSON.stringify(content, null, 2))
//
} else {
//
const content = JSON.parse(ctx.runtime.fs.readFileSync(pkgPath))
content.exports = {
...content.exports,
...Object.fromEntries(exports),
'./styles.css': stylesDir,
}

await ctx.runtime.fs.writeFile(pkgPath, JSON.stringify(content, null, 2))
}

logger.info('cli', `Emit package.json to ${pkgPath}`)
})

cli
.command('mcp', 'Start MCP server for AI assistants')
.option('-c, --config <path>', 'Path to panda config file')
Expand Down
27 changes: 10 additions & 17 deletions packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,6 @@ export interface DebugCommandFlags {
logfile?: string
}

export interface ShipCommandFlags {
silent?: boolean
minify?: boolean
outfile?: string
cwd?: string
config?: string
watch?: boolean
poll?: boolean
}

export interface CodegenCommandFlags extends Pick<Config, 'cwd' | 'poll' | 'watch'> {
clean?: boolean
silent?: boolean
Expand All @@ -75,6 +65,16 @@ export interface CodegenCommandFlags extends Pick<Config, 'cwd' | 'poll' | 'watc
logfile?: string
}

export interface LibCommandFlags {
silent?: boolean
outdir?: string
preset?: string
config?: string
cwd?: string
watch?: boolean
poll?: boolean
}

export interface MainCommandFlags extends Pick<Config, 'cwd' | 'poll' | 'watch'> {
outdir?: string
minify?: boolean
Expand All @@ -91,13 +91,6 @@ export interface MainCommandFlags extends Pick<Config, 'cwd' | 'poll' | 'watch'>
logfile?: string
}

export interface EmitPackageCommandFlags {
outdir: string
silent?: boolean
cwd: string
base?: string
}

export interface McpCommandFlags {
cwd?: string
config?: string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"schemaVersion": 1,
"name": "@panda-test/broken-buildinfo",
"version": "1.0.0",
"panda": "^1.0.0",
"preset": "./preset.js",
"importMap": {},
"buildinfo": "./nonexistent.json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { name: '@panda-test/broken-buildinfo/preset' }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@panda-test/broken-buildinfo",
"version": "1.0.0",
"private": true,
"exports": {
"./panda.lib.json": "./dist/panda.lib.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"schemaVersion": 1,
"name": "@panda-test/forward-compat",
"version": "1.0.0",
"panda": "^1.0.0",
"preset": "./preset.js",
"importMap": {},
"buildinfo": "./panda.buildinfo.json",
"futureField": "v2-only-field",
"anotherUnknown": { "nested": true }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@panda-test/forward-compat",
"version": "1.0.0",
"exports": {
"./panda.lib.json": "./dist/panda.lib.json",
"./panda.buildinfo.json": "./dist/panda.buildinfo.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"schemaVersion": 1,
"name": "@panda-test/incomplete"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@panda-test/incomplete",
"version": "1.0.0",
"private": true,
"exports": {
"./panda.lib.json": "./dist/panda.lib.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ this is not json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@panda-test/malformed",
"version": "1.0.0",
"private": true,
"exports": {
"./panda.lib.json": "./dist/panda.lib.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"schemaVersion": 99,
"name": "@panda-test/newer-version",
"version": "1.0.0",
"panda": "^99.0.0",
"preset": "./preset.js",
"importMap": {},
"buildinfo": "./panda.buildinfo.json"
}
Loading