funuicss 3.7.14 → 3.7.16
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/css/fun.css +665 -0
- package/index.d.ts +2 -0
- package/index.js +5 -1
- package/package.json +1 -1
- package/ui/feature/Feature.d.ts +130 -0
- package/ui/feature/Feature.js +380 -0
- package/ui/footer/Footer.d.ts +89 -0
- package/ui/footer/Footer.js +329 -0
- package/ui/icons/Dynamic.d.ts +12 -0
- package/ui/icons/Dynamic.js +163 -0
- package/ui/theme/theme.d.ts +1 -0
- package/ui/theme/theme.js +571 -23
- package/ui/vista/Vista.js +8 -12
- package/utils/componentUtils.d.ts +126 -19
- package/utils/componentUtils.js +994 -57
package/utils/componentUtils.js
CHANGED
|
@@ -10,8 +10,17 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
};
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
14
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
15
|
+
if (ar || !(i in from)) {
|
|
16
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
17
|
+
ar[i] = from[i];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
21
|
+
};
|
|
13
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.getAvailableVariants = exports.hasComponentVariant = exports.useComponentProps = exports.useComponentConfiguration = exports.mergeComponentConfig = exports.getComponentConfig = void 0;
|
|
23
|
+
exports.getVariableByName = exports.getAssetByName = exports.getUsedReferences = exports.needsInterpolation = exports.createAssetReference = exports.createVariableReference = exports.formatReferenceForDisplay = exports.isAssetReference = exports.isVariableReference = exports.useAssetUrl = exports.useAsset = exports.useVariable = exports.useValue = exports.getProjectAssets = exports.getProjectVariables = exports.getAvailableVariants = exports.hasComponentVariant = exports.useComponentProps = exports.useComponentConfiguration = exports.mergeComponentConfig = exports.getComponentConfig = void 0;
|
|
15
24
|
var theme_1 = require("../ui/theme/theme");
|
|
16
25
|
var react_1 = require("react");
|
|
17
26
|
/**
|
|
@@ -24,23 +33,144 @@ var isValidVariantName = function (variantName) {
|
|
|
24
33
|
* Filter out empty string and undefined values from component props
|
|
25
34
|
*/
|
|
26
35
|
var filterEmptyProps = function (props) {
|
|
36
|
+
if (!props)
|
|
37
|
+
return {};
|
|
27
38
|
var filtered = {};
|
|
28
39
|
for (var key in props) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
if (Object.prototype.hasOwnProperty.call(props, key)) {
|
|
41
|
+
var value = props[key];
|
|
42
|
+
// Only include props that are not undefined and not empty strings
|
|
43
|
+
if (value !== undefined && value !== '') {
|
|
44
|
+
filtered[key] = value;
|
|
45
|
+
}
|
|
33
46
|
}
|
|
34
47
|
}
|
|
35
48
|
return filtered;
|
|
36
49
|
};
|
|
37
50
|
/**
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
* Extract variable name from {{variable_name}} pattern
|
|
52
|
+
*/
|
|
53
|
+
var extractVariableName = function (value) {
|
|
54
|
+
if (typeof value !== 'string')
|
|
55
|
+
return null;
|
|
56
|
+
// Match exact {{variable}} pattern
|
|
57
|
+
var match = value.match(/^\{\{\s*([^}]+)\s*\}\}$/);
|
|
58
|
+
return match ? match[1].trim() : null;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Extract asset name from {{{asset_name}}} pattern
|
|
62
|
+
*/
|
|
63
|
+
var extractAssetName = function (value) {
|
|
64
|
+
if (typeof value !== 'string')
|
|
65
|
+
return null;
|
|
66
|
+
// Match exact {{{asset}}} pattern
|
|
67
|
+
var match = value.match(/^\{\{\{\s*([^}]+)\s*\}\}\}$/);
|
|
68
|
+
return match ? match[1].trim() : null;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Get variable value from project variables
|
|
72
|
+
*/
|
|
73
|
+
var getVariableValue = function (variableName, projectData) {
|
|
74
|
+
if (!(projectData === null || projectData === void 0 ? void 0 : projectData.variables) || !variableName)
|
|
75
|
+
return null;
|
|
76
|
+
var variable = projectData.variables.find(function (v) { return v.name === variableName; });
|
|
77
|
+
return (variable === null || variable === void 0 ? void 0 : variable.value) || null;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Get asset URL from project assets
|
|
81
|
+
*/
|
|
82
|
+
var getAssetUrl = function (assetName, projectData) {
|
|
83
|
+
if (!(projectData === null || projectData === void 0 ? void 0 : projectData.assets) || !assetName)
|
|
84
|
+
return null;
|
|
85
|
+
var asset = projectData.assets.find(function (a) { return a.name === assetName; });
|
|
86
|
+
return (asset === null || asset === void 0 ? void 0 : asset.url) || null;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Get asset by name
|
|
90
|
+
*/
|
|
91
|
+
var getAsset = function (assetName, projectData) {
|
|
92
|
+
if (!(projectData === null || projectData === void 0 ? void 0 : projectData.assets) || !assetName)
|
|
93
|
+
return null;
|
|
94
|
+
var asset = projectData.assets.find(function (a) { return a.name === assetName; });
|
|
95
|
+
return asset || null;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Interpolate values (variables and assets) in props
|
|
99
|
+
*/
|
|
100
|
+
var interpolateValues = function (props, projectData) {
|
|
101
|
+
if (!props || Object.keys(props).length === 0) {
|
|
102
|
+
return props || {};
|
|
103
|
+
}
|
|
104
|
+
var result = {};
|
|
105
|
+
// Create lookup maps for faster access
|
|
106
|
+
var variableMap = {};
|
|
107
|
+
var assetMap = {};
|
|
108
|
+
if (projectData === null || projectData === void 0 ? void 0 : projectData.variables) {
|
|
109
|
+
projectData.variables.forEach(function (variable) {
|
|
110
|
+
variableMap[variable.name] = variable.value;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (projectData === null || projectData === void 0 ? void 0 : projectData.assets) {
|
|
114
|
+
projectData.assets.forEach(function (asset) {
|
|
115
|
+
assetMap[asset.name] = asset.url;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
for (var key in props) {
|
|
119
|
+
if (!Object.prototype.hasOwnProperty.call(props, key))
|
|
120
|
+
continue;
|
|
121
|
+
var value = props[key];
|
|
122
|
+
// Handle strings with interpolation
|
|
123
|
+
if (typeof value === 'string') {
|
|
124
|
+
// Check for asset reference first ({{{asset}}})
|
|
125
|
+
var assetName = extractAssetName(value);
|
|
126
|
+
if (assetName && assetMap[assetName]) {
|
|
127
|
+
result[key] = assetMap[assetName];
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// Check for variable reference ({{variable}})
|
|
131
|
+
var variableName = extractVariableName(value);
|
|
132
|
+
if (variableName && variableMap[variableName]) {
|
|
133
|
+
result[key] = variableMap[variableName];
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
// No interpolation needed
|
|
137
|
+
result[key] = value;
|
|
138
|
+
}
|
|
139
|
+
// Handle arrays - process string elements only
|
|
140
|
+
else if (Array.isArray(value)) {
|
|
141
|
+
result[key] = value.map(function (item) {
|
|
142
|
+
if (typeof item === 'string') {
|
|
143
|
+
// Check for asset reference
|
|
144
|
+
var assetName = extractAssetName(item);
|
|
145
|
+
if (assetName && assetMap[assetName]) {
|
|
146
|
+
return assetMap[assetName];
|
|
147
|
+
}
|
|
148
|
+
// Check for variable reference
|
|
149
|
+
var variableName = extractVariableName(item);
|
|
150
|
+
if (variableName && variableMap[variableName]) {
|
|
151
|
+
return variableMap[variableName];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return item;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// Handle objects - create shallow copy (no deep interpolation)
|
|
158
|
+
else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
159
|
+
result[key] = __assign({}, value);
|
|
160
|
+
}
|
|
161
|
+
// Handle arrays that are objects - create shallow copy
|
|
162
|
+
else if (Array.isArray(value)) {
|
|
163
|
+
result[key] = __spreadArray([], value, true);
|
|
164
|
+
}
|
|
165
|
+
// All other values pass through
|
|
166
|
+
else {
|
|
167
|
+
result[key] = value;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return result;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Universal component config getter with interpolation
|
|
44
174
|
*/
|
|
45
175
|
var getComponentConfig = function (projectData, componentName, variantName) {
|
|
46
176
|
var _a;
|
|
@@ -83,8 +213,10 @@ var getComponentConfig = function (projectData, componentName, variantName) {
|
|
|
83
213
|
var variantData = component[targetVariant];
|
|
84
214
|
// Filter out empty string and undefined props from config
|
|
85
215
|
var filteredComponentProps = filterEmptyProps((variantData === null || variantData === void 0 ? void 0 : variantData.componentProps) || {});
|
|
216
|
+
// Apply interpolation to component props
|
|
217
|
+
var interpolatedProps = interpolateValues(filteredComponentProps, projectData);
|
|
86
218
|
return {
|
|
87
|
-
componentProps:
|
|
219
|
+
componentProps: interpolatedProps,
|
|
88
220
|
variantExists: variantExists,
|
|
89
221
|
actualVariant: targetVariant,
|
|
90
222
|
availableVariants: availableVariants,
|
|
@@ -94,70 +226,54 @@ var getComponentConfig = function (projectData, componentName, variantName) {
|
|
|
94
226
|
exports.getComponentConfig = getComponentConfig;
|
|
95
227
|
/**
|
|
96
228
|
* Smart merge utility - LOCAL PROPS OVERRIDE CONFIG PROPS
|
|
97
|
-
* If a prop exists in both local and config, local wins
|
|
98
229
|
*/
|
|
99
|
-
var smartMergeWithLocalOverride = function (configProps, localProps) {
|
|
100
|
-
|
|
101
|
-
|
|
230
|
+
var smartMergeWithLocalOverride = function (configProps, localProps, projectData) {
|
|
231
|
+
// Start with interpolated config props
|
|
232
|
+
var interpolatedConfigProps = interpolateValues(configProps, projectData);
|
|
233
|
+
// Simple merge: local props override config props
|
|
234
|
+
var result = __assign({}, interpolatedConfigProps);
|
|
235
|
+
// Apply local props (they will be interpolated in the final pass)
|
|
102
236
|
for (var key in localProps) {
|
|
103
|
-
if (localProps
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
localProps[key] !== null &&
|
|
108
|
-
typeof configProps[key] === 'object' &&
|
|
109
|
-
!Array.isArray(configProps[key]) &&
|
|
110
|
-
configProps[key] !== null) {
|
|
111
|
-
// Merge nested objects but local properties still win
|
|
112
|
-
result[key] = __assign(__assign({}, configProps[key]), localProps[key]);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
// Primitive values or arrays - local always wins
|
|
116
|
-
result[key] = localProps[key];
|
|
237
|
+
if (Object.prototype.hasOwnProperty.call(localProps, key)) {
|
|
238
|
+
var value = localProps[key];
|
|
239
|
+
if (value !== undefined) {
|
|
240
|
+
result[key] = value;
|
|
117
241
|
}
|
|
118
242
|
}
|
|
119
243
|
}
|
|
120
|
-
|
|
244
|
+
// Final interpolation pass to handle any variable/asset references in local props
|
|
245
|
+
return interpolateValues(result, projectData);
|
|
121
246
|
};
|
|
122
247
|
/**
|
|
123
|
-
* Merge component config with local props
|
|
124
|
-
*
|
|
125
|
-
* @param config - Component configuration from getComponentConfig
|
|
126
|
-
* @param localProps - Props passed directly to the component (OVERRIDES CONFIG)
|
|
127
|
-
* @returns Merged configuration with metadata
|
|
248
|
+
* Merge component config with local props
|
|
128
249
|
*/
|
|
129
|
-
var mergeComponentConfig = function (config, localProps) {
|
|
250
|
+
var mergeComponentConfig = function (config, localProps, projectData) {
|
|
130
251
|
if (localProps === void 0) { localProps = {}; }
|
|
131
252
|
// Only apply config if variant exists and has actual configuration
|
|
132
253
|
var hasValidConfig = config.variantExists && Object.keys(config.componentProps).length > 0;
|
|
133
254
|
if (!hasValidConfig) {
|
|
255
|
+
// Still interpolate values in local props even if no config
|
|
256
|
+
var interpolatedLocalProps = interpolateValues(localProps, projectData);
|
|
134
257
|
return {
|
|
135
|
-
props:
|
|
258
|
+
props: interpolatedLocalProps,
|
|
136
259
|
variant: config.actualVariant,
|
|
137
260
|
hasConfig: false
|
|
138
261
|
};
|
|
139
262
|
}
|
|
140
|
-
// LOCAL PROPS OVERRIDE CONFIG PROPS
|
|
141
263
|
return {
|
|
142
|
-
props: smartMergeWithLocalOverride(config.componentProps, localProps),
|
|
264
|
+
props: smartMergeWithLocalOverride(config.componentProps, localProps, projectData),
|
|
143
265
|
variant: config.actualVariant,
|
|
144
266
|
hasConfig: true
|
|
145
267
|
};
|
|
146
268
|
};
|
|
147
269
|
exports.mergeComponentConfig = mergeComponentConfig;
|
|
148
270
|
/**
|
|
149
|
-
* Hook for easy component config usage
|
|
150
|
-
* Uses useMemo to prevent unnecessary re-computation
|
|
151
|
-
*
|
|
152
|
-
* @param componentName - Name of the component
|
|
153
|
-
* @param variantName - Optional variant name
|
|
154
|
-
* @returns Configuration object with helper methods
|
|
271
|
+
* Hook for easy component config usage
|
|
155
272
|
*/
|
|
156
273
|
var useComponentConfiguration = function (componentName, variantName) {
|
|
157
274
|
var projectData = (0, theme_1.useTheme)().projectData;
|
|
158
|
-
// Memoize config computation
|
|
275
|
+
// Memoize config computation
|
|
159
276
|
var config = (0, react_1.useMemo)(function () {
|
|
160
|
-
// Check for valid variant name (not empty or whitespace only)
|
|
161
277
|
if (!isValidVariantName(variantName)) {
|
|
162
278
|
return {
|
|
163
279
|
componentProps: {},
|
|
@@ -169,31 +285,33 @@ var useComponentConfiguration = function (componentName, variantName) {
|
|
|
169
285
|
}
|
|
170
286
|
return (0, exports.getComponentConfig)(projectData, componentName, variantName);
|
|
171
287
|
}, [projectData, componentName, variantName]);
|
|
172
|
-
// Memoize merge function
|
|
288
|
+
// Memoize merge function
|
|
173
289
|
var mergeWithLocal = (0, react_1.useMemo)(function () {
|
|
174
290
|
return function (localProps) {
|
|
175
291
|
if (localProps === void 0) { localProps = {}; }
|
|
176
|
-
// If no valid variant name was provided, return local props as-is
|
|
177
292
|
if (!isValidVariantName(variantName)) {
|
|
293
|
+
var interpolatedLocalProps = interpolateValues(localProps, projectData);
|
|
178
294
|
return {
|
|
179
|
-
props:
|
|
295
|
+
props: interpolatedLocalProps,
|
|
180
296
|
variant: '',
|
|
181
297
|
hasConfig: false
|
|
182
298
|
};
|
|
183
299
|
}
|
|
184
|
-
return (0, exports.mergeComponentConfig)(config, localProps);
|
|
300
|
+
return (0, exports.mergeComponentConfig)(config, localProps, projectData);
|
|
185
301
|
};
|
|
186
|
-
}, [config, variantName]);
|
|
187
|
-
// Memoize getProp function
|
|
302
|
+
}, [config, variantName, projectData]);
|
|
303
|
+
// Memoize getProp function
|
|
188
304
|
var getProp = (0, react_1.useMemo)(function () {
|
|
189
|
-
return function (propName, defaultValue) {
|
|
305
|
+
return function (propName, defaultValue) {
|
|
306
|
+
var value = config.componentProps[propName];
|
|
307
|
+
return (value !== undefined ? value : defaultValue);
|
|
308
|
+
};
|
|
190
309
|
}, [config.componentProps]);
|
|
191
310
|
return __assign(__assign({}, config), { mergeWithLocal: mergeWithLocal, getProp: getProp, hasVariant: config.variantExists, isDefaultVariant: config.actualVariant === 'default' });
|
|
192
311
|
};
|
|
193
312
|
exports.useComponentConfiguration = useComponentConfiguration;
|
|
194
313
|
/**
|
|
195
314
|
* Hook that directly returns merged props with local override
|
|
196
|
-
* Perfect for direct use in components
|
|
197
315
|
*/
|
|
198
316
|
var useComponentProps = function (componentName, variantName, localProps) {
|
|
199
317
|
if (variantName === void 0) { variantName = 'default'; }
|
|
@@ -201,7 +319,7 @@ var useComponentProps = function (componentName, variantName, localProps) {
|
|
|
201
319
|
var projectData = (0, theme_1.useTheme)().projectData;
|
|
202
320
|
return (0, react_1.useMemo)(function () {
|
|
203
321
|
var config = (0, exports.getComponentConfig)(projectData, componentName, variantName);
|
|
204
|
-
var merged = (0, exports.mergeComponentConfig)(config, localProps);
|
|
322
|
+
var merged = (0, exports.mergeComponentConfig)(config, localProps, projectData);
|
|
205
323
|
return merged.props;
|
|
206
324
|
}, [projectData, componentName, variantName, localProps]);
|
|
207
325
|
};
|
|
@@ -222,3 +340,822 @@ var getAvailableVariants = function (projectData, componentName) {
|
|
|
222
340
|
return Object.keys(((_a = projectData === null || projectData === void 0 ? void 0 : projectData.components) === null || _a === void 0 ? void 0 : _a[componentName]) || {});
|
|
223
341
|
};
|
|
224
342
|
exports.getAvailableVariants = getAvailableVariants;
|
|
343
|
+
/**
|
|
344
|
+
* Get all variables from project
|
|
345
|
+
*/
|
|
346
|
+
var getProjectVariables = function (projectData) {
|
|
347
|
+
var _a;
|
|
348
|
+
return ((_a = projectData === null || projectData === void 0 ? void 0 : projectData.variables) === null || _a === void 0 ? void 0 : _a.map(function (v) { return ({
|
|
349
|
+
name: v.name,
|
|
350
|
+
value: v.value
|
|
351
|
+
}); })) || [];
|
|
352
|
+
};
|
|
353
|
+
exports.getProjectVariables = getProjectVariables;
|
|
354
|
+
/**
|
|
355
|
+
* Get all assets from project
|
|
356
|
+
*/
|
|
357
|
+
var getProjectAssets = function (projectData) {
|
|
358
|
+
return (projectData === null || projectData === void 0 ? void 0 : projectData.assets) || [];
|
|
359
|
+
};
|
|
360
|
+
exports.getProjectAssets = getProjectAssets;
|
|
361
|
+
/**
|
|
362
|
+
* Hook to get interpolated value for a specific variable or asset reference
|
|
363
|
+
*/
|
|
364
|
+
var useValue = function (value) {
|
|
365
|
+
var projectData = (0, theme_1.useTheme)().projectData;
|
|
366
|
+
return (0, react_1.useMemo)(function () {
|
|
367
|
+
if (typeof value !== 'string')
|
|
368
|
+
return value;
|
|
369
|
+
// Check for asset reference ({{{asset}}})
|
|
370
|
+
var assetName = extractAssetName(value);
|
|
371
|
+
if (assetName) {
|
|
372
|
+
var assetUrl = getAssetUrl(assetName, projectData);
|
|
373
|
+
return assetUrl || value;
|
|
374
|
+
}
|
|
375
|
+
// Check for variable reference ({{variable}})
|
|
376
|
+
var variableName = extractVariableName(value);
|
|
377
|
+
if (variableName) {
|
|
378
|
+
var variableValue = getVariableValue(variableName, projectData);
|
|
379
|
+
return variableValue || value;
|
|
380
|
+
}
|
|
381
|
+
return value;
|
|
382
|
+
}, [value, projectData]);
|
|
383
|
+
};
|
|
384
|
+
exports.useValue = useValue;
|
|
385
|
+
/**
|
|
386
|
+
* Hook to get a specific variable value
|
|
387
|
+
*/
|
|
388
|
+
var useVariable = function (variableName) {
|
|
389
|
+
var projectData = (0, theme_1.useTheme)().projectData;
|
|
390
|
+
return (0, react_1.useMemo)(function () {
|
|
391
|
+
if (!variableName || !(projectData === null || projectData === void 0 ? void 0 : projectData.variables))
|
|
392
|
+
return null;
|
|
393
|
+
var variable = projectData.variables.find(function (v) { return v.name === variableName; });
|
|
394
|
+
return (variable === null || variable === void 0 ? void 0 : variable.value) || null;
|
|
395
|
+
}, [variableName, projectData]);
|
|
396
|
+
};
|
|
397
|
+
exports.useVariable = useVariable;
|
|
398
|
+
/**
|
|
399
|
+
* Hook to get a specific asset
|
|
400
|
+
*/
|
|
401
|
+
var useAsset = function (assetName) {
|
|
402
|
+
var projectData = (0, theme_1.useTheme)().projectData;
|
|
403
|
+
return (0, react_1.useMemo)(function () {
|
|
404
|
+
if (!assetName || !(projectData === null || projectData === void 0 ? void 0 : projectData.assets))
|
|
405
|
+
return null;
|
|
406
|
+
return getAsset(assetName, projectData);
|
|
407
|
+
}, [assetName, projectData]);
|
|
408
|
+
};
|
|
409
|
+
exports.useAsset = useAsset;
|
|
410
|
+
/**
|
|
411
|
+
* Hook to get a specific asset URL
|
|
412
|
+
*/
|
|
413
|
+
var useAssetUrl = function (assetName) {
|
|
414
|
+
var projectData = (0, theme_1.useTheme)().projectData;
|
|
415
|
+
return (0, react_1.useMemo)(function () {
|
|
416
|
+
if (!assetName || !(projectData === null || projectData === void 0 ? void 0 : projectData.assets))
|
|
417
|
+
return null;
|
|
418
|
+
return getAssetUrl(assetName, projectData);
|
|
419
|
+
}, [assetName, projectData]);
|
|
420
|
+
};
|
|
421
|
+
exports.useAssetUrl = useAssetUrl;
|
|
422
|
+
/**
|
|
423
|
+
* Check if a value is a variable reference
|
|
424
|
+
*/
|
|
425
|
+
var isVariableReference = function (value) {
|
|
426
|
+
return typeof value === 'string' && !!extractVariableName(value);
|
|
427
|
+
};
|
|
428
|
+
exports.isVariableReference = isVariableReference;
|
|
429
|
+
/**
|
|
430
|
+
* Check if a value is an asset reference
|
|
431
|
+
*/
|
|
432
|
+
var isAssetReference = function (value) {
|
|
433
|
+
return typeof value === 'string' && !!extractAssetName(value);
|
|
434
|
+
};
|
|
435
|
+
exports.isAssetReference = isAssetReference;
|
|
436
|
+
/**
|
|
437
|
+
* Helper to convert variable/asset references for UI display
|
|
438
|
+
*/
|
|
439
|
+
var formatReferenceForDisplay = function (value) {
|
|
440
|
+
if (!value || typeof value !== 'string') {
|
|
441
|
+
return { type: 'custom', display: value || '' };
|
|
442
|
+
}
|
|
443
|
+
var variableName = extractVariableName(value);
|
|
444
|
+
if (variableName) {
|
|
445
|
+
return { type: 'variable', display: variableName };
|
|
446
|
+
}
|
|
447
|
+
var assetName = extractAssetName(value);
|
|
448
|
+
if (assetName) {
|
|
449
|
+
return { type: 'asset', display: assetName };
|
|
450
|
+
}
|
|
451
|
+
return { type: 'custom', display: value };
|
|
452
|
+
};
|
|
453
|
+
exports.formatReferenceForDisplay = formatReferenceForDisplay;
|
|
454
|
+
/**
|
|
455
|
+
* Create a variable reference string
|
|
456
|
+
*/
|
|
457
|
+
var createVariableReference = function (variableName) {
|
|
458
|
+
return "{{".concat(variableName, "}}");
|
|
459
|
+
};
|
|
460
|
+
exports.createVariableReference = createVariableReference;
|
|
461
|
+
/**
|
|
462
|
+
* Create an asset reference string
|
|
463
|
+
*/
|
|
464
|
+
var createAssetReference = function (assetName) {
|
|
465
|
+
return "{{{".concat(assetName, "}}}");
|
|
466
|
+
};
|
|
467
|
+
exports.createAssetReference = createAssetReference;
|
|
468
|
+
/**
|
|
469
|
+
* Check if a prop value needs interpolation
|
|
470
|
+
*/
|
|
471
|
+
var needsInterpolation = function (value) {
|
|
472
|
+
if (typeof value !== 'string')
|
|
473
|
+
return false;
|
|
474
|
+
return (0, exports.isVariableReference)(value) || (0, exports.isAssetReference)(value);
|
|
475
|
+
};
|
|
476
|
+
exports.needsInterpolation = needsInterpolation;
|
|
477
|
+
/**
|
|
478
|
+
* Get all references (variables and assets) used in props
|
|
479
|
+
*/
|
|
480
|
+
var getUsedReferences = function (props, projectData) {
|
|
481
|
+
var variables = [];
|
|
482
|
+
var assets = [];
|
|
483
|
+
if (!props || !projectData)
|
|
484
|
+
return { variables: variables, assets: assets };
|
|
485
|
+
var processValue = function (value) {
|
|
486
|
+
if (typeof value === 'string') {
|
|
487
|
+
var variableName = extractVariableName(value);
|
|
488
|
+
if (variableName) {
|
|
489
|
+
variables.push(variableName);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
var assetName = extractAssetName(value);
|
|
493
|
+
if (assetName) {
|
|
494
|
+
assets.push(assetName);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
else if (Array.isArray(value)) {
|
|
498
|
+
value.forEach(processValue);
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
Object.values(props).forEach(processValue);
|
|
502
|
+
return {
|
|
503
|
+
variables: Array.from(new Set(variables)),
|
|
504
|
+
assets: Array.from(new Set(assets))
|
|
505
|
+
};
|
|
506
|
+
};
|
|
507
|
+
exports.getUsedReferences = getUsedReferences;
|
|
508
|
+
/**
|
|
509
|
+
* Get asset by name (exported version)
|
|
510
|
+
*/
|
|
511
|
+
var getAssetByName = function (assetName, projectData) {
|
|
512
|
+
return getAsset(assetName, projectData);
|
|
513
|
+
};
|
|
514
|
+
exports.getAssetByName = getAssetByName;
|
|
515
|
+
/**
|
|
516
|
+
* Get variable by name (exported version)
|
|
517
|
+
*/
|
|
518
|
+
var getVariableByName = function (variableName, projectData) {
|
|
519
|
+
if (!(projectData === null || projectData === void 0 ? void 0 : projectData.variables) || !variableName)
|
|
520
|
+
return null;
|
|
521
|
+
var variable = projectData.variables.find(function (v) { return v.name === variableName; });
|
|
522
|
+
return variable ? { name: variable.name, value: variable.value } : null;
|
|
523
|
+
};
|
|
524
|
+
exports.getVariableByName = getVariableByName;
|
|
525
|
+
exports.default = {
|
|
526
|
+
getComponentConfig: exports.getComponentConfig,
|
|
527
|
+
mergeComponentConfig: exports.mergeComponentConfig,
|
|
528
|
+
useComponentConfiguration: exports.useComponentConfiguration,
|
|
529
|
+
useComponentProps: exports.useComponentProps,
|
|
530
|
+
hasComponentVariant: exports.hasComponentVariant,
|
|
531
|
+
getAvailableVariants: exports.getAvailableVariants,
|
|
532
|
+
getProjectVariables: exports.getProjectVariables,
|
|
533
|
+
getProjectAssets: exports.getProjectAssets,
|
|
534
|
+
useValue: exports.useValue,
|
|
535
|
+
useVariable: exports.useVariable,
|
|
536
|
+
useAsset: exports.useAsset,
|
|
537
|
+
useAssetUrl: exports.useAssetUrl,
|
|
538
|
+
isVariableReference: exports.isVariableReference,
|
|
539
|
+
isAssetReference: exports.isAssetReference,
|
|
540
|
+
formatReferenceForDisplay: exports.formatReferenceForDisplay,
|
|
541
|
+
createVariableReference: exports.createVariableReference,
|
|
542
|
+
createAssetReference: exports.createAssetReference,
|
|
543
|
+
needsInterpolation: exports.needsInterpolation,
|
|
544
|
+
getUsedReferences: exports.getUsedReferences,
|
|
545
|
+
getAssetByName: exports.getAssetByName,
|
|
546
|
+
getVariableByName: exports.getVariableByName
|
|
547
|
+
};
|
|
548
|
+
// import { useTheme } from "../ui/theme/theme"
|
|
549
|
+
// import { useMemo } from "react"
|
|
550
|
+
// // utils/componentUtils.ts
|
|
551
|
+
// // Type definitions
|
|
552
|
+
// export interface ComponentProps {
|
|
553
|
+
// [key: string]: any
|
|
554
|
+
// }
|
|
555
|
+
// export interface ComponentMetadata {
|
|
556
|
+
// createdAt?: Date
|
|
557
|
+
// updatedAt?: Date
|
|
558
|
+
// isCustom?: boolean
|
|
559
|
+
// baseVariant?: string
|
|
560
|
+
// }
|
|
561
|
+
// export interface ComponentVariant {
|
|
562
|
+
// componentProps: ComponentProps
|
|
563
|
+
// metadata?: ComponentMetadata
|
|
564
|
+
// }
|
|
565
|
+
// export interface ComponentConfig {
|
|
566
|
+
// componentProps: ComponentProps
|
|
567
|
+
// variantExists: boolean
|
|
568
|
+
// actualVariant: string
|
|
569
|
+
// availableVariants: string[]
|
|
570
|
+
// metadata: ComponentMetadata
|
|
571
|
+
// }
|
|
572
|
+
// export interface ProjectData {
|
|
573
|
+
// components?: {
|
|
574
|
+
// [componentName: string]: {
|
|
575
|
+
// [variantName: string]: ComponentVariant
|
|
576
|
+
// }
|
|
577
|
+
// }
|
|
578
|
+
// variables?: Array<{
|
|
579
|
+
// name: string;
|
|
580
|
+
// value: string;
|
|
581
|
+
// category?: string;
|
|
582
|
+
// createdBy?: string;
|
|
583
|
+
// createdAt?: number;
|
|
584
|
+
// updatedBy?: string;
|
|
585
|
+
// updatedAt?: number;
|
|
586
|
+
// }>
|
|
587
|
+
// }
|
|
588
|
+
// export interface MergedConfig {
|
|
589
|
+
// props: ComponentProps
|
|
590
|
+
// variant: string
|
|
591
|
+
// hasConfig: boolean
|
|
592
|
+
// }
|
|
593
|
+
// export interface UseComponentConfigReturn extends ComponentConfig {
|
|
594
|
+
// mergeWithLocal: (localProps?: ComponentProps) => MergedConfig
|
|
595
|
+
// getProp: <T = any>(propName: string, defaultValue?: T) => T
|
|
596
|
+
// hasVariant: boolean
|
|
597
|
+
// isDefaultVariant: boolean
|
|
598
|
+
// }
|
|
599
|
+
// /**
|
|
600
|
+
// * Extract variable name from {{variable_name}} pattern
|
|
601
|
+
// */
|
|
602
|
+
// const extractVariableName = (value: string): string | null => {
|
|
603
|
+
// if (typeof value !== 'string') return null;
|
|
604
|
+
// const match = value.match(/\{\{\s*([^}]+)\s*\}\}/);
|
|
605
|
+
// return match ? match[1].trim() : null;
|
|
606
|
+
// }
|
|
607
|
+
// /**
|
|
608
|
+
// * Get variable value from project variables
|
|
609
|
+
// */
|
|
610
|
+
// const getVariableValue = (
|
|
611
|
+
// variableName: string,
|
|
612
|
+
// projectData: ProjectData | null | undefined
|
|
613
|
+
// ): string | null => {
|
|
614
|
+
// if (!projectData?.variables || !variableName) return null;
|
|
615
|
+
// const variable = projectData.variables.find(v => v.name === variableName);
|
|
616
|
+
// return variable?.value || null;
|
|
617
|
+
// }
|
|
618
|
+
// /**
|
|
619
|
+
// * SAFE Interpolate variables in props - NO RECURSION to prevent stack overflow
|
|
620
|
+
// */
|
|
621
|
+
// const interpolateVariables = (
|
|
622
|
+
// props: ComponentProps,
|
|
623
|
+
// projectData: ProjectData | null | undefined
|
|
624
|
+
// ): ComponentProps => {
|
|
625
|
+
// // Quick return if no variables or empty props
|
|
626
|
+
// if (!projectData?.variables || !props || Object.keys(props).length === 0) {
|
|
627
|
+
// return props;
|
|
628
|
+
// }
|
|
629
|
+
// const result: ComponentProps = {};
|
|
630
|
+
// // Create a lookup map for faster variable access
|
|
631
|
+
// const variableMap = projectData.variables.reduce((acc, variable) => {
|
|
632
|
+
// acc[variable.name] = variable.value;
|
|
633
|
+
// return acc;
|
|
634
|
+
// }, {} as Record<string, string>);
|
|
635
|
+
// // Process each property safely
|
|
636
|
+
// for (const key in props) {
|
|
637
|
+
// if (!Object.prototype.hasOwnProperty.call(props, key)) continue;
|
|
638
|
+
// const value = props[key];
|
|
639
|
+
// // Handle strings with variable interpolation
|
|
640
|
+
// if (typeof value === 'string') {
|
|
641
|
+
// const variableName = extractVariableName(value);
|
|
642
|
+
// if (variableName && variableMap[variableName]) {
|
|
643
|
+
// result[key] = variableMap[variableName];
|
|
644
|
+
// } else {
|
|
645
|
+
// result[key] = value;
|
|
646
|
+
// }
|
|
647
|
+
// }
|
|
648
|
+
// // Handle arrays - shallow process only
|
|
649
|
+
// else if (Array.isArray(value)) {
|
|
650
|
+
// result[key] = value.map(item => {
|
|
651
|
+
// if (typeof item === 'string') {
|
|
652
|
+
// const variableName = extractVariableName(item);
|
|
653
|
+
// return variableName && variableMap[variableName]
|
|
654
|
+
// ? variableMap[variableName]
|
|
655
|
+
// : item;
|
|
656
|
+
// }
|
|
657
|
+
// return item;
|
|
658
|
+
// });
|
|
659
|
+
// }
|
|
660
|
+
// // Handle objects - ONLY shallow copy, NO deep processing
|
|
661
|
+
// else if (value && typeof value === 'object') {
|
|
662
|
+
// // Create a shallow copy to avoid modifying original
|
|
663
|
+
// const shallowCopy = Array.isArray(value) ? [...value] : { ...value };
|
|
664
|
+
// result[key] = shallowCopy;
|
|
665
|
+
// }
|
|
666
|
+
// // All other values pass through
|
|
667
|
+
// else {
|
|
668
|
+
// result[key] = value;
|
|
669
|
+
// }
|
|
670
|
+
// }
|
|
671
|
+
// return result;
|
|
672
|
+
// }
|
|
673
|
+
// /**
|
|
674
|
+
// * Check if a variant name is valid (not empty or whitespace only)
|
|
675
|
+
// */
|
|
676
|
+
// const isValidVariantName = (variantName: string | undefined): boolean => {
|
|
677
|
+
// return !!variantName && variantName.trim() !== '';
|
|
678
|
+
// }
|
|
679
|
+
// /**
|
|
680
|
+
// * Filter out empty string and undefined values from component props
|
|
681
|
+
// */
|
|
682
|
+
// const filterEmptyProps = (props: ComponentProps): ComponentProps => {
|
|
683
|
+
// const filtered: ComponentProps = {};
|
|
684
|
+
// for (const key in props) {
|
|
685
|
+
// const value = props[key];
|
|
686
|
+
// // Only include props that are not undefined and not empty strings
|
|
687
|
+
// if (value !== undefined && value !== '') {
|
|
688
|
+
// filtered[key] = value;
|
|
689
|
+
// }
|
|
690
|
+
// }
|
|
691
|
+
// return filtered;
|
|
692
|
+
// }
|
|
693
|
+
// /**
|
|
694
|
+
// * Universal component config getter with variable interpolation
|
|
695
|
+
// */
|
|
696
|
+
// export const getComponentConfig = (
|
|
697
|
+
// projectData: ProjectData | null | undefined,
|
|
698
|
+
// componentName: string,
|
|
699
|
+
// variantName: string = 'default'
|
|
700
|
+
// ): ComponentConfig => {
|
|
701
|
+
// // Early return if no component exists
|
|
702
|
+
// if (!projectData?.components?.[componentName]) {
|
|
703
|
+
// return {
|
|
704
|
+
// componentProps: {},
|
|
705
|
+
// variantExists: false,
|
|
706
|
+
// actualVariant: variantName,
|
|
707
|
+
// availableVariants: [],
|
|
708
|
+
// metadata: {}
|
|
709
|
+
// }
|
|
710
|
+
// }
|
|
711
|
+
// const component = projectData.components[componentName];
|
|
712
|
+
// const availableVariants = Object.keys(component);
|
|
713
|
+
// // Find the best variant match with fallback chain
|
|
714
|
+
// let targetVariant = variantName;
|
|
715
|
+
// let variantExists = availableVariants.includes(variantName);
|
|
716
|
+
// if (!variantExists) {
|
|
717
|
+
// // Fallback priority: default → first available → none
|
|
718
|
+
// if (availableVariants.includes('default')) {
|
|
719
|
+
// targetVariant = 'default';
|
|
720
|
+
// variantExists = true;
|
|
721
|
+
// } else if (availableVariants.length > 0) {
|
|
722
|
+
// targetVariant = availableVariants[0];
|
|
723
|
+
// variantExists = true;
|
|
724
|
+
// } else {
|
|
725
|
+
// return {
|
|
726
|
+
// componentProps: {},
|
|
727
|
+
// variantExists: false,
|
|
728
|
+
// actualVariant: variantName,
|
|
729
|
+
// availableVariants: [],
|
|
730
|
+
// metadata: {}
|
|
731
|
+
// };
|
|
732
|
+
// }
|
|
733
|
+
// }
|
|
734
|
+
// const variantData = component[targetVariant];
|
|
735
|
+
// // Filter out empty string and undefined props from config
|
|
736
|
+
// let filteredComponentProps = filterEmptyProps(variantData?.componentProps || {});
|
|
737
|
+
// // Apply variable interpolation to component props
|
|
738
|
+
// filteredComponentProps = interpolateVariables(filteredComponentProps, projectData);
|
|
739
|
+
// return {
|
|
740
|
+
// componentProps: filteredComponentProps,
|
|
741
|
+
// variantExists,
|
|
742
|
+
// actualVariant: targetVariant,
|
|
743
|
+
// availableVariants,
|
|
744
|
+
// metadata: variantData?.metadata || {}
|
|
745
|
+
// };
|
|
746
|
+
// }
|
|
747
|
+
// /**
|
|
748
|
+
// * Smart merge utility - LOCAL PROPS OVERRIDE CONFIG PROPS with variable interpolation
|
|
749
|
+
// */
|
|
750
|
+
// const smartMergeWithLocalOverride = (
|
|
751
|
+
// configProps: ComponentProps,
|
|
752
|
+
// localProps: ComponentProps,
|
|
753
|
+
// projectData: ProjectData | null | undefined
|
|
754
|
+
// ): ComponentProps => {
|
|
755
|
+
// // Start with interpolated config props
|
|
756
|
+
// const interpolatedConfigProps = interpolateVariables(configProps, projectData);
|
|
757
|
+
// const interpolatedLocalProps = interpolateVariables(localProps, projectData);
|
|
758
|
+
// // Simple merge: local props override config props
|
|
759
|
+
// const result = { ...interpolatedConfigProps };
|
|
760
|
+
// for (const key in interpolatedLocalProps) {
|
|
761
|
+
// if (interpolatedLocalProps[key] !== undefined) {
|
|
762
|
+
// result[key] = interpolatedLocalProps[key];
|
|
763
|
+
// }
|
|
764
|
+
// }
|
|
765
|
+
// return result;
|
|
766
|
+
// }
|
|
767
|
+
// /**
|
|
768
|
+
// * Merge component config with local props
|
|
769
|
+
// */
|
|
770
|
+
// export const mergeComponentConfig = (
|
|
771
|
+
// config: ComponentConfig,
|
|
772
|
+
// localProps: ComponentProps = {},
|
|
773
|
+
// projectData: ProjectData | null | undefined
|
|
774
|
+
// ): MergedConfig => {
|
|
775
|
+
// // Only apply config if variant exists and has actual configuration
|
|
776
|
+
// const hasValidConfig = config.variantExists && Object.keys(config.componentProps).length > 0;
|
|
777
|
+
// if (!hasValidConfig) {
|
|
778
|
+
// // Still interpolate variables in local props even if no config
|
|
779
|
+
// const interpolatedLocalProps = interpolateVariables(localProps, projectData);
|
|
780
|
+
// return {
|
|
781
|
+
// props: interpolatedLocalProps,
|
|
782
|
+
// variant: config.actualVariant,
|
|
783
|
+
// hasConfig: false
|
|
784
|
+
// };
|
|
785
|
+
// }
|
|
786
|
+
// return {
|
|
787
|
+
// props: smartMergeWithLocalOverride(config.componentProps, localProps, projectData),
|
|
788
|
+
// variant: config.actualVariant,
|
|
789
|
+
// hasConfig: true
|
|
790
|
+
// };
|
|
791
|
+
// }
|
|
792
|
+
// /**
|
|
793
|
+
// * Hook for easy component config usage
|
|
794
|
+
// */
|
|
795
|
+
// export const useComponentConfiguration = (
|
|
796
|
+
// componentName: string,
|
|
797
|
+
// variantName?: string
|
|
798
|
+
// ): UseComponentConfigReturn => {
|
|
799
|
+
// const { projectData } = useTheme();
|
|
800
|
+
// // Memoize config computation
|
|
801
|
+
// const config = useMemo(() => {
|
|
802
|
+
// if (!isValidVariantName(variantName)) {
|
|
803
|
+
// return {
|
|
804
|
+
// componentProps: {},
|
|
805
|
+
// variantExists: false,
|
|
806
|
+
// actualVariant: '',
|
|
807
|
+
// availableVariants: [],
|
|
808
|
+
// metadata: {}
|
|
809
|
+
// };
|
|
810
|
+
// }
|
|
811
|
+
// return getComponentConfig(projectData, componentName, variantName!);
|
|
812
|
+
// }, [projectData, componentName, variantName]);
|
|
813
|
+
// // Memoize merge function
|
|
814
|
+
// const mergeWithLocal = useMemo(() => {
|
|
815
|
+
// return (localProps: ComponentProps = {}): MergedConfig => {
|
|
816
|
+
// if (!isValidVariantName(variantName)) {
|
|
817
|
+
// const interpolatedLocalProps = interpolateVariables(localProps, projectData);
|
|
818
|
+
// return {
|
|
819
|
+
// props: interpolatedLocalProps,
|
|
820
|
+
// variant: '',
|
|
821
|
+
// hasConfig: false
|
|
822
|
+
// };
|
|
823
|
+
// }
|
|
824
|
+
// return mergeComponentConfig(config, localProps, projectData);
|
|
825
|
+
// };
|
|
826
|
+
// }, [config, variantName, projectData]);
|
|
827
|
+
// // Memoize getProp function
|
|
828
|
+
// const getProp = useMemo(() => {
|
|
829
|
+
// return <T = any>(propName: string, defaultValue?: T): T =>
|
|
830
|
+
// (config.componentProps[propName] ?? defaultValue) as T;
|
|
831
|
+
// }, [config.componentProps]);
|
|
832
|
+
// return {
|
|
833
|
+
// ...config,
|
|
834
|
+
// mergeWithLocal,
|
|
835
|
+
// getProp,
|
|
836
|
+
// hasVariant: config.variantExists,
|
|
837
|
+
// isDefaultVariant: config.actualVariant === 'default'
|
|
838
|
+
// };
|
|
839
|
+
// }
|
|
840
|
+
// /**
|
|
841
|
+
// * Hook that directly returns merged props with local override
|
|
842
|
+
// */
|
|
843
|
+
// export const useComponentProps = (
|
|
844
|
+
// componentName: string,
|
|
845
|
+
// variantName: string = 'default',
|
|
846
|
+
// localProps: ComponentProps = {}
|
|
847
|
+
// ): ComponentProps => {
|
|
848
|
+
// const { projectData } = useTheme();
|
|
849
|
+
// return useMemo(() => {
|
|
850
|
+
// const config = getComponentConfig(projectData, componentName, variantName);
|
|
851
|
+
// const merged = mergeComponentConfig(config, localProps, projectData);
|
|
852
|
+
// return merged.props;
|
|
853
|
+
// }, [projectData, componentName, variantName, localProps]);
|
|
854
|
+
// }
|
|
855
|
+
// /**
|
|
856
|
+
// * Quick utility to check if a component variant exists
|
|
857
|
+
// */
|
|
858
|
+
// export const hasComponentVariant = (
|
|
859
|
+
// projectData: ProjectData | null | undefined,
|
|
860
|
+
// componentName: string,
|
|
861
|
+
// variantName: string
|
|
862
|
+
// ): boolean => {
|
|
863
|
+
// return !!projectData?.components?.[componentName]?.[variantName];
|
|
864
|
+
// }
|
|
865
|
+
// /**
|
|
866
|
+
// * Get all available variants for a component
|
|
867
|
+
// */
|
|
868
|
+
// export const getAvailableVariants = (
|
|
869
|
+
// projectData: ProjectData | null | undefined,
|
|
870
|
+
// componentName: string
|
|
871
|
+
// ): string[] => {
|
|
872
|
+
// return Object.keys(projectData?.components?.[componentName] || {});
|
|
873
|
+
// }
|
|
874
|
+
// /**
|
|
875
|
+
// * Get all variables from project
|
|
876
|
+
// */
|
|
877
|
+
// export const getProjectVariables = (
|
|
878
|
+
// projectData: ProjectData | null | undefined
|
|
879
|
+
// ): Array<{name: string; value: string}> => {
|
|
880
|
+
// return projectData?.variables?.map(v => ({
|
|
881
|
+
// name: v.name,
|
|
882
|
+
// value: v.value
|
|
883
|
+
// })) || [];
|
|
884
|
+
// }
|
|
885
|
+
// /**
|
|
886
|
+
// * Hook to get interpolated value for a specific variable or string
|
|
887
|
+
// */
|
|
888
|
+
// export const useVariable = (value: string): string => {
|
|
889
|
+
// const { projectData } = useTheme();
|
|
890
|
+
// return useMemo(() => {
|
|
891
|
+
// if (typeof value !== 'string') return value;
|
|
892
|
+
// const variableName = extractVariableName(value);
|
|
893
|
+
// if (!variableName) return value;
|
|
894
|
+
// const variableValue = getVariableValue(variableName, projectData);
|
|
895
|
+
// return variableValue || value;
|
|
896
|
+
// }, [value, projectData]);
|
|
897
|
+
// }
|
|
898
|
+
// import { useTheme } from "../ui/theme/theme"
|
|
899
|
+
// import { useMemo } from "react"
|
|
900
|
+
// // utils/componentUtils.ts
|
|
901
|
+
// // Type definitions
|
|
902
|
+
// export interface ComponentProps {
|
|
903
|
+
// [key: string]: any
|
|
904
|
+
// }
|
|
905
|
+
// export interface ComponentMetadata {
|
|
906
|
+
// createdAt?: Date
|
|
907
|
+
// updatedAt?: Date
|
|
908
|
+
// isCustom?: boolean
|
|
909
|
+
// baseVariant?: string
|
|
910
|
+
// }
|
|
911
|
+
// export interface ComponentVariant {
|
|
912
|
+
// componentProps: ComponentProps
|
|
913
|
+
// metadata?: ComponentMetadata
|
|
914
|
+
// }
|
|
915
|
+
// export interface ComponentConfig {
|
|
916
|
+
// componentProps: ComponentProps
|
|
917
|
+
// variantExists: boolean
|
|
918
|
+
// actualVariant: string
|
|
919
|
+
// availableVariants: string[]
|
|
920
|
+
// metadata: ComponentMetadata
|
|
921
|
+
// }
|
|
922
|
+
// export interface ProjectData {
|
|
923
|
+
// components?: {
|
|
924
|
+
// [componentName: string]: {
|
|
925
|
+
// [variantName: string]: ComponentVariant
|
|
926
|
+
// }
|
|
927
|
+
// }
|
|
928
|
+
// }
|
|
929
|
+
// export interface MergedConfig {
|
|
930
|
+
// props: ComponentProps
|
|
931
|
+
// variant: string
|
|
932
|
+
// hasConfig: boolean
|
|
933
|
+
// }
|
|
934
|
+
// export interface UseComponentConfigReturn extends ComponentConfig {
|
|
935
|
+
// mergeWithLocal: (localProps?: ComponentProps) => MergedConfig
|
|
936
|
+
// getProp: <T = any>(propName: string, defaultValue?: T) => T
|
|
937
|
+
// hasVariant: boolean
|
|
938
|
+
// isDefaultVariant: boolean
|
|
939
|
+
// }
|
|
940
|
+
// /**
|
|
941
|
+
// * Check if a variant name is valid (not empty or whitespace only)
|
|
942
|
+
// */
|
|
943
|
+
// const isValidVariantName = (variantName: string | undefined): boolean => {
|
|
944
|
+
// return !!variantName && variantName.trim() !== '';
|
|
945
|
+
// }
|
|
946
|
+
// /**
|
|
947
|
+
// * Filter out empty string and undefined values from component props
|
|
948
|
+
// */
|
|
949
|
+
// const filterEmptyProps = (props: ComponentProps): ComponentProps => {
|
|
950
|
+
// const filtered: ComponentProps = {};
|
|
951
|
+
// for (const key in props) {
|
|
952
|
+
// const value = props[key];
|
|
953
|
+
// // Only include props that are not undefined and not empty strings
|
|
954
|
+
// if (value !== undefined && value !== '') {
|
|
955
|
+
// filtered[key] = value;
|
|
956
|
+
// }
|
|
957
|
+
// }
|
|
958
|
+
// return filtered;
|
|
959
|
+
// }
|
|
960
|
+
// /**
|
|
961
|
+
// * Universal component config getter
|
|
962
|
+
// *
|
|
963
|
+
// * @param projectData - The project configuration data
|
|
964
|
+
// * @param componentName - Name of the component to get config for
|
|
965
|
+
// * @param variantName - Name of the variant (defaults to 'default')
|
|
966
|
+
// * @returns Component configuration with metadata
|
|
967
|
+
// */
|
|
968
|
+
// export const getComponentConfig = (
|
|
969
|
+
// projectData: ProjectData | null | undefined,
|
|
970
|
+
// componentName: string,
|
|
971
|
+
// variantName: string = 'default'
|
|
972
|
+
// ): ComponentConfig => {
|
|
973
|
+
// // Early return if no component exists
|
|
974
|
+
// if (!projectData?.components?.[componentName]) {
|
|
975
|
+
// return {
|
|
976
|
+
// componentProps: {},
|
|
977
|
+
// variantExists: false,
|
|
978
|
+
// actualVariant: variantName,
|
|
979
|
+
// availableVariants: [],
|
|
980
|
+
// metadata: {}
|
|
981
|
+
// }
|
|
982
|
+
// }
|
|
983
|
+
// const component = projectData.components[componentName]
|
|
984
|
+
// const availableVariants = Object.keys(component)
|
|
985
|
+
// // Find the best variant match with fallback chain
|
|
986
|
+
// let targetVariant = variantName
|
|
987
|
+
// let variantExists = availableVariants.includes(variantName)
|
|
988
|
+
// if (!variantExists) {
|
|
989
|
+
// // Fallback priority: default → first available → none
|
|
990
|
+
// if (availableVariants.includes('default')) {
|
|
991
|
+
// targetVariant = 'default'
|
|
992
|
+
// variantExists = true
|
|
993
|
+
// } else if (availableVariants.length > 0) {
|
|
994
|
+
// targetVariant = availableVariants[0]
|
|
995
|
+
// variantExists = true
|
|
996
|
+
// } else {
|
|
997
|
+
// return {
|
|
998
|
+
// componentProps: {},
|
|
999
|
+
// variantExists: false,
|
|
1000
|
+
// actualVariant: variantName,
|
|
1001
|
+
// availableVariants: [],
|
|
1002
|
+
// metadata: {}
|
|
1003
|
+
// }
|
|
1004
|
+
// }
|
|
1005
|
+
// }
|
|
1006
|
+
// const variantData = component[targetVariant]
|
|
1007
|
+
// // Filter out empty string and undefined props from config
|
|
1008
|
+
// const filteredComponentProps = filterEmptyProps(variantData?.componentProps || {})
|
|
1009
|
+
// return {
|
|
1010
|
+
// componentProps: filteredComponentProps,
|
|
1011
|
+
// variantExists,
|
|
1012
|
+
// actualVariant: targetVariant,
|
|
1013
|
+
// availableVariants,
|
|
1014
|
+
// metadata: variantData?.metadata || {}
|
|
1015
|
+
// }
|
|
1016
|
+
// }
|
|
1017
|
+
// /**
|
|
1018
|
+
// * Smart merge utility - LOCAL PROPS OVERRIDE CONFIG PROPS
|
|
1019
|
+
// * If a prop exists in both local and config, local wins
|
|
1020
|
+
// */
|
|
1021
|
+
// const smartMergeWithLocalOverride = (
|
|
1022
|
+
// configProps: ComponentProps,
|
|
1023
|
+
// localProps: ComponentProps
|
|
1024
|
+
// ): ComponentProps => {
|
|
1025
|
+
// const result = { ...configProps }
|
|
1026
|
+
// // Apply local props - they override config props
|
|
1027
|
+
// for (const key in localProps) {
|
|
1028
|
+
// if (localProps[key] !== undefined) {
|
|
1029
|
+
// // For objects, do smart merge but local object properties still override
|
|
1030
|
+
// if (typeof localProps[key] === 'object' &&
|
|
1031
|
+
// !Array.isArray(localProps[key]) &&
|
|
1032
|
+
// localProps[key] !== null &&
|
|
1033
|
+
// typeof configProps[key] === 'object' &&
|
|
1034
|
+
// !Array.isArray(configProps[key]) &&
|
|
1035
|
+
// configProps[key] !== null) {
|
|
1036
|
+
// // Merge nested objects but local properties still win
|
|
1037
|
+
// result[key] = { ...configProps[key], ...localProps[key] }
|
|
1038
|
+
// } else {
|
|
1039
|
+
// // Primitive values or arrays - local always wins
|
|
1040
|
+
// result[key] = localProps[key]
|
|
1041
|
+
// }
|
|
1042
|
+
// }
|
|
1043
|
+
// }
|
|
1044
|
+
// return result
|
|
1045
|
+
// }
|
|
1046
|
+
// /**
|
|
1047
|
+
// * Merge component config with local props - LOCAL PROPS OVERRIDE CONFIG
|
|
1048
|
+
// *
|
|
1049
|
+
// * @param config - Component configuration from getComponentConfig
|
|
1050
|
+
// * @param localProps - Props passed directly to the component (OVERRIDES CONFIG)
|
|
1051
|
+
// * @returns Merged configuration with metadata
|
|
1052
|
+
// */
|
|
1053
|
+
// export const mergeComponentConfig = (
|
|
1054
|
+
// config: ComponentConfig,
|
|
1055
|
+
// localProps: ComponentProps = {}
|
|
1056
|
+
// ): MergedConfig => {
|
|
1057
|
+
// // Only apply config if variant exists and has actual configuration
|
|
1058
|
+
// const hasValidConfig = config.variantExists && Object.keys(config.componentProps).length > 0
|
|
1059
|
+
// if (!hasValidConfig) {
|
|
1060
|
+
// return {
|
|
1061
|
+
// props: localProps,
|
|
1062
|
+
// variant: config.actualVariant,
|
|
1063
|
+
// hasConfig: false
|
|
1064
|
+
// }
|
|
1065
|
+
// }
|
|
1066
|
+
// // LOCAL PROPS OVERRIDE CONFIG PROPS
|
|
1067
|
+
// return {
|
|
1068
|
+
// props: smartMergeWithLocalOverride(config.componentProps, localProps),
|
|
1069
|
+
// variant: config.actualVariant,
|
|
1070
|
+
// hasConfig: true
|
|
1071
|
+
// }
|
|
1072
|
+
// }
|
|
1073
|
+
// /**
|
|
1074
|
+
// * Hook for easy component config usage with LOCAL PROP OVERRIDE
|
|
1075
|
+
// * Uses useMemo to prevent unnecessary re-computation
|
|
1076
|
+
// *
|
|
1077
|
+
// * @param componentName - Name of the component
|
|
1078
|
+
// * @param variantName - Optional variant name
|
|
1079
|
+
// * @returns Configuration object with helper methods
|
|
1080
|
+
// */
|
|
1081
|
+
// export const useComponentConfiguration = (
|
|
1082
|
+
// componentName: string,
|
|
1083
|
+
// variantName?: string
|
|
1084
|
+
// ): UseComponentConfigReturn => {
|
|
1085
|
+
// const { projectData } = useTheme()
|
|
1086
|
+
// // Memoize config computation - only recompute when dependencies change
|
|
1087
|
+
// const config = useMemo(() => {
|
|
1088
|
+
// // Check for valid variant name (not empty or whitespace only)
|
|
1089
|
+
// if (!isValidVariantName(variantName)) {
|
|
1090
|
+
// return {
|
|
1091
|
+
// componentProps: {},
|
|
1092
|
+
// variantExists: false,
|
|
1093
|
+
// actualVariant: '',
|
|
1094
|
+
// availableVariants: [],
|
|
1095
|
+
// metadata: {}
|
|
1096
|
+
// }
|
|
1097
|
+
// }
|
|
1098
|
+
// return getComponentConfig(projectData, componentName, variantName!)
|
|
1099
|
+
// }, [projectData, componentName, variantName])
|
|
1100
|
+
// // Memoize merge function - LOCAL PROPS OVERRIDE CONFIG
|
|
1101
|
+
// const mergeWithLocal = useMemo(() => {
|
|
1102
|
+
// return (localProps: ComponentProps = {}): MergedConfig => {
|
|
1103
|
+
// // If no valid variant name was provided, return local props as-is
|
|
1104
|
+
// if (!isValidVariantName(variantName)) {
|
|
1105
|
+
// return {
|
|
1106
|
+
// props: localProps,
|
|
1107
|
+
// variant: '',
|
|
1108
|
+
// hasConfig: false
|
|
1109
|
+
// }
|
|
1110
|
+
// }
|
|
1111
|
+
// return mergeComponentConfig(config, localProps)
|
|
1112
|
+
// }
|
|
1113
|
+
// }, [config, variantName])
|
|
1114
|
+
// // Memoize getProp function (gets from config only, not merged)
|
|
1115
|
+
// const getProp = useMemo(() => {
|
|
1116
|
+
// return <T = any>(propName: string, defaultValue?: T): T =>
|
|
1117
|
+
// (config.componentProps[propName] ?? defaultValue) as T
|
|
1118
|
+
// }, [config.componentProps])
|
|
1119
|
+
// return {
|
|
1120
|
+
// ...config,
|
|
1121
|
+
// mergeWithLocal,
|
|
1122
|
+
// getProp,
|
|
1123
|
+
// hasVariant: config.variantExists,
|
|
1124
|
+
// isDefaultVariant: config.actualVariant === 'default'
|
|
1125
|
+
// }
|
|
1126
|
+
// }
|
|
1127
|
+
// /**
|
|
1128
|
+
// * Hook that directly returns merged props with local override
|
|
1129
|
+
// * Perfect for direct use in components
|
|
1130
|
+
// */
|
|
1131
|
+
// export const useComponentProps = (
|
|
1132
|
+
// componentName: string,
|
|
1133
|
+
// variantName: string = 'default',
|
|
1134
|
+
// localProps: ComponentProps = {}
|
|
1135
|
+
// ): ComponentProps => {
|
|
1136
|
+
// const { projectData } = useTheme()
|
|
1137
|
+
// return useMemo(() => {
|
|
1138
|
+
// const config = getComponentConfig(projectData, componentName, variantName)
|
|
1139
|
+
// const merged = mergeComponentConfig(config, localProps)
|
|
1140
|
+
// return merged.props
|
|
1141
|
+
// }, [projectData, componentName, variantName, localProps])
|
|
1142
|
+
// }
|
|
1143
|
+
// /**
|
|
1144
|
+
// * Quick utility to check if a component variant exists
|
|
1145
|
+
// */
|
|
1146
|
+
// export const hasComponentVariant = (
|
|
1147
|
+
// projectData: ProjectData | null | undefined,
|
|
1148
|
+
// componentName: string,
|
|
1149
|
+
// variantName: string
|
|
1150
|
+
// ): boolean => {
|
|
1151
|
+
// return !!projectData?.components?.[componentName]?.[variantName]
|
|
1152
|
+
// }
|
|
1153
|
+
// /**
|
|
1154
|
+
// * Get all available variants for a component
|
|
1155
|
+
// */
|
|
1156
|
+
// export const getAvailableVariants = (
|
|
1157
|
+
// projectData: ProjectData | null | undefined,
|
|
1158
|
+
// componentName: string
|
|
1159
|
+
// ): string[] => {
|
|
1160
|
+
// return Object.keys(projectData?.components?.[componentName] || {})
|
|
1161
|
+
// }
|