2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
import { definePropType } from './props'
export const iconPropType = definePropType<string>([String])
export const FormValidateIconsMap = {
validating: 'loading',
success: 'success-circle',
error: 'close-circle',
}
+4
View File
@@ -0,0 +1,4 @@
export * from './typescript'
export * from './install'
export * from './props'
export * from './icon'
+56
View File
@@ -0,0 +1,56 @@
import { isEmptyVariableInDefault } from '../is-empty'
import type { App, Directive } from 'vue'
import type { SFCInstallWithContext, SFCWithInstall } from './typescript'
// 注册组件
export const withInstall = <T, E extends Record<string, any>>(
main: T,
extra?: E
) => {
// 将组件注册到应用程序中
;(main as SFCWithInstall<T>).install = (app: App) => {
for (const comp of [
main,
...Object.values(isEmptyVariableInDefault<E>(extra, {})),
]) {
app.component(comp.name, comp)
}
}
// 为组件添加额外的属性
if (extra) {
for (const [key, comp] of Object.entries(extra)) {
;(main as any)[key] = comp
}
}
return main as SFCWithInstall<T> & E
}
// 将 fn 包装成一个带有 install 方法的 Vue 3 插件,并返回包装后的插件函数
export const withInstallFunction = <T>(fn: T, name: string) => {
;(fn as SFCWithInstall<T>).install = (app: App) => {
;(fn as SFCInstallWithContext<T>)._content = app._context
app.config.globalProperties[name] = fn
}
return fn as SFCInstallWithContext<T>
}
// 注册指令
export const withInstallDirective = <T extends Directive>(
directive: T,
name: string
) => {
;(directive as SFCWithInstall<T>).install = (app: App) => {
app.directive(name, directive)
}
}
// 返回一个新的组件对象,这个组件对象具有一个空的 install 方法
export const withNoopInstall = <T>(component: T) => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
;(component as SFCWithInstall<T>).install = () => {}
return component as SFCWithInstall<T>
}
+3
View File
@@ -0,0 +1,3 @@
export * from './util'
export * from './types'
export * from './runtime'
+124
View File
@@ -0,0 +1,124 @@
/* eslint-disable eslint-comments/no-unlimited-disable */
import { warn } from 'vue'
import { fromPairs } from '../../../libs/lodash'
import { isObject } from '../../types'
import { hasOwn } from '../../objects'
import type { PropType } from 'vue'
import type {
IfNativePropType,
IfTnProp,
NativePropType,
TnProp,
TnPropConvert,
TnPropFinalized,
TnPropInput,
TnPropMergeType,
} from './types'
export const tnPropKey = '__tnPropKey'
export const definePropType = <T>(val: any): PropType<T> => val
export const isTnProp = (val: unknown): val is TnProp<any, any, any> =>
isObject(val) && !!(val as any)[tnPropKey]
/**
* 生成 prop,能更好地优化类型
* @example
// limited options
// the type will be PropType<'light' | 'dark'>
buildProp({
type: String,
values: ['light', 'dark'],
} as const)
* @example
// limited options and other types
// the type will be PropType<'small' | 'large' | number>
buildProp({
type: [String, Number],
values: ['small', 'large'],
validator: (val: unknown): val is number => typeof val === 'number',
} as const)
*/
// eslint-disable-next-line eslint-comments/no-duplicate-disable
// eslint-disable-next-line eslint-comments/no-unlimited-disable
/* eslint-disable */
export const buildProp = <
Type = never,
Value = never,
Validator = never,
Default extends TnPropMergeType<Type, Value, Validator> = never,
Required extends boolean = false
>(
prop: TnPropInput<Type, Value, Validator, Default, Required>,
key?: string
): TnPropFinalized<Type, Value, Validator, Default, Required> => {
if (!isObject(prop) || isTnProp(prop)) return prop as any
const { values, required, default: defaultValue, type, validator } = prop
const _validator =
values || validator
? (val: unknown) => {
let valid = false
let allowedValues: unknown[] = []
if (values) {
allowedValues = Array.from(values)
if (hasOwn(prop, 'default')) {
allowedValues.push(defaultValue)
}
valid ||= allowedValues.includes(val)
}
if (validator) valid ||= validator(val)
if (!valid && allowedValues.length > 0) {
const allowValuesText = [...new Set(allowedValues)]
.map((value) => JSON.stringify(value))
.join(', ')
warn(
`Invalid prop: validation failed${
key ? ` for prop "${key}"` : ''
}. Expected one of [${allowValuesText}], got value ${JSON.stringify(
val
)}.`
)
}
return valid
}
: undefined
const tnProp: any = {
type,
required: !!required,
validator: _validator,
[tnPropKey]: true,
}
if (hasOwn(prop, 'default')) tnProp.default = defaultValue
return tnProp
}
export const buildProps = <
Props extends Record<
string,
| { [tnPropKey]: true }
| NativePropType
| TnPropInput<any, any, any, any, any>
>
>(
props: Props
): {
[K in keyof Props]: IfTnProp<
Props[K],
Props[K],
IfNativePropType<Props[K], Props[K], TnPropConvert<Props[K]>>
>
} =>
fromPairs(
Object.entries(props).map(([key, option]) => [
key,
buildProp(option as any, key),
])
) as any
/* eslint-enable */
+133
View File
@@ -0,0 +1,133 @@
import type { ExtractPropTypes, PropType } from 'vue'
import type { tnPropKey } from './runtime'
import type { IfNever, UnknowToNever, WriteableArray } from './util'
type Value<T> = T[keyof T]
/**
* 提取单个 prop 的参数类型
*
* @example
* ExtractPropType<{ type: StringConstructor }> => string | undefined
* ExtractPropType<{ type: StringConstructor, required: true }> => string
* ExtractPropType<{ type: BooleanConstructor }> => boolean
*/
export type ExtractPropType<T extends object> = Value<
ExtractPropTypes<{ key: T }>
>
/**
* 通过 `ExtractPropTypes` 提取类型,接受 `PropType<T>`、`XXXConstructor`、`never`...
*
* @example
* ResolvePropType<BooleanConstructor> => boolean
* ResolvePropType<PropType<T>> => T
*/
export type ResolvePropType<T> = IfNever<
T,
never,
ExtractPropType<{
type: WriteableArray<T>
required: true
}>
>
/**
* 合并 Type、Value、Validator 的类型
*
* @example
* EpPropMergeType<StringConstructor, '1', 1> => 1 | "1" // ignores StringConstructor
* EpPropMergeType<StringConstructor, never, number> => string | number
*/
export type TnPropMergeType<Type, Value, Validator> =
| IfNever<UnknowToNever<Value>, ResolvePropType<Type>, never>
| UnknowToNever<Value>
| UnknowToNever<Validator>
/**
* 处理输入参数的默认值(约束)
*/
export type TnPropInputDefault<
Required extends boolean,
Default
> = Required extends true
? never
: Default extends Record<string, unknown> | Array<any>
? () => Default
: (() => Default) | Default
/**
* 原生 prop `类型,BooleanConstructor`、`StringConstructor`、`null`、`undefined` 等
*/
export type NativePropType =
| ((...args: any) => any)
| { new (...args: any): any }
| undefined
| null
export type IfNativePropType<T, Y, N> = [T] extends [NativePropType] ? Y : N
/**
* prop 输入参数(约束)
*
* @example
* EpPropInput<StringConstructor, 'a', never, never, true>
* {
type?: StringConstructor | undefined;
required?: true | undefined;
values?: readonly "a"[] | undefined;
validator?: ((val: any) => boolean) | ((val: any) => val is never) | undefined;
default?: undefined;
}
*/
export type TnPropInput<
Type,
Value,
Validator,
Default extends TnPropMergeType<Type, Value, Validator>,
Required extends boolean
> = {
type?: Type
required?: Required
values?: readonly Value[]
validator?: ((val: any) => val is Validator) | ((val: any) => boolean)
default?: TnPropInputDefault<Required, Default>
}
/**
* prop 输出参数(约束)
*
* @example
* EpProp<'a', 'b', true>
* {
readonly type: PropType<"a">;
readonly required: true;
readonly validator: ((val: unknown) => boolean) | undefined;
readonly default: "b";
__epPropKey: true;
}
*/
export type TnProp<Type, Default, Required> = {
readonly type: PropType<Type>
readonly required: [Required] extends [true] ? true : false
readonly validator: ((val: unknown) => boolean) | undefined
[tnPropKey]: true
} & IfNever<Default, unknown, { readonly default: Default }>
export type IfTnProp<T, Y, N> = T extends { [tnPropKey]: true } ? Y : N
export type TnPropConvert<Input> = Input extends TnPropInput<
infer Type,
infer Value,
infer Validator,
any,
infer Required
>
? TnPropFinalized<Type, Value, Validator, Input['default'], Required>
: never
export type TnPropFinalized<Type, Value, Validator, Default, Required> = TnProp<
TnPropMergeType<Type, Value, Validator>,
UnknowToNever<Default>,
Required
>
export {}
+10
View File
@@ -0,0 +1,10 @@
export type Writable<T> = { -readonly [P in keyof T]: T[P] }
export type WriteableArray<T> = T extends readonly any[] ? Writable<T> : T
export type IfNever<T, Y = true, N = false> = [T] extends [never] ? Y : N
export type IfUnknown<T, Y, N> = [unknown] extends [T] ? Y : N
export type UnknowToNever<T> = IfUnknown<T, never, T>
export {}
+9
View File
@@ -0,0 +1,9 @@
import type { AppContext, Plugin, Ref } from 'vue'
export type SFCWithInstall<T> = T & Plugin
export type SFCInstallWithContext<T> = SFCWithInstall<T> & {
_content: AppContext | null
}
export type MaybeRef<T> = T | Ref<T>