vueless 1.3.9-beta.8 → 1.4.0
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/composables/useUI.ts +187 -155
- package/composables/useVirtualScroll.ts +100 -0
- package/package.json +2 -2
- package/types.ts +11 -0
- package/ui.button-link/ULink.vue +18 -2
- package/ui.data-table/UTable.vue +597 -198
- package/ui.data-table/UTableRow.vue +372 -168
- package/ui.data-table/config.ts +33 -5
- package/ui.data-table/storybook/stories.ts +163 -0
- package/ui.data-table/tests/UTable.test.ts +456 -20
- package/ui.data-table/tests/UTableRow.test.ts +35 -104
- package/ui.data-table/types.ts +57 -0
- package/ui.data-table/utilTable.ts +16 -10
- package/ui.form-checkbox/UCheckbox.vue +3 -7
- package/ui.text-notify/config.ts +1 -1
- package/ui.text-number/UNumber.vue +36 -2
- package/ui.text-number/config.ts +1 -0
- package/ui.text-number/storybook/stories.ts +11 -0
- package/ui.text-number/tests/UNumber.test.ts +90 -0
- package/ui.text-number/types.ts +5 -0
- package/utils/node/mergeConfigs.d.ts +2 -2
- package/utils/node/mergeConfigs.js +240 -121
- package/utils/node/vuelessConfig.d.ts +1 -1
|
@@ -1,7 +1,67 @@
|
|
|
1
|
-
import { cloneDeep } from "lodash-es";
|
|
2
|
-
|
|
3
1
|
import { SYSTEM_CONFIG_KEY } from "../../constants.js";
|
|
4
2
|
|
|
3
|
+
const {
|
|
4
|
+
i18n: I18N,
|
|
5
|
+
defaults: DEFAULTS,
|
|
6
|
+
unstyled: UNSTYLED,
|
|
7
|
+
colors: COLORS,
|
|
8
|
+
defaultVariants: DEFAULT_VARIANTS,
|
|
9
|
+
compoundVariants: COMPOUND_VARIANTS,
|
|
10
|
+
} = SYSTEM_CONFIG_KEY;
|
|
11
|
+
|
|
12
|
+
const EMPTY_OBJECT = Object.freeze({});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Shallow clone a plain object (one level deep).
|
|
16
|
+
* Avoids the overhead of lodash cloneDeep for flat config objects.
|
|
17
|
+
*/
|
|
18
|
+
function shallowClone(object) {
|
|
19
|
+
if (!object || typeof object !== "object") return {};
|
|
20
|
+
|
|
21
|
+
return Object.assign({}, object);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Deep clone plain objects and arrays recursively.
|
|
26
|
+
* Handles only primitives, plain objects, and arrays (sufficient for config data).
|
|
27
|
+
*/
|
|
28
|
+
function deepClone(source) {
|
|
29
|
+
if (source === null || typeof source !== "object") return source;
|
|
30
|
+
|
|
31
|
+
if (Array.isArray(source)) {
|
|
32
|
+
const result = new Array(source.length);
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < source.length; i++) {
|
|
35
|
+
result[i] = deepClone(source[i]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = {};
|
|
42
|
+
|
|
43
|
+
for (const key in source) {
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
45
|
+
result[key] = deepClone(source[key]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if a plain object has own keys (avoids Object.keys allocation).
|
|
54
|
+
*/
|
|
55
|
+
function hasOwnKeys(object) {
|
|
56
|
+
if (!object || typeof object !== "object") return false;
|
|
57
|
+
|
|
58
|
+
for (const _ in object) {
|
|
59
|
+
if (Object.prototype.hasOwnProperty.call(object, _)) return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
5
65
|
export function createMergeConfigs(cx) {
|
|
6
66
|
/**
|
|
7
67
|
* Recursively merge config objects with removing tailwind classes duplicates.
|
|
@@ -15,86 +75,91 @@ export function createMergeConfigs(cx) {
|
|
|
15
75
|
config = {},
|
|
16
76
|
isVariants = false,
|
|
17
77
|
}) {
|
|
18
|
-
|
|
19
|
-
|
|
78
|
+
const globalObj = stringToObject(globalConfig, true);
|
|
79
|
+
const propsObj = stringToObject(propsConfig, true);
|
|
20
80
|
|
|
21
|
-
const isGlobalConfig =
|
|
22
|
-
const isPropsConfig =
|
|
81
|
+
const isGlobalConfig = hasOwnKeys(globalObj);
|
|
82
|
+
const isPropsConfig = hasOwnKeys(propsObj);
|
|
23
83
|
|
|
24
|
-
//
|
|
25
|
-
|
|
84
|
+
// Early return: no overrides, just return a shallow clone of the default
|
|
85
|
+
if (!isGlobalConfig && !isPropsConfig) {
|
|
86
|
+
return shallowClone(stringToObject(defaultConfig, true));
|
|
87
|
+
}
|
|
26
88
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
89
|
+
// Build composedConfig with all unique keys
|
|
90
|
+
const defaultObj = stringToObject(defaultConfig, true);
|
|
91
|
+
const composedConfig = Object.assign({}, defaultObj);
|
|
92
|
+
|
|
93
|
+
// Add unique keys from globalConfig
|
|
94
|
+
for (const key in globalObj) {
|
|
95
|
+
if (!(key in composedConfig)) {
|
|
96
|
+
composedConfig[key] = globalObj[key];
|
|
31
97
|
}
|
|
32
98
|
}
|
|
33
99
|
|
|
34
|
-
// Add unique keys from propsConfig
|
|
35
|
-
for (const key in
|
|
36
|
-
if (!
|
|
37
|
-
composedConfig[key] =
|
|
100
|
+
// Add unique keys from propsConfig
|
|
101
|
+
for (const key in propsObj) {
|
|
102
|
+
if (!(key in composedConfig)) {
|
|
103
|
+
composedConfig[key] = propsObj[key];
|
|
38
104
|
}
|
|
39
105
|
}
|
|
40
106
|
|
|
41
|
-
const { i18n, defaults, unstyled, colors, defaultVariants, compoundVariants } =
|
|
42
|
-
SYSTEM_CONFIG_KEY;
|
|
43
|
-
|
|
44
107
|
for (const key in composedConfig) {
|
|
45
|
-
if (
|
|
46
|
-
if (key
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
108
|
+
if (key === COLORS) {
|
|
109
|
+
if (propsObj[key]) {
|
|
110
|
+
// eslint-disable-next-line no-console
|
|
111
|
+
console.warn(`Passing '${key}' key in 'config' prop is not allowed.`);
|
|
112
|
+
}
|
|
113
|
+
} else if (key === UNSTYLED) {
|
|
114
|
+
config[key] = propsObj[key] || globalObj[key] || defaultObj[key];
|
|
115
|
+
} else if (key === DEFAULTS || key === DEFAULT_VARIANTS) {
|
|
116
|
+
config[key] = {
|
|
117
|
+
...defaultObj[key],
|
|
118
|
+
...globalObj[key],
|
|
119
|
+
...propsObj[key],
|
|
120
|
+
};
|
|
121
|
+
} else if (key === COMPOUND_VARIANTS) {
|
|
122
|
+
config[key] = mergeCompoundVariants({
|
|
123
|
+
defaultConfig: defaultObj,
|
|
124
|
+
globalConfig: globalObj,
|
|
125
|
+
propsConfig: propsObj,
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
const composedValue = composedConfig[key];
|
|
129
|
+
const globalValue = globalObj[key];
|
|
130
|
+
const propsValue = propsObj[key];
|
|
131
|
+
|
|
132
|
+
const isObject =
|
|
133
|
+
(composedValue !== null && typeof composedValue === "object") ||
|
|
134
|
+
(globalValue !== undefined && typeof globalValue === "object") ||
|
|
135
|
+
(propsValue !== undefined && typeof propsValue === "object");
|
|
136
|
+
const isEmpty = composedValue === null;
|
|
137
|
+
const isI18n = key === I18N;
|
|
138
|
+
|
|
139
|
+
if (key === "variants" && !isVariants) {
|
|
140
|
+
isVariants = true;
|
|
141
|
+
}
|
|
73
142
|
|
|
74
|
-
|
|
75
|
-
isVariants = true;
|
|
76
|
-
}
|
|
143
|
+
let mergedKey = "";
|
|
77
144
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
mergedKey = mergeConfigs({
|
|
82
|
-
defaultConfig: stringToObject(composedConfig[key], { addBase: !isVariants }),
|
|
83
|
-
globalConfig: stringToObject(globalConfig[key], { addBase: !isVariants }),
|
|
84
|
-
propsConfig: stringToObject(propsConfig[key], { addBase: !isVariants }),
|
|
85
|
-
config: stringToObject(composedConfig[key], { addBase: !isVariants }),
|
|
86
|
-
isVariants,
|
|
87
|
-
});
|
|
88
|
-
} else if (isI18n) {
|
|
89
|
-
mergedKey = propsConfig[key] || globalConfig[key] || defaultConfig[key];
|
|
90
|
-
} else {
|
|
91
|
-
mergedKey = cx([defaultConfig[key], globalConfig[key], propsConfig[key]]);
|
|
92
|
-
}
|
|
145
|
+
if (isObject && !isEmpty && !isI18n) {
|
|
146
|
+
const addBase = !isVariants;
|
|
147
|
+
const defaultNested = stringToObject(composedValue, addBase);
|
|
93
148
|
|
|
94
|
-
|
|
149
|
+
mergedKey = mergeConfigs({
|
|
150
|
+
defaultConfig: defaultNested,
|
|
151
|
+
globalConfig: stringToObject(globalValue, addBase),
|
|
152
|
+
propsConfig: stringToObject(propsValue, addBase),
|
|
153
|
+
config: shallowClone(defaultNested),
|
|
154
|
+
isVariants,
|
|
155
|
+
});
|
|
156
|
+
} else if (isI18n) {
|
|
157
|
+
mergedKey = propsValue || globalValue || defaultObj[key];
|
|
158
|
+
} else {
|
|
159
|
+
mergedKey = cx([defaultObj[key], globalValue, propsValue]);
|
|
95
160
|
}
|
|
96
|
-
|
|
97
|
-
config[key] =
|
|
161
|
+
|
|
162
|
+
config[key] = mergedKey;
|
|
98
163
|
}
|
|
99
164
|
}
|
|
100
165
|
|
|
@@ -114,51 +179,70 @@ export function createMergeConfigs(cx) {
|
|
|
114
179
|
console.error("CompoundVariants should be an array.");
|
|
115
180
|
}
|
|
116
181
|
|
|
182
|
+
// Early return: no compound variants at all
|
|
183
|
+
if (
|
|
184
|
+
!defaultConfig.compoundVariants &&
|
|
185
|
+
!globalConfig.compoundVariants &&
|
|
186
|
+
!propsConfig.compoundVariants
|
|
187
|
+
) {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
|
|
117
191
|
const defaultCompoundVariants = expandCompoundVariants(defaultConfig.compoundVariants);
|
|
118
192
|
const globalCompoundVariants = expandCompoundVariants(globalConfig.compoundVariants);
|
|
119
193
|
const propsCompoundVariants = expandCompoundVariants(propsConfig.compoundVariants);
|
|
120
194
|
|
|
195
|
+
// Track consumed indices via Sets instead of splicing arrays (avoids O(n) shifts)
|
|
196
|
+
const consumedGlobalIndices = new Set();
|
|
197
|
+
const consumedPropsIndices = new Set();
|
|
198
|
+
|
|
121
199
|
const config = defaultCompoundVariants?.map((defaultConfigItem) => {
|
|
200
|
+
const defaultKeys = Object.keys(defaultConfigItem);
|
|
201
|
+
|
|
122
202
|
/**
|
|
123
|
-
* Compare two objects by keys for match.
|
|
203
|
+
* Compare two objects by keys for match (avoids .map().every() — uses plain loop).
|
|
124
204
|
*/
|
|
125
205
|
function isSameItem(configItem) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
206
|
+
for (let i = 0; i < defaultKeys.length; i++) {
|
|
207
|
+
const key = defaultKeys[i];
|
|
208
|
+
|
|
209
|
+
if (key !== "class" && defaultConfigItem[key] !== configItem[key]) return false;
|
|
210
|
+
}
|
|
129
211
|
|
|
130
|
-
const
|
|
131
|
-
.map((key) => defaultConfigItem[key] === configItem[key] || key === "class")
|
|
132
|
-
.every((item) => Boolean(item));
|
|
212
|
+
const configKeys = Object.keys(configItem);
|
|
133
213
|
|
|
134
|
-
|
|
214
|
+
for (let i = 0; i < configKeys.length; i++) {
|
|
215
|
+
const key = configKeys[i];
|
|
216
|
+
|
|
217
|
+
if (key !== "class" && defaultConfigItem[key] !== configItem[key]) return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return true;
|
|
135
221
|
}
|
|
136
222
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
*/
|
|
140
|
-
function findItem(config = []) {
|
|
141
|
-
config = cloneDeep(config);
|
|
223
|
+
let globalConfigItem;
|
|
224
|
+
let propsConfigItem;
|
|
142
225
|
|
|
143
|
-
|
|
144
|
-
|
|
226
|
+
// Find matching global compound variant (skip already consumed)
|
|
227
|
+
for (let i = 0; i < globalCompoundVariants.length; i++) {
|
|
228
|
+
if (!consumedGlobalIndices.has(i) && isSameItem(globalCompoundVariants[i])) {
|
|
229
|
+
globalConfigItem = globalCompoundVariants[i];
|
|
230
|
+
consumedGlobalIndices.add(i);
|
|
145
231
|
|
|
146
|
-
|
|
147
|
-
config.push(globalCompoundVariants[globalConfigSimilarItemIndex]);
|
|
148
|
-
globalCompoundVariants.splice(globalConfigSimilarItemIndex, 1);
|
|
232
|
+
break;
|
|
149
233
|
}
|
|
234
|
+
}
|
|
150
235
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
236
|
+
// Find matching props compound variant (skip already consumed)
|
|
237
|
+
for (let i = 0; i < propsCompoundVariants.length; i++) {
|
|
238
|
+
if (!consumedPropsIndices.has(i) && isSameItem(propsCompoundVariants[i])) {
|
|
239
|
+
propsConfigItem = propsCompoundVariants[i];
|
|
240
|
+
consumedPropsIndices.add(i);
|
|
155
241
|
|
|
156
|
-
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
157
244
|
}
|
|
158
245
|
|
|
159
|
-
const globalConfigItem = findItem(globalCompoundVariants);
|
|
160
|
-
const propsConfigItem = findItem(propsCompoundVariants);
|
|
161
|
-
|
|
162
246
|
return globalConfigItem || propsConfigItem
|
|
163
247
|
? {
|
|
164
248
|
...defaultConfigItem,
|
|
@@ -167,35 +251,68 @@ export function createMergeConfigs(cx) {
|
|
|
167
251
|
: defaultConfigItem;
|
|
168
252
|
});
|
|
169
253
|
|
|
170
|
-
|
|
254
|
+
// Collect unconsumed global and props variants (avoids spread of spliced arrays)
|
|
255
|
+
const remaining = [];
|
|
256
|
+
|
|
257
|
+
for (let i = 0; i < globalCompoundVariants.length; i++) {
|
|
258
|
+
if (!consumedGlobalIndices.has(i)) remaining.push(globalCompoundVariants[i]);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
for (let i = 0; i < propsCompoundVariants.length; i++) {
|
|
262
|
+
if (!consumedPropsIndices.has(i)) remaining.push(propsCompoundVariants[i]);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return config && config.length ? config.concat(remaining) : remaining;
|
|
171
266
|
}
|
|
172
267
|
|
|
173
268
|
/**
|
|
174
269
|
* Convert compound variants with arrays in values into compound variants with primitives.
|
|
175
270
|
*/
|
|
176
271
|
function expandCompoundVariants(compoundVariants) {
|
|
177
|
-
|
|
272
|
+
if (!compoundVariants || !compoundVariants.length) return [];
|
|
273
|
+
|
|
274
|
+
// Deep clone only once at the top level
|
|
275
|
+
const cloned = deepClone(compoundVariants);
|
|
178
276
|
|
|
179
277
|
function expand(compoundVariant) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
)
|
|
278
|
+
let firstArrayKey;
|
|
279
|
+
|
|
280
|
+
for (const key in compoundVariant) {
|
|
281
|
+
if (Array.isArray(compoundVariant[key])) {
|
|
282
|
+
firstArrayKey = key;
|
|
183
283
|
|
|
184
|
-
|
|
185
|
-
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
186
286
|
}
|
|
187
287
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
288
|
+
if (!firstArrayKey) return [compoundVariant];
|
|
289
|
+
|
|
290
|
+
const values = compoundVariant[firstArrayKey];
|
|
291
|
+
const result = [];
|
|
292
|
+
|
|
293
|
+
for (let i = 0; i < values.length; i++) {
|
|
294
|
+
const expanded = Object.assign({}, compoundVariant, { [firstArrayKey]: values[i] });
|
|
295
|
+
const subExpanded = expand(expanded);
|
|
193
296
|
|
|
194
|
-
|
|
195
|
-
|
|
297
|
+
for (let j = 0; j < subExpanded.length; j++) {
|
|
298
|
+
result.push(subExpanded[j]);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const result = [];
|
|
306
|
+
|
|
307
|
+
for (let i = 0; i < cloned.length; i++) {
|
|
308
|
+
const expanded = expand(cloned[i]);
|
|
309
|
+
|
|
310
|
+
for (let j = 0; j < expanded.length; j++) {
|
|
311
|
+
result.push(expanded[j]);
|
|
312
|
+
}
|
|
196
313
|
}
|
|
197
314
|
|
|
198
|
-
return
|
|
315
|
+
return result;
|
|
199
316
|
}
|
|
200
317
|
|
|
201
318
|
return mergeConfigs;
|
|
@@ -208,18 +325,16 @@ export function createGetMergedConfig(cx) {
|
|
|
208
325
|
* Get merged config based on config merging strategy.
|
|
209
326
|
*/
|
|
210
327
|
function getMergedConfig({ defaultConfig, globalConfig, propsConfig, unstyled }) {
|
|
211
|
-
defaultConfig = cloneDeep(defaultConfig);
|
|
212
|
-
|
|
213
328
|
const isUnstyled = propsConfig?.unstyled || globalConfig?.unstyled || unstyled;
|
|
214
329
|
|
|
215
330
|
if (isUnstyled) {
|
|
216
|
-
const { i18n, defaults, unstyled } = SYSTEM_CONFIG_KEY;
|
|
217
|
-
|
|
218
331
|
defaultConfig = {
|
|
219
|
-
...(defaultConfig[
|
|
220
|
-
...(defaultConfig[
|
|
221
|
-
[
|
|
332
|
+
...(defaultConfig[I18N] ? { [I18N]: defaultConfig[I18N] } : EMPTY_OBJECT),
|
|
333
|
+
...(defaultConfig[DEFAULTS] ? { [DEFAULTS]: defaultConfig[DEFAULTS] } : EMPTY_OBJECT),
|
|
334
|
+
[UNSTYLED]: defaultConfig[UNSTYLED],
|
|
222
335
|
};
|
|
336
|
+
} else {
|
|
337
|
+
defaultConfig = shallowClone(defaultConfig);
|
|
223
338
|
}
|
|
224
339
|
|
|
225
340
|
return mergeConfigs({ defaultConfig, globalConfig, propsConfig });
|
|
@@ -229,12 +344,16 @@ export function createGetMergedConfig(cx) {
|
|
|
229
344
|
}
|
|
230
345
|
|
|
231
346
|
/**
|
|
232
|
-
Turn simplified nested component config to regular config.
|
|
347
|
+
* Turn simplified nested component config to regular config.
|
|
233
348
|
*/
|
|
234
|
-
function stringToObject(value,
|
|
235
|
-
if (
|
|
236
|
-
return { base:
|
|
349
|
+
function stringToObject(value, addBase) {
|
|
350
|
+
if (value === undefined || value === null) {
|
|
351
|
+
return addBase ? { base: "" } : EMPTY_OBJECT;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (typeof value !== "object") {
|
|
355
|
+
return addBase ? { base: value || "" } : EMPTY_OBJECT;
|
|
237
356
|
}
|
|
238
357
|
|
|
239
|
-
return
|
|
358
|
+
return value;
|
|
240
359
|
}
|