Skip to content

Commit 323213f

Browse files
committed
refactor: handle nested notation in include/exclude
1 parent 413c65a commit 323213f

File tree

3 files changed

+63
-54
lines changed

3 files changed

+63
-54
lines changed

packages/token-dictionary/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
"@pandacss/logger": "workspace:^",
4242
"@pandacss/shared": "workspace:*",
4343
"@pandacss/types": "workspace:*",
44+
"picomatch": "^4.0.0",
4445
"ts-pattern": "5.8.0"
46+
},
47+
"devDependencies": {
48+
"@types/picomatch": "4.0.2"
4549
}
4650
}

packages/token-dictionary/src/transform.ts

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { isCssUnit, isString, PandaError } from '@pandacss/shared'
22
import type { TokenDataTypes } from '@pandacss/types'
3+
import picomatch from 'picomatch'
34
import { P, match } from 'ts-pattern'
45
import type { TokenTransformer } from './dictionary'
56
import { isCompositeBorder, isCompositeGradient, isCompositeShadow } from './is-composite'
@@ -238,58 +239,56 @@ export const addColorPalette: TokenTransformer = {
238239
// If disabled, don't add colorPalette extensions
239240
if (!enabled) return {}
240241

241-
let tokenPathClone = [...token.path]
242-
tokenPathClone.pop()
243-
tokenPathClone.shift()
244-
245-
if (tokenPathClone.length === 0) {
246-
const newPath = [...token.path]
247-
newPath.shift()
248-
tokenPathClone = newPath
242+
// Extract color path (remove 'colors' prefix and last segment)
243+
// ['colors', 'blue', '500'] -> ['blue']
244+
// ['colors', 'button', 'light', 'accent', 'secondary'] -> ['button', 'light', 'accent']
245+
// ['colors', 'primary'] -> ['primary'] (handle flat tokens)
246+
let colorPath = token.path.slice(1, -1)
247+
248+
// If no nested segments, use the path without the 'colors' prefix
249+
if (colorPath.length === 0) {
250+
colorPath = token.path.slice(1)
251+
if (colorPath.length === 0) {
252+
return {}
253+
}
249254
}
250255

251-
if (tokenPathClone.length === 0) {
252-
return {}
256+
// Convert path segments to dot-notation string for pattern matching
257+
const colorPathString = colorPath.join('.')
258+
259+
// Check include/exclude filters using picomatch (supports glob patterns)
260+
// Exclude takes precedence over include
261+
if (exclude?.length) {
262+
const excludeMatchers = exclude.map((pattern) => picomatch(pattern))
263+
if (excludeMatchers.some((matcher) => matcher(colorPathString))) {
264+
return {}
265+
}
253266
}
254267

255-
// Check include/exclude filters
256-
const colorName = token.path[1] // e.g., 'blue' from ['colors', 'blue', '500']
257-
if (include && !include.includes(colorName)) return {}
258-
if (exclude && exclude.includes(colorName)) return {}
268+
if (include?.length) {
269+
const includeMatchers = include.map((pattern) => picomatch(pattern))
270+
if (!includeMatchers.some((matcher) => matcher(colorPathString))) {
271+
return {}
272+
}
273+
}
259274

260275
/**
261-
* If this is the nested color palette:
262-
* ```json
263-
* {
264-
* "colors": {
265-
* "button": {
266-
* "light": {
267-
* "accent": {
268-
* "secondary": {
269-
* value: 'blue',
270-
* },
271-
* },
272-
* },
273-
* },
274-
* },
275-
* },
276-
* ```
276+
* Generate all possible color palette roots from the color path.
277+
*
278+
* For ['button', 'light', 'accent']:
279+
* - ['button']
280+
* - ['button', 'light']
281+
* - ['button', 'light', 'accent']
277282
*
278-
* The `colorPaletteRoots` will be `['button', 'button.light', 'button.light.accent']`.
279-
* It holds all the possible values you can pass to the css `colorPalette` property.
280-
* It's used by the `addVirtualPalette` middleware to build the virtual `colorPalette` token for each color pattern root.
283+
* These represent all possible values you can pass to the css `colorPalette` property.
281284
*/
282-
const colorPaletteRoots = tokenPathClone.reduce(
283-
(acc, _, i, arr) => {
284-
const next = arr.slice(0, i + 1)
285-
acc.push(next)
286-
return acc
287-
},
288-
[] as Array<string[]>,
289-
)
290-
291-
const colorPaletteRoot = tokenPathClone[0]
292-
const colorPalette = dict.formatTokenName(tokenPathClone)
285+
const colorPaletteRoots: string[][] = []
286+
for (let i = 0; i < colorPath.length; i++) {
287+
colorPaletteRoots.push(colorPath.slice(0, i + 1))
288+
}
289+
290+
const colorPaletteRoot = colorPath[0]
291+
const colorPalette = dict.formatTokenName(colorPath)
293292

294293
/**
295294
* If this is the nested color palette:
@@ -343,16 +342,15 @@ export const addColorPalette: TokenTransformer = {
343342
* })}
344343
* />
345344
*/
346-
const colorPaletteTokenKeys = token.path
347-
// Remove everything before colorPalette root and the root itself
348-
.slice(token.path.indexOf(colorPaletteRoot) + 1)
349-
.reduce(
350-
(acc, _, i, arr) => {
351-
acc.push(arr.slice(i))
352-
return acc
353-
},
354-
[] as Array<string[]>,
355-
)
345+
// Remove everything before colorPalette root and the root itself
346+
const startIndex = token.path.indexOf(colorPaletteRoot) + 1
347+
const remainingPath = token.path.slice(startIndex)
348+
const colorPaletteTokenKeys: string[][] = []
349+
350+
// Generate all suffixes of the remaining path
351+
for (let i = 0; i < remainingPath.length; i++) {
352+
colorPaletteTokenKeys.push(remainingPath.slice(i))
353+
}
356354

357355
// https://github.com/chakra-ui/panda/issues/1421
358356
if (colorPaletteTokenKeys.length === 0) {

pnpm-lock.yaml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)