_validNumber: val => (
val !== undefined &&
val !== null &&
!Object.is(val, NaN) &&
val.constructor === Number &&
Number.isFinite(val)
),
_validString: val => (
val !== undefined &&
val !== null &&
val.constructor === String &&
val.length > 0
),
_numeric: (val, unit) => {
if (!css._validNumber(val)) {
throw new Error(Invalid value: ${val}. Must be a finite number.);
}
return ${val}${unit};
},
// Distance
em: val => css._numeric(val, 'em'), // Font size of the element.
ex: val => css._numeric(val, 'ex'), // x-height of the element's font.
cap: val => css._numeric(val, 'cap'), // Cap height (the nominal height of capital letters) of the element's font.
ch: val => css._numeric(val, 'ch'), // Average character advance of a narrow glyph in the element's font, as represented by the "0" (ZERO, U+0030) glyph.
ic: val => css._numeric(val, 'ic'), // Average character advance of a full width glyph in the element's font, as represented by the "水" (CJK water ideograph, U+6C34) glyph.
rem: val => css._numeric(val, 'rem'), // Font size of the root element.
lh: val => css._numeric(val, 'lh'), // Line height of the element.
rlh: val => css._numeric(val, 'rlh'), // Line height of the root element.
vw: val => css._numeric(val, 'vw'), // 1% of viewport's width.
vh: val => css._numeric(val, 'vh'), // 1% of viewport's height.
vi: val => css._numeric(val, 'vi'), // 1% of viewport's size in the root element's inline axis.
vb: val => css._numeric(val, 'vb'), // 1% of viewport's size in the root element's block axis.
vmin: val => css._numeric(val, 'vmin'), // 1% of viewport's smaller dimension.
vmax: val => css._numeric(val, 'vmax'), // 1% of viewport's larger dimension.
cqw: val => css._numeric(val, 'cqw'), // 1% of a query container's width
cqh: val => css._numeric(val, 'cqh'), // 1% of a query container's height
cqi: val => css._numeric(val, 'cqi'), // 1% of a query container's inline size
cqb: val => css._numeric(val, 'cqb'), // 1% of a query container's block size
cqmin: val => css._numeric(val, 'cqmin'), // The smaller value of cqi or cqb
cqmax: val => css._numeric(val, 'cqmax'), // The larger value of cqi or cqb
cm: val => css._numeric(val, 'cm'), // Centimeters 1cm = 96px/2.54
mm: val => css._numeric(val, 'mm'), // Millimeters 1mm = 1/10th of 1cm
Q: val => css._numeric(val, 'Q'), // Quarter-millimeters 1Q = 1/40th of 1cm
in: val => css._numeric(val, 'in'), // Inches 1in = 2.54cm = 96px
pc: val => css._numeric(val, 'pc'), // Picas 1pc = 1/6th of 1in
pt: val => css._numeric(val, 'pt'), // Points 1pt = 1/72th of 1in
px: val => css._numeric(val, 'px'), // Pixels 1px = 1/96th of 1in
// Angle
deg: val => css._numeric(val, 'deg'), // Degrees: There are 360 degrees in a full circle.
grad: val => css._numeric(val, 'grad'), // Gradians: There are 400 gradians in a full circle.
rad: val => css._numeric(val, 'rad'), // Radians: There are 2π radians in a full circle.
turn: val => css._numeric(val, 'turn'), // Turns: There is 1 turn in a full circle.
// Time
s: val => css._numeric(val, 's'), // Seconds
ms: val => css._numeric(val, 'ms'), // There are 1,000 milliseconds in a second.
// Frequency
hz: val => css._numeric(val, 'Hz'), // Hertz: Represents the number of occurrences per second.
khz: val => css._numeric(val, 'kHz'), // KiloHertz: A kiloHertz is 1000 Hertz.
// Flex units
fr: val => css._numeric(val, 'fr'), // Represents a fraction of the available space in the grid container.
// Resolution units
dpi: val => css._numeric(val, 'dpi'), // Dots per inch.
dpcm: val => css._numeric(val, 'dpcm'), // Dots per centimeter.
dppx: val => css._numeric(val, 'dppx'), // Dots per px unit.
// Percentage
prcnt: val => css._numeric(val, '%'), // Percentage
// Color
hex: val => {
if (!css._validString(val) || val.length > 8) {
throw new Error(Invalid value: ${val}. Must be a string with a maximum length of 8.);
}
if (!css._validNumber(parseInt(val, 16))) {
throw new Error(Invalid value: ${val}. Must be a valid hexadecimal number.);
}
return #${val};
},
rgb: (r, g, b, a) => { // Red, Green, Blue, Alpha
if (!css._validNumber(r)) {
throw new Error(Invalid value: ${r}. Must be a finite number.);
}
if (!css._validNumber(g)) {
throw new Error(Invalid value: ${g}. Must be a finite number.);
}
if (!css._validNumber(b)) {
throw new Error(Invalid value: ${b}. Must be a finite number.);
}
if (!css._validNumber(a)) {
throw new Error(Invalid value: ${a}. Must be a finite number.);
}
return rgb(${r}, ${g}, ${b}, ${a});
},
hsl: (h, s, l, a) => { // Hue, Saturation, Lightness, Alpha
if (!css._validNumber(h)) {
throw new Error(Invalid value: ${h}. Must be a finite number.);
}
if (!css._validNumber(s)) {
throw new Error(Invalid value: ${s}. Must be a finite number.);
}
if (!css._validNumber(l)) {
throw new Error(Invalid value: ${l}. Must be a finite number.);
}
if (!css._validNumber(a)) {
throw new Error(Invalid value: ${a}. Must be a finite number.);
}
return hsl(${h}, ${s}, ${l}, ${a});
}
const css = { // CSS values and units
_validNumber: val => ( val !== undefined && val !== null && !Object.is(val, NaN) && val.constructor === Number && Number.isFinite(val) ),
_validString: val => ( val !== undefined && val !== null && val.constructor === String && val.length > 0 ),
_numeric: (val, unit) => { if (!css._validNumber(val)) { throw new Error(
Invalid value: ${val}. Must be a finite number.
); } return${val}${unit}
; },// Distance em: val => css._numeric(val, 'em'), // Font size of the element. ex: val => css._numeric(val, 'ex'), // x-height of the element's font. cap: val => css._numeric(val, 'cap'), // Cap height (the nominal height of capital letters) of the element's font. ch: val => css._numeric(val, 'ch'), // Average character advance of a narrow glyph in the element's font, as represented by the "0" (ZERO, U+0030) glyph. ic: val => css._numeric(val, 'ic'), // Average character advance of a full width glyph in the element's font, as represented by the "水" (CJK water ideograph, U+6C34) glyph. rem: val => css._numeric(val, 'rem'), // Font size of the root element. lh: val => css._numeric(val, 'lh'), // Line height of the element. rlh: val => css._numeric(val, 'rlh'), // Line height of the root element. vw: val => css._numeric(val, 'vw'), // 1% of viewport's width. vh: val => css._numeric(val, 'vh'), // 1% of viewport's height. vi: val => css._numeric(val, 'vi'), // 1% of viewport's size in the root element's inline axis. vb: val => css._numeric(val, 'vb'), // 1% of viewport's size in the root element's block axis. vmin: val => css._numeric(val, 'vmin'), // 1% of viewport's smaller dimension. vmax: val => css._numeric(val, 'vmax'), // 1% of viewport's larger dimension.
cqw: val => css._numeric(val, 'cqw'), // 1% of a query container's width cqh: val => css._numeric(val, 'cqh'), // 1% of a query container's height cqi: val => css._numeric(val, 'cqi'), // 1% of a query container's inline size cqb: val => css._numeric(val, 'cqb'), // 1% of a query container's block size cqmin: val => css._numeric(val, 'cqmin'), // The smaller value of cqi or cqb cqmax: val => css._numeric(val, 'cqmax'), // The larger value of cqi or cqb
cm: val => css._numeric(val, 'cm'), // Centimeters 1cm = 96px/2.54 mm: val => css._numeric(val, 'mm'), // Millimeters 1mm = 1/10th of 1cm Q: val => css._numeric(val, 'Q'), // Quarter-millimeters 1Q = 1/40th of 1cm in: val => css._numeric(val, 'in'), // Inches 1in = 2.54cm = 96px pc: val => css._numeric(val, 'pc'), // Picas 1pc = 1/6th of 1in pt: val => css._numeric(val, 'pt'), // Points 1pt = 1/72th of 1in px: val => css._numeric(val, 'px'), // Pixels 1px = 1/96th of 1in
// Angle deg: val => css._numeric(val, 'deg'), // Degrees: There are 360 degrees in a full circle. grad: val => css._numeric(val, 'grad'), // Gradians: There are 400 gradians in a full circle. rad: val => css._numeric(val, 'rad'), // Radians: There are 2π radians in a full circle. turn: val => css._numeric(val, 'turn'), // Turns: There is 1 turn in a full circle.
// Time s: val => css._numeric(val, 's'), // Seconds ms: val => css._numeric(val, 'ms'), // There are 1,000 milliseconds in a second.
// Frequency hz: val => css._numeric(val, 'Hz'), // Hertz: Represents the number of occurrences per second. khz: val => css._numeric(val, 'kHz'), // KiloHertz: A kiloHertz is 1000 Hertz.
// Flex units fr: val => css._numeric(val, 'fr'), // Represents a fraction of the available space in the grid container.
// Resolution units dpi: val => css._numeric(val, 'dpi'), // Dots per inch. dpcm: val => css._numeric(val, 'dpcm'), // Dots per centimeter. dppx: val => css._numeric(val, 'dppx'), // Dots per px unit.
// Percentage prcnt: val => css._numeric(val, '%'), // Percentage
// Color hex: val => { if (!css._validString(val) || val.length > 8) { throw new Error(
Invalid value: ${val}. Must be a string with a maximum length of 8.
); } if (!css._validNumber(parseInt(val, 16))) { throw new Error(Invalid value: ${val}. Must be a valid hexadecimal number.
); } return#${val}
; },rgb: (r, g, b, a) => { // Red, Green, Blue, Alpha if (!css._validNumber(r)) { throw new Error(
Invalid value: ${r}. Must be a finite number.
); } if (!css._validNumber(g)) { throw new Error(Invalid value: ${g}. Must be a finite number.
); } if (!css._validNumber(b)) { throw new Error(Invalid value: ${b}. Must be a finite number.
); } if (!css._validNumber(a)) { throw new Error(Invalid value: ${a}. Must be a finite number.
); } returnrgb(${r}, ${g}, ${b}, ${a})
; },hsl: (h, s, l, a) => { // Hue, Saturation, Lightness, Alpha if (!css._validNumber(h)) { throw new Error(
Invalid value: ${h}. Must be a finite number.
); } if (!css._validNumber(s)) { throw new Error(Invalid value: ${s}. Must be a finite number.
); } if (!css._validNumber(l)) { throw new Error(Invalid value: ${l}. Must be a finite number.
); } if (!css._validNumber(a)) { throw new Error(Invalid value: ${a}. Must be a finite number.
); } returnhsl(${h}, ${s}, ${l}, ${a})
; }};