import { lowerFirst, upperFirst } from '@antv/util';
import type { ReplacePrefix } from '../types';
/**
* 是否以某个前缀开头
*
* Whether starts with prefix
* @param str - 字符串 | string
* @param prefix - 前缀 | prefix
* @returns 是否以某个前缀开头 | whether starts with prefix
*/
export function startsWith(str: string, prefix: string) {
if (!str.startsWith(prefix)) return false;
const nextChart = str[prefix.length];
return nextChart >= 'A' && nextChart <= 'Z';
}
/**
* 添加前缀
*
* Add prefix
* @param str - 字符串 | string
* @param prefix - 前缀 | prefix
* @returns 添加前缀后的字符串 | string with prefix
*/
export function addPrefix(str: string, prefix: string): string {
return `${prefix}${upperFirst(str)}`;
}
/**
* 移除前缀
*
* Remove prefix
* @param string - 字符串 | string
* @param prefix - 前缀 | prefix
* @param lowercaseFirstLetter - 是否小写首字母 | whether lowercase first letter
* @returns 移除前缀后的字符串 | string without prefix
*/
export function removePrefix(string: string, prefix?: string, lowercaseFirstLetter: boolean = true) {
if (!prefix) return string;
if (!startsWith(string, prefix)) return string;
const str = string.slice(prefix.length);
return lowercaseFirstLetter ? lowerFirst(str) : str;
}
/**
* 从样式中提取子样式
*
* Extract sub style from style
* @param style - 样式 | style
* @param prefix - 子样式前缀 | sub style prefix
* @returns 子样式 | sub style
*/
export function subStyleProps>(style: object, prefix: string) {
const subStyle = Object.entries(style).reduce((acc, [key, value]) => {
if (key === 'className' || key === 'class') return acc;
if (startsWith(key, prefix)) {
Object.assign(acc, { [removePrefix(key, prefix)]: value });
}
return acc;
}, {} as T);
// 向下传递透明度,但避免覆盖子样式中的透明度属性
// Pass down opacity, but avoid overwriting the opacity property in the sub-style
if ('opacity' in style) {
const subOpacityKey = addPrefix('opacity', prefix) as keyof typeof style;
const opacity = style.opacity as number;
if (subOpacityKey in style) {
const subOpacity = style[subOpacityKey] as number;
Object.assign(subStyle, { opacity: opacity * subOpacity });
} else Object.assign(subStyle, { opacity });
}
return subStyle;
}
/**
* 从对象中提取指定前缀的属性,并移除前缀
*
* Extract properties with the specified prefix from the object and remove the prefix
* @param obj - 对象 | object
* @param prefix - 前缀 | prefix
* @returns 新对象 | new object
*/
export function subObject(obj: Record, prefix: string): Record {
const prefixLength = prefix.length;
return Object.keys(obj).reduce(
(acc, key) => {
if (key.startsWith(prefix)) {
const newKey = key.slice(prefixLength);
acc[newKey] = obj[key];
}
return acc;
},
{} as Record,
);
}
/**
* 从样式中排除子样式
*
* Omit sub style from style
* @param style - 样式 | style
* @param prefix - 子样式前缀 | sub style prefix
* @returns 排除子样式后的样式 | style without sub style
*/
export function omitStyleProps>(style: Record, prefix: string | string[]) {
const prefixArray = typeof prefix === 'string' ? [prefix] : prefix;
const omitStyle: Record = {};
Object.keys(style).forEach((key) => {
if (!prefixArray.find((p) => key.startsWith(p))) {
omitStyle[key] = style[key];
}
});
return omitStyle as T;
}
/**
* 替换前缀
*
* Replace prefix
* @param style - 样式 | style
* @param oldPrefix - 旧前缀 | old prefix
* @param newPrefix - 新前缀 | new prefix
* @returns 替换前缀后的样式 | style with replaced prefix
*/
export function replacePrefix(style: T, oldPrefix: string, newPrefix: string) {
return Object.entries(style).reduce(
(acc, [key, value]) => {
if (startsWith(key, oldPrefix)) {
acc[addPrefix(removePrefix(key, oldPrefix, false), newPrefix) as keyof typeof acc] = value;
} else {
acc[key as keyof typeof acc] = value;
}
return acc;
},
{} as ReplacePrefix,
);
}