Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into chore/update-ts-56
Browse files Browse the repository at this point in the history
  • Loading branch information
segunadebayo committed Dec 24, 2024
2 parents 029d2eb + cea56ec commit e4a3c0f
Show file tree
Hide file tree
Showing 40 changed files with 6,944 additions and 5,679 deletions.
19 changes: 19 additions & 0 deletions .changeset/nervous-pans-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'@pandacss/types': minor
'@pandacss/node': minor
'@pandacss/dev': minor
'@pandacss/reporter': minor
---

Adds support for static analysis of used tokens and recipe variants. It helps to get a birds-eye view of how your design
system is used and answers the following questions:

- What tokens are most used?
- What recipe variants are most used?
- How many hardcoded values vs tokens do we have?

```sh
panda analyze --scope=<token|recipe>
```

> Still work in progress but we're excited to get your feedback!
32 changes: 32 additions & 0 deletions .changeset/stale-drinks-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
'@pandacss/token-dictionary': minor
'@pandacss/generator': minor
'@pandacss/types': minor
---

Add support for semantic tokens in composite shadow `blur`, `offsetX`, `offsetY` and `spread` properties.

This enables the use of semantic tokens in composite shadow properties.

```ts
// panda.config.ts

export default defineConfig({
theme: {
tokens: {
// ...
shadows: {
sm: {
value: {
offsetX: '{spacing.3}',
offsetY: '{spacing.3}',
blur: '1rem',
spread: '{spacing.3}',
color: '{colors.red}',
},
},
},
},
},
})
```
17 changes: 17 additions & 0 deletions .changeset/tasty-ducks-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@pandacss/parser': patch
'@pandacss/core': patch
---

Improve inference of slots in slot recipes when spreading and concatenating slot names.

This handles the following case gracefully:

```ts
const styles = sva({
className: 'foo',
slots: [...componentAnatomy.keys(), 'additional', 'slots', 'here'],
})
```

Panda will now infer the slots from the anatomy and add them to the recipe.
27 changes: 17 additions & 10 deletions packages/cli/src/cli-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { findConfig } from '@pandacss/config'
import { colors, logger } from '@pandacss/logger'
import {
PandaContext,
analyzeTokens,
analyze,
buildInfo,
codegen,
cssgen,
Expand All @@ -14,7 +14,6 @@ import {
setupGitIgnore,
setupPostcss,
startProfiling,
writeAnalyzeJSON,
type CssGenOptions,
} from '@pandacss/node'
import { PandaError, compact } from '@pandacss/shared'
Expand Down Expand Up @@ -361,10 +360,14 @@ export async function main() {
.command('analyze [glob]', 'Analyze design token usage in glob')
.option('--outfile [filepath]', 'Output analyze report in JSON')
.option('--silent', "Don't print any logs")
.option('--scope <type>', 'Select analysis scope (token or recipe)')
.option('-c, --config <path>', 'Path to panda config file')
.option('--cwd <cwd>', 'Current working directory', { default: cwd })
.action(async (maybeGlob?: string, flags: AnalyzeCommandFlags = {}) => {
const { silent, config: configPath } = flags
const { silent, config: configPath, scope } = flags

const tokenScope = scope == null || scope === 'token'
const recipeScope = scope == null || scope === 'recipe'

const cwd = resolve(flags.cwd!)

Expand All @@ -378,19 +381,23 @@ export async function main() {
configPath,
})

const result = analyzeTokens(ctx, {
onResult(file) {
logger.info('cli', `Analyzed ${colors.bold(file)}`)
},
})
const result = analyze(ctx)

if (flags?.outfile && typeof flags.outfile === 'string') {
await writeAnalyzeJSON(flags.outfile, result, ctx)
await result.writeReport(flags.outfile)
logger.info('cli', `JSON report saved to ${resolve(flags.outfile)}`)
return
}

logger.info('cli', `Found ${result.propByIndex.size} token used in ${result.derived.byFilePathMaps.size} files`)
if (tokenScope && !ctx.tokens.isEmpty) {
const tokenAnalysis = result.getTokenReport()
logger.info('analyze:tokens', `Token usage report 🎨 \n${tokenAnalysis.formatted}`)
}

if (recipeScope && !ctx.recipes.isEmpty()) {
const recipeAnalysis = result.getRecipeReport()
logger.info('analyze:recipes', `Recipe usage report 🎛️ \n${recipeAnalysis.formatted}`)
}
})

cli
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export interface AnalyzeCommandFlags {
outfile?: string
cwd?: string
config?: string
scope?: 'token' | 'recipe'
}

export interface DebugCommandFlags {
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,10 @@ export class Context {
recipes: this.recipes,
patterns: this.patterns,
jsx: this.jsx,
syntax: config.syntax,
config: this.config,
tokens: this.tokens,
conditions: this.conditions,
utility: this.utility,
encoder: this.encoder,
tsOptions: this.conf.tsOptions,
join: (...paths: string[]) => paths.join('/'),
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/recipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export class Recipes {

private context!: SerializeContext

get config() {
return this.recipes
}

constructor(private recipes: RecipeRecord = {}) {
this.prune()
}
Expand Down Expand Up @@ -296,6 +300,13 @@ export class Recipes {
})
})

recipe.compoundVariants?.forEach((compoundVariant) => {
if (!compoundVariant) return
Object.keys(compoundVariant.css ?? {}).forEach((name) => {
slots.add(name)
})
})

return Array.from(slots)
}

Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/style-encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
normalizeStyleObject,
toResponsiveObject,
traverse,
uniq,
} from '@pandacss/shared'
import type {
Dict,
Expand Down Expand Up @@ -268,7 +269,9 @@ export class StyleEncoder {
}

processAtomicSlotRecipe = (recipe: PartialBy<SlotRecipeDefinition, 'slots'>) => {
if (!recipe.slots?.filter(Boolean).length) recipe.slots = Recipes.inferSlots(recipe)
const inferredSlots = Recipes.inferSlots(recipe)
recipe.slots = uniq([...(recipe.slots ?? []), ...inferredSlots].filter(Boolean))

const slots = getSlotRecipes(recipe)

for (const slotRecipe of Object.values(slots)) {
Expand Down
10 changes: 8 additions & 2 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { TokenDictionary } from '@pandacss/token-dictionary'
import type {
Config,
Dict,
Expand All @@ -9,13 +10,15 @@ import type {
TSConfig,
UserConfig,
} from '@pandacss/types'
import type { Conditions } from './conditions'
import type { Context } from './context'
import type { ImportMap } from './import-map'
import type { JsxEngine } from './jsx'
import type { Layers } from './layers'
import type { Patterns } from './patterns'
import type { Recipes } from './recipes'
import type { StyleEncoder } from './style-encoder'
import type { Context } from './context'
import type { Utility } from './utility'

export interface TransformResult {
layer?: string
Expand Down Expand Up @@ -114,9 +117,12 @@ export interface ParserOptions {
hash: HashOptions
imports: ImportMap
jsx: JsxEngine
syntax: Config['syntax']
config: Config
recipes: Recipes
tokens: TokenDictionary
patterns: Patterns
utility: Utility
conditions: Conditions
encoder: StyleEncoder
join: (...paths: string[]) => string
compilerOptions: TSConfig['compilerOptions']
Expand Down
31 changes: 26 additions & 5 deletions packages/core/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,17 +413,24 @@ export class Utility {
return this
}

private getTransformArgs = (raw: string): TransformArgs => {
const token = Object.assign(this.getToken.bind(this), {
private getTokenFn = () => {
return Object.assign(this.getToken.bind(this), {
raw: (path: string) => this.tokens.getByName(path),
})
}

const _colorMix = (value: string) => colorMix(value, token)
resolveColorMix = (value: string) => {
const token = this.getTokenFn()
return colorMix(value, token)
}

private getTransformArgs = (raw: string): TransformArgs => {
return {
token,
token: this.getTokenFn(),
raw,
utils: { colorMix: _colorMix },
utils: {
colorMix: this.resolveColorMix.bind(this),
},
}
}

Expand Down Expand Up @@ -548,4 +555,18 @@ export class Utility {
isDeprecated = (prop: string) => {
return this.deprecated.has(prop)
}

/**
* Returns the token type for a given property
*/
getTokenType = (prop: string) => {
const set = this.types.get(prop)
if (!set) return
for (const type of set) {
const match = type.match(TOKEN_TYPE_PATTERN)
if (match) return match[1]
}
}
}

const TOKEN_TYPE_PATTERN = /type:Tokens\["([^"]+)"\]/
9 changes: 9 additions & 0 deletions packages/extractor/src/box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ export const box = {
return new BoxNodeConditional({ type: 'conditional', whenTrue, whenFalse, node, stack })
},
from: toBoxNode,
objectToMap: (value: Record<string, unknown>, node: Node, stack: Node[]) => {
const map = new Map(
Object.entries(value).map(([k, v]: [string, any]) => {
const boxed = box.from(v, node, stack)
return [k, boxed || null]
}),
)
return new BoxNodeMap({ type: 'map', value: map, node, stack })
},
//
emptyObject: (node: Node, stack: Node[]) => {
return new BoxNodeObject({ type: 'object', value: {}, isEmpty: true, node, stack })
Expand Down
37 changes: 37 additions & 0 deletions packages/generator/__tests__/generate-token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,43 @@ describe('generator', () => {
`)
})

test('shadow tokens - composite', () => {
const css = tokenCss({
eject: true,
theme: {
tokens: {
spacing: {
'3': { value: '1rem' },
},
colors: {
red: { value: '#ff0000' },
},
shadows: {
sm: {
value: {
offsetX: '{spacing.3}',
offsetY: '{spacing.3}',
blur: '1rem',
spread: '{spacing.3}',
color: '{colors.red}',
},
},
},
},
},
})

expect(css).toMatchInlineSnapshot(`
"@layer tokens {
:where(html) {
--spacing-3: 1rem;
--colors-red: #ff0000;
--shadows-sm: var(--spacing-3) var(--spacing-3) 1rem var(--spacing-3) var(--colors-red);
}
}"
`)
})

test('[css] should generate css', () => {
expect(tokenCss()).toMatchInlineSnapshot(`
"@layer tokens {
Expand Down
4 changes: 1 addition & 3 deletions packages/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
"dependencies": {
"@pandacss/config": "workspace:*",
"@pandacss/core": "workspace:*",
"@pandacss/extractor": "workspace:*",
"@pandacss/generator": "workspace:*",
"@pandacss/reporter": "workspace:*",
"@pandacss/logger": "workspace:*",
"@pandacss/parser": "workspace:*",
"@pandacss/shared": "workspace:*",
Expand All @@ -49,8 +49,6 @@
"browserslist": "4.23.3",
"chokidar": "3.6.0",
"fast-glob": "3.3.2",
"file-size": "1.0.0",
"filesize": "10.1.6",
"fs-extra": "11.2.0",
"glob-parent": "6.0.2",
"is-glob": "4.0.3",
Expand Down
Loading

0 comments on commit e4a3c0f

Please sign in to comment.