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
|
const dlv = require('dlv')
import { State } from './state'
import removeMeta from './removeMeta'
import { TinyColor } from '@ctrl/tinycolor'
import { ensureArray, dedupe, flatten } from '../../util/array'
const COLOR_PROPS = [
'caret-color',
'color',
'column-rule-color',
'background-color',
'border-color',
'border-top-color',
'border-right-color',
'border-bottom-color',
'border-left-color',
'fill',
'outline-color',
'stop-color',
'stroke',
'text-decoration-color',
]
export function getColor(
state: State,
keys: string[]
): { documentation?: string } {
const item = dlv(state.classNames.classNames, keys)
if (!item.__rule) return null
const props = Object.keys(removeMeta(item))
if (props.length === 0) return null
const nonCustomProps = props.filter((prop) => !prop.startsWith('--'))
const areAllCustom = nonCustomProps.length === 0
if (
!areAllCustom &&
nonCustomProps.some((prop) => !COLOR_PROPS.includes(prop))
) {
// they should all be color-based props
return null
}
const propsToCheck = areAllCustom ? props : nonCustomProps
const colors = flatten(
propsToCheck.map((prop) => ensureArray(item[prop]).map(createColor))
)
// check that all of the values are valid colors
if (colors.some((color) => !color.isValid)) {
return null
}
// check that all of the values are the same color
const colorStrings = colors.map((color) => color.toRgbString())
if (dedupe(colorStrings).length !== 1) {
return null
}
return { documentation: colorStrings[0] }
}
export function getColorFromValue(value: unknown): string {
if (typeof value !== 'string') return null
if (value === 'transparent') {
return 'rgba(0, 0, 0, 0.01)'
}
const color = new TinyColor(value)
if (color.isValid) {
return color.toRgbString()
}
return null
}
function createColor(str: string): TinyColor {
if (str === 'transparent') {
return new TinyColor({ r: 0, g: 0, b: 0, a: 0.01 })
}
// matches: rgba(<r>, <g>, <b>, var(--bg-opacity))
// TODO: support other formats? e.g. hsla, css level 4
const match = str.match(
/^\s*rgba\(\s*(?<r>[0-9]{1,3})\s*,\s*(?<g>[0-9]{1,3})\s*,\s*(?<b>[0-9]{1,3})\s*,\s*var/
)
if (match) {
return new TinyColor({
r: match.groups.r,
g: match.groups.g,
b: match.groups.b,
})
}
return new TinyColor(str)
}
|