|
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