vanilla-jui 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +39 -20
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/accordion.ts +6 -12
- package/src/components/flow.ts +17 -26
- package/src/components/form.ts +11 -28
- package/src/components/menu.ts +7 -13
- package/src/components/modal.ts +40 -26
- package/src/components/offcanvas.ts +6 -12
- package/src/components/pagination.ts +10 -24
- package/src/components/swiper.ts +7 -13
- package/src/components/tabs.ts +6 -12
- package/src/components/toc.ts +5 -8
- package/src/css/themes/default/menu.css +12 -6
- package/src/index.ts +4 -1
- package/src/primitives/drop.ts +5 -8
- package/src/primitives/parabola.ts +6 -12
- package/src/primitives/popup.ts +3 -3
- package/src/primitives/sticky.ts +3 -3
- package/src/primitives/theme.ts +29 -14
- package/src/primitives/toast.ts +17 -12
- package/src/primitives/tooltip.ts +5 -19
- package/src/utilities/config.ts +158 -0
- package/src/utilities/id.ts +121 -2
- package/src/utilities/merge.ts +97 -0
- package/src/utilities/types.ts +3 -82
- package/src/utilities/validator.ts +6 -17
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { isPlainObject } from './object.ts';
|
|
2
|
+
|
|
3
|
+
export type MergeStrategy =
|
|
4
|
+
| 'replace'
|
|
5
|
+
| 'shallow'
|
|
6
|
+
| 'deep'
|
|
7
|
+
| ((
|
|
8
|
+
defaultValue: unknown,
|
|
9
|
+
inputValue: unknown,
|
|
10
|
+
context: MergeContext
|
|
11
|
+
) => unknown);
|
|
12
|
+
|
|
13
|
+
export interface MergeContext {
|
|
14
|
+
key: string;
|
|
15
|
+
path: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type LooseRecord = Record<string, unknown>;
|
|
19
|
+
|
|
20
|
+
const UNSAFE_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
|
|
21
|
+
|
|
22
|
+
function isSafeKey(key: string): boolean {
|
|
23
|
+
return !UNSAFE_KEYS.has(key);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function cloneConfigValue<T>(value: T): T {
|
|
27
|
+
if (Array.isArray(value)) return value.map(cloneConfigValue) as T;
|
|
28
|
+
if (!isPlainObject(value)) return value;
|
|
29
|
+
|
|
30
|
+
const result: LooseRecord = {};
|
|
31
|
+
for (const [key, child] of Object.entries(value as LooseRecord)) {
|
|
32
|
+
if (!isSafeKey(key)) continue;
|
|
33
|
+
result[key] = cloneConfigValue(child);
|
|
34
|
+
}
|
|
35
|
+
return result as T;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function mergeShallowConfig(
|
|
39
|
+
defaultValue: unknown,
|
|
40
|
+
inputValue: unknown
|
|
41
|
+
): unknown {
|
|
42
|
+
if (!isPlainObject(defaultValue) || !isPlainObject(inputValue)) {
|
|
43
|
+
return cloneConfigValue(inputValue);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const result = cloneConfigValue(defaultValue) as LooseRecord;
|
|
47
|
+
for (const [key, value] of Object.entries(inputValue as LooseRecord)) {
|
|
48
|
+
if (!isSafeKey(key)) continue;
|
|
49
|
+
result[key] = cloneConfigValue(value);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function mergeDeepConfig(
|
|
55
|
+
defaultValue: unknown,
|
|
56
|
+
inputValue: unknown
|
|
57
|
+
): unknown {
|
|
58
|
+
if (!isPlainObject(defaultValue) || !isPlainObject(inputValue)) {
|
|
59
|
+
return cloneConfigValue(inputValue);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const result = cloneConfigValue(defaultValue) as LooseRecord;
|
|
63
|
+
for (const [key, value] of Object.entries(inputValue as LooseRecord)) {
|
|
64
|
+
if (!isSafeKey(key)) continue;
|
|
65
|
+
const current = result[key];
|
|
66
|
+
result[key] =
|
|
67
|
+
isPlainObject(current) && isPlainObject(value)
|
|
68
|
+
? mergeDeepConfig(current, value)
|
|
69
|
+
: cloneConfigValue(value);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function mergeConfigValue(
|
|
75
|
+
defaultValue: unknown,
|
|
76
|
+
inputValue: unknown,
|
|
77
|
+
strategy: MergeStrategy | undefined,
|
|
78
|
+
context: MergeContext
|
|
79
|
+
): unknown {
|
|
80
|
+
if (typeof strategy === 'function') {
|
|
81
|
+
return strategy(
|
|
82
|
+
cloneConfigValue(defaultValue),
|
|
83
|
+
cloneConfigValue(inputValue),
|
|
84
|
+
context
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (strategy === 'shallow') {
|
|
89
|
+
return mergeShallowConfig(defaultValue, inputValue);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (strategy === 'deep') {
|
|
93
|
+
return mergeDeepConfig(defaultValue, inputValue);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return cloneConfigValue(inputValue);
|
|
97
|
+
}
|
package/src/utilities/types.ts
CHANGED
|
@@ -55,14 +55,7 @@ export type ValidateCondition =
|
|
|
55
55
|
message?: string;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
export interface
|
|
59
|
-
key: string;
|
|
60
|
-
input: TInput;
|
|
61
|
-
options: LooseRecord;
|
|
62
|
-
schema: ResolveSchema<TInput>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface ParamRule<TInput extends LooseRecord = LooseRecord> {
|
|
58
|
+
export interface ParamRule<_TInput extends LooseRecord = LooseRecord> {
|
|
66
59
|
type?: TypeRule;
|
|
67
60
|
types?: TypeRule;
|
|
68
61
|
required?: boolean;
|
|
@@ -78,13 +71,11 @@ export interface ParamRule<TInput extends LooseRecord = LooseRecord> {
|
|
|
78
71
|
lessThan?: number;
|
|
79
72
|
plain?: boolean;
|
|
80
73
|
items?: ParamRuleInput;
|
|
81
|
-
shape?:
|
|
74
|
+
shape?: ParamShapeSchema;
|
|
82
75
|
conditions?: ValidateCondition | readonly ValidateCondition[];
|
|
83
76
|
validate?: (value: unknown) => boolean;
|
|
84
77
|
message?: string;
|
|
85
|
-
normalize?: (value: unknown, context: NormalizeContext<TInput>) => unknown;
|
|
86
78
|
default?: unknown;
|
|
87
|
-
factory?: boolean;
|
|
88
79
|
[key: string]: unknown;
|
|
89
80
|
}
|
|
90
81
|
|
|
@@ -92,21 +83,11 @@ export type ParamRuleInput<TInput extends LooseRecord = LooseRecord> =
|
|
|
92
83
|
| TypeRule
|
|
93
84
|
| ParamRule<TInput>;
|
|
94
85
|
|
|
95
|
-
export type
|
|
86
|
+
export type ParamShapeSchema<TInput extends LooseRecord = LooseRecord> = Record<
|
|
96
87
|
string,
|
|
97
88
|
ParamRuleInput<TInput>
|
|
98
89
|
>;
|
|
99
90
|
|
|
100
|
-
export type ResolvedProps<TSchema extends object> = LooseRecord & {
|
|
101
|
-
[Key in keyof TSchema]: unknown;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
function cloneDefault<T>(value: T): T {
|
|
105
|
-
if (Array.isArray(value)) return value.slice() as T;
|
|
106
|
-
if (isPlainObject(value)) return { ...(value as LooseRecord) } as T;
|
|
107
|
-
return value;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
91
|
function normalizeRule<TInput extends LooseRecord = LooseRecord>(
|
|
111
92
|
rule: ParamRuleInput<TInput> = {}
|
|
112
93
|
): ParamRule<TInput> {
|
|
@@ -332,66 +313,6 @@ export function validateParam<TInput extends LooseRecord = LooseRecord>(
|
|
|
332
313
|
return value;
|
|
333
314
|
}
|
|
334
315
|
|
|
335
|
-
export function resolveProps<
|
|
336
|
-
TInput extends LooseRecord,
|
|
337
|
-
TSchema extends ResolveSchema<TInput>,
|
|
338
|
-
>(
|
|
339
|
-
input: TInput | null | undefined = {} as TInput,
|
|
340
|
-
schema: TSchema = {} as TSchema,
|
|
341
|
-
namespace = 'Options'
|
|
342
|
-
): TInput & ResolvedProps<TSchema> {
|
|
343
|
-
const source = input == null ? {} : input;
|
|
344
|
-
if (typeof source !== 'object' || Array.isArray(source)) {
|
|
345
|
-
throw new Error(`${namespace} expects object.`);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const sourceRecord = source as TInput;
|
|
349
|
-
const resolved: LooseRecord = { ...sourceRecord };
|
|
350
|
-
const entries = Object.entries(schema || {}) as Array<
|
|
351
|
-
[string, ParamRuleInput<TInput>]
|
|
352
|
-
>;
|
|
353
|
-
|
|
354
|
-
for (const [key, rawRule] of entries) {
|
|
355
|
-
const rule = normalizeRule<TInput>(rawRule);
|
|
356
|
-
resolved[key] = Object.hasOwn(sourceRecord, key)
|
|
357
|
-
? sourceRecord[key]
|
|
358
|
-
: resolveDefault(rule);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
for (const [key, rawRule] of entries) {
|
|
362
|
-
const rule = normalizeRule<TInput>(rawRule);
|
|
363
|
-
if (typeof rule.normalize === 'function') {
|
|
364
|
-
resolved[key] = rule.normalize(resolved[key], {
|
|
365
|
-
key,
|
|
366
|
-
input: sourceRecord,
|
|
367
|
-
options: resolved,
|
|
368
|
-
schema,
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
for (const [key, rule] of entries) {
|
|
374
|
-
validateParam(key, resolved[key], rule, namespace);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return resolved as TInput & ResolvedProps<TSchema>;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
interface DefaultRule {
|
|
381
|
-
default?: unknown;
|
|
382
|
-
factory?: boolean;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function resolveDefault(rule: DefaultRule): unknown {
|
|
386
|
-
if (!Object.hasOwn(rule, 'default')) return undefined;
|
|
387
|
-
const defaultValue = rule.default;
|
|
388
|
-
const value =
|
|
389
|
-
rule.factory && typeof defaultValue === 'function'
|
|
390
|
-
? defaultValue()
|
|
391
|
-
: defaultValue;
|
|
392
|
-
return cloneDefault(value);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
316
|
/**
|
|
396
317
|
* 判断是否为普通可构造函数(排除箭头函数和类)。
|
|
397
318
|
* @param fn - 需要判断的值
|
|
@@ -7,12 +7,8 @@ import {
|
|
|
7
7
|
resolveElement,
|
|
8
8
|
} from '../utilities/dom.ts';
|
|
9
9
|
import { createEventManager } from '../utilities/events.ts';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
type ResolveSchema,
|
|
13
|
-
resolveProps,
|
|
14
|
-
validateParam,
|
|
15
|
-
} from '../utilities/types.ts';
|
|
10
|
+
import { type ConfigSchema, resolveConfig } from '../utilities/config.ts';
|
|
11
|
+
import { validateParam } from '../utilities/types.ts';
|
|
16
12
|
|
|
17
13
|
type ValidatorElement =
|
|
18
14
|
| HTMLInputElement
|
|
@@ -99,21 +95,14 @@ const VALIDATOR_PROPS_SCHEMA = {
|
|
|
99
95
|
vanilla: { default: false, type: 'boolean' },
|
|
100
96
|
className: {
|
|
101
97
|
default: DEFAULT_CLASS_NAMES,
|
|
102
|
-
type: '
|
|
103
|
-
|
|
98
|
+
type: 'plainObject',
|
|
99
|
+
merge: 'shallow',
|
|
104
100
|
},
|
|
105
101
|
onSubmit: { default: null, types: ['function', 'null'] },
|
|
106
|
-
} satisfies
|
|
107
|
-
|
|
108
|
-
function resolveClassNames(value: unknown): ValidatorClassNames {
|
|
109
|
-
return {
|
|
110
|
-
...DEFAULT_CLASS_NAMES,
|
|
111
|
-
...(isPlainObject(value) ? (value as ValidatorClassNameConfig) : {}),
|
|
112
|
-
} as ValidatorClassNames;
|
|
113
|
-
}
|
|
102
|
+
} satisfies ConfigSchema<ValidatorProps>;
|
|
114
103
|
|
|
115
104
|
function normalizeProps(input: ValidatorProps): ResolvedValidatorProps {
|
|
116
|
-
const props =
|
|
105
|
+
const props = resolveConfig(input, VALIDATOR_PROPS_SCHEMA, 'Validator.props');
|
|
117
106
|
return {
|
|
118
107
|
rules: props.rules as Record<string, ValidatorRule>,
|
|
119
108
|
messages: props.messages as ValidatorMessageMap,
|