diff --git a/docs/plugins/changelog-to-json/libs.ts b/docs/plugins/changelog-to-json/libs.ts index 9826b2c0c3..fcab4e4f3b 100644 --- a/docs/plugins/changelog-to-json/libs.ts +++ b/docs/plugins/changelog-to-json/libs.ts @@ -3,7 +3,7 @@ import { MOBILE_COMPONENT_MAP, NON_PASCAL_CASE_NAMES, WEB_COMPONENT_MAP, -} from '../../../js/components'; +} from '../../../js/common/components'; import type { Platform } from './types'; export const convert2PascalCase = (name: string) => diff --git a/js/avatar/index.ts b/js/avatar/index.ts new file mode 100644 index 0000000000..04bca77e0d --- /dev/null +++ b/js/avatar/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/js/calendar/index.ts b/js/calendar/index.ts new file mode 100644 index 0000000000..d3973932af --- /dev/null +++ b/js/calendar/index.ts @@ -0,0 +1,3 @@ +export * from './consts'; +export * from './types'; +export * from './utils'; diff --git a/js/utils/swapDragArrayElement.ts b/js/common/array.ts similarity index 65% rename from js/utils/swapDragArrayElement.ts rename to js/common/array.ts index 75a63fc784..4587a06f07 100644 --- a/js/utils/swapDragArrayElement.ts +++ b/js/common/array.ts @@ -1,5 +1,7 @@ -// 拖拽排序场景中:调整某个元素的顺序 -export default function swapDragArrayElement(data: any[], currentIndex: number, targetIndex: number) { +/** + * 拖拽排序场景中:调整某个元素的顺序 + */ +export function swapDragArrayElement(data: any[], currentIndex: number, targetIndex: number) { const newData = [...data]; if (targetIndex - currentIndex > 0) { newData.splice(targetIndex + 1, 0, newData[currentIndex]); diff --git a/js/components.ts b/js/common/components.ts similarity index 100% rename from js/components.ts rename to js/common/components.ts diff --git a/js/common/constants.ts b/js/common/constants.ts new file mode 100644 index 0000000000..84b8084bd9 --- /dev/null +++ b/js/common/constants.ts @@ -0,0 +1,20 @@ +export enum EKeyboardDirection { + left = 37, + up = 38, + right = 39, + down = 40, +} + +export const ARROW_DOWN_REG = /^ArrowDown$/i; +export const ARROW_UP_REG = /^ArrowUp$/i; +export const ARROW_LEFT_REG = /^ArrowLeft$/i; +export const ARROW_RIGHT_REG = /^ArrowRight$/i; +export const ESCAPE_REG = /^Escape$/i; +export const SPACE_REG = /^Space$/i; +export const ENTER_REG = /^Enter$/i; +export const SHIFT_REG = /^(Shift|ShiftLeft|ShiftRight)$/i; +export const CLEAR_REG = /^KeyC$/i; +export const ALL_REG = /^(KeyA|KeyL)$/i; +export const CHECKED_CODE_REG = /^(Enter|Space)$/i; + +export const THEME_MODE = 'theme-mode'; diff --git a/js/common/dom.ts b/js/common/dom.ts new file mode 100644 index 0000000000..dea4bd005a --- /dev/null +++ b/js/common/dom.ts @@ -0,0 +1,274 @@ +import { Styles } from './types'; + +/** + * 观察元素是否进入视口 + */ +export function observe( + element: HTMLElement, + root: HTMLElement, + callback: Function, + marginBottom: number +): IntersectionObserver { + if (typeof window === 'undefined') return null; + if (!window || !window.IntersectionObserver) { + callback(); + return null; + } + let io: IntersectionObserver = null; + try { + io = new window.IntersectionObserver( + (entries) => { + const entry = entries[0]; + if (entry.isIntersecting) { + callback(); + io.unobserve(element); + } + }, + { + rootMargin: `0px 0px ${marginBottom}px 0px`, + root, + } + ); + io.observe(element); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + callback(); + } + return io; +} + +/** + * 用于为节点增加 styles + */ +export function setStyle(el: HTMLElement, styles: Styles): void { + const keys = Object.keys(styles); + keys.forEach((key) => { + // @ts-ignore + // eslint-disable-next-line no-param-reassign + el.style[key] = styles[key]; + }); +} + +/** + * 注入样式到 document + */ +export function injectStyle(style: string): void { + const styleElement = document.createElement('style'); + let styleSheet = null; + document.head.appendChild(styleElement); + styleSheet = styleElement.sheet; + styleSheet.insertRule(style, styleSheet.cssRules.length); +} + +/** + * 获取 IE 浏览器版本 + */ +export function getIEVersion(): number { + if (typeof navigator === 'undefined' || !navigator) return Number.MAX_SAFE_INTEGER; + + const { userAgent } = navigator; + const isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1; + const isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1; + if (isIE) { + const reIE = /MSIE (\d+\.\d+);/; + const match = userAgent.match(reIE); + if (!match) return -1; + const fIEVersion = parseFloat(match[1]); + return fIEVersion < 7 ? 6 : fIEVersion; + } + if (isIE11) { + return 11; + } + return Number.MAX_SAFE_INTEGER; +} + +/** + * 计算滚动条宽度(基于 CSS 设置) + */ +export function getScrollbarWidthWithCSS(): number { + const defaultScrollbarWidth = 6; + if (typeof navigator === 'undefined' || !navigator) return defaultScrollbarWidth; + if (/(Chrome|Safari)/i.test(navigator.userAgent)) return defaultScrollbarWidth; + const scrollDiv = document.createElement('div'); + scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; + document.body.appendChild(scrollDiv); + let scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; + document.body.removeChild(scrollDiv); + if (/Firefox/.test(navigator.userAgent)) { + scrollbarWidth -= 4; + } + if (getIEVersion() <= 11) { + scrollbarWidth = 12; + } + return scrollbarWidth; +} + +/** + * 计算滚动条宽度 + */ +export function getScrollbarWidth(container: HTMLElement = document.body): number { + if (container === document.body) { + return window.innerWidth - document.documentElement.clientWidth; + } + return container.offsetWidth - container.clientWidth; +} + +/** + * 检测是否需要 flex gap polyfill + */ +export function getFlexGapPolyFill(): boolean { + if (typeof navigator === 'undefined' || !navigator) return false; + const ua = navigator.userAgent; + const chromeMatch = ua.match(/AppleWebKit.+Chrome\/(.+) Safari\/.+/i); + if (Number(chromeMatch?.[1]?.split('.')[0]) < 100) return true; + const safariMatch = ua.match(/AppleWebKit.+Version\/(.+) Safari\/.+/i); + if (Number(safariMatch?.[1]?.split('.')[0]) < 12) return true; + const ieVersion = getIEVersion(); + if (ieVersion <= 11) return true; + const fireFoxMatch = ua.match(/Firefox\/(.+)/i); + if (Number(fireFoxMatch?.[1]?.split('.')[0]) < 100) return true; + return false; +} + +const DOM_STYLE_PROPS = [ + 'padding-top', + 'padding-bottom', + 'padding-left', + 'padding-right', + 'font-family', + 'font-weight', + 'font-size', + 'font-variant', + 'text-rendering', + 'text-transform', + 'width', + 'text-indent', + 'border-width', + 'box-sizing', + 'line-height', + 'letter-spacing', +]; + +/** + * 计算 dom 元素盒模型尺寸 + */ +export function calculateNodeSize(targetElement: HTMLElement) { + if (typeof window === 'undefined') { + return { + paddingSize: 0, + borderSize: 0, + boxSizing: 0, + sizingStyle: '', + }; + } + + const style = window.getComputedStyle(targetElement); + + const boxSizing = + style.getPropertyValue('box-sizing') || + style.getPropertyValue('-moz-box-sizing') || + style.getPropertyValue('-webkit-box-sizing'); + + const paddingSize = + parseFloat(style.getPropertyValue('padding-bottom')) + parseFloat(style.getPropertyValue('padding-top')); + + const borderSize = + parseFloat(style.getPropertyValue('border-bottom-width')) + parseFloat(style.getPropertyValue('border-top-width')); + + const sizingStyle = DOM_STYLE_PROPS.map((name) => `${name}:${style.getPropertyValue(name)}`).join(';'); + + return { + paddingSize, + borderSize, + boxSizing, + sizingStyle, + }; +} + +type CalculateStyleType = { + height?: string; + minHeight?: string; +}; + +type LimitType = number | null; + +const TEXTAREA_STYLE = ` + min-height:0 !important; + max-height:none !important; + height:0 !important; + visibility:hidden !important; + overflow:hidden !important; + position:absolute !important; + z-index:-1000 !important; + top:0 !important; + right:0 !important +`; + +let hiddenTextarea: HTMLTextAreaElement; + +/** + * 计算 textarea 高度 + */ +export function calcTextareaHeight( + targetElement: HTMLTextAreaElement, + minRows: LimitType = 1, + maxRows: LimitType = null +): CalculateStyleType { + if (!hiddenTextarea) { + hiddenTextarea = document.createElement('textarea'); + document.body.appendChild(hiddenTextarea); + } + + const { paddingSize, borderSize, boxSizing, sizingStyle } = calculateNodeSize(targetElement); + + hiddenTextarea.setAttribute('style', `${sizingStyle};${TEXTAREA_STYLE}`); + hiddenTextarea.value = targetElement.value || targetElement.placeholder || ''; + + let height = hiddenTextarea.scrollHeight; + const result: CalculateStyleType = {}; + const isBorderbox = boxSizing === 'border-box'; + const isContentbox = boxSizing === 'content-box'; + + if (isBorderbox) { + height += borderSize; + } else if (isContentbox) { + height -= paddingSize; + } + + hiddenTextarea.value = ''; + const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize; + hiddenTextarea?.parentNode?.removeChild(hiddenTextarea); + // @ts-ignore + hiddenTextarea = null; + + const calcHeight = (rows: number) => { + let rowsHeight = singleRowHeight * rows; + if (isBorderbox) { + rowsHeight = rowsHeight + paddingSize + borderSize; + } + return rowsHeight; + }; + + if (minRows !== null) { + const minHeight = calcHeight(minRows); + height = Math.max(minHeight, height); + result.minHeight = `${minHeight}px`; + } + if (maxRows !== null) { + height = Math.min(calcHeight(maxRows), height); + } + result.height = `${height}px`; + return result; +} + +/** + * 获取颜色 token 的色值 + * @example getColorTokenColor('--td-brand-color') + */ +export function getColorTokenColor(token: string): string { + if (typeof window === 'undefined') return ''; + const targetElement = document?.documentElement; + const styles = getComputedStyle(targetElement); + return styles.getPropertyValue(token).trim() ?? ''; +} diff --git a/js/common/helper.ts b/js/common/helper.ts new file mode 100644 index 0000000000..1344e25a09 --- /dev/null +++ b/js/common/helper.ts @@ -0,0 +1,8 @@ +/** + * 判断是否为 Safari 浏览器 + */ +export function isSafari(): boolean { + if (typeof window === 'undefined' || !window?.navigator) return false; + const ua = window.navigator.userAgent; + return /Safari/.test(ua) && !/Chrome/.test(ua); +} diff --git a/js/common/index.ts b/js/common/index.ts new file mode 100644 index 0000000000..27464992e5 --- /dev/null +++ b/js/common/index.ts @@ -0,0 +1,11 @@ +export * from './types'; +export * from './constants'; +export * from './components'; +export * from './dom'; +export * from './number'; +export * from './string'; +export * from './object'; +export * from './array'; +export * from './style'; +export * from './layout'; +export * from './helper'; diff --git a/js/utils/getPosition.ts b/js/common/layout.ts similarity index 75% rename from js/utils/getPosition.ts rename to js/common/layout.ts index 8ed8293c14..e860d2e990 100644 --- a/js/utils/getPosition.ts +++ b/js/common/layout.ts @@ -1,12 +1,15 @@ type Placement = 'top' | 'bottom' | 'left' | 'right' | 'mouse'; -const getPosition = ( +/** + * 获取元素定位位置 + */ +export function getPosition( targetEle: HTMLElement, contentEle: HTMLElement, placement: Partial, clientX?: Number, clientY?: Number -): { left: number; top: number } => { +): { left: number; top: number } { const targetRect = targetEle.getBoundingClientRect() as DOMRect; const contentRect = contentEle.getBoundingClientRect() as DOMRect; @@ -17,7 +20,6 @@ const getPosition = ( if (targetRect && contentRect) { const dWidth = targetRect.width - contentRect.width; - // eslint-disable-next-line default-case switch (placement) { case 'top': position.left += targetRect.left + dWidth / 2; @@ -31,7 +33,8 @@ const getPosition = ( position.left += Number(clientX); position.top += typeof clientY !== 'undefined' ? Number(clientY) + 16 : targetRect.top + targetRect.height + 8; break; - // 后续有需要可以再扩展 + default: + break; } if (placement === 'mouse') { @@ -42,12 +45,10 @@ const getPosition = ( bottom: document.documentElement.scrollTop + document.documentElement.clientHeight, }; - // 底部溢出时,定位到元素上方 if (position.top > edges.bottom - contentRect.height) { position.top = document.documentElement.scrollTop + targetRect.top - contentRect.height - 8; } - // 右侧溢出时,确保元素能完全展示 if (position.left > edges.right - contentRect.width) { position.left = edges.right - contentRect.width; } @@ -55,6 +56,25 @@ const getPosition = ( } return position; -}; +} -export default getPosition; +/** + * 根据宽度计算响应式尺寸 + */ +export function calcSize(width: number): string { + let size = 'xs'; + if (width < 768) { + size = 'xs'; + } else if (width >= 768 && width < 992) { + size = 'sm'; + } else if (width >= 992 && width < 1200) { + size = 'md'; + } else if (width >= 1200 && width < 1400) { + size = 'lg'; + } else if (width >= 1400 && width < 1880) { + size = 'xl'; + } else { + size = 'xxl'; + } + return size; +} diff --git a/js/utils/easing.ts b/js/common/number.ts similarity index 65% rename from js/utils/easing.ts rename to js/common/number.ts index 62b4e4193d..74fbd5e870 100644 --- a/js/utils/easing.ts +++ b/js/common/number.ts @@ -9,12 +9,7 @@ export interface EasingFunction { } /** - * @export - * @param {number} current 当前时间 - * @param {number} start 开始值 - * @param {number} end 结束值 - * @param {number} duration 持续时间 - * @returns + * 线性缓动 */ export const linear: EasingFunction = (current, start, end, duration) => { const change = end - start; @@ -23,12 +18,7 @@ export const linear: EasingFunction = (current, start, end, duration) => { }; /** - * @export - * @param {number} current 当前时间 - * @param {number} start 开始值 - * @param {number} end 结束值 - * @param {number} duration 持续时间 - * @returns + * 三次缓入缓出 */ export const easeInOutCubic: EasingFunction = (current, start, end, duration) => { const change = (end - start) / 2; @@ -37,6 +27,5 @@ export const easeInOutCubic: EasingFunction = (current, start, end, duration) => return change * time * time * time + start; } time -= 2; - // eslint-disable-next-line no-return-assign return change * (time * time * time + 2) + start; }; diff --git a/js/common/object.ts b/js/common/object.ts new file mode 100644 index 0000000000..cf209c5704 --- /dev/null +++ b/js/common/object.ts @@ -0,0 +1,56 @@ +import { isFunction, isObject, isUndefined, isNull } from 'lodash-es'; + +const { hasOwnProperty } = Object.prototype; + +export const hasOwn = (val: T, key: string | symbol | number): key is keyof T => + hasOwnProperty.call(val, key); + +export const getPropertyValFromObj = ( + val: T, + key: string | symbol | number +): T[keyof T] | undefined => (hasOwn(val, key) ? val[key] : undefined); + +const objectToString: typeof Object.prototype.toString = Object.prototype.toString; +const toTypeString = (value: unknown): string => objectToString.call(value); + +export const isPlainObject = (val: unknown): val is T => toTypeString(val) === '[object Object]'; + +export const isPromise = (val: unknown): val is Promise => + (isObject(val) || isFunction(val)) && isFunction((val as any).then) && isFunction((val as any).catch); + +export function omit(obj: Record, fields: string[]) { + const shallowCopy = { ...obj }; + for (let i = 0; i < fields.length; i++) { + const key = fields[i]; + delete shallowCopy[key]; + } + return shallowCopy; +} + +export function getValidAttrs>(obj: T): Partial { + const newObj: Partial = {}; + Object.keys(obj).forEach((key) => { + if (!isUndefined(obj[key]) || isNull(obj[key])) { + newObj[key as keyof T] = obj[key]; + } + }); + return newObj; +} + +export function removeEmptyAttrs>(obj: T): Partial { + const newObj: Partial = {}; + Object.keys(obj).forEach((key) => { + if (!isUndefined(obj[key]) || isNull(obj[key])) { + newObj[key as keyof T] = obj[key]; + } + }); + return newObj; +} + +export function getTabElementByValue(tabs: [] = [], value: string): object { + const [result] = tabs.filter((item) => { + const { id } = item as any; + return id === value; + }); + return result || null; +} diff --git a/js/common/string.ts b/js/common/string.ts new file mode 100644 index 0000000000..63bd348529 --- /dev/null +++ b/js/common/string.ts @@ -0,0 +1,62 @@ +import { isNumber } from 'lodash-es'; + +/** + * 用正则实现模板字符串功能 + */ +export function template>(str: string, vars: T): string { + return str.replace(/\${(.*?)}/g, (_, prop: string) => vars[prop.trim()] ?? ''); +} + +/** + * 首字母大写 + */ +export function firstUpperCase(str: string): string { + return str.toLowerCase().replace(/( |^)[a-z]/g, (char: string) => char.toUpperCase()); +} + +/** + * 计算字符串字符的长度并可以截取字符串 + */ +export function getCharacterLength(str: string): number; +export function getCharacterLength(str: string, maxCharacter?: number): { length: number; characters: string }; +export function getCharacterLength(str: string, maxCharacter?: number) { + const hasMaxCharacter = isNumber(maxCharacter); + if (!str || str.length === 0) { + if (hasMaxCharacter) { + return { length: 0, characters: str }; + } + return 0; + } + let len = 0; + for (let i = 0; i < str.length; i++) { + let currentStringLength = 0; + if (str.charCodeAt(i) > 127) { + currentStringLength = 2; + } else { + currentStringLength = 1; + } + if (hasMaxCharacter && len + currentStringLength > maxCharacter) { + return { length: len, characters: str.slice(0, i) }; + } + len += currentStringLength; + } + if (hasMaxCharacter) { + return { length: len, characters: str }; + } + return len; +} + +/** + * 返回 Unicode 字符长度 + */ +export function getUnicodeLength(str?: string): number { + return [...(str ?? '')].length; +} + +/** + * 修正 Unicode 最大字符长度 + */ +export function limitUnicodeMaxLength(str?: string, maxLength?: number, oldStr?: string): string { + if ([...(oldStr ?? '')].slice().length === maxLength) return oldStr || ''; + return [...(str ?? '')].slice(0, maxLength).join(''); +} diff --git a/js/common/style.ts b/js/common/style.ts new file mode 100644 index 0000000000..af967a4fdd --- /dev/null +++ b/js/common/style.ts @@ -0,0 +1,38 @@ +import { isString, isArray, isNumber } from 'lodash-es'; + +export type Gradients = { [percent: string]: string }; +export type FromTo = { from: string; to: string }; +export type LinearGradient = { direction?: string } & (Gradients | FromTo); + +/** + * 获取背景色 + */ +export function getBackgroundColor(color: string | string[] | LinearGradient): string { + if (isString(color)) { + return color; + } + if (isArray(color)) { + if (color[0] && color[0][0] === '#') { + color.unshift('90deg'); + } + return `linear-gradient( ${color.join(',')} )`; + } + const { from, to, direction = 'to right', ...rest } = color; + let keys = Object.keys(rest); + if (keys.length) { + keys = keys.sort((a, b) => { + const c = parseFloat(a.substr(0, a.length - 1)) - parseFloat(b.substr(0, b.length - 1)); + return c; + }); + const tempArr = keys.map((key: any) => `${rest[key as keyof typeof rest]} ${key}`); + return `linear-gradient(${direction}, ${tempArr.join(',')})`; + } + return `linear-gradient(${direction}, ${from}, ${to})`; +} + +/** + * 兼容样式中支持 number/string 类型的传值 + */ +export function pxCompat(param: string | number): string { + return isNumber(param) ? `${param}px` : param; +} diff --git a/js/common.ts b/js/common/types.ts similarity index 54% rename from js/common.ts rename to js/common/types.ts index c615f60a62..a60b0c933a 100644 --- a/js/common.ts +++ b/js/common/types.ts @@ -1,3 +1,18 @@ +/** + * 类型函数 + * 将字符类型转换成 CamelCase 类型 + * @param S 字符串 + * @param B 字符串的分隔符,默认为 '_' + * @example CamelCase<'a_b_c'> -> aBC + * @example CamelCase<'a-b-c', '-'> -> aBC + */ +export type CamelCase = + S extends Lowercase + ? S extends `${infer F}${B}${infer RF}${infer R}` + ? `${F}${Uppercase}${CamelCase}` + : S + : CamelCase, B>; + export type PlainObject = { [key: string]: any }; export type OptionData = { @@ -28,24 +43,3 @@ export type CSSSelector = string; export interface Styles { [css: string]: string | number; } - -export enum EKeyboardDirection { - left = 37, - up = 38, - right = 39, - down = 40, -} - -export const ARROW_DOWN_REG = /^ArrowDown$/i; -export const ARROW_UP_REG = /^ArrowUp$/i; -export const ARROW_LEFT_REG = /^ArrowLeft$/i; -export const ARROW_RIGHT_REG = /^ArrowRight$/i; -export const ESCAPE_REG = /^Escape$/i; -export const SPACE_REG = /^Space$/i; -export const ENTER_REG = /^Enter$/i; -export const SHIFT_REG = /^(Shift|ShiftLeft|ShiftRight)$/i; -export const CLEAR_REG = /^KeyC$/i; -export const ALL_REG = /^(KeyA|KeyL)$/i; -export const CHECKED_CODE_REG = /^(Enter|Space)$/i; - -export const THEME_MODE = 'theme-mode'; diff --git a/js/date-picker/format.ts b/js/date-picker/format.ts index 3b264a4a3e..d2e9a0a776 100644 --- a/js/date-picker/format.ts +++ b/js/date-picker/format.ts @@ -4,7 +4,7 @@ import isoWeeksInYear from 'dayjs/plugin/isoWeeksInYear'; import isLeapYear from 'dayjs/plugin/isLeapYear'; import customParseFormat from 'dayjs/plugin/customParseFormat'; -import log from '../log'; +import { log } from '../log'; type DateValue = string | number | Date; diff --git a/js/date-picker/index.ts b/js/date-picker/index.ts new file mode 100644 index 0000000000..86020b1db4 --- /dev/null +++ b/js/date-picker/index.ts @@ -0,0 +1,2 @@ +export * from './format'; +export * from './utils'; diff --git a/js/drawer/index.ts b/js/drawer/index.ts new file mode 100644 index 0000000000..04bca77e0d --- /dev/null +++ b/js/drawer/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/js/global-config/index.ts b/js/global-config/index.ts new file mode 100644 index 0000000000..78db07b566 --- /dev/null +++ b/js/global-config/index.ts @@ -0,0 +1,2 @@ +export * from './t'; +export { default as defaultConfig } from './default-config'; diff --git a/js/global-config/locale/index.ts b/js/global-config/locale/index.ts new file mode 100644 index 0000000000..b525120a65 --- /dev/null +++ b/js/global-config/locale/index.ts @@ -0,0 +1,8 @@ +export { default as arKW } from './ar_KW'; +export { default as enUS } from './en_US'; +export { default as itIT } from './it_IT'; +export { default as jaJP } from './ja_JP'; +export { default as koKR } from './ko_KR'; +export { default as ruRU } from './ru_RU'; +export { default as zhCN } from './zh_CN'; +export { default as zhTW } from './zh_TW'; diff --git a/js/global-config/mobile/index.ts b/js/global-config/mobile/index.ts new file mode 100644 index 0000000000..f7a59251ed --- /dev/null +++ b/js/global-config/mobile/index.ts @@ -0,0 +1 @@ +export { default as defaultConfig } from './default-config'; diff --git a/js/global-config/mobile/locale/index.ts b/js/global-config/mobile/locale/index.ts new file mode 100644 index 0000000000..b525120a65 --- /dev/null +++ b/js/global-config/mobile/locale/index.ts @@ -0,0 +1,8 @@ +export { default as arKW } from './ar_KW'; +export { default as enUS } from './en_US'; +export { default as itIT } from './it_IT'; +export { default as jaJP } from './ja_JP'; +export { default as koKR } from './ko_KR'; +export { default as ruRU } from './ru_RU'; +export { default as zhCN } from './zh_CN'; +export { default as zhTW } from './zh_TW'; diff --git a/js/image-viewer/index.ts b/js/image-viewer/index.ts new file mode 100644 index 0000000000..f0c4eaa5e0 --- /dev/null +++ b/js/image-viewer/index.ts @@ -0,0 +1,2 @@ +export * from './utils'; +export * from './types'; diff --git a/js/image-viewer/types.d.ts b/js/image-viewer/types.ts similarity index 100% rename from js/image-viewer/types.d.ts rename to js/image-viewer/types.ts diff --git a/js/input-number/index.ts b/js/input-number/index.ts new file mode 100644 index 0000000000..544482f8dc --- /dev/null +++ b/js/input-number/index.ts @@ -0,0 +1,2 @@ +export * from './large-number'; +export * from './number'; diff --git a/js/input-number/large-number.ts b/js/input-number/large-number.ts index c12ed4086f..6353f949f0 100644 --- a/js/input-number/large-number.ts +++ b/js/input-number/large-number.ts @@ -1,5 +1,5 @@ import { isString, isNumber, isObject } from 'lodash-es'; -import log from '../log/log'; +import { log } from '../log'; export type InputNumberDecimalPlaces = number | { enableRound: boolean; places: number }; diff --git a/js/input-number/number.ts b/js/input-number/number.ts index 4cbe207eea..3fd2125347 100644 --- a/js/input-number/number.ts +++ b/js/input-number/number.ts @@ -8,7 +8,7 @@ import { largeNumberAdd, largeNumberSubtract, } from './large-number'; -import log from '../log'; +import { log } from '../log'; import type { InputNumberDecimalPlaces } from './large-number'; export * from './large-number'; diff --git a/js/loading/circle-adapter.ts b/js/loading/circle-adapter.ts index cc4278ab87..a6841f8da4 100644 --- a/js/loading/circle-adapter.ts +++ b/js/loading/circle-adapter.ts @@ -1,7 +1,6 @@ -import setStyle from '../utils/setStyle'; -import { getIEVersion } from '../utils/helper'; +import { setStyle, getIEVersion } from '../common'; -export default function circleAdapter(circleElem: HTMLElement) { +export function circleAdapter(circleElem: HTMLElement) { let basicStyle = {}; if (!circleElem || typeof window === 'undefined') { @@ -11,7 +10,6 @@ export default function circleAdapter(circleElem: HTMLElement) { const computedStyle = window.getComputedStyle?.(circleElem); const color = computedStyle?.color || ''; const fontSize = computedStyle?.fontSize || '12px'; // 默认字体大小 - // to fix the browser compat of foreignObject in Safari, // https://bugs.webkit.org/show_bug.cgi?id=23113 const ua = window?.navigator?.userAgent; diff --git a/js/loading/index.ts b/js/loading/index.ts new file mode 100644 index 0000000000..5d542d587b --- /dev/null +++ b/js/loading/index.ts @@ -0,0 +1 @@ +export * from './circle-adapter'; diff --git a/js/log/index.ts b/js/log/index.ts index 32e158ef09..33fd1accb6 100644 --- a/js/log/index.ts +++ b/js/log/index.ts @@ -1,3 +1 @@ -import log from './log'; - -export default log; +export * from './log'; diff --git a/js/log/log.ts b/js/log/log.ts index 89de238635..eae52741c1 100644 --- a/js/log/log.ts +++ b/js/log/log.ts @@ -3,7 +3,7 @@ import { Log } from './types'; const logSet = new Set(); -const log: Log = { +export const log: Log = { warn(componentName, message): void { console.warn(`TDesign ${componentName} Warn: ${message}`); }, @@ -26,5 +26,3 @@ const log: Log = { console.info(`TDesign ${componentName} Info: ${message}`); }, }; - -export default log; diff --git a/js/message/animation.ts b/js/message/animation.ts index 1518377a4d..0b023f64c5 100644 --- a/js/message/animation.ts +++ b/js/message/animation.ts @@ -70,7 +70,7 @@ function getFadeOutKeyframes(placement: string, offsetHeight: Number): Array | null = getFadeOutKeyframes(placement, offsetHeight); @@ -104,5 +104,3 @@ function fadeOut(dom: HTMLElement, placement: string, onFinish: Function) { onFinish(); } } - -export { fadeIn, fadeOut }; diff --git a/js/package.json b/js/package.json index 561fe85b67..339ed1d3df 100644 --- a/js/package.json +++ b/js/package.json @@ -1,9 +1,8 @@ { - "name": "@tdesign/common-js", - "private": true, + "name": "@tdesign/utils", "author": "tdesign", "license": "MIT", "exports": { - "./*": "./*.ts" + "./*": "./*/index.ts" } } diff --git a/js/progress/index.ts b/js/progress/index.ts new file mode 100644 index 0000000000..0866817c55 --- /dev/null +++ b/js/progress/index.ts @@ -0,0 +1,2 @@ +export * from './const'; +export * from './utils'; diff --git a/js/qrcode/index.ts b/js/qrcode/index.ts new file mode 100644 index 0000000000..bdf23fe3ba --- /dev/null +++ b/js/qrcode/index.ts @@ -0,0 +1,3 @@ +export * from './qrcodegen'; +export * from './types'; +export * from './utils'; diff --git a/js/slider/index.ts b/js/slider/index.ts new file mode 100644 index 0000000000..04bca77e0d --- /dev/null +++ b/js/slider/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/js/statistic/index.ts b/js/statistic/index.ts new file mode 100644 index 0000000000..854189d1e9 --- /dev/null +++ b/js/statistic/index.ts @@ -0,0 +1,2 @@ +export * from './tween'; +export * from './utils'; diff --git a/js/statistic/tween.ts b/js/statistic/tween.ts index 1408c5b575..3493cc57b8 100644 --- a/js/statistic/tween.ts +++ b/js/statistic/tween.ts @@ -4,7 +4,7 @@ * TDesign vue 2 need to ensure compatibility with users who are using IE and Vue2, * it is necessary to use setInterval instead of requestAnimationFrame when the browser version is less than 9 */ -import { getIEVersion } from '../utils/helper'; +import { getIEVersion } from '../common'; export interface TweenSettings { from: Record; @@ -18,7 +18,7 @@ export interface TweenSettings { const quartOut = (t: number) => 1 - Math.abs((t - 1) ** 4); -export default class Tween { +export class Tween { private from: Record; private to: Record; diff --git a/js/table/index.ts b/js/table/index.ts new file mode 100644 index 0000000000..488a335787 --- /dev/null +++ b/js/table/index.ts @@ -0,0 +1,3 @@ +export * from './tree-store'; +export * from './types'; +export * from './utils'; diff --git a/js/table/tree-store.ts b/js/table/tree-store.ts index 335e151a98..05261a364e 100644 --- a/js/table/tree-store.ts +++ b/js/table/tree-store.ts @@ -4,7 +4,7 @@ import { isUndefined, get, set } from 'lodash-es'; /* eslint-disable no-use-before-define */ import { isRowSelectedDisabled } from './utils'; import { PrimaryTableCol, TableRowState, TableRowValue, TableRowData } from './types'; -import log from '../log'; +import { log } from '../log'; export type TableTreeDataMap = Map; @@ -51,7 +51,7 @@ export function getUniqueRowValue(row: TableRowData, colKey: string, rowIndex: n * @remove 移除行数据,及其子节点 * @appendTo 追加子节点到末尾 */ -class TableTreeStore { +export class TableTreeStore { /** 树形结构 Map 存储 */ treeDataMap: TableTreeDataMap = new Map(); @@ -729,8 +729,6 @@ class TableTreeStore { } } -export default TableTreeStore; - /** * 更新展开的子节点数量 * @param rowSate 行数据和状态 diff --git a/js/tabs/index.ts b/js/tabs/index.ts new file mode 100644 index 0000000000..8a185aaecc --- /dev/null +++ b/js/tabs/index.ts @@ -0,0 +1 @@ +export * from './base'; diff --git a/js/time-picker/index.ts b/js/time-picker/index.ts new file mode 100644 index 0000000000..0866817c55 --- /dev/null +++ b/js/time-picker/index.ts @@ -0,0 +1,2 @@ +export * from './const'; +export * from './utils'; diff --git a/js/tree-select/index.ts b/js/tree-select/index.ts new file mode 100644 index 0000000000..04bca77e0d --- /dev/null +++ b/js/tree-select/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/js/tree-v1/index.ts b/js/tree-v1/index.ts new file mode 100644 index 0000000000..a780df704d --- /dev/null +++ b/js/tree-v1/index.ts @@ -0,0 +1,4 @@ +export * from './tree-node'; +export * from './tree-node-model'; +export * from './tree-store'; +export * from './types'; diff --git a/js/tree-v1/tree-node-model.ts b/js/tree-v1/tree-node-model.ts index 838e83aa7e..c70c86e2a1 100644 --- a/js/tree-v1/tree-node-model.ts +++ b/js/tree-v1/tree-node-model.ts @@ -2,7 +2,7 @@ import { isUndefined, isBoolean, pick, omit } from 'lodash-es'; import { TreeNode } from './tree-node'; import { OptionData } from '../common'; import { TreeNodeValue, TypeTreeNodeModel, TypeTreeNodeData, TypeTreeItem, TreeNodeModelProps } from './types'; -import log from '../log/log'; +import { log } from '../log'; // 获取节点需要暴露的属性 function getExposedProps(node: TreeNode): TreeNodeModelProps { diff --git a/js/tree-v1/tree-node.ts b/js/tree-v1/tree-node.ts index c91e45f626..facfe4bb1c 100644 --- a/js/tree-v1/tree-node.ts +++ b/js/tree-v1/tree-node.ts @@ -1,5 +1,5 @@ import { get, isBoolean, isFunction, isNil, isNull, isNumber, uniqueId } from 'lodash-es'; -import log from '../log'; +import { log } from '../log'; import { createNodeModel, updateNodeModel } from './tree-node-model'; import { TreeStore } from './tree-store'; import type { @@ -1448,5 +1448,3 @@ export class TreeNode { return model; } } - -export default TreeNode; diff --git a/js/tree-v1/tree-store.ts b/js/tree-v1/tree-store.ts index 541b63429a..65231e0047 100644 --- a/js/tree-v1/tree-store.ts +++ b/js/tree-v1/tree-store.ts @@ -946,5 +946,3 @@ export class TreeStore { }); } } - -export default TreeStore; diff --git a/js/tree/index.ts b/js/tree/index.ts new file mode 100644 index 0000000000..2fa6c1b6ee --- /dev/null +++ b/js/tree/index.ts @@ -0,0 +1,3 @@ +export * from './tree-node'; +export * from './tree-node-model'; +export * from './tree-store'; diff --git a/js/tree/tree-node-model.ts b/js/tree/tree-node-model.ts index 23f1deeda8..043dabbcd1 100644 --- a/js/tree/tree-node-model.ts +++ b/js/tree/tree-node-model.ts @@ -2,7 +2,7 @@ import { isUndefined, isBoolean, omit, get } from 'lodash-es'; import { TreeNode } from './tree-node'; import { OptionData } from '../common'; import { TreeNodeValue, TypeTreeNodeModel, TypeTreeNodeData, TypeTreeItem } from './types'; -import log from '../log/log'; +import { log } from '../log'; export const nodeKey = '__tdesign_tree-node__'; diff --git a/js/tree/tree-node.ts b/js/tree/tree-node.ts index 39a94c9a35..b27f1b18af 100644 --- a/js/tree/tree-node.ts +++ b/js/tree/tree-node.ts @@ -1,5 +1,5 @@ import { get, isBoolean, isFunction, isNil, isNull, isNumber, uniqueId } from 'lodash-es'; -import log from '../log'; +import { log } from '../log'; import { createNodeModel } from './tree-node-model'; import { TreeStore } from './tree-store'; import type { diff --git a/js/upload/index.ts b/js/upload/index.ts new file mode 100644 index 0000000000..97d12399ef --- /dev/null +++ b/js/upload/index.ts @@ -0,0 +1,4 @@ +export * from './main'; +export * from './types'; +export * from './utils'; +export * from './xhr'; diff --git a/js/upload/main.ts b/js/upload/main.ts index 6c998426e8..d5077ea417 100644 --- a/js/upload/main.ts +++ b/js/upload/main.ts @@ -2,7 +2,7 @@ import { isFunction, isNumber } from 'lodash-es'; /* eslint-disable no-param-reassign */ import { getCurrentDate, isOverSizeLimit } from './utils'; import xhr from './xhr'; -import log from '../log/log'; +import { log } from '../log'; import { UploadFile, SizeLimitObj, diff --git a/js/upload/utils.ts b/js/upload/utils.ts index 2beade61f5..dc545c5926 100644 --- a/js/upload/utils.ts +++ b/js/upload/utils.ts @@ -1,5 +1,5 @@ import { SizeUnit } from './types'; -import log from '../log/log'; +import { log } from '../log'; export const IMAGE_REGEXP = /(.png|.jpg|.jpeg|.jpe|.webp|.avif|.svg|.gif|.bmp)/i; export const IMAGE_ALL_REGEXP = /(.png|.jpg|.jpeg|.jpe|.webp|.avif|.svg|.gif|.bmp|.dwg|.dxf|.svf|.tif|.tiff|.arw)/i; diff --git a/js/upload/xhr.ts b/js/upload/xhr.ts index 5b2e2252ed..72c2a7ddae 100644 --- a/js/upload/xhr.ts +++ b/js/upload/xhr.ts @@ -1,6 +1,6 @@ import { isFunction } from 'lodash-es'; /* eslint-disable no-param-reassign */ -import log from '../log/log'; +import { log } from '../log'; import { UploadFile, XhrOptions } from './types'; import { getCurrentDate } from './utils'; diff --git a/js/utils/calcTextareaHeight.ts b/js/utils/calcTextareaHeight.ts deleted file mode 100644 index ad029d9168..0000000000 --- a/js/utils/calcTextareaHeight.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { isNull } from 'lodash-es'; -import { calculateNodeSize } from './helper'; - -type CalculateStyleType = { - height?: string; - minHeight?: string; -}; - -type LimitType = number | null; - -const TEXTAREA_STYLE = ` - min-height:0 !important; - max-height:none !important; - height:0 !important; - visibility:hidden !important; - overflow:hidden !important; - position:absolute !important; - z-index:-1000 !important; - top:0 !important; - right:0 !important -`; - -let hiddenTextarea: HTMLTextAreaElement; - -function calcTextareaHeight( - targetElement: HTMLTextAreaElement, - minRows: LimitType = 1, - maxRows: LimitType = null -): CalculateStyleType { - if (!hiddenTextarea) { - hiddenTextarea = document.createElement('textarea'); - document.body.appendChild(hiddenTextarea); - } - - const { paddingSize, borderSize, boxSizing, sizingStyle } = calculateNodeSize(targetElement); - - hiddenTextarea.setAttribute('style', `${sizingStyle};${TEXTAREA_STYLE}`); - hiddenTextarea.value = targetElement.value || targetElement.placeholder || ''; - - let height = hiddenTextarea.scrollHeight; - const result: CalculateStyleType = {}; - const isBorderbox = boxSizing === 'border-box'; - const isContentbox = boxSizing === 'content-box'; - - if (isBorderbox) { - height += borderSize; - } else if (isContentbox) { - height -= paddingSize; - } - - hiddenTextarea.value = ''; - const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize; - hiddenTextarea?.parentNode?.removeChild(hiddenTextarea); - // @ts-ignore - hiddenTextarea = null; - - const calcHeight = (rows: number) => { - let rowsHeight = singleRowHeight * rows; - if (isBorderbox) { - rowsHeight = rowsHeight + paddingSize + borderSize; - } - return rowsHeight; - }; - - if (!isNull(minRows)) { - const minHeight = calcHeight(minRows); - height = Math.max(minHeight, height); - result.minHeight = `${minHeight}px`; - } - if (!isNull(maxRows)) { - height = Math.min(calcHeight(maxRows), height); - } - result.height = `${height}px`; - return result; -} - -export default calcTextareaHeight; diff --git a/js/utils/general.ts b/js/utils/general.ts deleted file mode 100644 index 2f8aeb87fb..0000000000 --- a/js/utils/general.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { isFunction, isObject } from 'lodash-es'; - -const { hasOwnProperty } = Object.prototype; - -export const hasOwn = (val: T, key: string | symbol | number): key is keyof T => - hasOwnProperty.call(val, key); -export const getPropertyValFromObj = ( - val: T, - key: string | symbol | number -): T[keyof T] | undefined => (hasOwn(val, key) ? val[key] : undefined); - -const objectToString: typeof Object.prototype.toString = Object.prototype.toString; -const toTypeString = (value: unknown): string => objectToString.call(value); -export const isPlainObject = (val: unknown): val is T => toTypeString(val) === '[object Object]'; -export const isPromise = (val: unknown): val is Promise => - (isObject(val) || isFunction(val)) && isFunction((val as any).then) && isFunction((val as any).catch); diff --git a/js/utils/getColorTokenColor.ts b/js/utils/getColorTokenColor.ts deleted file mode 100644 index 04a0c39110..0000000000 --- a/js/utils/getColorTokenColor.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 获取颜色token的色值 - * @example getColorTokenColor('--td-brand-color') - * @returns string - */ -export const getColorTokenColor = (token: string): string => { - if (typeof window === 'undefined') return ''; - const targetElement = document?.documentElement; - const styles = getComputedStyle(targetElement); - return styles.getPropertyValue(token).trim() ?? ''; -}; - -export default getColorTokenColor; diff --git a/js/utils/getScrollbarWidth.ts b/js/utils/getScrollbarWidth.ts deleted file mode 100644 index 933d4ce93b..0000000000 --- a/js/utils/getScrollbarWidth.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * 计算滚动条宽度的方法 - * 新建一个带有滚动条的 div 元素,通过该元素的 offsetWidth 和 clientWidth 的差值即可获得 - * CSS 中设置了 -webkit-scrollbar { width: 6px; height: 6px },固定浏览器滚动条宽度,仅限 Chrome/Safari - * Safari UA - * "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) - * AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15" - * Chrome UA - * Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) - * AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36 - * FireFox UA - * Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0 - * IE UA - * "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; - * .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)" - */ -import { getIEVersion } from './helper'; - -export function getScrollbarWidthWithCSS() { - const defaultScrollbarWidth = 6; - if (typeof navigator === 'undefined' || !navigator) return defaultScrollbarWidth; - if (/(Chrome|Safari)/i.test(navigator.userAgent)) return defaultScrollbarWidth; - const scrollDiv = document.createElement('div'); - scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; - document.body.appendChild(scrollDiv); - let scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; - document.body.removeChild(scrollDiv); - // 火狐浏览器需要再减去 4 - if (/Firefox/.test(navigator.userAgent)) { - scrollbarWidth -= 4; - } - if (getIEVersion() <= 11) { - scrollbarWidth = 12; - } - return scrollbarWidth; -} - -/** - * @description: Calculate scroll bar width - * @param container Container used to calculate scrollbar width - * @default container: document.body - */ -export function getScrollbarWidth(container: HTMLElement = document.body) { - if (container === document.body) { - return window.innerWidth - document.documentElement.clientWidth; - } - return container.offsetWidth - container.clientWidth; -} diff --git a/js/utils/helper.ts b/js/utils/helper.ts deleted file mode 100644 index e4cd62b1b4..0000000000 --- a/js/utils/helper.ts +++ /dev/null @@ -1,266 +0,0 @@ -import { isString, isNull, isUndefined, isNumber, isArray } from 'lodash-es'; - -export function omit(obj: Record, fields: string[]) { - const shallowCopy = { - ...obj, - }; - for (let i = 0; i < fields.length; i++) { - const key = fields[i]; - delete shallowCopy[key]; - } - return shallowCopy; -} - -export function getValidAttrs>(obj: T): Partial { - const newObj: Partial = {}; - - Object.keys(obj).forEach((key) => { - if (!isUndefined(obj[key]) || isNull(obj[key])) { - newObj[key as keyof T] = obj[key]; - } - }); - - return newObj; -} - -export function removeEmptyAttrs>(obj: T): Partial { - const newObj: Partial = {}; - - Object.keys(obj).forEach((key) => { - if (!isUndefined(obj[key]) || isNull(obj[key])) { - newObj[key as keyof T] = obj[key]; - } - }); - - return newObj; -} - -export function getTabElementByValue(tabs: [] = [], value: string): object { - const [result] = tabs.filter((item) => { - const { id } = item as any; - return id === value; - }); - return result || null; -} - -export function firstUpperCase(str: string): string { - return str.toLowerCase().replace(/( |^)[a-z]/g, (char: string) => char.toUpperCase()); -} - -export type Gradients = { [percent: string]: string }; -export type FromTo = { from: string; to: string }; -export type LinearGradient = { direction?: string } & (Gradients | FromTo); -export function getBackgroundColor(color: string | string[] | LinearGradient): string { - if (isString(color)) { - return color; - } - if (isArray(color)) { - if (color[0] && color[0][0] === '#') { - color.unshift('90deg'); - } - return `linear-gradient( ${color.join(',')} )`; - } - const { from, to, direction = 'to right', ...rest } = color; - let keys = Object.keys(rest); - if (keys.length) { - keys = keys.sort((a, b) => { - const c = parseFloat(a.substr(0, a.length - 1)) - parseFloat(b.substr(0, b.length - 1)); - return c; - }); - const tempArr = keys.map((key: any) => `${rest[key as keyof typeof rest]} ${key}`); - return `linear-gradient(${direction}, ${tempArr.join(',')})`; - } - return `linear-gradient(${direction}, ${from}, ${to})`; -} - -/** - * - * @returns 获取 ie 浏览器版本 - */ -export function getIEVersion() { - if (typeof navigator === 'undefined' || !navigator) return Number.MAX_SAFE_INTEGER; - - const { userAgent } = navigator; - // 判断是否IE<11浏览器 - const isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1; - // 判断是否IE11浏览器 - const isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1; - if (isIE) { - const reIE = /MSIE (\d+\.\d+);/; - const match = userAgent.match(reIE); - if (!match) return -1; - const fIEVersion = parseFloat(match[1]); - return fIEVersion < 7 ? 6 : fIEVersion; - } - if (isIE11) { - // IE11 - return 11; - } - // 不是ie浏览器 - return Number.MAX_SAFE_INTEGER; -} - -/** - * Safari Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15 - * FireFox Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0 - * Chrome Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 - * Chrome 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.3 - * 搜狗 Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1. - * 360 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.9 Safari/537.36 QIHU 360EE - */ -export function getFlexGapPolyFill() { - if (typeof navigator === 'undefined' || !navigator) return false; - const ua = navigator.userAgent; - const chromeMatch = ua.match(/AppleWebKit.+Chrome\/(.+) Safari\/.+/i); - if (Number(chromeMatch?.[1]?.split('.')[0]) < 100) return true; - const safariMatch = ua.match(/AppleWebKit.+Version\/(.+) Safari\/.+/i); - if (Number(safariMatch?.[1]?.split('.')[0]) < 12) return true; - const ieVersion = getIEVersion(); - if (ieVersion <= 11) return true; - const fireFoxMatch = ua.match(/Firefox\/(.+)/i); - if (Number(fireFoxMatch?.[1]?.split('.')[0]) < 100) return true; - return false; -} - -/** - * 计算字符串字符的长度并可以截取字符串。 - * @param str 传入字符串 - * @param maxCharacter 规定最大字符串长度 - * @returns 当没有传入maxCharacter时返回字符串字符长度,当传入maxCharacter时返回截取之后的字符串和长度。 - */ -export function getCharacterLength(str: string): number; -export function getCharacterLength(str: string, maxCharacter?: number): { length: number; characters: string }; -export function getCharacterLength(str: string, maxCharacter?: number) { - const hasMaxCharacter = isNumber(maxCharacter); - if (!str || str.length === 0) { - if (hasMaxCharacter) { - return { - length: 0, - characters: str, - }; - } - return 0; - } - let len = 0; - for (let i = 0; i < str.length; i++) { - let currentStringLength = 0; - if (str.charCodeAt(i) > 127) { - currentStringLength = 2; - } else { - currentStringLength = 1; - } - if (hasMaxCharacter && len + currentStringLength > maxCharacter) { - return { - length: len, - characters: str.slice(0, i), - }; - } - len += currentStringLength; - } - if (hasMaxCharacter) { - return { - length: len, - characters: str, - }; - } - return len; -} - -/** - * 返回 Unicode 字符长度 - * '👨'.length === 2 - * getUnicodeLength('👨') === 1 - * @param str - * @returns {number} - */ -export function getUnicodeLength(str?: string): number { - return [...(str ?? '')].length; -} - -/** - * 修正 Unicode 最大字符长度 - * '👨👨👨'.slice(0, 2) === '👨' - * limitUnicodeMaxLength('👨👨👨', 2) === '👨👨' - * @param str - * @param maxLength - * @param oldStr - * @returns {string} - */ -export function limitUnicodeMaxLength(str?: string, maxLength?: number, oldStr?: string): string { - // 旧字符满足字数要求则返回 - if ([...(oldStr ?? '')].slice().length === maxLength) return oldStr || ''; - return [...(str ?? '')].slice(0, maxLength).join(''); -} - -/** - * 兼容样式中支持number/string类型的传值 得出最后的结果。 - * @param param number或string类型的可用于样式上的值 - * @returns 可使用的样式值。 - */ -export function pxCompat(param: string | number) { - return isNumber(param) ? `${param}px` : param; -} - -/** - * 计算dom元素盒模型尺寸 - * @param targetElement 需要计算盒模型尺寸的元素 - * @returns 计算出各维度尺寸。 - */ -const DOM_STYLE_PROPS = [ - 'padding-top', - 'padding-bottom', - 'padding-left', - 'padding-right', - 'font-family', - 'font-weight', - 'font-size', - 'font-variant', - 'text-rendering', - 'text-transform', - 'width', - 'text-indent', - 'border-width', - 'box-sizing', - 'line-height', - 'letter-spacing', -]; - -export function calculateNodeSize(targetElement: HTMLElement) { - if (typeof window === 'undefined') { - return { - paddingSize: 0, - borderSize: 0, - boxSizing: 0, - sizingStyle: '', - }; - } - - const style = window.getComputedStyle(targetElement); - - const boxSizing = - style.getPropertyValue('box-sizing') || - style.getPropertyValue('-moz-box-sizing') || - style.getPropertyValue('-webkit-box-sizing'); - - const paddingSize = - parseFloat(style.getPropertyValue('padding-bottom')) + parseFloat(style.getPropertyValue('padding-top')); - - const borderSize = - parseFloat(style.getPropertyValue('border-bottom-width')) + parseFloat(style.getPropertyValue('border-top-width')); - - const sizingStyle = DOM_STYLE_PROPS.map((name) => `${name}:${style.getPropertyValue(name)}`).join(';'); - - return { - paddingSize, - borderSize, - boxSizing, - sizingStyle, - }; -} - -export function isSafari(): boolean { - if (typeof window === 'undefined') return false; - - const ua = window?.navigator?.userAgent; - return /Safari/.test(ua) && !/Chrome/.test(ua); -} diff --git a/js/utils/injectStyle.ts b/js/utils/injectStyle.ts deleted file mode 100644 index 80b7dcc346..0000000000 --- a/js/utils/injectStyle.ts +++ /dev/null @@ -1,9 +0,0 @@ -const injectStyle = (style: string) => { - const styleElement = document.createElement('style'); - let styleSheet = null; - document.head.appendChild(styleElement); - styleSheet = styleElement.sheet; - styleSheet.insertRule(style, styleSheet.cssRules.length); -}; - -export default injectStyle; diff --git a/js/utils/observe.ts b/js/utils/observe.ts deleted file mode 100644 index cb261612f8..0000000000 --- a/js/utils/observe.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default function observe( - element: HTMLElement, - root: HTMLElement, - callback: Function, - marginBottom: number -): IntersectionObserver { - if (typeof window === 'undefined') return null; - if (!window || !window.IntersectionObserver) { - callback(); - return null; - } - let io: IntersectionObserver = null; - try { - io = new window.IntersectionObserver( - (entries) => { - const entry = entries[0]; - if (entry.isIntersecting) { - callback(); - io.unobserve(element); - } - }, - { - rootMargin: `0px 0px ${marginBottom}px 0px`, - root, - } - ); - io.observe(element); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - callback(); - } - return io; -} diff --git a/js/utils/responsive.ts b/js/utils/responsive.ts deleted file mode 100644 index 83e5fe69dd..0000000000 --- a/js/utils/responsive.ts +++ /dev/null @@ -1,17 +0,0 @@ -export const calcSize = (width: number) => { - let size = 'xs'; - if (width < 768) { - size = 'xs'; - } else if (width >= 768 && width < 992) { - size = 'sm'; - } else if (width >= 992 && width < 1200) { - size = 'md'; - } else if (width >= 1200 && width < 1400) { - size = 'lg'; - } else if (width >= 1400 && width < 1880) { - size = 'xl'; - } else { - size = 'xxl'; - } - return size; -}; diff --git a/js/utils/setStyle.ts b/js/utils/setStyle.ts deleted file mode 100644 index b5864f1a1d..0000000000 --- a/js/utils/setStyle.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Styles } from '../common'; - -/** - * 用于为节点增加styles - * @param el HTMLElement - * @param style Styles - */ -function setStyle(el: HTMLElement, styles: Styles): void { - const keys = Object.keys(styles); - keys.forEach((key) => { - // @ts-ignore - // eslint-disable-next-line no-param-reassign - el.style[key] = styles[key]; - }); - // TODO: 这个怎么样 - // Object.assign(el.style, styles); -} - -export default setStyle; diff --git a/js/utils/stringTemplate.ts b/js/utils/stringTemplate.ts deleted file mode 100644 index ea6441557a..0000000000 --- a/js/utils/stringTemplate.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * 用正则实现模板字符串功能 - * @param str 模板字符串 - * @param vars 取值的对象 - * @returns 替换后的字符串 - */ -export function template>(str: string, vars: T): string { - return str.replace(/\${(.*?)}/g, (_, prop: string) => vars[prop.trim()] ?? ''); -} diff --git a/js/utils/types.ts b/js/utils/types.ts deleted file mode 100644 index 07c7cc5bb3..0000000000 --- a/js/utils/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 类型函数 - * 将字符类型转换成 CamelCase 类型 - * @param S 字符串 - * @param B 字符串的分隔符,默认为 '_' - * @example CamelCase<'a_b_c'> -> aBC - * @example CamelCase<'a-b-c', '-'> -> aBC - */ -export type CamelCase = - S extends Lowercase - ? S extends `${infer F}${B}${infer RF}${infer R}` - ? `${F}${Uppercase}${CamelCase}` - : S - : CamelCase, B>; diff --git a/js/watermark/generateBase64Url.ts b/js/watermark/generateBase64Url.ts index 0d2cd6836d..ac8e76bb7d 100644 --- a/js/watermark/generateBase64Url.ts +++ b/js/watermark/generateBase64Url.ts @@ -1,6 +1,6 @@ import { WatermarkText, WatermarkImage, WatermarkLayout } from './type'; -export default function generateBase64Url( +export function generateBase64Url( { width, height, diff --git a/js/watermark/index.ts b/js/watermark/index.ts new file mode 100644 index 0000000000..9da2237394 --- /dev/null +++ b/js/watermark/index.ts @@ -0,0 +1,3 @@ +export * from './generateBase64Url'; +export * from './randomMovingStyle'; +export * from './type'; diff --git a/js/watermark/randomMovingStyle.ts b/js/watermark/randomMovingStyle.ts index c6768c2800..749189afd5 100644 --- a/js/watermark/randomMovingStyle.ts +++ b/js/watermark/randomMovingStyle.ts @@ -1,5 +1,5 @@ /* eslint-disable no-nested-ternary */ -export default function randomMovingStyle() { +export function randomMovingStyle() { const align = Math.floor(Math.random() * 4); const p1 = Math.floor(Math.random() * 70) + 30; const leftTopLimit = 0; diff --git a/test/unit/locale/locale.test.ts b/test/unit/locale/locale.test.ts index 249a2c247e..72b2ac249f 100644 --- a/test/unit/locale/locale.test.ts +++ b/test/unit/locale/locale.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from 'vitest'; -import { t } from '../../../js/global-config/t'; +import { t } from '../../../js/global-config'; describe('国际化函数 t', () => { describe('基本变量替换', () => {