twrnc
Version:
simple, expressive API for tailwindcss + react-native
408 lines (407 loc) • 16.6 kB
JavaScript
import fontSize from './resolve/font-size';
import lineHeight from './resolve/line-height';
import spacing from './resolve/spacing';
import screens from './screens';
import { isOrientation, isPlatform } from './types';
import fontFamily from './resolve/font-family';
import { color, colorOpacity } from './resolve/color';
import { border, borderRadius } from './resolve/borders';
import * as h from './helpers';
import { inset } from './resolve/inset';
import { flexGrowShrink, flexBasis, flex, gap } from './resolve/flex';
import { widthHeight, size, minMaxWidthHeight } from './resolve/width-height';
import { letterSpacing } from './resolve/letter-spacing';
import { opacity } from './resolve/opacity';
import { shadowOpacity, shadowOffset } from './resolve/shadow';
export default class UtilityParser {
constructor(input, config = {}, cache, device, platform) {
var _a;
this.config = config;
this.cache = cache;
this.position = 0;
this.isNull = false;
this.isNegative = false;
this.context = {};
this.context.device = device;
const parts = input.trim().split(`:`);
let prefixes = [];
if (parts.length === 1) {
this.string = input;
}
else {
this.string = (_a = parts.pop()) !== null && _a !== void 0 ? _a : ``;
prefixes = parts;
}
this.char = this.string[0];
this.parsePrefixes(prefixes, device, platform);
}
parse() {
if (this.isNull) {
return { kind: `null` };
}
// resolve things like ios:hidden, after prefix removed
const cached = this.cache.getIr(this.rest);
if (cached) {
if (this.order !== undefined) {
return { kind: `ordered`, order: this.order, styleIr: cached };
}
return cached;
}
this.parseIsNegative();
const ir = this.parseUtility();
if (!ir) {
return { kind: `null` };
}
if (this.order !== undefined) {
return { kind: `ordered`, order: this.order, styleIr: ir };
}
return ir;
}
parseUtility() {
var _a, _b, _c, _d, _e;
const theme = this.config.theme;
let style = null;
switch (this.char) {
case `m`:
case `p`: {
const match = this.peekSlice(1, 3).match(/^(t|b|r|l|x|y)?-/);
if (match) {
const prop = this.char === `m` ? `margin` : `padding`;
this.advance(((_b = (_a = match[0]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) + 1);
const spacingDirection = h.getDirection(match[1]);
const style = spacing(prop, spacingDirection, this.rest, this.context, (_c = this.config.theme) === null || _c === void 0 ? void 0 : _c[prop]);
if (style)
return style;
}
}
}
if (this.consumePeeked(`h-`)) {
style = widthHeight(`height`, this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.height);
if (style)
return style;
}
if (this.consumePeeked(`w-`)) {
style = widthHeight(`width`, this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.width);
if (style)
return style;
}
if (this.consumePeeked(`min-w-`)) {
style = minMaxWidthHeight(`minWidth`, this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.minWidth);
if (style)
return style;
}
if (this.consumePeeked(`min-h-`)) {
style = minMaxWidthHeight(`minHeight`, this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.minHeight);
if (style)
return style;
}
if (this.consumePeeked(`max-w-`)) {
style = minMaxWidthHeight(`maxWidth`, this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.maxWidth);
if (style)
return style;
}
if (this.consumePeeked(`max-h-`)) {
style = minMaxWidthHeight(`maxHeight`, this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.maxHeight);
if (style)
return style;
}
if (this.consumePeeked(`leading-`)) {
style = lineHeight(this.rest, theme === null || theme === void 0 ? void 0 : theme.lineHeight);
if (style)
return style;
}
if (this.consumePeeked(`text-`)) {
style = fontSize(this.rest, theme, this.context);
if (style)
return style;
style = color(`text`, this.rest, theme === null || theme === void 0 ? void 0 : theme.textColor);
if (style)
return style;
if (this.consumePeeked(`opacity-`)) {
style = colorOpacity(`text`, this.rest);
if (style)
return style;
}
}
if (this.consumePeeked(`font-`)) {
style = fontFamily(this.rest, theme === null || theme === void 0 ? void 0 : theme.fontFamily);
if (style)
return style;
}
if (this.consumePeeked(`aspect-`)) {
if (this.consumePeeked(`ratio-`)) {
h.warn(`\`aspect-ratio-{ratio}\` is deprecated, use \`aspect-{ratio}\` instead`);
}
style = h.getCompleteStyle(`aspectRatio`, this.rest, { fractions: true });
if (style)
return style;
}
if (this.consumePeeked(`tint-`)) {
style = color(`tint`, this.rest, theme === null || theme === void 0 ? void 0 : theme.colors);
if (style)
return style;
}
if (this.consumePeeked(`bg-`)) {
style = color(`bg`, this.rest, theme === null || theme === void 0 ? void 0 : theme.backgroundColor);
if (style)
return style;
if (this.consumePeeked(`opacity-`)) {
style = colorOpacity(`bg`, this.rest);
if (style)
return style;
}
}
if (this.consumePeeked(`border`)) {
style = border(this.rest, theme);
if (style)
return style;
if (this.consumePeeked(`-opacity-`)) {
style = colorOpacity(`border`, this.rest);
if (style)
return style;
}
}
if (this.consumePeeked(`rounded`)) {
style = borderRadius(this.rest, theme === null || theme === void 0 ? void 0 : theme.borderRadius);
if (style)
return style;
}
if (this.consumePeeked(`bottom-`)) {
style = inset(`bottom`, this.rest, this.isNegative, theme === null || theme === void 0 ? void 0 : theme.inset);
if (style)
return style;
}
if (this.consumePeeked(`top-`)) {
style = inset(`top`, this.rest, this.isNegative, theme === null || theme === void 0 ? void 0 : theme.inset);
if (style)
return style;
}
if (this.consumePeeked(`left-`)) {
style = inset(`left`, this.rest, this.isNegative, theme === null || theme === void 0 ? void 0 : theme.inset);
if (style)
return style;
}
if (this.consumePeeked(`right-`)) {
style = inset(`right`, this.rest, this.isNegative, theme === null || theme === void 0 ? void 0 : theme.inset);
if (style)
return style;
}
if (this.consumePeeked(`inset-`)) {
style = inset(`inset`, this.rest, this.isNegative, theme === null || theme === void 0 ? void 0 : theme.inset);
if (style)
return style;
}
if (this.consumePeeked(`flex-`)) {
if (this.consumePeeked(`basis`)) {
style = flexBasis(this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.flexBasis);
}
else if (this.consumePeeked(`grow`)) {
style = flexGrowShrink(`Grow`, this.rest, theme === null || theme === void 0 ? void 0 : theme.flexGrow);
}
else if (this.consumePeeked(`shrink`)) {
style = flexGrowShrink(`Shrink`, this.rest, theme === null || theme === void 0 ? void 0 : theme.flexShrink);
}
else {
style = flex(this.rest, theme === null || theme === void 0 ? void 0 : theme.flex);
}
if (style)
return style;
}
if (this.consumePeeked(`basis`)) {
style = flexBasis(this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.flexBasis);
if (style)
return style;
}
if (this.consumePeeked(`grow`)) {
style = flexGrowShrink(`Grow`, this.rest, theme === null || theme === void 0 ? void 0 : theme.flexGrow);
if (style)
return style;
}
if (this.consumePeeked(`shrink`)) {
style = flexGrowShrink(`Shrink`, this.rest, theme === null || theme === void 0 ? void 0 : theme.flexShrink);
if (style)
return style;
}
if (this.consumePeeked(`gap`)) {
style = gap(this.rest, this.context, theme === null || theme === void 0 ? void 0 : theme.gap);
if (style)
return style;
}
if (this.consumePeeked(`shadow-color-opacity-`)) {
style = colorOpacity(`shadow`, this.rest);
if (style)
return style;
}
if (this.consumePeeked(`shadow-opacity-`)) {
style = shadowOpacity(this.rest);
if (style)
return style;
}
if (this.consumePeeked(`shadow-offset-`)) {
style = shadowOffset(this.rest);
if (style)
return style;
}
if (this.consumePeeked(`shadow-radius-`)) {
style = h.unconfiggedStyle(`shadowRadius`, this.rest);
if (style)
return style;
}
if (this.consumePeeked(`shadow-`)) {
style = color(`shadow`, this.rest, theme === null || theme === void 0 ? void 0 : theme.colors);
if (style)
return style;
}
if (this.consumePeeked(`elevation-`)) {
const elevation = parseInt(this.rest, 10);
if (!Number.isNaN(elevation)) {
return h.complete({ elevation });
}
}
if (this.consumePeeked(`opacity-`)) {
style = opacity(this.rest, theme === null || theme === void 0 ? void 0 : theme.opacity);
if (style)
return style;
}
if (this.consumePeeked(`tracking-`)) {
style = letterSpacing(this.rest, this.isNegative, theme === null || theme === void 0 ? void 0 : theme.letterSpacing);
if (style)
return style;
}
if (this.consumePeeked(`z-`)) {
const zIndex = Number((_e = (_d = theme === null || theme === void 0 ? void 0 : theme.zIndex) === null || _d === void 0 ? void 0 : _d[this.rest]) !== null && _e !== void 0 ? _e : this.rest);
if (!Number.isNaN(zIndex)) {
return h.complete({ zIndex: this.isNegative ? -zIndex : zIndex });
}
}
if (this.consumePeeked(`size-`)) {
style = size(this.rest, this.context, theme);
if (style)
return style;
}
h.warn(`\`${this.rest}\` unknown or invalid utility`);
return null;
}
handlePossibleArbitraryBreakpointPrefix(prefix) {
var _a;
// save the expense of running the regex with a quick sniff test
if (prefix[0] !== `m`)
return false;
const match = prefix.match(/^(min|max)-(w|h)-\[([^\]]+)\]$/);
if (!match)
return false;
if (!((_a = this.context.device) === null || _a === void 0 ? void 0 : _a.windowDimensions)) {
this.isNull = true;
return true;
}
const windowDims = this.context.device.windowDimensions;
const [, type = ``, dir = ``, amount = ``] = match;
const checkDimension = dir === `w` ? windowDims.width : windowDims.height;
const parsedAmount = h.parseNumericValue(amount, this.context);
if (parsedAmount === null) {
this.isNull = true;
return true;
}
const [bound, unit] = parsedAmount;
if (unit !== `px`) {
this.isNull = true;
}
if (type === `min` ? checkDimension >= bound : checkDimension <= bound) {
this.incrementOrder();
}
else {
this.isNull = true;
}
return true;
}
advance(amount = 1) {
this.position += amount;
this.char = this.string[this.position];
}
get rest() {
return this.peekSlice(0, this.string.length);
}
peekSlice(begin, end) {
return this.string.slice(this.position + begin, this.position + end);
}
consumePeeked(string) {
if (this.peekSlice(0, string.length) === string) {
this.advance(string.length);
return true;
}
return false;
}
parsePrefixes(prefixes, device, platform) {
var _a, _b, _c, _d, _e;
const widthBreakpoints = screens((_a = this.config.theme) === null || _a === void 0 ? void 0 : _a.screens);
// loop through the prefixes ONE time, extracting useful info
for (const prefix of prefixes) {
if (widthBreakpoints[prefix]) {
const breakpointOrder = (_b = widthBreakpoints[prefix]) === null || _b === void 0 ? void 0 : _b[2];
if (breakpointOrder !== undefined) {
this.order = ((_c = this.order) !== null && _c !== void 0 ? _c : 0) + breakpointOrder;
}
const windowWidth = (_d = device.windowDimensions) === null || _d === void 0 ? void 0 : _d.width;
if (windowWidth) {
const [min, max] = (_e = widthBreakpoints[prefix]) !== null && _e !== void 0 ? _e : [0, 0];
if (windowWidth < min || windowWidth >= max) {
// breakpoint does not match
this.isNull = true;
}
}
else {
this.isNull = true;
}
}
else if (isPlatform(prefix)) {
this.isNull = prefix !== platform;
}
else if (isOrientation(prefix)) {
if (!device.windowDimensions) {
this.isNull = true;
}
else {
const deviceOrientation = device.windowDimensions.width > device.windowDimensions.height
? `landscape`
: `portrait`;
if (deviceOrientation !== prefix) {
this.isNull = true;
}
else {
this.incrementOrder();
}
}
}
else if (prefix === `retina`) {
if (device.pixelDensity === 2) {
this.incrementOrder();
}
else {
this.isNull = true;
}
}
else if (prefix === `dark`) {
if (device.colorScheme !== `dark`) {
this.isNull = true;
}
else {
this.incrementOrder();
}
}
else if (!this.handlePossibleArbitraryBreakpointPrefix(prefix)) {
this.isNull = true;
}
}
}
parseIsNegative() {
if (this.char === `-`) {
this.advance();
this.isNegative = true;
this.context.isNegative = true;
}
}
incrementOrder() {
var _a;
this.order = ((_a = this.order) !== null && _a !== void 0 ? _a : 0) + 1;
}
}