@aws-amplify/ui 6.0.17 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/i18n/dictionaries/authenticator/ja.mjs +2 -2
- package/dist/esm/i18n/dictionaries/authenticator/kr.mjs +10 -0
- package/dist/esm/index.mjs +5 -3
- package/dist/esm/theme/createTheme/createAnimationCSS.mjs +23 -0
- package/dist/esm/theme/createTheme/createColorPalette.mjs +21 -0
- package/dist/esm/theme/createTheme/createComponentCSS.mjs +86 -0
- package/dist/esm/theme/createTheme/createComponentClasses.mjs +60 -0
- package/dist/esm/theme/{createTheme.mjs → createTheme/createTheme.mjs} +33 -44
- package/dist/esm/theme/createTheme/defineComponentTheme.mjs +55 -0
- package/dist/esm/theme/createTheme/utils.mjs +236 -0
- package/dist/esm/utils/utils.mjs +21 -1
- package/dist/index.js +431 -37
- package/dist/types/theme/components/accordion.d.ts +4 -0
- package/dist/types/theme/components/alert.d.ts +4 -0
- package/dist/types/theme/components/autocomplete.d.ts +8 -0
- package/dist/types/theme/components/badge.d.ts +4 -0
- package/dist/types/theme/components/breadcrumbs.d.ts +7 -0
- package/dist/types/theme/components/button.d.ts +7 -0
- package/dist/types/theme/components/buttonGroup.d.ts +2 -0
- package/dist/types/theme/components/card.d.ts +2 -0
- package/dist/types/theme/components/checkbox.d.ts +7 -0
- package/dist/types/theme/components/checkboxField.d.ts +2 -0
- package/dist/types/theme/components/collection.d.ts +4 -0
- package/dist/types/theme/components/divider.d.ts +2 -0
- package/dist/types/theme/components/dropZone.d.ts +2 -0
- package/dist/types/theme/components/field.d.ts +6 -0
- package/dist/types/theme/components/fieldGroup.d.ts +11 -0
- package/dist/types/theme/components/fieldset.d.ts +4 -0
- package/dist/types/theme/components/heading.d.ts +4 -0
- package/dist/types/theme/components/highlightMatch.d.ts +4 -0
- package/dist/types/theme/components/index.d.ts +92 -0
- package/dist/types/theme/components/input.d.ts +2 -0
- package/dist/types/theme/components/loader.d.ts +4 -0
- package/dist/types/theme/components/menu.d.ts +4 -0
- package/dist/types/theme/components/message.d.ts +4 -0
- package/dist/types/theme/components/pagination.d.ts +4 -0
- package/dist/types/theme/components/placeholder.d.ts +2 -0
- package/dist/types/theme/components/radio.d.ts +6 -0
- package/dist/types/theme/components/rating.d.ts +5 -0
- package/dist/types/theme/components/scrollview.d.ts +2 -0
- package/dist/types/theme/components/searchField.d.ts +4 -0
- package/dist/types/theme/components/select.d.ts +5 -0
- package/dist/types/theme/components/selectField.d.ts +2 -0
- package/dist/types/theme/components/sliderField.d.ts +9 -0
- package/dist/types/theme/components/stepperField.d.ts +6 -0
- package/dist/types/theme/components/storageManager.d.ts +20 -0
- package/dist/types/theme/components/switchField.d.ts +8 -0
- package/dist/types/theme/components/table.d.ts +4 -0
- package/dist/types/theme/components/tabs.d.ts +6 -0
- package/dist/types/theme/components/text.d.ts +3 -0
- package/dist/types/theme/components/textField.d.ts +2 -0
- package/dist/types/theme/components/textarea.d.ts +2 -0
- package/dist/types/theme/components/textareaField.d.ts +2 -0
- package/dist/types/theme/components/toggleButton.d.ts +3 -0
- package/dist/types/theme/components/utils.d.ts +52 -0
- package/dist/types/theme/createTheme/createAnimationCSS.d.ts +6 -0
- package/dist/types/theme/createTheme/createColorPalette.d.ts +16 -0
- package/dist/types/theme/createTheme/createComponentCSS.d.ts +7 -0
- package/dist/types/theme/createTheme/createComponentClasses.d.ts +25 -0
- package/dist/types/theme/{createTheme.d.ts → createTheme/createTheme.d.ts} +3 -2
- package/dist/types/theme/createTheme/defineComponentTheme.d.ts +54 -0
- package/dist/types/theme/createTheme/index.d.ts +4 -0
- package/dist/types/theme/createTheme/utils.d.ts +92 -0
- package/dist/types/theme/index.d.ts +1 -2
- package/dist/types/theme/types.d.ts +20 -3
- package/dist/types/utils/classNames.d.ts +1 -1
- package/dist/types/utils/index.d.ts +1 -1
- package/dist/types/utils/utils.d.ts +8 -0
- package/package.json +3 -3
- package/dist/esm/theme/utils.mjs +0 -81
- package/dist/types/theme/utils.d.ts +0 -35
|
@@ -23,7 +23,7 @@ const jaDict = {
|
|
|
23
23
|
'Enter your Username': 'ユーザー名を入力 ',
|
|
24
24
|
'Forgot your password?': 'パスワードを忘れましたか? ',
|
|
25
25
|
'Hide password': 'パスワードを非表示',
|
|
26
|
-
'It may take a minute to arrive': '到着するまでに 1
|
|
26
|
+
'It may take a minute to arrive': '到着するまでに 1 分かかることがあります',
|
|
27
27
|
Loading: 'ロード中',
|
|
28
28
|
'New password': '新しいパスワード',
|
|
29
29
|
or: '又は',
|
|
@@ -53,7 +53,7 @@ const jaDict = {
|
|
|
53
53
|
Verify: '確認',
|
|
54
54
|
'We Sent A Code': 'コードが送信されました',
|
|
55
55
|
'We Texted You': 'テキストが送信されました',
|
|
56
|
-
'Your code is on the way. To log in, enter the code we sent you': '
|
|
56
|
+
'Your code is on the way. To log in, enter the code we sent you': 'コードが途中です。ログインするには、送信したコードを入力してください',
|
|
57
57
|
// Additional translations provided by customers
|
|
58
58
|
'An account with the given email already exists.': '入力されたメールアドレスのアカウントが既に存在します',
|
|
59
59
|
'Confirm a Code': 'コードを確認',
|
|
@@ -16,10 +16,19 @@ const krDict = {
|
|
|
16
16
|
'Creating Account': '회원가입중',
|
|
17
17
|
'Dismiss alert': '알림 무시',
|
|
18
18
|
Email: '이메일',
|
|
19
|
+
'Enter your Birthdate': '생년월일 입력',
|
|
19
20
|
'Enter your code': '인증번호를 입력해주세요',
|
|
21
|
+
'Enter your Confirmation Code': '확인 코드 입력',
|
|
20
22
|
'Enter your Email': '이메일 입력',
|
|
23
|
+
'Enter your Family Name': '성 입력',
|
|
24
|
+
'Enter your Given Name': '사용장 이름 입력',
|
|
25
|
+
'Enter your Name': '이름 입력',
|
|
26
|
+
'Enter your Nickname': '닉네임 입력',
|
|
27
|
+
'Enter your Password': '비밀번호 입력',
|
|
21
28
|
'Enter your phone number': '전화번호 입력',
|
|
29
|
+
'Enter your Preferred Username': '선호하는 아이디 입력',
|
|
22
30
|
'Enter your username': '아이디를 입력해주세요',
|
|
31
|
+
'Forgot password?': '비밀번호를 잊으셨나요?',
|
|
23
32
|
'Hide password': '비밀번호 숨기기',
|
|
24
33
|
'It may take a minute to arrive': '도착하는 데 1분 정도 걸릴 수 있습니다',
|
|
25
34
|
Loading: '로딩중',
|
|
@@ -27,6 +36,7 @@ const krDict = {
|
|
|
27
36
|
or: '또는',
|
|
28
37
|
Password: '비밀번호',
|
|
29
38
|
'Phone Number': '전화번호',
|
|
39
|
+
'Please confirm your Password': '비밀번호를 확인해 주세요.',
|
|
30
40
|
'Resend Code': '인증번호 재전송',
|
|
31
41
|
'Reset your password': '비밀번호 재설정',
|
|
32
42
|
'Reset your Password': '비밀번호 재설정',
|
package/dist/esm/index.mjs
CHANGED
|
@@ -14,15 +14,17 @@ export { getLogger } from './helpers/utils.mjs';
|
|
|
14
14
|
export { countryDialCodes } from './i18n/country-dial-codes.mjs';
|
|
15
15
|
export { DefaultTexts, hasTranslation, translate, translations } from './i18n/translations.mjs';
|
|
16
16
|
export { createAuthenticatorMachine } from './machines/authenticator/index.mjs';
|
|
17
|
-
export { createTheme } from './theme/createTheme.mjs';
|
|
17
|
+
export { createTheme } from './theme/createTheme/createTheme.mjs';
|
|
18
|
+
export { defineComponentTheme } from './theme/createTheme/defineComponentTheme.mjs';
|
|
19
|
+
export { cssNameTransform, isDesignToken, setupTokens } from './theme/createTheme/utils.mjs';
|
|
20
|
+
export { createComponentClasses } from './theme/createTheme/createComponentClasses.mjs';
|
|
18
21
|
export { defaultTheme } from './theme/defaultTheme.mjs';
|
|
19
22
|
export { defaultDarkModeOverride, reactNativeDarkTokens } from './theme/defaultDarkModeOverride.mjs';
|
|
20
23
|
export { reactNativeTokens } from './theme/tokens/index.mjs';
|
|
21
|
-
export { cssNameTransform, isDesignToken, setupTokens } from './theme/utils.mjs';
|
|
22
24
|
export { FederatedIdentityProviders, UnverifiedContactMethodType } from './types/authenticator/user.mjs';
|
|
23
25
|
export { isUnverifiedContactMethodType } from './types/authenticator/utils.mjs';
|
|
24
26
|
export { LoginMechanismArray, authFieldsWithDefaults, isAuthFieldsWithDefaults, signUpFieldsWithDefault, signUpFieldsWithoutDefault } from './types/authenticator/attributes.mjs';
|
|
25
27
|
export { ComponentClassName } from './types/primitives/componentClassName.mjs';
|
|
26
28
|
export { setUserAgent } from './utils/setUserAgent/setUserAgent.mjs';
|
|
27
|
-
export { areEmptyArrays, areEmptyObjects, capitalize, classNameModifier, classNameModifierByFlag, groupLog, has, isEmpty, isEmptyObject, isFunction, isMap, isNil, isObject, isSet, isString, isTypedFunction, isUndefined, noop, sanitizeNamespaceImport, templateJoin } from './utils/utils.mjs';
|
|
29
|
+
export { areEmptyArrays, areEmptyObjects, capitalize, classNameModifier, classNameModifierByFlag, groupLog, has, isEmpty, isEmptyObject, isFunction, isMap, isNil, isObject, isSet, isString, isTypedFunction, isUndefined, noop, sanitizeNamespaceImport, splitObject, templateJoin } from './utils/utils.mjs';
|
|
28
30
|
export { classNames } from './utils/classNames.mjs';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import '@aws-amplify/core/internals/utils';
|
|
2
|
+
import '../../utils/setUserAgent/constants.mjs';
|
|
3
|
+
import { isFunction } from '../../utils/utils.mjs';
|
|
4
|
+
import { propsToString } from './utils.mjs';
|
|
5
|
+
|
|
6
|
+
function createAnimationCSS({ animations, tokens, }) {
|
|
7
|
+
let cssText = '';
|
|
8
|
+
Object.entries(animations).forEach(([key, value]) => {
|
|
9
|
+
cssText += `\n @keyframes ${key} {`;
|
|
10
|
+
Object.entries(value).forEach(([step, properties]) => {
|
|
11
|
+
cssText += `\n ${step} {\n`;
|
|
12
|
+
const animationProperties = isFunction(properties)
|
|
13
|
+
? properties(tokens)
|
|
14
|
+
: properties;
|
|
15
|
+
cssText += propsToString(animationProperties);
|
|
16
|
+
cssText += `\n }`;
|
|
17
|
+
});
|
|
18
|
+
cssText += `\n }`;
|
|
19
|
+
});
|
|
20
|
+
return cssText;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { createAnimationCSS };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Takes a set of keys and a color name and returns an object of design tokens,
|
|
3
|
+
* used for applying a primary color at the theme level to our tokens.
|
|
4
|
+
*
|
|
5
|
+
* createColorPalette({keys: ['10','20',...], value: 'red'})
|
|
6
|
+
* returns {
|
|
7
|
+
* 10: { value: '{colors.red.10.value}' },
|
|
8
|
+
* 20: { value: '{colors.red.20.value}' },
|
|
9
|
+
* ...
|
|
10
|
+
* }
|
|
11
|
+
*/
|
|
12
|
+
function createColorPalette({ keys, value }) {
|
|
13
|
+
return keys.reduce((acc, key) => {
|
|
14
|
+
return {
|
|
15
|
+
...acc,
|
|
16
|
+
[key]: { value: `{colors.${value}.${key}.value}` },
|
|
17
|
+
};
|
|
18
|
+
}, {});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { createColorPalette };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { propsToString } from './utils.mjs';
|
|
2
|
+
import '@aws-amplify/core/internals/utils';
|
|
3
|
+
import '../../utils/setUserAgent/constants.mjs';
|
|
4
|
+
import { isFunction, splitObject } from '../../utils/utils.mjs';
|
|
5
|
+
|
|
6
|
+
function addVars(selector, vars) {
|
|
7
|
+
if (!vars)
|
|
8
|
+
return '';
|
|
9
|
+
return `${selector} { ${Object.entries(vars)
|
|
10
|
+
.map(([key, value]) => {
|
|
11
|
+
return `--${key}:${value}; `;
|
|
12
|
+
})
|
|
13
|
+
.join(' ')}}\n`;
|
|
14
|
+
}
|
|
15
|
+
function recursiveComponentCSS(baseSelector, theme) {
|
|
16
|
+
let str = '';
|
|
17
|
+
const { _modifiers = {}, _element = {}, _vars, ...props } = theme;
|
|
18
|
+
// if there are no props, skip
|
|
19
|
+
if (Object.keys(props).length) {
|
|
20
|
+
// separate psuedo/attribute selectors
|
|
21
|
+
const [selectors, other] = splitObject(props, (key) => key.startsWith(':') || key.startsWith('['));
|
|
22
|
+
Object.entries(selectors).forEach(([selector, value]) => {
|
|
23
|
+
// need to remove nested things like vars and elements
|
|
24
|
+
const { _modifiers = {}, _element = {}, _vars, ...props } = value;
|
|
25
|
+
str += `${baseSelector}${selector} { ${propsToString(props)} }\n`;
|
|
26
|
+
str += addVars(`${baseSelector}${selector}`, _vars);
|
|
27
|
+
});
|
|
28
|
+
str += `${baseSelector} { ${propsToString(other)} }\n`;
|
|
29
|
+
}
|
|
30
|
+
str += addVars(baseSelector, _vars);
|
|
31
|
+
Object.entries(_modifiers).forEach(([key, value]) => {
|
|
32
|
+
if (value && Object.keys(value).length) {
|
|
33
|
+
str += recursiveComponentCSS(`${baseSelector}--${key}`, value);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.entries(_element).forEach(([key, value]) => {
|
|
37
|
+
if (value && Object.keys(value).length) {
|
|
38
|
+
str += recursiveComponentCSS(`${baseSelector}__${key}`, value);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return str;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* This will take a component theme and create the appropriate CSS for it.
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
function createComponentCSS(themeName, components, tokens, breakpoints) {
|
|
48
|
+
let cssText = '';
|
|
49
|
+
components.forEach(({ name, theme, overrides }) => {
|
|
50
|
+
const baseComponentClassName = `amplify-${name}`;
|
|
51
|
+
const componentClassName = `[data-amplify-theme="${themeName}"] .${baseComponentClassName}`;
|
|
52
|
+
// unwrap the component theme
|
|
53
|
+
// if it is a function: call it with the defaultTheme to get a static object
|
|
54
|
+
const componentTheme = isFunction(theme)
|
|
55
|
+
? theme(tokens)
|
|
56
|
+
: theme;
|
|
57
|
+
cssText += recursiveComponentCSS(componentClassName, componentTheme);
|
|
58
|
+
// if the component theme has overrides
|
|
59
|
+
// generate the appropriate CSS for each of them
|
|
60
|
+
if (overrides) {
|
|
61
|
+
overrides.forEach((override) => {
|
|
62
|
+
// unwrap the override component theme just like above
|
|
63
|
+
const componentTheme = isFunction(override.theme)
|
|
64
|
+
? override.theme(tokens)
|
|
65
|
+
: override.theme;
|
|
66
|
+
if ('mediaQuery' in override) {
|
|
67
|
+
cssText += `@media (${override.mediaQuery}) {\n ${recursiveComponentCSS(componentClassName, componentTheme)} \n}`;
|
|
68
|
+
}
|
|
69
|
+
if ('breakpoint' in override) {
|
|
70
|
+
const breakpoint = breakpoints.values[override.breakpoint];
|
|
71
|
+
cssText += `\n@media (min-width: ${breakpoint}px) {\n ${recursiveComponentCSS(componentClassName, componentTheme)} \n}`;
|
|
72
|
+
}
|
|
73
|
+
if ('selector' in override) {
|
|
74
|
+
cssText += recursiveComponentCSS(`${override.selector} .${baseComponentClassName}`, componentTheme);
|
|
75
|
+
}
|
|
76
|
+
if ('colorMode' in override) {
|
|
77
|
+
cssText += `\n@media (prefers-color-scheme: ${override.colorMode}) {\n${recursiveComponentCSS(`[data-amplify-theme="${themeName}"][data-amplify-color-mode="system"] .${baseComponentClassName}`, componentTheme)}\n}\n`;
|
|
78
|
+
cssText += recursiveComponentCSS(`[data-amplify-theme="${themeName}"][data-amplify-color-mode="${override.colorMode}"] .${baseComponentClassName}`, componentTheme);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return cssText;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { createComponentCSS };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import '@aws-amplify/core/internals/utils';
|
|
2
|
+
import '../../utils/setUserAgent/constants.mjs';
|
|
3
|
+
import { isString, isObject } from '../../utils/utils.mjs';
|
|
4
|
+
import { classNames } from '../../utils/classNames.mjs';
|
|
5
|
+
|
|
6
|
+
function createComponentClasses({ name, prefix = 'amplify-' }) {
|
|
7
|
+
const className = (props = {}, extraClassnames = []) => {
|
|
8
|
+
const baseComponentClassName = `${prefix}${name}`;
|
|
9
|
+
// get the element if there is one
|
|
10
|
+
// the _element argument can be a string
|
|
11
|
+
// like { _element: 'icon' }
|
|
12
|
+
// or it could be an object where the key is
|
|
13
|
+
// the element name and the value is the modifiers
|
|
14
|
+
// like { _element: { icon: [size] } }
|
|
15
|
+
const element = isString(props._element)
|
|
16
|
+
? props._element
|
|
17
|
+
: isObject(props._element)
|
|
18
|
+
? Object.keys(props._element)[0]
|
|
19
|
+
: undefined;
|
|
20
|
+
const className = element
|
|
21
|
+
? `${baseComponentClassName}__${element}`
|
|
22
|
+
: baseComponentClassName;
|
|
23
|
+
const names = [className];
|
|
24
|
+
if (element) {
|
|
25
|
+
const modifiers = props._element[element];
|
|
26
|
+
names.push(...modifierClassnames({ className, modifiers }));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
names.push(...modifierClassnames({
|
|
30
|
+
className,
|
|
31
|
+
modifiers: props._modifiers,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
return classNames([...names, ...extraClassnames]);
|
|
35
|
+
};
|
|
36
|
+
return className;
|
|
37
|
+
}
|
|
38
|
+
function modifierClassnames({ className, modifiers, }) {
|
|
39
|
+
if (Array.isArray(modifiers)) {
|
|
40
|
+
return modifiers.map((modifier) => {
|
|
41
|
+
if (!modifier || !isString(modifier)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
return `${className}--${modifier}`;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (isObject(modifiers)) {
|
|
48
|
+
return Object.entries(modifiers).map(([key, value]) => {
|
|
49
|
+
if (value) {
|
|
50
|
+
return `${className}--${key}`;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (isString(modifiers)) {
|
|
55
|
+
return [`${className}--${modifiers}`];
|
|
56
|
+
}
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { createComponentClasses };
|
|
@@ -1,45 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import flattenProperties from '
|
|
3
|
-
import {
|
|
4
|
-
import { setupTokens, cssNameTransform, cssValue } from './utils.mjs';
|
|
1
|
+
import { defaultTheme } from '../defaultTheme.mjs';
|
|
2
|
+
import { deepExtend, setupTokens, setupToken, flattenProperties } from './utils.mjs';
|
|
3
|
+
import { createComponentCSS } from './createComponentCSS.mjs';
|
|
5
4
|
import '@aws-amplify/core/internals/utils';
|
|
6
|
-
import '
|
|
7
|
-
import { isString } from '
|
|
5
|
+
import '../../utils/setUserAgent/constants.mjs';
|
|
6
|
+
import { isString } from '../../utils/utils.mjs';
|
|
7
|
+
import { createColorPalette } from './createColorPalette.mjs';
|
|
8
|
+
import { createAnimationCSS } from './createAnimationCSS.mjs';
|
|
8
9
|
|
|
9
|
-
// Internal Style Dictionary methods
|
|
10
|
-
/**
|
|
11
|
-
* This will take a design token and add some data to it for it
|
|
12
|
-
* to be used in JS/CSS. It will create its CSS var name and update
|
|
13
|
-
* the value to use a CSS var if it is a reference. It will also
|
|
14
|
-
* add a `.toString()` method to make it easier to use in JS.
|
|
15
|
-
*
|
|
16
|
-
* We should see if there is a way to share this logic with style dictionary...
|
|
17
|
-
*/
|
|
18
|
-
const setupToken = ({ token, path }) => {
|
|
19
|
-
const name = `--${cssNameTransform({ path })}`;
|
|
20
|
-
const { value: original } = token;
|
|
21
|
-
const value = cssValue(token);
|
|
22
|
-
return { name, original, path, value, toString: () => `var(${name})` };
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* Takes a set of keys and a color name and returns an object of design tokens,
|
|
26
|
-
* used for applying a primary color at the theme level to our tokens.
|
|
27
|
-
*
|
|
28
|
-
* createColorPalette({keys: ['10','20',...], value: 'red'})
|
|
29
|
-
* returns {
|
|
30
|
-
* 10: { value: '{colors.red.10.value}' },
|
|
31
|
-
* 20: { value: '{colors.red.20.value}' },
|
|
32
|
-
* ...
|
|
33
|
-
* }
|
|
34
|
-
*/
|
|
35
|
-
function createColorPalette({ keys, value }) {
|
|
36
|
-
return keys.reduce((acc, key) => {
|
|
37
|
-
return {
|
|
38
|
-
...acc,
|
|
39
|
-
[key]: { value: `{colors.${value}.${key}.value}` },
|
|
40
|
-
};
|
|
41
|
-
}, {});
|
|
42
|
-
}
|
|
43
10
|
/**
|
|
44
11
|
* This will be used like `const myTheme = createTheme({})`
|
|
45
12
|
* `myTheme` can then be passed to a Provider or the generated CSS
|
|
@@ -52,7 +19,14 @@ function createTheme(theme, DefaultTheme = defaultTheme) {
|
|
|
52
19
|
// deepExtend is an internal Style Dictionary method
|
|
53
20
|
// that performs a deep merge on n objects. We could change
|
|
54
21
|
// this to another 3p deep merge solution too.
|
|
55
|
-
const mergedTheme = deepExtend([
|
|
22
|
+
const mergedTheme = deepExtend([
|
|
23
|
+
{},
|
|
24
|
+
DefaultTheme,
|
|
25
|
+
{
|
|
26
|
+
...theme,
|
|
27
|
+
components: {},
|
|
28
|
+
},
|
|
29
|
+
]);
|
|
56
30
|
const { primaryColor, secondaryColor } = mergedTheme;
|
|
57
31
|
// apply primaryColor and secondaryColor if present
|
|
58
32
|
if (isString(primaryColor)) {
|
|
@@ -83,7 +57,16 @@ function createTheme(theme, DefaultTheme = defaultTheme) {
|
|
|
83
57
|
.map((token) => `${token.name}: ${token.value};`)
|
|
84
58
|
.join('\n') +
|
|
85
59
|
`\n}\n`;
|
|
60
|
+
if (theme?.components) {
|
|
61
|
+
cssText += createComponentCSS(name, theme.components, tokens, mergedTheme.breakpoints);
|
|
62
|
+
}
|
|
86
63
|
let overrides = [];
|
|
64
|
+
if (mergedTheme.animations) {
|
|
65
|
+
cssText += createAnimationCSS({
|
|
66
|
+
animations: mergedTheme.animations,
|
|
67
|
+
tokens,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
87
70
|
/**
|
|
88
71
|
* For each override, we setup the tokens and then generate the CSS.
|
|
89
72
|
* This allows us to have one single CSS string for all possible overrides
|
|
@@ -91,11 +74,11 @@ function createTheme(theme, DefaultTheme = defaultTheme) {
|
|
|
91
74
|
*/
|
|
92
75
|
if (mergedTheme.overrides) {
|
|
93
76
|
overrides = mergedTheme.overrides.map((override) => {
|
|
94
|
-
const
|
|
77
|
+
const overrideTokens = setupTokens({
|
|
95
78
|
tokens: override.tokens,
|
|
96
79
|
setupToken,
|
|
97
80
|
});
|
|
98
|
-
const customProperties = flattenProperties(
|
|
81
|
+
const customProperties = flattenProperties(overrideTokens)
|
|
99
82
|
.map((token) => `${token.name}: ${token.value};`)
|
|
100
83
|
.join('\n');
|
|
101
84
|
// Overrides can have a selector, media query, breakpoint, or color mode
|
|
@@ -132,7 +115,7 @@ function createTheme(theme, DefaultTheme = defaultTheme) {
|
|
|
132
115
|
}
|
|
133
116
|
return {
|
|
134
117
|
...override,
|
|
135
|
-
tokens,
|
|
118
|
+
tokens: overrideTokens,
|
|
136
119
|
};
|
|
137
120
|
});
|
|
138
121
|
}
|
|
@@ -141,6 +124,12 @@ function createTheme(theme, DefaultTheme = defaultTheme) {
|
|
|
141
124
|
breakpoints,
|
|
142
125
|
name,
|
|
143
126
|
cssText,
|
|
127
|
+
containerProps: ({ colorMode } = {}) => {
|
|
128
|
+
return {
|
|
129
|
+
'data-amplify-theme': name,
|
|
130
|
+
'data-amplify-color-mode': colorMode,
|
|
131
|
+
};
|
|
132
|
+
},
|
|
144
133
|
// keep overrides separate from base theme
|
|
145
134
|
// this allows web platforms to use plain CSS scoped to a
|
|
146
135
|
// selector and only override the CSS vars needed. This
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createComponentClasses } from './createComponentClasses.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Use this to create the theme of a component. You can use this
|
|
5
|
+
* to both completely customize built-in components and
|
|
6
|
+
* build your own components!
|
|
7
|
+
*
|
|
8
|
+
* @experimental
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* // built-in component styling
|
|
12
|
+
* const alertTheme = defineComponentTheme({
|
|
13
|
+
* name: 'alert',
|
|
14
|
+
* theme: (tokens) => {
|
|
15
|
+
* return {
|
|
16
|
+
* padding: tokens.space.large
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // custom component styling
|
|
22
|
+
* const avatarTheme = defineComponentTheme({
|
|
23
|
+
* name: 'avatar',
|
|
24
|
+
* theme: (tokens) => {
|
|
25
|
+
* return {
|
|
26
|
+
* padding: tokens.space.large
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* const theme = createTheme({
|
|
32
|
+
* name: 'my-theme',
|
|
33
|
+
* components: [alertTheme, avatarTheme]
|
|
34
|
+
* })
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} params
|
|
38
|
+
* @param {string} params.name - The name of the component. Use a built-in component name like button to theme buttons.
|
|
39
|
+
* @returns
|
|
40
|
+
*/
|
|
41
|
+
function defineComponentTheme({ name, theme, overrides, }) {
|
|
42
|
+
const prefix = 'amplify-';
|
|
43
|
+
const className = createComponentClasses({
|
|
44
|
+
name,
|
|
45
|
+
prefix,
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
className,
|
|
49
|
+
theme,
|
|
50
|
+
overrides,
|
|
51
|
+
name,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { defineComponentTheme };
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import kebabCase from 'lodash/kebabCase.js';
|
|
2
|
+
import '@aws-amplify/core/internals/utils';
|
|
3
|
+
import '../../utils/setUserAgent/constants.mjs';
|
|
4
|
+
import { isObject, has, isString } from '../../utils/utils.mjs';
|
|
5
|
+
|
|
6
|
+
const CSS_VARIABLE_PREFIX = 'amplify';
|
|
7
|
+
/**
|
|
8
|
+
* This will take an object like:
|
|
9
|
+
* {paddingTop:'20px',color:'{colors.font.primary}'}
|
|
10
|
+
* and turn it into a CSS string:
|
|
11
|
+
* `padding-top:20px; color: var(--colors-font-primary);`
|
|
12
|
+
*/
|
|
13
|
+
function propsToString(props) {
|
|
14
|
+
return Object.entries(props)
|
|
15
|
+
.map(([key, value]) => {
|
|
16
|
+
const _value = isDesignToken(value)
|
|
17
|
+
? value.toString()
|
|
18
|
+
: // @ts-ignore
|
|
19
|
+
cssValue({ value });
|
|
20
|
+
return `${kebabCase(key)}:${_value}; `;
|
|
21
|
+
})
|
|
22
|
+
.join(' ');
|
|
23
|
+
}
|
|
24
|
+
function cssNameTransform({ path = [] }) {
|
|
25
|
+
return `${kebabCase([CSS_VARIABLE_PREFIX, ...path].join(' '))}`;
|
|
26
|
+
}
|
|
27
|
+
// Important: these properties should not be altered in
|
|
28
|
+
// order to maintain the expected order of the CSS `box-shadow` property
|
|
29
|
+
const SHADOW_PROPERTIES = [
|
|
30
|
+
'offsetX',
|
|
31
|
+
'offsetY',
|
|
32
|
+
'blurRadius',
|
|
33
|
+
'spreadRadius',
|
|
34
|
+
'color',
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Will take a design token in a theme and return its value as CSS
|
|
38
|
+
*
|
|
39
|
+
* @param token
|
|
40
|
+
* @returns
|
|
41
|
+
*/
|
|
42
|
+
function cssValue(token) {
|
|
43
|
+
const { value } = token;
|
|
44
|
+
if (isString(value)) {
|
|
45
|
+
return referenceValue(value);
|
|
46
|
+
}
|
|
47
|
+
if (isShadowTokenObject(value)) {
|
|
48
|
+
return SHADOW_PROPERTIES.map((property) => {
|
|
49
|
+
return referenceValue(
|
|
50
|
+
// lookup property against `token` first for custom non-nested value, then lookup
|
|
51
|
+
// property against `value` for design token value
|
|
52
|
+
isShadowTokenObject(token) ? token[property] : value[property]);
|
|
53
|
+
}).join(' ');
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Helper function to test if something is a design token or not.
|
|
59
|
+
* Used in the React component style props.
|
|
60
|
+
*
|
|
61
|
+
* @param value - thing to test if it is a design token or not
|
|
62
|
+
* @returns boolean
|
|
63
|
+
*/
|
|
64
|
+
function isDesignToken(value) {
|
|
65
|
+
return isObject(value) && has(value, 'value');
|
|
66
|
+
}
|
|
67
|
+
function isShadowTokenObject(value) {
|
|
68
|
+
return isObject(value) && has(value, 'offsetX');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Function that sees if a string contains a design token reference
|
|
72
|
+
* and if so will turn that into a CSS variable.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} value
|
|
75
|
+
* @returns string
|
|
76
|
+
*/
|
|
77
|
+
function referenceValue(value) {
|
|
78
|
+
if (!value)
|
|
79
|
+
return '';
|
|
80
|
+
if (usesReference(value)) {
|
|
81
|
+
const path = value.replace(/\{|\}/g, '').replace('.value', '').split('.');
|
|
82
|
+
return `var(--${cssNameTransform({ path })})`;
|
|
83
|
+
}
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* This will take a design token and add some data to it for it
|
|
88
|
+
* to be used in JS/CSS. It will create its CSS var name and update
|
|
89
|
+
* the value to use a CSS var if it is a reference. It will also
|
|
90
|
+
* add a `.toString()` method to make it easier to use in JS.
|
|
91
|
+
*
|
|
92
|
+
* We should see if there is a way to share this logic with style dictionary...
|
|
93
|
+
*/
|
|
94
|
+
const setupToken = ({ token, path }) => {
|
|
95
|
+
const name = `--${cssNameTransform({ path })}`;
|
|
96
|
+
const { value: original } = token;
|
|
97
|
+
const value = cssValue(token);
|
|
98
|
+
return { name, original, path, value, toString: () => `var(${name})` };
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Recursive function that will walk down the token object
|
|
102
|
+
* and perform the setupToken function on each token.
|
|
103
|
+
* Similar to what Style Dictionary does.
|
|
104
|
+
*/
|
|
105
|
+
function setupTokens({ tokens, path = [], setupToken, }) {
|
|
106
|
+
if (has(tokens, 'value')) {
|
|
107
|
+
return setupToken({ token: tokens, path });
|
|
108
|
+
}
|
|
109
|
+
const output = {};
|
|
110
|
+
for (const name in tokens) {
|
|
111
|
+
if (has(tokens, name)) {
|
|
112
|
+
const value = tokens[name];
|
|
113
|
+
const nextTokens = isObject(value) ? value : { value };
|
|
114
|
+
output[name] = setupTokens({
|
|
115
|
+
tokens: nextTokens,
|
|
116
|
+
path: path.concat(name),
|
|
117
|
+
setupToken,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return output;
|
|
122
|
+
}
|
|
123
|
+
// Internal Style Dictionary methods
|
|
124
|
+
// copied from amzn/style-dictionary with the owner's permission
|
|
125
|
+
/**
|
|
126
|
+
* Takes an plain javascript object and will make a flat array of all the leaf nodes.
|
|
127
|
+
* A leaf node in this context has a 'value' property. Potentially refactor this to
|
|
128
|
+
* be more generic.
|
|
129
|
+
* @private
|
|
130
|
+
* @param {Object} properties - The plain object you want flattened into an array.
|
|
131
|
+
* @param {Array} [to_ret=[]] - Properties array. This function is recursive therefore this is what gets passed along.
|
|
132
|
+
* @return {Array}
|
|
133
|
+
*/
|
|
134
|
+
function flattenProperties(properties, to_ret) {
|
|
135
|
+
to_ret = to_ret || [];
|
|
136
|
+
for (var name in properties) {
|
|
137
|
+
if (has(properties, name)) {
|
|
138
|
+
if (isObject(properties[name]) && 'value' in properties[name]) {
|
|
139
|
+
to_ret.push(properties[name]);
|
|
140
|
+
}
|
|
141
|
+
else if (isObject(properties[name])) {
|
|
142
|
+
flattenProperties(properties[name], to_ret);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return to_ret;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Performs an deep extend on the objects, from right to left.
|
|
150
|
+
* @private
|
|
151
|
+
* @param {Object[]} objects - An array of JS objects
|
|
152
|
+
* @param {Function} collision - A function to be called when a merge collision happens.
|
|
153
|
+
* @param {string[]} path - (for internal use) An array of strings which is the current path down the object when this is called recursively.
|
|
154
|
+
* @returns {Object}
|
|
155
|
+
*/
|
|
156
|
+
function deepExtend(objects, collision, path) {
|
|
157
|
+
if (objects == null)
|
|
158
|
+
return {};
|
|
159
|
+
var src, copyIsArray, copy, name, options, clone, target = objects[0] || {}, i = 1, length = objects.length;
|
|
160
|
+
path = path || [];
|
|
161
|
+
// Handle case when target is a string or something (possible in deep copy)
|
|
162
|
+
if (typeof target !== 'object') {
|
|
163
|
+
target = {};
|
|
164
|
+
}
|
|
165
|
+
for (; i < length; i++) {
|
|
166
|
+
// Only deal with non-null/undefined values
|
|
167
|
+
if ((options = objects[i]) != null) {
|
|
168
|
+
// Extend the base object
|
|
169
|
+
for (name in options) {
|
|
170
|
+
if (!has(options, name))
|
|
171
|
+
continue;
|
|
172
|
+
if (name === '__proto__')
|
|
173
|
+
continue;
|
|
174
|
+
src = target[name];
|
|
175
|
+
copy = options[name];
|
|
176
|
+
// Prevent never-ending loop
|
|
177
|
+
if (target === copy) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
// Recurse if we're merging plain objects or arrays
|
|
181
|
+
if (copy && (isObject(copy) || (copyIsArray = Array.isArray(copy)))) {
|
|
182
|
+
if (copyIsArray) {
|
|
183
|
+
copyIsArray = false;
|
|
184
|
+
clone = src && Array.isArray(src) ? src : [];
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
clone = src && isObject(src) ? src : {};
|
|
188
|
+
}
|
|
189
|
+
var nextPath = path.slice(0);
|
|
190
|
+
nextPath.push(name);
|
|
191
|
+
// Never move original objects, clone them
|
|
192
|
+
target[name] = deepExtend([clone, copy], collision, nextPath);
|
|
193
|
+
// Don't bring in undefined values
|
|
194
|
+
}
|
|
195
|
+
else if (copy !== undefined) {
|
|
196
|
+
if (src != null && typeof collision == 'function') {
|
|
197
|
+
collision({ target: target, copy: options, path: path, key: name });
|
|
198
|
+
}
|
|
199
|
+
target[name] = copy;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return target;
|
|
205
|
+
}
|
|
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
|
+
|
|
236
|
+
export { CSS_VARIABLE_PREFIX, cssNameTransform, cssValue, deepExtend, flattenProperties, isDesignToken, isShadowTokenObject, propsToString, referenceValue, setupToken, setupTokens, usesReference };
|