@aws-amplify/ui 6.6.2 → 6.6.3
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/esm/index.mjs +4 -2
- package/dist/esm/theme/createTheme/constants.mjs +8 -0
- package/dist/esm/theme/createTheme/resolveObject.mjs +133 -0
- package/dist/esm/theme/createTheme/utils.mjs +2 -30
- package/dist/esm/utils/references.mjs +70 -0
- package/dist/esm/utils/utils.mjs +18 -1
- package/dist/index.js +223 -29
- package/dist/types/theme/createTheme/constants.d.ts +9 -0
- package/dist/types/theme/createTheme/index.d.ts +2 -1
- package/dist/types/theme/createTheme/resolveObject.d.ts +24 -0
- package/dist/types/theme/createTheme/utils.d.ts +1 -7
- package/dist/types/theme/index.d.ts +1 -1
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/references.d.ts +15 -0
- package/dist/types/utils/utils.d.ts +1 -0
- package/package.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -18,8 +18,9 @@ export { createTheme } from './theme/createTheme/createTheme.mjs';
|
|
|
18
18
|
export { defineComponentTheme } from './theme/createTheme/defineComponentTheme.mjs';
|
|
19
19
|
export { createComponentCSS } from './theme/createTheme/createComponentCSS.mjs';
|
|
20
20
|
export { createGlobalCSS } from './theme/createTheme/createGlobalCSS.mjs';
|
|
21
|
-
export { cssNameTransform, isDesignToken, setupTokens } from './theme/createTheme/utils.mjs';
|
|
21
|
+
export { cssNameTransform, deepExtend, isDesignToken, setupTokens } from './theme/createTheme/utils.mjs';
|
|
22
22
|
export { createComponentClasses } from './theme/createTheme/createComponentClasses.mjs';
|
|
23
|
+
export { resolveObject } from './theme/createTheme/resolveObject.mjs';
|
|
23
24
|
export { defaultTheme } from './theme/defaultTheme.mjs';
|
|
24
25
|
export { defaultDarkModeOverride, reactNativeDarkTokens } from './theme/defaultDarkModeOverride.mjs';
|
|
25
26
|
export { reactNativeTokens } from './theme/tokens/index.mjs';
|
|
@@ -28,6 +29,7 @@ export { isUnverifiedContactMethodType } from './types/authenticator/utils.mjs';
|
|
|
28
29
|
export { LoginMechanismArray, authFieldsWithDefaults, isAuthFieldsWithDefaults, signUpFieldsWithDefault, signUpFieldsWithoutDefault } from './types/authenticator/attributes.mjs';
|
|
29
30
|
export { ComponentClassName } from './types/primitives/componentClassName.mjs';
|
|
30
31
|
export { setUserAgent } from './utils/setUserAgent/setUserAgent.mjs';
|
|
31
|
-
export { areEmptyArrays, areEmptyObjects, capitalize, classNameModifier, classNameModifierByFlag, groupLog, has, isEmpty, isEmptyObject, isFunction, isMap, isNil, isObject, isSet, isString, isUndefined, noop, sanitizeNamespaceImport, splitObject, templateJoin } from './utils/utils.mjs';
|
|
32
|
+
export { areEmptyArrays, areEmptyObjects, capitalize, classNameModifier, classNameModifierByFlag, cloneDeep, groupLog, has, isEmpty, isEmptyObject, isFunction, isMap, isNil, isObject, isSet, isString, isUndefined, noop, sanitizeNamespaceImport, splitObject, templateJoin } from './utils/utils.mjs';
|
|
32
33
|
export { classNames } from './utils/classNames.mjs';
|
|
33
34
|
export { humanFileSize } from './utils/humanFileSize.mjs';
|
|
35
|
+
export { getName, getPathFromName, resolveReference, usesReference } from './utils/references.mjs';
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import '@aws-amplify/core/internals/utils';
|
|
2
|
+
import '../../utils/setUserAgent/constants.mjs';
|
|
3
|
+
import { cloneDeep, has } from '../../utils/utils.mjs';
|
|
4
|
+
import { getName, getPathFromName, resolveReference, usesReference } from '../../utils/references.mjs';
|
|
5
|
+
import { REFERENCE_REGEX } from './constants.mjs';
|
|
6
|
+
|
|
7
|
+
const DEFAULTS = {
|
|
8
|
+
ignoreKeys: ['original'],
|
|
9
|
+
};
|
|
10
|
+
function resolveObject(object) {
|
|
11
|
+
const foundCirc = {};
|
|
12
|
+
const clone = cloneDeep(object); // This object will be edited
|
|
13
|
+
const currentContext = []; // To maintain the context to be able to test for circular definitions
|
|
14
|
+
if (typeof object === 'object') {
|
|
15
|
+
return traverseObject({
|
|
16
|
+
slice: clone,
|
|
17
|
+
fullObj: clone,
|
|
18
|
+
currentContext,
|
|
19
|
+
foundCirc,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
throw new Error('Please pass an object in');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Recursively traverses an object (slice) to resolve and uses
|
|
28
|
+
* compileValue to replace any string references found within it
|
|
29
|
+
*/
|
|
30
|
+
function traverseObject({ slice, fullObj, currentContext, foundCirc, }) {
|
|
31
|
+
for (let key in slice) {
|
|
32
|
+
if (!has(slice, key)) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const prop = slice[key];
|
|
36
|
+
// We want to check for ignoredKeys, this is to
|
|
37
|
+
// skip over attributes that should not be
|
|
38
|
+
// mutated, like a copy of the original property.
|
|
39
|
+
if (DEFAULTS.ignoreKeys && DEFAULTS.ignoreKeys.indexOf(key) !== -1) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
currentContext.push(key);
|
|
43
|
+
if (typeof prop === 'object') {
|
|
44
|
+
traverseObject({ currentContext, slice: prop, fullObj, foundCirc });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
if (typeof prop === 'string' && prop.indexOf('{') > -1) {
|
|
48
|
+
slice[key] = compileValue({
|
|
49
|
+
value: prop,
|
|
50
|
+
stack: [getName(currentContext)],
|
|
51
|
+
foundCirc,
|
|
52
|
+
fullObj,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
currentContext.pop();
|
|
57
|
+
}
|
|
58
|
+
return fullObj;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolves references in a value, performing recursive lookups when references are nested.
|
|
62
|
+
* value: The string that may contain references (e.g., {color.border.light}) that need to be replaced
|
|
63
|
+
* stack: keeps track of the current chain of references to detect circular references
|
|
64
|
+
* foundCirc: stores any detected circular references
|
|
65
|
+
* fullObj: The full object where references are looked up, essentially the source of all values
|
|
66
|
+
*/
|
|
67
|
+
function compileValue({ value, stack, foundCirc, fullObj }) {
|
|
68
|
+
let toRet = value, ref;
|
|
69
|
+
const regex = new RegExp(REFERENCE_REGEX);
|
|
70
|
+
// Replace the reference inline, but don't replace the whole string because
|
|
71
|
+
// references can be part of the value such as "1px solid {color.border.light}"
|
|
72
|
+
value.replace(regex, function (match, variable) {
|
|
73
|
+
variable = variable.trim();
|
|
74
|
+
// Find what the value is referencing
|
|
75
|
+
const pathName = getPathFromName(variable);
|
|
76
|
+
const refHasValue = pathName[pathName.length - 1] === 'value';
|
|
77
|
+
stack.push(variable);
|
|
78
|
+
ref = resolveReference(pathName, fullObj);
|
|
79
|
+
// If the reference doesn't end in 'value'
|
|
80
|
+
// and
|
|
81
|
+
// the reference points to someplace that has a `value` attribute
|
|
82
|
+
// we should take the '.value' of the reference
|
|
83
|
+
// per the W3C draft spec where references do not have .value
|
|
84
|
+
// https://design-tokens.github.io/community-group/format/#aliases-references
|
|
85
|
+
if (!refHasValue && ref && has(ref, 'value')) {
|
|
86
|
+
ref = ref.value;
|
|
87
|
+
}
|
|
88
|
+
if (typeof ref !== 'undefined') {
|
|
89
|
+
if (typeof ref === 'string' || typeof ref === 'number') {
|
|
90
|
+
toRet = value.replace(match, ref);
|
|
91
|
+
// Recursive, therefore we can compute multi-layer variables like a = b, b = c, eventually a = c
|
|
92
|
+
if (usesReference(toRet)) {
|
|
93
|
+
var reference = toRet.slice(1, -1);
|
|
94
|
+
// Compare to found circular references
|
|
95
|
+
if (has(foundCirc, reference)) ;
|
|
96
|
+
else if (stack.indexOf(reference) !== -1) {
|
|
97
|
+
// If the current stack already contains the current reference, we found a new circular reference
|
|
98
|
+
// chop down only the circular part, save it to our circular reference info, and spit out an error
|
|
99
|
+
// Get the position of the existing reference in the stack
|
|
100
|
+
var stackIndexReference = stack.indexOf(reference);
|
|
101
|
+
// Get the portion of the stack that starts at the circular reference and brings you through until the end
|
|
102
|
+
var circStack = stack.slice(stackIndexReference);
|
|
103
|
+
// For all the references in this list, add them to the list of references that end up in a circular reference
|
|
104
|
+
circStack.forEach(function (key) {
|
|
105
|
+
foundCirc[key] = true;
|
|
106
|
+
});
|
|
107
|
+
// Add our found circular reference to the end of the cycle
|
|
108
|
+
circStack.push(reference);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
toRet = compileValue({ value: toRet, stack, foundCirc, fullObj });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// if evaluated value is a number and equal to the reference, we want to keep the type
|
|
115
|
+
if (typeof ref === 'number' && ref.toString() === toRet) {
|
|
116
|
+
toRet = ref;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// if evaluated value is not a string or number, we want to keep the type
|
|
121
|
+
toRet = ref;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
toRet = ref;
|
|
126
|
+
}
|
|
127
|
+
stack.pop(variable);
|
|
128
|
+
return toRet;
|
|
129
|
+
});
|
|
130
|
+
return toRet;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { compileValue, resolveObject, traverseObject };
|
|
@@ -2,6 +2,7 @@ import kebabCase from 'lodash/kebabCase.js';
|
|
|
2
2
|
import '@aws-amplify/core/internals/utils';
|
|
3
3
|
import '../../utils/setUserAgent/constants.mjs';
|
|
4
4
|
import { isObject, has, isString } from '../../utils/utils.mjs';
|
|
5
|
+
import { usesReference } from '../../utils/references.mjs';
|
|
5
6
|
|
|
6
7
|
const CSS_VARIABLE_PREFIX = 'amplify';
|
|
7
8
|
/**
|
|
@@ -203,34 +204,5 @@ function deepExtend(objects, collision, path) {
|
|
|
203
204
|
}
|
|
204
205
|
return target;
|
|
205
206
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Checks if the value uses a value reference.
|
|
208
|
-
* @param {string} value
|
|
209
|
-
* @returns {boolean} - True, if the value uses a value reference
|
|
210
|
-
*/
|
|
211
|
-
function usesReference(value) {
|
|
212
|
-
const regex = new RegExp('\\{([^}]+)\\}', 'g');
|
|
213
|
-
if (typeof value === 'string') {
|
|
214
|
-
return regex.test(value);
|
|
215
|
-
}
|
|
216
|
-
if (typeof value === 'object') {
|
|
217
|
-
let hasReference = false;
|
|
218
|
-
// iterate over each property in the object,
|
|
219
|
-
// if any element passes the regex test,
|
|
220
|
-
// the whole thing should be true
|
|
221
|
-
for (const key in value) {
|
|
222
|
-
if (has(value, key)) {
|
|
223
|
-
const element = value[key];
|
|
224
|
-
let reference = usesReference(element);
|
|
225
|
-
if (reference) {
|
|
226
|
-
hasReference = true;
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return hasReference;
|
|
232
|
-
}
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
207
|
|
|
236
|
-
export { CSS_VARIABLE_PREFIX, cssNameTransform, cssValue, deepExtend, flattenProperties, isDesignToken, isShadowTokenObject, propsToString, referenceValue, setupToken, setupTokens
|
|
208
|
+
export { CSS_VARIABLE_PREFIX, cssNameTransform, cssValue, deepExtend, flattenProperties, isDesignToken, isShadowTokenObject, propsToString, referenceValue, setupToken, setupTokens };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { has } from './utils.mjs';
|
|
2
|
+
import { OPTIONS, REFERENCE_REGEX } from '../theme/createTheme/constants.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks if the value uses a value reference.
|
|
6
|
+
* @param {string} value
|
|
7
|
+
* @returns {boolean} - True, if the value uses a value reference
|
|
8
|
+
*/
|
|
9
|
+
function usesReference(value) {
|
|
10
|
+
const regex = new RegExp(REFERENCE_REGEX);
|
|
11
|
+
if (typeof value === 'string') {
|
|
12
|
+
return regex.test(value);
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === 'object') {
|
|
15
|
+
let hasReference = false;
|
|
16
|
+
// iterate over each property in the object,
|
|
17
|
+
// if any element passes the regex test,
|
|
18
|
+
// the whole thing should be true
|
|
19
|
+
for (const key in value) {
|
|
20
|
+
if (has(value, key)) {
|
|
21
|
+
const element = value[key];
|
|
22
|
+
let reference = usesReference(element);
|
|
23
|
+
if (reference) {
|
|
24
|
+
hasReference = true;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return hasReference;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
function resolveReference(path, obj) {
|
|
34
|
+
let ref = obj;
|
|
35
|
+
if (!Array.isArray(path)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
for (let i = 0; i < path.length; i++) {
|
|
39
|
+
// Check for undefined as 0 is a valid, truthy value
|
|
40
|
+
if (typeof ref[path[i]] !== 'undefined') {
|
|
41
|
+
ref = ref[path[i]];
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// set the reference as undefined if we don't find anything
|
|
45
|
+
ref = undefined;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return ref;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the path from a path name be splitting the name by a given separator.
|
|
53
|
+
*/
|
|
54
|
+
function getPathFromName(pathName) {
|
|
55
|
+
if (typeof pathName !== 'string') {
|
|
56
|
+
throw new Error('Getting path from name failed. Name must be a string');
|
|
57
|
+
}
|
|
58
|
+
return pathName.split(OPTIONS.separator);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns the paths name be joining its parts with a given separator.
|
|
62
|
+
*/
|
|
63
|
+
function getName(path) {
|
|
64
|
+
if (!path || !(path instanceof Array)) {
|
|
65
|
+
throw new Error('Getting name for path failed. Path must be an array');
|
|
66
|
+
}
|
|
67
|
+
return path.join(OPTIONS.separator);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { getName, getPathFromName, resolveReference, usesReference };
|
package/dist/esm/utils/utils.mjs
CHANGED
|
@@ -234,5 +234,22 @@ function splitObject(obj, predicate) {
|
|
|
234
234
|
});
|
|
235
235
|
return [left, right];
|
|
236
236
|
}
|
|
237
|
+
const cloneDeep = (obj) => {
|
|
238
|
+
if (obj === null || obj === undefined || typeof obj !== 'object') {
|
|
239
|
+
return obj;
|
|
240
|
+
}
|
|
241
|
+
if (obj instanceof Array) {
|
|
242
|
+
return obj.reduce((arr, item, i) => {
|
|
243
|
+
arr[i] = cloneDeep(item);
|
|
244
|
+
return arr;
|
|
245
|
+
}, []);
|
|
246
|
+
}
|
|
247
|
+
if (obj instanceof Object) {
|
|
248
|
+
return Object.keys(obj || {}).reduce((cpObj, key) => {
|
|
249
|
+
cpObj[key] = cloneDeep(obj[key]);
|
|
250
|
+
return cpObj;
|
|
251
|
+
}, {});
|
|
252
|
+
}
|
|
253
|
+
};
|
|
237
254
|
|
|
238
|
-
export { areEmptyArrays, areEmptyObjects, capitalize, classNameModifier, classNameModifierByFlag, groupLog, has, isEmpty, isEmptyObject, isFunction, isMap, isNil, isObject, isSet, isString, isUndefined, noop, sanitizeNamespaceImport, splitObject, templateJoin };
|
|
255
|
+
export { areEmptyArrays, areEmptyObjects, capitalize, classNameModifier, classNameModifierByFlag, cloneDeep, groupLog, has, isEmpty, isEmptyObject, isFunction, isMap, isNil, isObject, isSet, isString, isUndefined, noop, sanitizeNamespaceImport, splitObject, templateJoin };
|
package/dist/index.js
CHANGED
|
@@ -316,6 +316,23 @@ function splitObject(obj, predicate) {
|
|
|
316
316
|
});
|
|
317
317
|
return [left, right];
|
|
318
318
|
}
|
|
319
|
+
const cloneDeep = (obj) => {
|
|
320
|
+
if (obj === null || obj === undefined || typeof obj !== 'object') {
|
|
321
|
+
return obj;
|
|
322
|
+
}
|
|
323
|
+
if (obj instanceof Array) {
|
|
324
|
+
return obj.reduce((arr, item, i) => {
|
|
325
|
+
arr[i] = cloneDeep(item);
|
|
326
|
+
return arr;
|
|
327
|
+
}, []);
|
|
328
|
+
}
|
|
329
|
+
if (obj instanceof Object) {
|
|
330
|
+
return Object.keys(obj || {}).reduce((cpObj, key) => {
|
|
331
|
+
cpObj[key] = cloneDeep(obj[key]);
|
|
332
|
+
return cpObj;
|
|
333
|
+
}, {});
|
|
334
|
+
}
|
|
335
|
+
};
|
|
319
336
|
|
|
320
337
|
/**
|
|
321
338
|
* @example
|
|
@@ -448,6 +465,79 @@ function humanFileSize(bytes, si = false, dp = 1) {
|
|
|
448
465
|
return bytes.toFixed(dp) + ' ' + units[unit];
|
|
449
466
|
}
|
|
450
467
|
|
|
468
|
+
const OPTIONS = {
|
|
469
|
+
openingCharacter: '{',
|
|
470
|
+
closingCharacter: '}',
|
|
471
|
+
separator: '.',
|
|
472
|
+
};
|
|
473
|
+
const REFERENCE_REGEX = /\{([^}]+)\}/g;
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Checks if the value uses a value reference.
|
|
477
|
+
* @param {string} value
|
|
478
|
+
* @returns {boolean} - True, if the value uses a value reference
|
|
479
|
+
*/
|
|
480
|
+
function usesReference(value) {
|
|
481
|
+
const regex = new RegExp(REFERENCE_REGEX);
|
|
482
|
+
if (typeof value === 'string') {
|
|
483
|
+
return regex.test(value);
|
|
484
|
+
}
|
|
485
|
+
if (typeof value === 'object') {
|
|
486
|
+
let hasReference = false;
|
|
487
|
+
// iterate over each property in the object,
|
|
488
|
+
// if any element passes the regex test,
|
|
489
|
+
// the whole thing should be true
|
|
490
|
+
for (const key in value) {
|
|
491
|
+
if (has(value, key)) {
|
|
492
|
+
const element = value[key];
|
|
493
|
+
let reference = usesReference(element);
|
|
494
|
+
if (reference) {
|
|
495
|
+
hasReference = true;
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return hasReference;
|
|
501
|
+
}
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
function resolveReference(path, obj) {
|
|
505
|
+
let ref = obj;
|
|
506
|
+
if (!Array.isArray(path)) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
for (let i = 0; i < path.length; i++) {
|
|
510
|
+
// Check for undefined as 0 is a valid, truthy value
|
|
511
|
+
if (typeof ref[path[i]] !== 'undefined') {
|
|
512
|
+
ref = ref[path[i]];
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
// set the reference as undefined if we don't find anything
|
|
516
|
+
ref = undefined;
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return ref;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Returns the path from a path name be splitting the name by a given separator.
|
|
524
|
+
*/
|
|
525
|
+
function getPathFromName(pathName) {
|
|
526
|
+
if (typeof pathName !== 'string') {
|
|
527
|
+
throw new Error('Getting path from name failed. Name must be a string');
|
|
528
|
+
}
|
|
529
|
+
return pathName.split(OPTIONS.separator);
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Returns the paths name be joining its parts with a given separator.
|
|
533
|
+
*/
|
|
534
|
+
function getName(path) {
|
|
535
|
+
if (!path || !(path instanceof Array)) {
|
|
536
|
+
throw new Error('Getting name for path failed. Path must be an array');
|
|
537
|
+
}
|
|
538
|
+
return path.join(OPTIONS.separator);
|
|
539
|
+
}
|
|
540
|
+
|
|
451
541
|
/**
|
|
452
542
|
* Handles Amplify JS Auth hub events, by forwarding hub events as appropriate
|
|
453
543
|
* xstate events.
|
|
@@ -8649,35 +8739,6 @@ function deepExtend(objects, collision, path) {
|
|
|
8649
8739
|
}
|
|
8650
8740
|
return target;
|
|
8651
8741
|
}
|
|
8652
|
-
/**
|
|
8653
|
-
* Checks if the value uses a value reference.
|
|
8654
|
-
* @param {string} value
|
|
8655
|
-
* @returns {boolean} - True, if the value uses a value reference
|
|
8656
|
-
*/
|
|
8657
|
-
function usesReference(value) {
|
|
8658
|
-
const regex = new RegExp('\\{([^}]+)\\}', 'g');
|
|
8659
|
-
if (typeof value === 'string') {
|
|
8660
|
-
return regex.test(value);
|
|
8661
|
-
}
|
|
8662
|
-
if (typeof value === 'object') {
|
|
8663
|
-
let hasReference = false;
|
|
8664
|
-
// iterate over each property in the object,
|
|
8665
|
-
// if any element passes the regex test,
|
|
8666
|
-
// the whole thing should be true
|
|
8667
|
-
for (const key in value) {
|
|
8668
|
-
if (has(value, key)) {
|
|
8669
|
-
const element = value[key];
|
|
8670
|
-
let reference = usesReference(element);
|
|
8671
|
-
if (reference) {
|
|
8672
|
-
hasReference = true;
|
|
8673
|
-
break;
|
|
8674
|
-
}
|
|
8675
|
-
}
|
|
8676
|
-
}
|
|
8677
|
-
return hasReference;
|
|
8678
|
-
}
|
|
8679
|
-
return false;
|
|
8680
|
-
}
|
|
8681
8742
|
|
|
8682
8743
|
function addVars(selector, vars) {
|
|
8683
8744
|
if (!vars)
|
|
@@ -9059,6 +9120,132 @@ function createGlobalCSS(css) {
|
|
|
9059
9120
|
return cssText;
|
|
9060
9121
|
}
|
|
9061
9122
|
|
|
9123
|
+
const DEFAULTS = {
|
|
9124
|
+
ignoreKeys: ['original'],
|
|
9125
|
+
};
|
|
9126
|
+
function resolveObject(object) {
|
|
9127
|
+
const foundCirc = {};
|
|
9128
|
+
const clone = cloneDeep(object); // This object will be edited
|
|
9129
|
+
const currentContext = []; // To maintain the context to be able to test for circular definitions
|
|
9130
|
+
if (typeof object === 'object') {
|
|
9131
|
+
return traverseObject({
|
|
9132
|
+
slice: clone,
|
|
9133
|
+
fullObj: clone,
|
|
9134
|
+
currentContext,
|
|
9135
|
+
foundCirc,
|
|
9136
|
+
});
|
|
9137
|
+
}
|
|
9138
|
+
else {
|
|
9139
|
+
throw new Error('Please pass an object in');
|
|
9140
|
+
}
|
|
9141
|
+
}
|
|
9142
|
+
/**
|
|
9143
|
+
* Recursively traverses an object (slice) to resolve and uses
|
|
9144
|
+
* compileValue to replace any string references found within it
|
|
9145
|
+
*/
|
|
9146
|
+
function traverseObject({ slice, fullObj, currentContext, foundCirc, }) {
|
|
9147
|
+
for (let key in slice) {
|
|
9148
|
+
if (!has(slice, key)) {
|
|
9149
|
+
continue;
|
|
9150
|
+
}
|
|
9151
|
+
const prop = slice[key];
|
|
9152
|
+
// We want to check for ignoredKeys, this is to
|
|
9153
|
+
// skip over attributes that should not be
|
|
9154
|
+
// mutated, like a copy of the original property.
|
|
9155
|
+
if (DEFAULTS.ignoreKeys && DEFAULTS.ignoreKeys.indexOf(key) !== -1) {
|
|
9156
|
+
continue;
|
|
9157
|
+
}
|
|
9158
|
+
currentContext.push(key);
|
|
9159
|
+
if (typeof prop === 'object') {
|
|
9160
|
+
traverseObject({ currentContext, slice: prop, fullObj, foundCirc });
|
|
9161
|
+
}
|
|
9162
|
+
else {
|
|
9163
|
+
if (typeof prop === 'string' && prop.indexOf('{') > -1) {
|
|
9164
|
+
slice[key] = compileValue({
|
|
9165
|
+
value: prop,
|
|
9166
|
+
stack: [getName(currentContext)],
|
|
9167
|
+
foundCirc,
|
|
9168
|
+
fullObj,
|
|
9169
|
+
});
|
|
9170
|
+
}
|
|
9171
|
+
}
|
|
9172
|
+
currentContext.pop();
|
|
9173
|
+
}
|
|
9174
|
+
return fullObj;
|
|
9175
|
+
}
|
|
9176
|
+
/**
|
|
9177
|
+
* Resolves references in a value, performing recursive lookups when references are nested.
|
|
9178
|
+
* value: The string that may contain references (e.g., {color.border.light}) that need to be replaced
|
|
9179
|
+
* stack: keeps track of the current chain of references to detect circular references
|
|
9180
|
+
* foundCirc: stores any detected circular references
|
|
9181
|
+
* fullObj: The full object where references are looked up, essentially the source of all values
|
|
9182
|
+
*/
|
|
9183
|
+
function compileValue({ value, stack, foundCirc, fullObj }) {
|
|
9184
|
+
let toRet = value, ref;
|
|
9185
|
+
const regex = new RegExp(REFERENCE_REGEX);
|
|
9186
|
+
// Replace the reference inline, but don't replace the whole string because
|
|
9187
|
+
// references can be part of the value such as "1px solid {color.border.light}"
|
|
9188
|
+
value.replace(regex, function (match, variable) {
|
|
9189
|
+
variable = variable.trim();
|
|
9190
|
+
// Find what the value is referencing
|
|
9191
|
+
const pathName = getPathFromName(variable);
|
|
9192
|
+
const refHasValue = pathName[pathName.length - 1] === 'value';
|
|
9193
|
+
stack.push(variable);
|
|
9194
|
+
ref = resolveReference(pathName, fullObj);
|
|
9195
|
+
// If the reference doesn't end in 'value'
|
|
9196
|
+
// and
|
|
9197
|
+
// the reference points to someplace that has a `value` attribute
|
|
9198
|
+
// we should take the '.value' of the reference
|
|
9199
|
+
// per the W3C draft spec where references do not have .value
|
|
9200
|
+
// https://design-tokens.github.io/community-group/format/#aliases-references
|
|
9201
|
+
if (!refHasValue && ref && has(ref, 'value')) {
|
|
9202
|
+
ref = ref.value;
|
|
9203
|
+
}
|
|
9204
|
+
if (typeof ref !== 'undefined') {
|
|
9205
|
+
if (typeof ref === 'string' || typeof ref === 'number') {
|
|
9206
|
+
toRet = value.replace(match, ref);
|
|
9207
|
+
// Recursive, therefore we can compute multi-layer variables like a = b, b = c, eventually a = c
|
|
9208
|
+
if (usesReference(toRet)) {
|
|
9209
|
+
var reference = toRet.slice(1, -1);
|
|
9210
|
+
// Compare to found circular references
|
|
9211
|
+
if (has(foundCirc, reference)) ;
|
|
9212
|
+
else if (stack.indexOf(reference) !== -1) {
|
|
9213
|
+
// If the current stack already contains the current reference, we found a new circular reference
|
|
9214
|
+
// chop down only the circular part, save it to our circular reference info, and spit out an error
|
|
9215
|
+
// Get the position of the existing reference in the stack
|
|
9216
|
+
var stackIndexReference = stack.indexOf(reference);
|
|
9217
|
+
// Get the portion of the stack that starts at the circular reference and brings you through until the end
|
|
9218
|
+
var circStack = stack.slice(stackIndexReference);
|
|
9219
|
+
// For all the references in this list, add them to the list of references that end up in a circular reference
|
|
9220
|
+
circStack.forEach(function (key) {
|
|
9221
|
+
foundCirc[key] = true;
|
|
9222
|
+
});
|
|
9223
|
+
// Add our found circular reference to the end of the cycle
|
|
9224
|
+
circStack.push(reference);
|
|
9225
|
+
}
|
|
9226
|
+
else {
|
|
9227
|
+
toRet = compileValue({ value: toRet, stack, foundCirc, fullObj });
|
|
9228
|
+
}
|
|
9229
|
+
}
|
|
9230
|
+
// if evaluated value is a number and equal to the reference, we want to keep the type
|
|
9231
|
+
if (typeof ref === 'number' && ref.toString() === toRet) {
|
|
9232
|
+
toRet = ref;
|
|
9233
|
+
}
|
|
9234
|
+
}
|
|
9235
|
+
else {
|
|
9236
|
+
// if evaluated value is not a string or number, we want to keep the type
|
|
9237
|
+
toRet = ref;
|
|
9238
|
+
}
|
|
9239
|
+
}
|
|
9240
|
+
else {
|
|
9241
|
+
toRet = ref;
|
|
9242
|
+
}
|
|
9243
|
+
stack.pop(variable);
|
|
9244
|
+
return toRet;
|
|
9245
|
+
});
|
|
9246
|
+
return toRet;
|
|
9247
|
+
}
|
|
9248
|
+
|
|
9062
9249
|
const darkModeTokens = {
|
|
9063
9250
|
colors: {
|
|
9064
9251
|
red: {
|
|
@@ -9204,6 +9391,7 @@ exports.changePassword = changePassword;
|
|
|
9204
9391
|
exports.classNameModifier = classNameModifier;
|
|
9205
9392
|
exports.classNameModifierByFlag = classNameModifierByFlag;
|
|
9206
9393
|
exports.classNames = classNames;
|
|
9394
|
+
exports.cloneDeep = cloneDeep;
|
|
9207
9395
|
exports.countryDialCodes = countryDialCodes;
|
|
9208
9396
|
exports.createAuthenticatorMachine = createAuthenticatorMachine;
|
|
9209
9397
|
exports.createComponentCSS = createComponentCSS;
|
|
@@ -9211,6 +9399,7 @@ exports.createComponentClasses = createComponentClasses;
|
|
|
9211
9399
|
exports.createGlobalCSS = createGlobalCSS;
|
|
9212
9400
|
exports.createTheme = createTheme;
|
|
9213
9401
|
exports.cssNameTransform = cssNameTransform;
|
|
9402
|
+
exports.deepExtend = deepExtend;
|
|
9214
9403
|
exports.defaultAuthHubHandler = defaultAuthHubHandler;
|
|
9215
9404
|
exports.defaultDarkModeOverride = defaultDarkModeOverride;
|
|
9216
9405
|
exports.defaultFormFieldOptions = defaultFormFieldOptions;
|
|
@@ -9230,8 +9419,10 @@ exports.getErrors = getErrors;
|
|
|
9230
9419
|
exports.getFormDataFromEvent = getFormDataFromEvent;
|
|
9231
9420
|
exports.getFormFields = getFormFields;
|
|
9232
9421
|
exports.getLogger = getLogger;
|
|
9422
|
+
exports.getName = getName;
|
|
9233
9423
|
exports.getNextServiceContextFacade = getNextServiceContextFacade;
|
|
9234
9424
|
exports.getNextServiceFacade = getNextServiceFacade;
|
|
9425
|
+
exports.getPathFromName = getPathFromName;
|
|
9235
9426
|
exports.getPrimaryAlias = getPrimaryAlias;
|
|
9236
9427
|
exports.getSendEventAliases = getSendEventAliases;
|
|
9237
9428
|
exports.getServiceContextFacade = getServiceContextFacade;
|
|
@@ -9262,6 +9453,8 @@ exports.noop = noop;
|
|
|
9262
9453
|
exports.reactNativeDarkTokens = reactNativeDarkTokens;
|
|
9263
9454
|
exports.reactNativeTokens = reactNativeTokens;
|
|
9264
9455
|
exports.removeOrderKeys = removeOrderKeys;
|
|
9456
|
+
exports.resolveObject = resolveObject;
|
|
9457
|
+
exports.resolveReference = resolveReference;
|
|
9265
9458
|
exports.runFieldValidators = runFieldValidators;
|
|
9266
9459
|
exports.sanitizeNamespaceImport = sanitizeNamespaceImport;
|
|
9267
9460
|
exports.setFormOrder = setFormOrder;
|
|
@@ -9275,3 +9468,4 @@ exports.templateJoin = templateJoin;
|
|
|
9275
9468
|
exports.translate = translate;
|
|
9276
9469
|
exports.translations = translations;
|
|
9277
9470
|
exports.trimValues = trimValues;
|
|
9471
|
+
exports.usesReference = usesReference;
|
|
@@ -2,5 +2,6 @@ export { createTheme } from './createTheme';
|
|
|
2
2
|
export { defineComponentTheme } from './defineComponentTheme';
|
|
3
3
|
export { createComponentCSS } from './createComponentCSS';
|
|
4
4
|
export { createGlobalCSS } from './createGlobalCSS';
|
|
5
|
-
export { cssNameTransform, setupTokens, SetupToken,
|
|
5
|
+
export { cssNameTransform, deepExtend, isDesignToken, setupTokens, SetupToken, } from './utils';
|
|
6
6
|
export { createComponentClasses, ClassNameArgs, } from './createComponentClasses';
|
|
7
|
+
export { resolveObject } from './resolveObject';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare function resolveObject<T>(object: Record<string, any>): T;
|
|
2
|
+
/**
|
|
3
|
+
* Recursively traverses an object (slice) to resolve and uses
|
|
4
|
+
* compileValue to replace any string references found within it
|
|
5
|
+
*/
|
|
6
|
+
export declare function traverseObject<T>({ slice, fullObj, currentContext, foundCirc, }: {
|
|
7
|
+
slice: any;
|
|
8
|
+
fullObj: any;
|
|
9
|
+
currentContext: any;
|
|
10
|
+
foundCirc: any;
|
|
11
|
+
}): T;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves references in a value, performing recursive lookups when references are nested.
|
|
14
|
+
* value: The string that may contain references (e.g., {color.border.light}) that need to be replaced
|
|
15
|
+
* stack: keeps track of the current chain of references to detect circular references
|
|
16
|
+
* foundCirc: stores any detected circular references
|
|
17
|
+
* fullObj: The full object where references are looked up, essentially the source of all values
|
|
18
|
+
*/
|
|
19
|
+
export declare function compileValue({ value, stack, foundCirc, fullObj }: {
|
|
20
|
+
value: any;
|
|
21
|
+
stack: any;
|
|
22
|
+
foundCirc: any;
|
|
23
|
+
fullObj: any;
|
|
24
|
+
}): any;
|
|
@@ -63,7 +63,7 @@ type SetupTokensProps = {
|
|
|
63
63
|
* and perform the setupToken function on each token.
|
|
64
64
|
* Similar to what Style Dictionary does.
|
|
65
65
|
*/
|
|
66
|
-
export declare function setupTokens({ tokens, path, setupToken, }: SetupTokensProps): any
|
|
66
|
+
export declare function setupTokens({ tokens, path, setupToken, }: SetupTokensProps): Record<string, any>;
|
|
67
67
|
/**
|
|
68
68
|
* Takes an plain javascript object and will make a flat array of all the leaf nodes.
|
|
69
69
|
* A leaf node in this context has a 'value' property. Potentially refactor this to
|
|
@@ -83,10 +83,4 @@ export declare function flattenProperties(properties: object, to_ret?: object[])
|
|
|
83
83
|
* @returns {Object}
|
|
84
84
|
*/
|
|
85
85
|
export declare function deepExtend<T>(objects?: (object | undefined)[], collision?: Function, path?: string[]): T;
|
|
86
|
-
/**
|
|
87
|
-
* Checks if the value uses a value reference.
|
|
88
|
-
* @param {string} value
|
|
89
|
-
* @returns {boolean} - True, if the value uses a value reference
|
|
90
|
-
*/
|
|
91
|
-
export declare function usesReference(value: any): boolean;
|
|
92
86
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createTheme, defineComponentTheme, createComponentClasses, createComponentCSS, createGlobalCSS, cssNameTransform, isDesignToken, setupTokens, SetupToken, } from './createTheme';
|
|
1
|
+
export { createTheme, deepExtend, defineComponentTheme, createComponentClasses, createComponentCSS, createGlobalCSS, cssNameTransform, isDesignToken, resolveObject, setupTokens, SetupToken, } from './createTheme';
|
|
2
2
|
export { BaseComponentTheme } from './components';
|
|
3
3
|
export { defaultTheme } from './defaultTheme';
|
|
4
4
|
export { defaultDarkModeOverride, reactNativeDarkTokens, } from './defaultDarkModeOverride';
|
|
@@ -2,3 +2,4 @@ export { setUserAgent, SetUserAgentOptions } from './setUserAgent';
|
|
|
2
2
|
export * from './utils';
|
|
3
3
|
export { classNames, ClassNamesArgs } from './classNames';
|
|
4
4
|
export { humanFileSize } from './humanFileSize';
|
|
5
|
+
export { getName, getPathFromName, resolveReference, usesReference, } from './references';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the value uses a value reference.
|
|
3
|
+
* @param {string} value
|
|
4
|
+
* @returns {boolean} - True, if the value uses a value reference
|
|
5
|
+
*/
|
|
6
|
+
export declare function usesReference(value: unknown): boolean;
|
|
7
|
+
export declare function resolveReference(path: string[], obj: object): object;
|
|
8
|
+
/**
|
|
9
|
+
* Returns the path from a path name be splitting the name by a given separator.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getPathFromName(pathName: string): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Returns the paths name be joining its parts with a given separator.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getName(path: Array<string>): string;
|
|
@@ -146,3 +146,4 @@ export declare function groupLog(groupName: string, ...events: any[]): void;
|
|
|
146
146
|
* @returns
|
|
147
147
|
*/
|
|
148
148
|
export declare function splitObject(obj: Record<string, unknown>, predicate: (key: string) => boolean): readonly [Record<string, unknown>, Record<string, unknown>];
|
|
149
|
+
export declare const cloneDeep: (obj: unknown) => any;
|