Skip to content

Commit

Permalink
fix: parse bracket correctly in variable variant
Browse files Browse the repository at this point in the history
  • Loading branch information
MellowCo committed Jul 10, 2022
1 parent d5d11e8 commit 0b7ee2a
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 82 deletions.
69 changes: 8 additions & 61 deletions src/utils/colors.ts
@@ -1,5 +1,6 @@
import type { CSSColorValue, RGBAColorValue } from '@unocss/core'
import { escapeRegExp } from '@unocss/core'
import { getComponents } from './utilities'

/* eslint-disable no-case-declarations */

Expand Down Expand Up @@ -34,7 +35,11 @@ export function parseCssColor(str = ''): CSSColorValue | undefined {
if (cssColorFunctions.includes(type) && ![1, 3].includes(components.length))
return

return { type, components, alpha }
return {
type,
components: components.map(c => typeof c === 'string' ? c.trim() : c),
alpha: typeof alpha === 'string' ? alpha.trim() : alpha,
}
}

export function colorOpacityToString(color: CSSColorValue) {
Expand Down Expand Up @@ -189,7 +194,7 @@ function parseCssColorFunction(color: string): CSSColorValue | undefined {
}

function parseCssSpaceColorValues(componentString: string) {
const components = getComponents(componentString)
const components = getComponents(componentString, ' ')
if (!components)
return

Expand All @@ -211,7 +216,7 @@ function parseCssSpaceColorValues(componentString: string) {
}

// maybe (fn 1 2 3/4)
const withAlpha = getComponents(components[totalComponents - 1], '/', 3)
const withAlpha = getComponents(components[totalComponents - 1], '/', 2)
if (!withAlpha)
return

Expand All @@ -227,61 +232,3 @@ function parseCssSpaceColorValues(componentString: string) {
}
}

function getComponent(str: string, separator: string) {
str = str.trim()
if (str === '')
return

const l = str.length
let parenthesis = 0
for (let i = 0; i < l; i++) {
switch (str[i]) {
case '(':
parenthesis++
break

case ')':
if (--parenthesis < 0)
return
break

case separator:
if (parenthesis === 0) {
const component = str.slice(0, i).trim()
if (component === '')
return

return [
component,
str.slice(i + 1).trim(),
]
}
}
}

return [
str,
'',
]
}

export function getComponents(str: string, separator?: string, limit?: number) {
separator = separator ?? ' '
if (separator.length !== 1)
return
limit = limit ?? 10
const components = []
let i = 0
while (str !== '') {
if (++i > limit)
return
const componentPair = getComponent(str, separator)
if (!componentPair)
return
const [component, rest] = componentPair
components.push(component)
str = rest
}
if (components.length > 0)
return components
}
57 changes: 56 additions & 1 deletion src/utils/utilities.ts
Expand Up @@ -3,7 +3,7 @@ import type { CSSEntries, CSSObject, ParsedColorValue, Rule, RuleContext, Varian
import { toArray } from '@unocss/core'
import type { Theme } from '../theme'
import { restoreSelector } from '../transform'
import { colorOpacityToString, colorToString, getComponents, parseCssColor } from './colors'
import { colorOpacityToString, colorToString, parseCssColor } from './colors'
import { handler as h } from './handlers'
import { directionMap, globalKeywords } from './mappings'

Expand Down Expand Up @@ -209,3 +209,58 @@ export const resolveVerticalBreakpoints = ({ theme, generator }: Readonly<Varian
export const makeGlobalStaticRules = (prefix: string, property?: string) => {
return globalKeywords.map(keyword => [`${prefix}-${keyword}`, { [property ?? prefix]: keyword }] as Rule)
}

export function getComponent(str: string, open: string, close: string, separator: string) {
if (str === '')
return

const l = str.length
let parenthesis = 0
for (let i = 0; i < l; i++) {
switch (str[i]) {
case open:
parenthesis++
break

case close:
if (--parenthesis < 0)
return
break

case separator:
if (parenthesis === 0) {
if (i === 0 || i === l - 1)
return
return [
str.slice(0, i),
str.slice(i + 1),
]
}
}
}

return [
str,
'',
]
}

export function getComponents(str: string, separator: string, limit?: number) {
if (separator.length !== 1)
return
limit = limit ?? 10
const components = []
let i = 0
while (str !== '') {
if (++i > limit)
return
const componentPair = getComponent(str, '(', ')', separator)
if (!componentPair)
return
const [component, rest] = componentPair
components.push(component)
str = rest
}
if (components.length > 0)
return components
}
46 changes: 26 additions & 20 deletions src/variants/misc.ts
@@ -1,5 +1,5 @@
import type { Variant } from '@unocss/core'
import { handler as h } from '../utils'
import { getComponent, handler as h } from '../utils'

export const variantSelector: Variant = {
name: 'selector',
Expand Down Expand Up @@ -59,26 +59,32 @@ export const variantScope: Variant = {
export const variantVariables: Variant = {
name: 'variables',
match(matcher) {
const match = matcher.match(/^(\[.+?\]):/)
if (match) {
const variant = h.bracket(match[1]) ?? ''
if (!matcher.startsWith('['))
return

return {
matcher: matcher.slice(match[0].length),
handle(input, next) {
const updates = variant.startsWith('@')
? {
parent: `${input.parent ? `${input.parent} $$ ` : ''}${variant}`,
}
: {
selector: variant.replace(/&/g, input.selector),
}
return next({
...input,
...updates,
})
},
}
const [match, rest] = getComponent(matcher, '[', ']', ':') ?? []
if (!(match && rest && rest !== ''))
return

const variant = h.bracket(match) ?? ''
if (!(variant.startsWith('@') || variant.includes('&')))
return

return {
matcher: rest,
handle(input, next) {
const updates = variant.startsWith('@')
? {
parent: `${input.parent ? `${input.parent} $$ ` : ''}${variant}`,
}
: {
selector: variant.replace(/&/g, input.selector),
}
return next({
...input,
...updates,
})
},
}
},
multiPass: true,
Expand Down
2 changes: 2 additions & 0 deletions test/__snapshots__/preset-mini.test.ts.snap
Expand Up @@ -74,6 +74,7 @@ div:hover .group-\\\\[div\\\\:hover\\\\]-\\\\[combinator\\\\:test-4\\\\]{combina
.\\\\!m-\\\\$c-m{margin:var(--c-m) !important;}
.\\\\[\\\\&_\\\\&\\\\]\\\\:m-13 .\\\\[\\\\&_\\\\&\\\\]\\\\:m-13{margin:104rpx;}
.\\\\[\\\\&\\\\:nth-child\\\\(2\\\\)\\\\]\\\\:m-10:nth-child(2){margin:80rpx;}
.\\\\[\\\\&\\\\[open\\\\]\\\\:readonly\\\\]\\\\:m-16[open]:readonly{margin:128rpx;}
.\\\\[\\\\&\\\\[open\\\\]\\\\]\\\\:m-14[open]{margin:112rpx;}
.\\\\[\\\\&\\\\[readonly\\\\]\\\\[disabled\\\\]\\\\]\\\\:m-15[readonly][disabled]{margin:120rpx;}
.\\\\[\\\\&\\\\>\\\\*\\\\]\\\\:m-11>*{margin:88rpx;}
Expand All @@ -85,6 +86,7 @@ div:hover .group-\\\\[div\\\\:hover\\\\]-\\\\[combinator\\\\:test-4\\\\]{combina
.m-1\\\\/2{margin:50%;}
.m-inherit{margin:inherit;}
.m-none{margin:0;}
*[open]:readonly .\\\\[\\\\*\\\\[open\\\\]\\\\:readonly_\\\\&\\\\]\\\\:\\\\[\\\\&\\\\[open\\\\]\\\\:disabled\\\\]\\\\:m-17[open]:disabled{margin:136rpx;}
*>.\\\\[\\\\*\\\\>\\\\&\\\\]\\\\:m-12{margin:96rpx;}
.m-xy,
.mxy{margin:32rpx;}
Expand Down
2 changes: 2 additions & 0 deletions test/assets/preset-mini-targets.ts
Expand Up @@ -953,6 +953,8 @@ export const presetMiniTargets: string[] = [
'[&_&]:m-13',
'[&[open]]:m-14',
'[&[readonly][disabled]]:m-15',
'[&[open]:readonly]:m-16',
'[*[open]:readonly_&]:[&[open]:disabled]:m-17',
'[@supports(display:grid)]:bg-red/33',
'[@supports(display:grid)]:[*+&]:bg-red/34',

Expand Down

0 comments on commit 0b7ee2a

Please sign in to comment.