forked from unocss/unocss
/
variants.ts
78 lines (74 loc) · 2.47 KB
/
variants.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import type { VariantHandlerContext, VariantObject } from '@unocss/core'
import { escapeRegExp } from '@unocss/core'
import { getBracket } from '../utils'
export const variantMatcher = (name: string, handler: (input: VariantHandlerContext) => Record<string, any>): VariantObject => {
const re = new RegExp(`^${escapeRegExp(name)}[:-]`)
return {
name,
match(input) {
const match = input.match(re)
if (match) {
return {
matcher: input.slice(match[0].length),
handle: (input, next) => next({
...input,
...handler(input),
}),
}
}
},
autocomplete: `${name}:`,
}
}
export const variantParentMatcher = (name: string, parent: string): VariantObject => {
const re = new RegExp(`^${escapeRegExp(name)}[:-]`)
return {
name,
match(input) {
const match = input.match(re)
if (match) {
return {
matcher: input.slice(match[0].length),
handle: (input, next) => next({
...input,
parent: `${input.parent ? `${input.parent} $$ ` : ''}${parent}`,
}),
}
}
},
autocomplete: `${name}:`,
}
}
export const variantGetBracket = (prefix: string, matcher: string, separators: string[]): string[] | undefined => {
if (matcher.startsWith(`${prefix}[`)) {
const [match, rest] = getBracket(matcher.slice(prefix.length), '[', ']') ?? []
if (match && rest) {
for (const separator of separators) {
if (rest.startsWith(separator))
return [match, rest.slice(separator.length), separator]
}
return [match, rest, '']
}
}
}
export const variantGetParameter = (prefix: string, matcher: string, separators: string[]): string[] | undefined => {
if (matcher.startsWith(prefix)) {
const body = variantGetBracket(prefix, matcher, separators)
if (body) {
const [label = '', rest = body[1]] = variantGetParameter('/', body[1], separators) ?? []
return [body[0], rest, label]
}
for (const separator of separators.filter(x => x !== '/')) {
const pos = matcher.indexOf(separator, prefix.length)
if (pos !== -1) {
const labelPos = matcher.indexOf('/', prefix.length)
const unlabelled = labelPos === -1 || pos <= labelPos
return [
matcher.slice(prefix.length, unlabelled ? pos : labelPos),
matcher.slice(pos + separator.length),
unlabelled ? '' : matcher.slice(labelPos + 1, pos),
]
}
}
}
}