UNPKG

twrnc

Version:
133 lines (132 loc) 5.01 kB
import { isObject, isString } from '../types'; import { warn } from '../helpers'; export function color(type, value, config) { var _a; if (!config) { return null; } // support opacity shorthand: `bg-red-200/50` let shorthandOpacity = undefined; if (value.includes(`/`)) { [value = ``, shorthandOpacity] = value.split(`/`, 2); } let color = ``; // arbitrary hex/rgb(a) support: `bg-[#eaeaea]`, `text-[rgba(1, 1, 1, 0.5)]` if (value.startsWith(`[#`) || value.startsWith(`[rgb`)) { color = value.slice(1, -1); // arbitrary named colors: `bg-[lemonchiffon]` } else if (value.startsWith(`[`) && value.slice(1, -1).match(/^[a-z]{3,}$/)) { color = value.slice(1, -1); } else { color = (_a = configColor(value, config)) !== null && _a !== void 0 ? _a : ``; } if (!color) { return null; } if (shorthandOpacity) { const opacity = Number(shorthandOpacity); if (!Number.isNaN(opacity)) { color = addOpacity(color, opacity / 100); return { // even though we know the bg opacity, return `dependent` to work around // subtle dark-mode ordering issue when combining shorthand & non-shorthand // @see https://github.com/jaredh159/tailwind-react-native-classnames/pull/269 kind: `dependent`, complete(style) { style[STYLE_PROPS[type].color] = color; }, }; } } // return a dependent style to support merging of classes // like `bg-red-800 bg-opacity-75` return { kind: `dependent`, complete(style) { const opacityProp = STYLE_PROPS[type].opacity; const opacity = style[opacityProp]; if (typeof opacity === `number`) { color = addOpacity(color, opacity); } style[STYLE_PROPS[type].color] = color; }, }; } export function colorOpacity(type, value) { const percentage = parseInt(value, 10); if (Number.isNaN(percentage)) { return null; } const opacity = percentage / 100; const style = { [STYLE_PROPS[type].opacity]: opacity }; return { kind: `complete`, style }; } function addOpacity(color, opacity) { if (color.startsWith(`#`)) { color = hexToRgba(color); } else if (color.startsWith(`rgb(`)) { color = color.replace(/^rgb\(/, `rgba(`).replace(/\)$/, `, 1)`); } // @TODO: support hls/hlsa if anyone opens an issue... return color.replace(/, ?\d*\.?(\d+)\)$/, `, ${opacity})`); } export function removeOpacityHelpers(style) { for (const key in style) { if (key.startsWith(`__opacity_`)) { delete style[key]; } } } const STYLE_PROPS = { bg: { opacity: `__opacity_bg`, color: `backgroundColor` }, text: { opacity: `__opacity_text`, color: `color` }, border: { opacity: `__opacity_border`, color: `borderColor` }, borderTop: { opacity: `__opacity_border`, color: `borderTopColor` }, borderBottom: { opacity: `__opacity_border`, color: `borderBottomColor` }, borderLeft: { opacity: `__opacity_border`, color: `borderLeftColor` }, borderRight: { opacity: `__opacity_border`, color: `borderRightColor` }, shadow: { opacity: `__opacity_shadow`, color: `shadowColor` }, tint: { opacity: `__opacity_tint`, color: `tintColor` }, }; function hexToRgba(hex) { var _a, _b, _c; const orig = hex; hex = hex.replace(MATCH_SHORT_HEX, (_, r, g, b) => r + r + g + g + b + b); const result = MATCH_FULL_HEX.exec(hex); if (!result) { warn(`invalid config hex color value: ${orig}`); return `rgba(0, 0, 0, 1)`; } const r = parseInt((_a = result[1]) !== null && _a !== void 0 ? _a : ``, 16); const g = parseInt((_b = result[2]) !== null && _b !== void 0 ? _b : ``, 16); const b = parseInt((_c = result[3]) !== null && _c !== void 0 ? _c : ``, 16); return `rgba(${r}, ${g}, ${b}, 1)`; } export function configColor(colorName, config) { const color = config[colorName]; // the color is found at the current config level if (isString(color)) { return color; } else if (isObject(color) && isString(color.DEFAULT)) { return color.DEFAULT; } // search for a matching sub-string at the current config level let [colorNameStart = ``, ...colorNameRest] = colorName.split(`-`); while (colorNameStart !== colorName) { const subConfig = config[colorNameStart]; if (isObject(subConfig)) { return configColor(colorNameRest.join(`-`), subConfig); } else if (colorNameRest.length === 0) { return null; } colorNameStart = `${colorNameStart}-${colorNameRest.shift()}`; } return null; } const MATCH_SHORT_HEX = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; const MATCH_FULL_HEX = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;