/
border.ts
121 lines (104 loc) · 5.6 KB
/
border.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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import type { CSSEntries, CSSObject, Rule, RuleContext } from '@unocss/core'
import type { Theme } from '../theme'
import { colorOpacityToString, colorToString, cornerMap, directionMap, globalKeywords, handler as h, hasParseableColor, parseColor } from '../utils'
export const borderStyles = ['solid', 'dashed', 'dotted', 'double', 'hidden', 'none', 'groove', 'ridge', 'inset', 'outset', ...globalKeywords]
export const borders: Rule[] = [
// compound
[/^(?:border|b)()(?:-(.+))?$/, handlerBorder, { autocomplete: '(border|b)-<directions>' }],
[/^(?:border|b)-([xy])(?:-(.+))?$/, handlerBorder],
[/^(?:border|b)-([rltbse])(?:-(.+))?$/, handlerBorder],
[/^(?:border|b)-(block|inline)(?:-(.+))?$/, handlerBorder],
[/^(?:border|b)-([bi][se])(?:-(.+))?$/, handlerBorder],
// size
[/^(?:border|b)-()(?:width|size)-(.+)$/, handlerBorderSize, { autocomplete: ['(border|b)-<num>', '(border|b)-<directions>-<num>'] }],
[/^(?:border|b)-([xy])-(?:width|size)-(.+)$/, handlerBorderSize],
[/^(?:border|b)-([rltbse])-(?:width|size)-(.+)$/, handlerBorderSize],
[/^(?:border|b)-(block|inline)-(?:width|size)-(.+)$/, handlerBorderSize],
[/^(?:border|b)-([bi][se])-(?:width|size)-(.+)$/, handlerBorderSize],
// colors
[/^(?:border|b)-()(?:color-)?(.+)$/, handlerBorderColor, { autocomplete: ['(border|b)-$colors', '(border|b)-<directions>-$colors'] }],
[/^(?:border|b)-([xy])-(?:color-)?(.+)$/, handlerBorderColor],
[/^(?:border|b)-([rltbse])-(?:color-)?(.+)$/, handlerBorderColor],
[/^(?:border|b)-(block|inline)-(?:color-)?(.+)$/, handlerBorderColor],
[/^(?:border|b)-([bi][se])-(?:color-)?(.+)$/, handlerBorderColor],
// opacity
[/^(?:border|b)-()op(?:acity)?-?(.+)$/, handlerBorderOpacity, { autocomplete: '(border|b)-(op|opacity)-<percent>' }],
[/^(?:border|b)-([xy])-op(?:acity)?-?(.+)$/, handlerBorderOpacity],
[/^(?:border|b)-([rltbse])-op(?:acity)?-?(.+)$/, handlerBorderOpacity],
[/^(?:border|b)-(block|inline)-op(?:acity)?-?(.+)$/, handlerBorderOpacity],
[/^(?:border|b)-([bi][se])-op(?:acity)?-?(.+)$/, handlerBorderOpacity],
// radius
[/^(?:border-|b-)?(?:rounded|rd)()(?:-(.+))?$/, handlerRounded, { autocomplete: ['(border|b)-(rounded|rd)', '(border|b)-(rounded|rd)-<num>', '(rounded|rd)', '(rounded|rd)-<num>'] }],
[/^(?:border-|b-)?(?:rounded|rd)-([rltb])(?:-(.+))?$/, handlerRounded],
[/^(?:border-|b-)?(?:rounded|rd)-([rltb]{2})(?:-(.+))?$/, handlerRounded],
[/^(?:border-|b-)?(?:rounded|rd)-([bi][se])(?:-(.+))?$/, handlerRounded],
[/^(?:border-|b-)?(?:rounded|rd)-([bi][se]-[bi][se])(?:-(.+))?$/, handlerRounded],
// style
[/^(?:border|b)-(?:style-)?()(.+)$/, handlerBorderStyle, { autocomplete: ['(border|b)-style', `(border|b)-(${borderStyles.join('|')})`, '(border|b)-<directions>-style', `(border|b)-<directions>-(${borderStyles.join('|')})`, `(border|b)-<directions>-style-(${borderStyles.join('|')})`, `(border|b)-style-(${borderStyles.join('|')})`] }],
[/^(?:border|b)-([xy])-(?:style-)?(.+)$/, handlerBorderStyle],
[/^(?:border|b)-([rltbse])-(?:style-)?(.+)$/, handlerBorderStyle],
[/^(?:border|b)-(block|inline)-(?:style-)?(.+)$/, handlerBorderStyle],
[/^(?:border|b)-([bi][se])-(?:style-)?(.+)$/, handlerBorderStyle],
]
const borderColorResolver = (direction: string) => ([, body]: string[], theme: Theme): CSSObject | undefined => {
const data = parseColor(body, theme)
if (!data)
return
const { alpha, color, cssColor } = data
if (cssColor) {
if (alpha != null) {
return {
[`border${direction}-color`]: colorToString(cssColor, alpha),
}
}
if (direction === '') {
return {
'--un-border-opacity': colorOpacityToString(cssColor),
'border-color': colorToString(cssColor, 'var(--un-border-opacity)'),
}
}
else {
return {
// Separate this return since if `direction` is an empty string, the first key will be overwritten by the second.
'--un-border-opacity': colorOpacityToString(cssColor),
[`--un-border${direction}-opacity`]: 'var(--un-border-opacity)',
[`border${direction}-color`]: colorToString(cssColor, `var(--un-border${direction}-opacity)`),
}
}
}
else if (color) {
return {
[`border${direction}-color`]: colorToString(color, alpha),
}
}
}
function handlerBorder(m: string[], ctx: RuleContext): CSSEntries | undefined {
return handlerBorderSize(m, ctx)
}
function handlerBorderSize([, a = '', b]: string[], { theme }: RuleContext<Theme>): CSSEntries | undefined {
const v = theme.lineWidth?.[b || 'DEFAULT'] ?? h.bracket.cssvar.global.px(b || '1')
if (a in directionMap && v != null)
return directionMap[a].map(i => [`border${i}-width`, v])
}
function handlerBorderColor([, a = '', c]: string[], { theme }: RuleContext<Theme>): CSSObject | undefined {
if (a in directionMap && hasParseableColor(c, theme)) {
return Object.assign(
{},
...directionMap[a].map(i => borderColorResolver(i)(['', c], theme)),
)
}
}
function handlerBorderOpacity([, a = '', opacity]: string[]): CSSEntries | undefined {
const v = h.bracket.percent(opacity)
if (a in directionMap && v != null)
return directionMap[a].map(i => [`--un-border${i}-opacity`, v])
}
function handlerRounded([, a = '', s]: string[], { theme }: RuleContext<Theme>): CSSEntries | undefined {
const v = theme.borderRadius?.[s || 'DEFAULT'] || h.bracket.cssvar.global.fraction.rem(s || '1')
if (a in cornerMap && v != null)
return cornerMap[a].map(i => [`border${i}-radius`, v])
}
export function handlerBorderStyle([, a = '', s]: string[]): CSSEntries | undefined {
if (borderStyles.includes(s) && a in directionMap)
return directionMap[a].map(i => [`border${i}-style`, s])
}