H5-contact/node_modules/@dcloudio/uni-nvue-styler/dist/uni-nvue-styler.es.js

641 lines
23 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { hyphenate, capitalize } from '@vue/shared';
function createDecl(prop, value, important, raws, source) {
const decl = {
type: 'decl',
prop,
value: value.toString(),
raws,
source,
};
if (important) {
decl.important = true;
}
return decl;
}
const isNumber = (val) => typeof val === 'number';
const cacheStringFunction = (fn) => {
const cache = Object.create(null);
return ((str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
});
};
const hyphenateRE = /([A-Z])/g;
const hyphenateStyleProperty = cacheStringFunction((str) => str
.replace(hyphenateRE, (_, m) => {
if (typeof m === 'string') {
return '-' + m.toLowerCase();
}
return m;
})
.toLowerCase());
function supportedValueWithTipsReason(k, v, tips) {
return ('ERROR: property value `' +
v +
'` is not supported for `' +
hyphenateStyleProperty(k) +
'` ' +
tips);
}
/**
* css value 分割多值,兼容包含括号的 css 方法,比如 var/env/calc() 等
*/
function splitValues(value) {
const trimmedValue = value.trim();
if (!trimmedValue.includes('(')) {
return trimmedValue.split(/\s+/);
}
const parts = [];
let current = '';
let depth = 0;
for (let i = 0; i < trimmedValue.length; i++) {
const char = trimmedValue[i];
if (char === '(') {
depth++;
current += char;
}
else if (char === ')') {
if (depth > 0) {
depth--;
}
current += char;
}
else if (/\s/.test(char)) {
if (depth === 0) {
if (current) {
parts.push(current);
current = '';
}
}
else {
// 多个空格处理一个
if (current.length > 0 && !/\s$/.test(current)) {
current += ' ';
}
}
}
else {
current += char;
}
}
if (current) {
parts.push(current);
}
return parts;
}
const backgroundColor = 'backgroundColor';
const backgroundImage = 'backgroundImage';
const handleTransformBackground = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
if (value === 'none') {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, value, important, raws, source),
];
}
else if (/^linear-gradient(.+)$/.test(value)) {
return [
createDecl(backgroundImage, value, important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
else if (value == '') {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
return [decl];
};
const handleTransformBackgroundNvue = (decl) => {
const { value, important, raws, source } = decl;
if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
return [createDecl(backgroundColor, value, important, raws, source)];
}
else if (/^linear-gradient(.+)$/.test(value)) {
return [createDecl(backgroundImage, value, important, raws, source)];
}
else if (value == '') {
return [decl];
}
return [decl];
};
function createTransformBackground(options) {
return (decl) => {
// nvue 平台维持原有逻辑不变
const isUvuePlatform = options.type === 'uvue';
if (isUvuePlatform) {
return handleTransformBackground(decl);
}
else {
return handleTransformBackgroundNvue(decl);
}
};
}
const borderTop = 'borderTop';
const borderRight = 'borderRight';
const borderBottom = 'borderBottom';
const borderLeft = 'borderLeft';
const transformBorderColor = (decl) => {
let { prop, value, important, raws, source } = decl;
value = value.trim();
const _property_split = hyphenate(prop).split('-');
let property = _property_split[_property_split.length - 1];
{
property = capitalize(property);
}
const splitResult = splitValues(value); // 1pt
switch (splitResult.length) {
case 1:
if (_property_split.length === 3) {
// border-top-width
return [decl];
}
// border-width
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTop + property, splitResult[0], important, raws, source),
createDecl(borderRight + property, splitResult[1], important, raws, source),
createDecl(borderBottom + property, splitResult[2], important, raws, source),
createDecl(borderLeft + property, splitResult[3], important, raws, source),
];
};
const transformBorderColorNvue = (decl) => {
let { prop, value, important, raws, source } = decl;
value = value.trim();
let property = hyphenate(prop).split('-')[1];
{
property = capitalize(property);
}
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
switch (splitResult.length) {
case 1:
return [decl];
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTop + property, splitResult[0], important, raws, source),
createDecl(borderRight + property, splitResult[1], important, raws, source),
createDecl(borderBottom + property, splitResult[2], important, raws, source),
createDecl(borderLeft + property, splitResult[3], important, raws, source),
];
};
const transformBorderStyle = transformBorderColor;
const transformBorderStyleNvue = transformBorderColorNvue;
const transformBorderWidth = transformBorderColor;
const transformBorderWidthNvue = transformBorderColorNvue;
function tryExpandSingleValueVarShorthand(decl, props, value) {
// 只在 dom2 运行时兜底展开,避免影响其它平台现有行为。
{
return null;
}
}
const borderWidth = 'Width';
const borderStyle = 'Style';
const borderColor = 'Color';
const BORDER_WIDTH_REGEXP = /^(?:[\d.]+\S*|thin|medium|thick)$/;
// 这里按完整 CSS line-style 识别,后续再交给 border-*-style 的既有校验逻辑报精确错误。
const BORDER_STYLE_REGEXP = /^(?:none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset)$/;
const BORDER_SHORTHAND_VAR_ORDER_WARNING = '__borderShorthandVarOrderWarning';
function createBorderVarOrderWarning(prop, value) {
return supportedValueWithTipsReason(prop, value, '(border shorthand with CSS variables must follow `width style color`, for example: `1px solid var(--color, #999999)`)');
}
function isCssVarValue(value) {
return value.startsWith('var(');
}
function isBorderWidthValue(value) {
return isCssVarValue(value) || BORDER_WIDTH_REGEXP.test(value);
}
function isBorderStyleValue(value) {
return isCssVarValue(value) || BORDER_STYLE_REGEXP.test(value);
}
function isBorderColorValue(value) {
return (isCssVarValue(value) ||
(!BORDER_WIDTH_REGEXP.test(value) && !BORDER_STYLE_REGEXP.test(value)));
}
function createTransformBorder(options) {
return (decl) => {
const { prop, value, important, raws, source } = decl;
const singleVarResult = tryExpandSingleValueVarShorthand();
// 单个 var() 无法提前判断是 width/style/colordom2 下先平铺后继续展开。
if (singleVarResult) {
return [
...transformBorderWidth(singleVarResult[0]),
...transformBorderStyle(singleVarResult[1]),
...transformBorderColor(singleVarResult[2]),
];
}
let splitResult = splitValues(value);
const havVar = splitResult.some((str) => str.startsWith('var('));
let result = [];
// 包含 var 时按位置解析,避免把 style 误判成 color
if (havVar) {
if (splitResult.length > 3 ||
(splitResult.length === 3 &&
(!isBorderWidthValue(splitResult[0]) ||
!isBorderStyleValue(splitResult[1]) ||
!isBorderColorValue(splitResult[2])))) {
decl[BORDER_SHORTHAND_VAR_ORDER_WARNING] =
createBorderVarOrderWarning(prop, value);
return [];
}
result = splitResult;
splitResult = [];
}
else {
result = [BORDER_WIDTH_REGEXP, BORDER_STYLE_REGEXP, /\S+/].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
}
if (splitResult.length > 0 && value != '') {
return [decl];
}
const defaultWidth = (str) => {
if (str != null) {
return str.trim();
}
return 'medium';
};
const defaultStyle = (str) => {
if (str != null) {
return str.trim();
}
return 'none';
};
const defaultColor = (str) => {
if (str != null) {
return str.trim();
}
return '#000000';
};
return [
...transformBorderWidth(createDecl(prop + borderWidth, defaultWidth(result[0]), important, raws, source)),
...transformBorderStyle(createDecl(prop + borderStyle, defaultStyle(result[1]), important, raws, source)),
...transformBorderColor(createDecl(prop + borderColor, defaultColor(result[2]), important, raws, source)),
];
};
}
/**
* nvue 逻辑不变
*/
function createTransformBorderNvue(options) {
return (decl) => {
let { prop, value, important, raws, source } = decl;
value = value.trim();
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
const result = [
/^[\d\.]+\S*|^(thin|medium|thick)$/,
/^(solid|dashed|dotted|none)$/,
/\S+/,
].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
if (splitResult.length) {
return [decl];
}
return [
createDecl(prop + borderWidth, (result[0] || '0').trim(), important, raws, source),
createDecl(prop + borderStyle, (result[1] || 'solid').trim(), important, raws, source),
createDecl(prop + borderColor, (result[2] || '#000000').trim(), important, raws, source),
];
};
}
const borderTopLeftRadius = 'borderTopLeftRadius';
const borderTopRightRadius = 'borderTopRightRadius';
const borderBottomRightRadius = 'borderBottomRightRadius';
const borderBottomLeftRadius = 'borderBottomLeftRadius';
const transformBorderRadius = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const splitResult = splitValues(value);
if (value.includes('/')) {
return [decl];
}
switch (splitResult.length) {
case 1:
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
createDecl(borderBottomRightRadius, splitResult[2], important, raws, source),
createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
];
};
const transformBorderRadiusNvue = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const splitResult = value.split(/\s+/);
if (value.includes('/')) {
return [decl];
}
// const isUvuePlatform = options.type === 'uvue'
switch (splitResult.length) {
case 1:
return [decl];
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
createDecl(borderBottomRightRadius, splitResult[2], important, raws, source),
createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
];
};
const flexDirection = 'flexDirection';
const flexWrap = 'flexWrap';
const transformFlexFlow = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const splitResult = splitValues(value);
const singleVarResult = tryExpandSingleValueVarShorthand();
// 单个 var() 无法提前判断是 direction 还是 wrapdom2 下直接平铺。
if (singleVarResult) {
return singleVarResult;
}
const result = [
/^(column|column-reverse|row|row-reverse)$/,
/^(nowrap|wrap|wrap-reverse)$/,
].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
if (splitResult.length) {
return [decl];
}
return [
createDecl(flexDirection, result[0] || 'column', important, raws, source),
createDecl(flexWrap, result[1] || 'nowrap', important, raws, source),
];
};
const top = 'Top';
const right = 'Right';
const bottom = 'Bottom';
const left = 'Left';
const createTransformBox = (type) => {
return (decl) => {
const { value, important, raws, source } = decl;
const splitResult = splitValues(value);
switch (splitResult.length) {
case 1:
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(type + top, splitResult[0], important, raws, source),
createDecl(type + right, splitResult[1], important, raws, source),
createDecl(type + bottom, splitResult[2], important, raws, source),
createDecl(type + left, splitResult[3], important, raws, source),
];
};
};
const transformMargin = createTransformBox('margin');
const transformPadding = createTransformBox('padding');
const transitionProperty = 'transitionProperty';
const transitionDuration = 'transitionDuration';
const transitionTimingFunction = 'transitionTimingFunction';
const transitionDelay = 'transitionDelay';
const transformTransition = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const result = [];
let match;
// 针对 cubic-bezier 特殊处理
// eg: cubic-bezier(0.42, 0, 1.0, 3) // (0.2,-2,0.8,2)
if (value.includes('cubic-bezier')) {
const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*((\S*)|cubic-bezier\(.*\))?\s*(\d*\.?\d+(?:ms|s)?)?$/;
match = value.match(CHUNK_REGEXP);
}
else {
const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?$/;
match = value.match(CHUNK_REGEXP);
}
if (!match) {
return result;
}
match[1] &&
result.push(createDecl(transitionProperty, match[1], important, raws, source));
match[2] &&
result.push(createDecl(transitionDuration, match[2], important, raws, source));
match[3] &&
result.push(createDecl(transitionTimingFunction, match[3], important, raws, source));
match[4] &&
result.push(createDecl(transitionDelay, match[4], important, raws, source));
return result;
};
const flexGrow = 'flexGrow';
const flexShrink = 'flexShrink';
const flexBasis = 'flexBasis';
const transformFlex = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const result = [];
const splitResult = splitValues(value);
const singleVarResult = tryExpandSingleValueVarShorthand();
// 单个 var() 无法提前拆出 grow/shrink/basisdom2 下按 border 的兜底逻辑平铺。
if (singleVarResult) {
return singleVarResult;
}
// 是否 flex-grow 的有效值 <number [0,∞]>
const isFlexGrowValid = (v) => isNumber(Number(v)) && !Number.isNaN(Number(v));
const isFlexShrinkValid = (v) => isNumber(Number(v)) && !Number.isNaN(Number(v)) && Number(v) >= 0;
const isFlexBasisValid = (v) => typeof v === 'string' && v.trim() !== '';
if (splitResult.length === 1) {
// 关键字处理
if (value === 'none') {
result.push(createDecl(flexGrow, '0', important, raws, source), createDecl(flexShrink, '0', important, raws, source), createDecl(flexBasis, 'auto', important, raws, source));
return result;
}
if (value === 'auto') {
result.push(createDecl(flexGrow, '1', important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, 'auto', important, raws, source));
return result;
}
if (value === 'initial') {
result.push(createDecl(flexGrow, '0', important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, 'auto', important, raws, source));
return result;
}
const v = splitResult[0];
// number 视为 flex-grow
if (isFlexGrowValid(v)) {
if (Number(v) < 0) {
return [];
}
result.push(createDecl(flexGrow, v, important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, '0%', important, raws, source));
return result;
}
else if (isFlexBasisValid(v)) {
result.push(createDecl(flexGrow, '1', important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, v, important, raws, source));
return result;
}
else {
return [decl];
}
}
else if (splitResult.length === 2) {
const [v1, v2] = splitResult;
if (isFlexGrowValid(v1)) {
if (isFlexShrinkValid(v2)) {
// flex: 1 2 => 1 2 0%
result.push(createDecl(flexGrow, v1, important, raws, source), createDecl(flexShrink, v2, important, raws, source), createDecl(flexBasis, '0%', important, raws, source));
return result;
}
else {
// flex: 1 100px => 1 1 100px
result.push(createDecl(flexGrow, v1, important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, v2, important, raws, source));
return result;
}
}
else {
return [decl];
}
}
else if (splitResult.length === 3) {
const [v1, v2, v3] = splitResult;
if (isFlexGrowValid(v1) && isFlexShrinkValid(v2)) {
result.push(createDecl(flexGrow, v1, important, raws, source), createDecl(flexShrink, v2, important, raws, source), createDecl(flexBasis, v3, important, raws, source));
return result;
}
else {
// fallback
return [decl];
}
}
// 其它情况,原样返回
return [decl];
};
function getDeclTransforms(options) {
const transformBorder = options.type === 'uvue'
? createTransformBorder()
: createTransformBorderNvue();
const styleMap = {
transition: transformTransition,
border: transformBorder,
background: createTransformBackground(options),
['borderTop']: transformBorder,
['borderRight']: transformBorder,
['borderBottom']: transformBorder,
['borderLeft']: transformBorder,
['borderStyle']: options.type === 'uvue' ? transformBorderStyle : transformBorderStyleNvue,
['borderWidth']: options.type === 'uvue' ? transformBorderWidth : transformBorderWidthNvue,
['borderColor']: options.type === 'uvue' ? transformBorderColor : transformBorderColorNvue,
['borderRadius']: options.type === 'uvue'
? transformBorderRadius
: transformBorderRadiusNvue,
// uvue已经支持这些简写属性不需要展开
// margin,padding继续展开确保样式的优先级
margin: transformMargin,
padding: transformPadding,
['flexFlow']: transformFlexFlow,
};
if (options.type === 'uvue') {
styleMap.flex = transformFlex;
}
let result = {};
{
result = styleMap;
}
return result;
}
let DeclTransforms;
const expanded = Symbol('expanded');
function expand(options) {
const plugin = {
postcssPlugin: `${options.type || 'nvue'}:expand`,
Declaration(decl, helper) {
if (decl[expanded]) {
return;
}
if (!DeclTransforms) {
DeclTransforms = getDeclTransforms(options);
}
const transform = DeclTransforms[decl.prop];
if (transform) {
const res = transform(decl);
const reason = decl[BORDER_SHORTHAND_VAR_ORDER_WARNING];
if (reason && helper && decl.warn) {
let needLog = false;
if (options.logLevel === 'NOTE') {
needLog = true;
}
else if (options.logLevel === 'ERROR') {
if (reason.startsWith('ERROR:')) {
needLog = true;
}
}
else {
if (!reason.startsWith('NOTE:')) {
needLog = true;
}
}
if (needLog) {
decl.warn(helper.result, reason);
}
delete decl[BORDER_SHORTHAND_VAR_ORDER_WARNING];
}
const isSame = res.length === 1 && res[0] === decl;
if (!isSame) {
decl.replaceWith(res);
}
}
decl[expanded] = true;
},
};
return plugin;
}
export { expand };