|
1 |
| -import CSS_COLOR_NAMES from "./html-colors"; |
2 |
| -import toPx from "./css-length-converter"; |
| 1 | +import CSS_COLOR_NAMES from "./external/bobspace:html-colors"; |
| 2 | +import toPx from "./external/heygrady:units:length"; |
3 | 3 |
|
4 |
| -function _getAttributeFromString(string, method, ...data) { |
5 |
| - if (!string) return false |
6 |
| - string = string.split(' ') |
7 |
| - for (let i in string) { |
8 |
| - if (!string.hasOwnProperty(i)) continue |
9 |
| - const res = method(string, Number(i), ...data) |
10 |
| - if (res) return res |
11 |
| - } |
12 |
| -} |
13 |
| - |
14 |
| -// eslint-disable-next-line no-extend-native |
15 |
| -String.prototype.matchesValidCSSLength = () => |
16 |
| - this.match(/(\d+(\.\d+)?(ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmax|vmin|vw)|0)/) |
17 |
| - |
18 |
| -function _getColor(b, i) { |
19 |
| - const val = b[i] |
| 4 | +/** @returns {string} */ |
| 5 | +function convertPlainColor(val) { |
| 6 | + if (!val) return '#000' |
| 7 | + val = val?.toLowerCase() |
20 | 8 | // color is a hex code
|
21 |
| - if (val.toLowerCase().match(/#([0-9a-f]{3}){1,2}/)) return val |
| 9 | + if (val?.match(/#([0-9a-f]{3}){1,2}/)) return val |
22 | 10 | // color is a function (rgb, rgba, hsl, hsla)
|
23 |
| - if (val.startsWith('rgb') || val.startsWith('hsl')) { |
24 |
| - let color = val; |
25 |
| - if (!val.endsWith(')')) |
26 |
| - for (let j = 1; !b[i + j - 1].endsWith(')'); j++) { |
27 |
| - color += b[i + j] |
28 |
| - } |
29 |
| - if (color[3] === 'a') |
30 |
| - color = color.replace('a', '').replace(/,[^),]+\)/, ')') |
31 |
| - return color |
32 |
| - } |
| 11 | + else if (val?.match(/^(rgb|hsl)a?\(([^,]{1,3},? *){3}(\d*\.?\d+)?\)/)) |
| 12 | + return val |
| 13 | + .replace('a', '') |
| 14 | + .replace(/\((([\d%]{1,3}, *){2}([\d%]{1,3}))(, *\d*\.?\d+)?\)/, '($1)') |
33 | 15 | // color is a html color name
|
34 |
| - if (CSS_COLOR_NAMES.map(color => color.toLowerCase()) |
| 16 | + else if (CSS_COLOR_NAMES.map(color => color.toLowerCase()) |
35 | 17 | .includes(val.toLowerCase()))
|
36 | 18 | return val
|
37 |
| - if (val === 'currentcolor') { |
| 19 | + else if (val === 'currentcolor') { |
38 | 20 | return 'currentcolor'
|
39 |
| - } |
40 |
| - return false |
41 |
| -} |
42 |
| - |
43 |
| -function _getImage(b, i) { |
44 |
| - const val = b[i] |
45 |
| - |
46 |
| - if (val.startsWith('url')) { |
47 |
| - let url = val; |
48 |
| - for (let j = 1; b[i + j]; j++) { |
49 |
| - url += b[i + j] |
50 |
| - } |
51 |
| - url = /url\(("[^"]+"|'[^']+'|[^)]+)\)/g.exec(url) |
52 |
| - url = url ? url[1] : false |
53 |
| - url = url?.startsWith('"') || url?.startsWith("'") |
54 |
| - ? url.substr(1, url.length - 2) |
55 |
| - : url |
56 |
| - return url |
57 |
| - } |
58 |
| -} |
59 |
| - |
60 |
| -function _getImageSize(b, i, element) { |
61 |
| - // "val" is always what is defined in backgrund-size ([i]th argument) |
62 |
| - const val = b[i] |
63 |
| - |
64 |
| - if (['cover', 'contain'].includes(val)) { |
65 |
| - return [val, null] |
66 |
| - } |
67 |
| - |
68 |
| - return __getTwoNumerics(b, i, element, htmlBackgroundSizeNotSvgError) |
| 21 | + } else return '#000' |
69 | 22 | }
|
70 | 23 |
|
71 |
| -function _getPosition(b, i, element) { |
72 |
| - // "val" is always what is defined in backgrund-size ([i]th argument) |
73 |
| - const val = b[i] |
74 |
| - const allWords = ['top', 'bottom', 'left', 'right', 'center'] |
75 |
| - |
76 |
| - if (b.length === 1 && allWords.includes(val)) { |
77 |
| - if (val === 'center') |
78 |
| - return ['center', 'center'] |
79 |
| - else if (['left', 'right'].includes(val)) |
80 |
| - return [val, 0] |
81 |
| - else if (['top', 'bottom'].includes(val)) |
82 |
| - return [0, val] |
83 |
| - } |
84 |
| - |
85 |
| - const a = [0, 0] |
86 |
| - |
87 |
| - if (allWords.includes(val)) { |
88 |
| - if (b[i + 1].matchesValidCSSLength()) { |
89 |
| - |
90 |
| - } |
91 |
| - } |
92 |
| - |
93 |
| - /*if (['cover', 'contain'].includes(val)) { |
94 |
| - return [val, null] |
95 |
| - }*/ |
96 |
| - |
97 |
| - return __getTwoNumerics(b, i, element, htmlBackgroundPositionNotSvgError) |
98 |
| -} |
99 |
| - |
100 |
| -function __getTwoNumerics(b, i, element, err) { |
101 |
| - const returnIfCSSNumeric = (val, throwErr) => { |
102 |
| - if (val?.endsWith('%')) |
103 |
| - return val |
104 |
| - else if (val?.matchesValidCSSLength()) { |
105 |
| - unitCheck(val, throwErr ? err : undefined) |
106 |
| - return toPx(element, val) |
107 |
| - } else |
108 |
| - return null |
109 |
| - } |
110 |
| - |
111 |
| - const convertedVal = returnIfCSSNumeric(b[i], true) // has null as fallback already |
112 |
| - // "background-size: 50% 50%" is different to "background-size: 50%" |
113 |
| - return [convertedVal, returnIfCSSNumeric(b[i + 1])] |
114 |
| -} |
115 |
| - |
116 |
| -function _getOpacity(b, i) { |
117 |
| - let val = b[i] |
118 |
| - if (val.startsWith('rgba') || val.startsWith('hsla')) { |
119 |
| - if (!val.endsWith(')')) |
120 |
| - for (let j = 1; !b[i + j - 1].endsWith(')'); j++) { |
121 |
| - val += b[i + j] |
122 |
| - } |
123 |
| - return val.replace(/(rgb|hsl)a?\(([^,)]+,){3}/, '').replace(/\)$/, '') |
124 |
| - } |
125 |
| - if (b.length - 1 === i) |
126 |
| - return 1 |
127 |
| -} |
128 |
| - |
129 |
| -function _getRepeat(b, i) { |
130 |
| - let val = b[i] |
131 |
| - if (val === 'repeat-x') |
132 |
| - return ['repeat', 'no-repeat'] |
133 |
| - else if (val === 'repeat-y') |
134 |
| - return ['no-repeat', 'repeat'] |
135 |
| - else if (['repeat', 'space', 'round', 'no-repeat'].includes(val)) { |
136 |
| - if (['repeat', 'space', 'round', 'no-repeat'].includes(b[i + 1] || '')) |
137 |
| - return [val, b[i + 1]] |
138 |
| - else |
139 |
| - return [val, val] |
140 |
| - } |
| 24 | +/** @returns {number} */ |
| 25 | +function convertColorOpacity(val) { |
| 26 | + if (val?.startsWith('rgba') || val?.startsWith('hsla')) { |
| 27 | + return Number(val.match(/(\d*\.?\d+)?\)$/)[1]) |
| 28 | + } else return 1 |
141 | 29 | }
|
142 | 30 |
|
143 | 31 | const htmlLengthNotSvgErrorTemplate = (a, b) => `<RoundDiv> ${a} must be ${b ? `either ${b}, or` : ''} in one of the following units: ch, cm, em, ex, in, mm, pc, pt, px, rem, vh, vmax, vmin, vw.`
|
144 | 32 | const htmlBorderLengthNotSvgError =
|
145 | 33 | new Error(htmlLengthNotSvgErrorTemplate('border lengths', '"thin", "medium", "thick"'))
|
146 |
| -const htmlBackgroundSizeNotSvgError = |
147 |
| - new Error(htmlLengthNotSvgErrorTemplate('background size', '"cover", "contain"')) |
148 |
| -const htmlBackgroundPositionNotSvgError = |
149 |
| - new Error(htmlLengthNotSvgErrorTemplate('background position', '"top", "bottom", "left", "right", "center"')) |
150 |
| - |
151 |
| -function unitCheck(length, err) { |
152 |
| - if (length?.match(/(cap|ic|lh|rlh|vi|vm|vb|Q|mozmm)/g)) |
| 34 | +const htmlBorderRadiusNotSvgError = |
| 35 | + new Error(htmlLengthNotSvgErrorTemplate('border radii')) |
| 36 | + |
| 37 | +function toNumber(length, element, err) { |
| 38 | + if (!length) return false |
| 39 | + if (typeof length === 'number' || !length.match(/\D+/)) |
| 40 | + return Number(length); |
| 41 | + else if (length?.match(/(cap|ic|lh|rlh|vi|vm|vb|Q|mozmm)/g)) |
153 | 42 | if (err) throw err
|
154 | 43 | else return false
|
155 |
| - return length |
| 44 | + else if (length?.match(/(\d+(\.\d+)?(ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmax|vmin|vw)|0)/)) |
| 45 | + return toPx(element, length) |
156 | 46 | }
|
157 | 47 |
|
158 |
| -function _getWidth(border, i, element) { |
159 |
| - const val = border[i] |
160 |
| - // width is 0 |
161 |
| - if (val === '0') return 0 |
| 48 | +/** @returns {number} */ |
| 49 | +function convertBorderWidth(val, element) { |
| 50 | + if (!val) return 0 |
162 | 51 | // width is a word
|
163 |
| - if (val.toLowerCase() === 'thin') return 1 |
164 |
| - if (val.toLowerCase() === 'medium') return 3 |
165 |
| - if (val.toLowerCase() === 'thick') return 5 |
166 |
| - unitCheck(val, htmlBorderLengthNotSvgError) |
| 52 | + if (val?.toLowerCase() === 'thin') |
| 53 | + return 1 |
| 54 | + else if (val?.toLowerCase() === 'medium') |
| 55 | + return 3 |
| 56 | + else if (val?.toLowerCase() === 'thick') |
| 57 | + return 5 |
167 | 58 | // width is <length>
|
168 |
| - if (val.matchesValidCSSLength()) |
169 |
| - return toPx(element, val) |
170 |
| - return false |
| 59 | + else |
| 60 | + return toNumber(val, element, htmlBorderLengthNotSvgError) || 0 |
171 | 61 | }
|
172 | 62 |
|
173 |
| -/** @returns {number} */ |
174 |
| -const getWidth = (s, el) => _getAttributeFromString(s, _getWidth, el), |
175 |
| - /** @returns {string} */ |
176 |
| - getImage = s => _getAttributeFromString(s, _getImage), |
177 |
| - /** @returns {Array<string|number>} */ |
178 |
| - getImageSize = (s, el) => _getAttributeFromString(s, _getImageSize, el), |
179 |
| - /** @returns {Array<string|number>} */ |
180 |
| - getPosition = (s, el) => _getAttributeFromString(s, _getPosition, el), |
181 |
| - /** @returns {string} */ |
182 |
| - getColor = s => _getAttributeFromString(s, _getColor), |
183 |
| - /** @returns {Array<string>} */ |
184 |
| - getRepeat = s => _getAttributeFromString(s, _getRepeat), |
185 |
| - /** @returns {number} */ |
186 |
| - getOpacity = s => _getAttributeFromString(s, _getOpacity) |
187 |
| - |
188 |
| -export {getWidth, getImage, getImageSize, getPosition, getColor, getRepeat, getOpacity} |
| 63 | +export {convertPlainColor, convertColorOpacity, convertBorderWidth, toNumber, htmlBorderRadiusNotSvgError} |
0 commit comments