@aws-amplify/ui-react 6.4.0 → 6.5.1

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.
Files changed (37) hide show
  1. package/dist/{Field-4b189104.js → Field-3db91851.js} +23 -12
  2. package/dist/{ThemeStyle-b2dce96a.js → ThemeStyle-7d5abbc4.js} +18 -12
  3. package/dist/esm/components/ThemeProvider/ComponentStyle.mjs +21 -0
  4. package/dist/esm/components/ThemeProvider/GlobalStyle.mjs +18 -0
  5. package/dist/esm/components/ThemeProvider/Style.mjs +62 -0
  6. package/dist/esm/components/ThemeProvider/ThemeStyle.mjs +7 -60
  7. package/dist/esm/server.mjs +2 -0
  8. package/dist/esm/version.mjs +1 -1
  9. package/dist/index.js +79 -80
  10. package/dist/internal.js +1 -2
  11. package/dist/server.js +61 -13
  12. package/dist/styles/breadcrumbs.css +4 -2
  13. package/dist/styles/breadcrumbs.layer.css +4 -2
  14. package/dist/styles/button.css +19 -10
  15. package/dist/styles/button.layer.css +19 -10
  16. package/dist/styles/input.css +3 -2
  17. package/dist/styles/input.layer.css +3 -2
  18. package/dist/styles/link.css +10 -5
  19. package/dist/styles/link.layer.css +10 -5
  20. package/dist/styles/reset.css +4 -1
  21. package/dist/styles/reset.layer.css +4 -1
  22. package/dist/styles/sliderField.css +3 -2
  23. package/dist/styles/sliderField.layer.css +3 -2
  24. package/dist/styles/textArea.css +3 -2
  25. package/dist/styles/textArea.layer.css +3 -2
  26. package/dist/styles.css +42 -23
  27. package/dist/styles.layer.css +42 -23
  28. package/dist/types/components/ThemeProvider/ComponentStyle.d.ts +22 -0
  29. package/dist/types/components/ThemeProvider/GlobalStyle.d.ts +20 -0
  30. package/dist/types/components/ThemeProvider/Style.d.ts +13 -0
  31. package/dist/types/components/ThemeProvider/ThemeStyle.d.ts +6 -4
  32. package/dist/types/primitives/shared/responsive/utils.d.ts +1 -1
  33. package/dist/types/server.d.ts +2 -0
  34. package/dist/types/version.d.ts +1 -1
  35. package/package.json +5 -4
  36. package/dist/primitiveWithForwardRef-7e929242.js +0 -36
  37. package/dist/types/primitives/Card/__test__/Card.test.d.ts +0 -1
@@ -5,7 +5,6 @@ var core = require('@aws-amplify/core');
5
5
  var auth = require('aws-amplify/auth');
6
6
  var uiReactCore = require('@aws-amplify/ui-react-core');
7
7
  var ui = require('@aws-amplify/ui');
8
- var primitiveWithForwardRef = require('./primitiveWithForwardRef-7e929242.js');
9
8
 
10
9
  function _interopNamespace(e) {
11
10
  if (e && e.__esModule) return e;
@@ -636,6 +635,17 @@ const useStyles = (props, style) => {
636
635
  }), [propStyles, style, breakpoints, breakpoint, tokens]);
637
636
  };
638
637
 
638
+ /**
639
+ * Updates the return type for primitives wrapped in `React.forwardRef` to
640
+ * `React.ReactElement`. In React 18 the return type of `React.ExoticComponent`
641
+ * was changed from `React.ReactElement` to `React.ReactNode`, which breaks
642
+ * clients using React 16 and 17.
643
+ *
644
+ * @param primitive UI Primitive to be wrapped with `React.forwardRef`
645
+ * @returns ForwaredRef wrapped UI Primitive
646
+ */
647
+ const primitiveWithForwardRef = (primitive) => React__namespace.forwardRef(primitive);
648
+
639
649
  const ViewPrimitive = ({ as = 'div', children, testId, ariaLabel, isDisabled, style, inert, ...rest }, ref) => {
640
650
  const { propStyles, nonStyleProps } = useStyles(rest, style);
641
651
  return React__namespace.createElement(as, {
@@ -651,7 +661,7 @@ const ViewPrimitive = ({ as = 'div', children, testId, ariaLabel, isDisabled, st
651
661
  /**
652
662
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/view)
653
663
  */
654
- const View = primitiveWithForwardRef.primitiveWithForwardRef(ViewPrimitive);
664
+ const View = primitiveWithForwardRef(ViewPrimitive);
655
665
  View.displayName = 'View';
656
666
 
657
667
  const defaultViewBox = { minX: 0, minY: 0, width: 24, height: 24 };
@@ -681,7 +691,7 @@ as = 'svg', fill = 'currentColor', pathData, viewBox = defaultViewBox, children,
681
691
  /**
682
692
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/icon)
683
693
  */
684
- const Icon = primitiveWithForwardRef.primitiveWithForwardRef(IconPrimitive);
694
+ const Icon = primitiveWithForwardRef(IconPrimitive);
685
695
  Icon.displayName = 'Icon';
686
696
 
687
697
  const IconsContext = React__namespace.createContext({});
@@ -994,7 +1004,7 @@ function useDropZone({ onDropComplete, onDragEnter: _onDragEnter, onDragLeave: _
994
1004
  const FieldGroupIconPrimitive = ({ className, children, isVisible = true, excludeFromTabOrder = false, ...rest }, ref) => {
995
1005
  return isVisible ? (React__namespace.createElement(View, { className: ui.classNames(ui.ComponentClassName.FieldGroupIcon, className), ref: ref, tabIndex: excludeFromTabOrder ? -1 : undefined, ...rest }, children)) : null;
996
1006
  };
997
- const FieldGroupIcon = primitiveWithForwardRef.primitiveWithForwardRef(FieldGroupIconPrimitive);
1007
+ const FieldGroupIcon = primitiveWithForwardRef(FieldGroupIconPrimitive);
998
1008
  FieldGroupIcon.displayName = 'FieldGroupIcon';
999
1009
 
1000
1010
  const FieldsetContext = React__namespace.createContext({
@@ -1011,7 +1021,7 @@ const FlexPrimitive = ({ className, children, ...rest }, ref) => (React__namespa
1011
1021
  /**
1012
1022
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/flex)
1013
1023
  */
1014
- const Flex = primitiveWithForwardRef.primitiveWithForwardRef(FlexPrimitive);
1024
+ const Flex = primitiveWithForwardRef(FlexPrimitive);
1015
1025
  Flex.displayName = 'Flex';
1016
1026
 
1017
1027
  const LINEAR_EMPTY = 'linear-empty';
@@ -1061,7 +1071,7 @@ const LoaderPrimitive = ({ className, filledColor, emptyColor, size, variation,
1061
1071
  /**
1062
1072
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/loader)
1063
1073
  */
1064
- const Loader = primitiveWithForwardRef.primitiveWithForwardRef(LoaderPrimitive);
1074
+ const Loader = primitiveWithForwardRef(LoaderPrimitive);
1065
1075
  Loader.displayName = 'Loader';
1066
1076
 
1067
1077
  // These variations support colorThemes. 'undefined' accounts for our
@@ -1085,11 +1095,11 @@ const ButtonPrimitive = ({ className, children, colorTheme, isFullWidth = false,
1085
1095
  /**
1086
1096
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/button)
1087
1097
  */
1088
- const Button = primitiveWithForwardRef.primitiveWithForwardRef(ButtonPrimitive);
1098
+ const Button = primitiveWithForwardRef(ButtonPrimitive);
1089
1099
  Button.displayName = 'Button';
1090
1100
 
1091
1101
  const FieldGroupIconButtonPrimitive = ({ children, className, ...rest }, ref) => (React__namespace.createElement(FieldGroupIcon, { as: Button, className: ui.classNames(ui.ComponentClassName.FieldGroupIconButton, className), ref: ref, ...rest }, children));
1092
- const FieldGroupIconButton = primitiveWithForwardRef.primitiveWithForwardRef(FieldGroupIconButtonPrimitive);
1102
+ const FieldGroupIconButton = primitiveWithForwardRef(FieldGroupIconButtonPrimitive);
1093
1103
  FieldGroupIconButton.displayName = 'FieldGroupIconButton';
1094
1104
 
1095
1105
  const ariaLabelText = ComponentText.Fields.clearButtonLabel;
@@ -1097,7 +1107,7 @@ const FieldClearButtonPrimitive = ({ ariaLabel = ariaLabelText, size, ...rest },
1097
1107
  const icons = useIcons('field');
1098
1108
  return (React__namespace.createElement(FieldGroupIconButton, { ariaLabel: ariaLabel, size: size, ref: ref, ...rest }, icons?.clear ?? React__namespace.createElement(IconClose, null)));
1099
1109
  };
1100
- const FieldClearButton = primitiveWithForwardRef.primitiveWithForwardRef(FieldClearButtonPrimitive);
1110
+ const FieldClearButton = primitiveWithForwardRef(FieldClearButtonPrimitive);
1101
1111
  FieldClearButton.displayName = 'FieldClearButton';
1102
1112
 
1103
1113
  const TextPrimitive = ({ as = 'p', className, children, isTruncated, variation, ...rest }, ref) => {
@@ -1107,7 +1117,7 @@ const TextPrimitive = ({ as = 'p', className, children, isTruncated, variation,
1107
1117
  /**
1108
1118
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/text)
1109
1119
  */
1110
- const Text = primitiveWithForwardRef.primitiveWithForwardRef(TextPrimitive);
1120
+ const Text = primitiveWithForwardRef(TextPrimitive);
1111
1121
  Text.displayName = 'Text';
1112
1122
 
1113
1123
  const QA_FIELD_DESCRIPTION = 'qa-field-description';
@@ -1126,7 +1136,7 @@ const LabelPrimitive = ({ children, className, visuallyHidden, ...rest }, ref) =
1126
1136
  [ui.ComponentClassName.VisuallyHidden]: visuallyHidden,
1127
1137
  }), ref: ref, ...rest }, children));
1128
1138
  };
1129
- const Label = primitiveWithForwardRef.primitiveWithForwardRef(LabelPrimitive);
1139
+ const Label = primitiveWithForwardRef(LabelPrimitive);
1130
1140
  Label.displayName = 'Label';
1131
1141
 
1132
1142
  const FieldPrimitive = (props, ref) => {
@@ -1137,7 +1147,7 @@ const FieldPrimitive = (props, ref) => {
1137
1147
  children,
1138
1148
  errorMessage ? (React__namespace.createElement(FieldErrorMessage, { hasError: hasError, errorMessage: errorMessage })) : null));
1139
1149
  };
1140
- const Field = primitiveWithForwardRef.primitiveWithForwardRef(FieldPrimitive);
1150
+ const Field = primitiveWithForwardRef(FieldPrimitive);
1141
1151
  Field.displayName = 'Field';
1142
1152
 
1143
1153
  exports.ARROW_DOWN = ARROW_DOWN;
@@ -1185,6 +1195,7 @@ exports.View = View;
1185
1195
  exports.getConsecutiveIntArray = getConsecutiveIntArray;
1186
1196
  exports.getStyleValue = getStyleValue;
1187
1197
  exports.getValueAtCurrentBreakpoint = getValueAtCurrentBreakpoint;
1198
+ exports.primitiveWithForwardRef = primitiveWithForwardRef;
1188
1199
  exports.strHasLength = strHasLength;
1189
1200
  exports.useAuth = useAuth;
1190
1201
  exports.useBreakpoint = useBreakpoint;
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var primitiveWithForwardRef = require('./primitiveWithForwardRef-7e929242.js');
5
4
 
6
5
  function _interopNamespace(e) {
7
6
  if (e && e.__esModule) return e;
@@ -23,10 +22,11 @@ function _interopNamespace(e) {
23
22
 
24
23
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
25
24
 
26
- const ThemeStylePrimitive = ({ theme, nonce, ...rest }, ref) => {
27
- if (!theme)
28
- return null;
29
- const { name, cssText } = theme;
25
+ /**
26
+ * @experimental
27
+ * [📖 Docs](https://ui.docs.amplify.aws/react/components/theme)
28
+ */
29
+ const Style = ({ cssText, ...rest }) => {
30
30
  /*
31
31
  Only inject theme CSS variables if given a theme.
32
32
  The CSS file users import already has the default theme variables in it.
@@ -72,20 +72,26 @@ const ThemeStylePrimitive = ({ theme, nonce, ...rest }, ref) => {
72
72
  Therefore, by only rendering CSS text which does not include a closing '</style>' tag,
73
73
  we ensure that the browser will correctly interpret all the text as CSS.
74
74
  */
75
- if (/<\/style/i.test(cssText)) {
75
+ if (cssText === undefined || /<\/style/i.test(cssText)) {
76
76
  return null;
77
77
  }
78
- else {
79
- return (React__namespace.createElement("style", { ...rest, ref: ref, id: `amplify-theme-${name}`,
80
- // eslint-disable-next-line react/no-danger
81
- dangerouslySetInnerHTML: { __html: cssText }, nonce: nonce }));
82
- }
78
+ return (React__namespace.createElement("style", { ...rest,
79
+ // eslint-disable-next-line react/no-danger
80
+ dangerouslySetInnerHTML: { __html: cssText } }));
83
81
  };
82
+ Style.displayName = 'Style';
83
+
84
84
  /**
85
85
  * @experimental
86
86
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/theme)
87
87
  */
88
- const ThemeStyle = primitiveWithForwardRef.primitiveWithForwardRef(ThemeStylePrimitive);
88
+ const ThemeStyle = ({ theme, ...rest }) => {
89
+ if (!theme)
90
+ return null;
91
+ const { name, cssText } = theme;
92
+ return React__namespace.createElement(Style, { ...rest, cssText: cssText, id: `amplify-theme-${name}` });
93
+ };
89
94
  ThemeStyle.displayName = 'ThemeStyle';
90
95
 
96
+ exports.Style = Style;
91
97
  exports.ThemeStyle = ThemeStyle;
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { createComponentCSS } from '@aws-amplify/ui';
3
+ import { Style } from './Style.mjs';
4
+
5
+ /**
6
+ * @experimental
7
+ * [📖 Docs](https://ui.docs.amplify.aws/react/components/theme)
8
+ */
9
+ const ComponentStyle = ({ theme, componentThemes = [], ...rest }) => {
10
+ if (!theme || !componentThemes.length) {
11
+ return null;
12
+ }
13
+ const cssText = createComponentCSS({
14
+ theme,
15
+ components: componentThemes,
16
+ });
17
+ return React.createElement(Style, { ...rest, cssText: cssText });
18
+ };
19
+ ComponentStyle.displayName = 'ComponentStyle';
20
+
21
+ export { ComponentStyle };
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ import { createGlobalCSS } from '@aws-amplify/ui';
3
+ import { Style } from './Style.mjs';
4
+
5
+ /**
6
+ * @experimental
7
+ * [📖 Docs](https://ui.docs.amplify.aws/react/components/theme)
8
+ */
9
+ const GlobalStyle = ({ styles, ...rest }) => {
10
+ if (!styles) {
11
+ return null;
12
+ }
13
+ const cssText = createGlobalCSS(styles);
14
+ return React.createElement(Style, { ...rest, cssText: cssText });
15
+ };
16
+ GlobalStyle.displayName = 'GlobalStyle';
17
+
18
+ export { GlobalStyle };
@@ -0,0 +1,62 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * @experimental
5
+ * [📖 Docs](https://ui.docs.amplify.aws/react/components/theme)
6
+ */
7
+ const Style = ({ cssText, ...rest }) => {
8
+ /*
9
+ Only inject theme CSS variables if given a theme.
10
+ The CSS file users import already has the default theme variables in it.
11
+ This will allow users to use the provider and theme with CSS variables
12
+ without having to worry about specificity issues because this stylesheet
13
+ will likely come after a user's defined CSS.
14
+
15
+ Q: Why are we using dangerouslySetInnerHTML?
16
+ A: We need to directly inject the theme's CSS string into the <style> tag without typical HTML escaping.
17
+ For example, JSX would escape characters meaningful in CSS such as ', ", < and >, thus breaking the CSS.
18
+ Q: Why not use a sanitization library such as DOMPurify?
19
+ A: For our use case, we specifically want to purify CSS text, *not* HTML.
20
+ DOMPurify, as well as any other HTML sanitization library, would escape/encode meaningful CSS characters
21
+ and break our CSS in the same way that JSX would.
22
+
23
+ Q: Are there any security risks in this particular use case?
24
+ A: Anything set inside of a <style> tag is always interpreted as CSS text, *not* HTML.
25
+ Reference: “Restrictions on the content of raw text elements” https://html.spec.whatwg.org/dev/syntax.html#cdata-rcdata-restrictions
26
+ And in our case, we are using dangerouslySetInnerHTML to set CSS text inside of a <style> tag.
27
+
28
+ Thus, it really comes down to the question: Could a malicious user escape from the context of the <style> tag?
29
+ For example, when inserting HTML into the DOM, could someone prematurely close the </style> tag and add a <script> tag?
30
+ e.g., </style><script>alert('hello')</script>
31
+ The answer depends on whether the code is rendered on the client or server side.
32
+
33
+ Client side
34
+ - To prevent XSS inside of the <style> tag, we need to make sure it's not closed prematurely.
35
+ - This is prevented by React because React creates a style DOM node (e.g., React.createElement(‘style’, ...)), and directly sets innerHTML as a string.
36
+ - Even if the string contains a closing </style> tag, it will still be interpreted as CSS text by the browser.
37
+ - Therefore, there is not an XSS vulnerability on the client side.
38
+
39
+ Server side
40
+ - When React code is rendered on the server side (e.g., NextJS), the code is sent to the browser as HTML text.
41
+ - Therefore, it *IS* possible to insert a closing </style> tag and escape the CSS context, which opens an XSS vulnerability.
42
+
43
+ Q: How are we mitigating the potential attack vector?
44
+ A: To fix this potential attack vector on the server side, we need to filter out any closing </style> tags,
45
+ as this the only way to escape from the context of the browser interpreting the text as CSS.
46
+ We also need to catch cases where there is any kind of whitespace character </style[HERE]>, such as tabs, carriage returns, etc:
47
+ </style
48
+
49
+ >
50
+ Therefore, by only rendering CSS text which does not include a closing '</style>' tag,
51
+ we ensure that the browser will correctly interpret all the text as CSS.
52
+ */
53
+ if (cssText === undefined || /<\/style/i.test(cssText)) {
54
+ return null;
55
+ }
56
+ return (React.createElement("style", { ...rest,
57
+ // eslint-disable-next-line react/no-danger
58
+ dangerouslySetInnerHTML: { __html: cssText } }));
59
+ };
60
+ Style.displayName = 'Style';
61
+
62
+ export { Style };
@@ -1,69 +1,16 @@
1
1
  import * as React from 'react';
2
- import { primitiveWithForwardRef } from '../../primitives/utils/primitiveWithForwardRef.mjs';
2
+ import { Style } from './Style.mjs';
3
3
 
4
- const ThemeStylePrimitive = ({ theme, nonce, ...rest }, ref) => {
5
- if (!theme)
6
- return null;
7
- const { name, cssText } = theme;
8
- /*
9
- Only inject theme CSS variables if given a theme.
10
- The CSS file users import already has the default theme variables in it.
11
- This will allow users to use the provider and theme with CSS variables
12
- without having to worry about specificity issues because this stylesheet
13
- will likely come after a user's defined CSS.
14
-
15
- Q: Why are we using dangerouslySetInnerHTML?
16
- A: We need to directly inject the theme's CSS string into the <style> tag without typical HTML escaping.
17
- For example, JSX would escape characters meaningful in CSS such as ', ", < and >, thus breaking the CSS.
18
- Q: Why not use a sanitization library such as DOMPurify?
19
- A: For our use case, we specifically want to purify CSS text, *not* HTML.
20
- DOMPurify, as well as any other HTML sanitization library, would escape/encode meaningful CSS characters
21
- and break our CSS in the same way that JSX would.
22
-
23
- Q: Are there any security risks in this particular use case?
24
- A: Anything set inside of a <style> tag is always interpreted as CSS text, *not* HTML.
25
- Reference: “Restrictions on the content of raw text elements” https://html.spec.whatwg.org/dev/syntax.html#cdata-rcdata-restrictions
26
- And in our case, we are using dangerouslySetInnerHTML to set CSS text inside of a <style> tag.
27
-
28
- Thus, it really comes down to the question: Could a malicious user escape from the context of the <style> tag?
29
- For example, when inserting HTML into the DOM, could someone prematurely close the </style> tag and add a <script> tag?
30
- e.g., </style><script>alert('hello')</script>
31
- The answer depends on whether the code is rendered on the client or server side.
32
-
33
- Client side
34
- - To prevent XSS inside of the <style> tag, we need to make sure it's not closed prematurely.
35
- - This is prevented by React because React creates a style DOM node (e.g., React.createElement(‘style’, ...)), and directly sets innerHTML as a string.
36
- - Even if the string contains a closing </style> tag, it will still be interpreted as CSS text by the browser.
37
- - Therefore, there is not an XSS vulnerability on the client side.
38
-
39
- Server side
40
- - When React code is rendered on the server side (e.g., NextJS), the code is sent to the browser as HTML text.
41
- - Therefore, it *IS* possible to insert a closing </style> tag and escape the CSS context, which opens an XSS vulnerability.
42
-
43
- Q: How are we mitigating the potential attack vector?
44
- A: To fix this potential attack vector on the server side, we need to filter out any closing </style> tags,
45
- as this the only way to escape from the context of the browser interpreting the text as CSS.
46
- We also need to catch cases where there is any kind of whitespace character </style[HERE]>, such as tabs, carriage returns, etc:
47
- </style
48
-
49
- >
50
- Therefore, by only rendering CSS text which does not include a closing '</style>' tag,
51
- we ensure that the browser will correctly interpret all the text as CSS.
52
- */
53
- if (/<\/style/i.test(cssText)) {
54
- return null;
55
- }
56
- else {
57
- return (React.createElement("style", { ...rest, ref: ref, id: `amplify-theme-${name}`,
58
- // eslint-disable-next-line react/no-danger
59
- dangerouslySetInnerHTML: { __html: cssText }, nonce: nonce }));
60
- }
61
- };
62
4
  /**
63
5
  * @experimental
64
6
  * [📖 Docs](https://ui.docs.amplify.aws/react/components/theme)
65
7
  */
66
- const ThemeStyle = primitiveWithForwardRef(ThemeStylePrimitive);
8
+ const ThemeStyle = ({ theme, ...rest }) => {
9
+ if (!theme)
10
+ return null;
11
+ const { name, cssText } = theme;
12
+ return React.createElement(Style, { ...rest, cssText: cssText, id: `amplify-theme-${name}` });
13
+ };
67
14
  ThemeStyle.displayName = 'ThemeStyle';
68
15
 
69
16
  export { ThemeStyle };
@@ -1,2 +1,4 @@
1
1
  export { ThemeStyle } from './components/ThemeProvider/ThemeStyle.mjs';
2
+ export { ComponentStyle } from './components/ThemeProvider/ComponentStyle.mjs';
3
+ export { GlobalStyle } from './components/ThemeProvider/GlobalStyle.mjs';
2
4
  export { createComponentClasses, createTheme, defaultDarkModeOverride, defaultTheme, defineComponentTheme } from '@aws-amplify/ui';
@@ -1,3 +1,3 @@
1
- const VERSION = '6.4.0';
1
+ const VERSION = '6.5.1';
2
2
 
3
3
  export { VERSION };