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.
@@ -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
- globalConfig = cloneDeep(stringToObject(globalConfig, { addBase: true }));
19
- propsConfig = cloneDeep(stringToObject(propsConfig, { addBase: true }));
78
+ const globalObj = stringToObject(globalConfig, true);
79
+ const propsObj = stringToObject(propsConfig, true);
20
80
 
21
- const isGlobalConfig = Object.keys(globalConfig).length;
22
- const isPropsConfig = Object.keys(propsConfig).length;
81
+ const isGlobalConfig = hasOwnKeys(globalObj);
82
+ const isPropsConfig = hasOwnKeys(propsObj);
23
83
 
24
- // Add unique keys from defaultConfig to composedConfig
25
- const composedConfig = cloneDeep(stringToObject(defaultConfig, { addBase: true }));
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
- // Add unique keys from globalConfig to composedConfig
28
- for (const key in globalConfig) {
29
- if (!Object.keys(composedConfig).includes(key)) {
30
- composedConfig[key] = globalConfig[key];
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 to composedConfig
35
- for (const key in propsConfig) {
36
- if (!Object.keys(composedConfig).includes(key)) {
37
- composedConfig[key] = propsConfig[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 (isGlobalConfig || isPropsConfig) {
46
- if (key === colors) {
47
- if (propsConfig[key]) {
48
- // eslint-disable-next-line no-console
49
- console.warn(`Passing '${key}' key in 'config' prop is not allowed.`);
50
- }
51
- } else if (key === unstyled) {
52
- config[key] = propsConfig[key] || globalConfig[key] || defaultConfig[key];
53
- } else if (key === defaults || key === defaultVariants) {
54
- config[key] = {
55
- ...defaultConfig[key],
56
- ...globalConfig[key],
57
- ...propsConfig[key],
58
- };
59
- } else if (key === compoundVariants) {
60
- config[key] = mergeCompoundVariants({
61
- defaultConfig,
62
- globalConfig,
63
- propsConfig,
64
- });
65
- } else {
66
- const isObjectComposedConfig = typeof composedConfig[key] === "object";
67
- const isObjectGlobalConfig = typeof globalConfig[key] === "object";
68
- const isObjectPropsConfig = typeof propsConfig[key] === "object";
69
-
70
- const isObject = isObjectComposedConfig || isObjectGlobalConfig || isObjectPropsConfig;
71
- const isEmpty = composedConfig[key] === null;
72
- const isI18n = key === i18n;
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
- if (key === "variants" && !isVariants) {
75
- isVariants = true;
76
- }
143
+ let mergedKey = "";
77
144
 
78
- let mergedKey = "";
79
-
80
- if (isObject && !isEmpty && !isI18n) {
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
- config[key] = mergedKey;
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
- } else {
97
- config[key] = composedConfig[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
- const hasConfigItemKeys = Object.keys(defaultConfigItem)
127
- .map((key) => defaultConfigItem[key] === configItem[key] || key === "class")
128
- .every((item) => Boolean(item));
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 hasDefaultConfigItemKeys = Object.keys(configItem)
131
- .map((key) => defaultConfigItem[key] === configItem[key] || key === "class")
132
- .every((item) => Boolean(item));
212
+ const configKeys = Object.keys(configItem);
133
213
 
134
- return hasConfigItemKeys && hasDefaultConfigItemKeys;
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
- * Find the same compound variant item in custom config if existed.
139
- */
140
- function findItem(config = []) {
141
- config = cloneDeep(config);
223
+ let globalConfigItem;
224
+ let propsConfigItem;
142
225
 
143
- const globalConfigSimilarItemIndex = globalCompoundVariants.findIndex(isSameItem);
144
- const propsConfigSimilarItemIndex = propsCompoundVariants.findIndex(isSameItem);
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
- if (~globalConfigSimilarItemIndex) {
147
- config.push(globalCompoundVariants[globalConfigSimilarItemIndex]);
148
- globalCompoundVariants.splice(globalConfigSimilarItemIndex, 1);
232
+ break;
149
233
  }
234
+ }
150
235
 
151
- if (~propsConfigSimilarItemIndex) {
152
- config.push(propsCompoundVariants[propsConfigSimilarItemIndex]);
153
- propsCompoundVariants.splice(propsConfigSimilarItemIndex, 1);
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
- return config.find(isSameItem);
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
- return [...(config || []), ...globalCompoundVariants, ...propsCompoundVariants];
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
- compoundVariants = cloneDeep(compoundVariants || []);
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
- const keysWithArray = Object.keys(compoundVariant).filter((key) =>
181
- Array.isArray(compoundVariant[key]),
182
- );
278
+ let firstArrayKey;
279
+
280
+ for (const key in compoundVariant) {
281
+ if (Array.isArray(compoundVariant[key])) {
282
+ firstArrayKey = key;
183
283
 
184
- if (!keysWithArray.length) {
185
- return [compoundVariant];
284
+ break;
285
+ }
186
286
  }
187
287
 
188
- const [firstKey] = keysWithArray;
189
- const expandedArray = compoundVariant[firstKey].map((value) => ({
190
- ...compoundVariant,
191
- [firstKey]: value,
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
- // Recursively expand the remaining array keys
195
- return expandedArray.flatMap((expandedCompoundVariant) => expand(expandedCompoundVariant));
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 compoundVariants.flatMap(expand);
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[i18n] ? { [i18n]: defaultConfig[i18n] } : {}),
220
- ...(defaultConfig[defaults] ? { [defaults]: defaultConfig[defaults] } : {}),
221
- [unstyled]: defaultConfig[unstyled],
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, { addBase = false }) {
235
- if (typeof value !== "object" && addBase) {
236
- return { base: value || "" };
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 typeof value === "object" ? value : addBase ? { base: value || "" } : {};
358
+ return value;
240
359
  }
@@ -6,4 +6,4 @@ export const getMergedConfig: ({ defaultConfig, globalConfig, propsConfig, unsty
6
6
  globalConfig: any;
7
7
  propsConfig: any;
8
8
  unstyled: any;
9
- }) => {};
9
+ }) => any;