@telus-uds/components-base 1.71.0 → 1.73.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +37 -2
  2. package/lib/Box/Box.js +17 -6
  3. package/lib/ColourToggle/ColourBubble.js +135 -0
  4. package/lib/ColourToggle/ColourToggle.js +101 -0
  5. package/lib/ColourToggle/index.js +10 -0
  6. package/lib/FlexGrid/Col/Col.js +42 -19
  7. package/lib/FlexGrid/FlexGrid.js +40 -17
  8. package/lib/FlexGrid/Row/Row.js +45 -22
  9. package/lib/Listbox/ListboxGroup.js +7 -1
  10. package/lib/Modal/ModalContent.js +4 -6
  11. package/lib/MultiSelectFilter/MultiSelectFilter.js +1 -0
  12. package/lib/Notification/Notification.js +13 -5
  13. package/lib/OrderedList/Item.js +180 -0
  14. package/lib/OrderedList/ItemBase.js +54 -0
  15. package/lib/OrderedList/OrderedList.js +71 -0
  16. package/lib/OrderedList/OrderedListBase.js +47 -0
  17. package/lib/OrderedList/index.js +10 -0
  18. package/lib/Responsive/Responsive.js +24 -14
  19. package/lib/Responsive/ResponsiveProp.js +46 -0
  20. package/lib/Responsive/ResponsiveWithMediaQueryStyleSheet.js +72 -0
  21. package/lib/ThemeProvider/ThemeProvider.js +5 -2
  22. package/lib/ThemeProvider/index.js +9 -1
  23. package/lib/ThemeProvider/useResponsiveThemeTokens.js +89 -0
  24. package/lib/Typography/Typography.js +48 -22
  25. package/lib/index.js +16 -0
  26. package/lib/server.js +40 -0
  27. package/lib/utils/ssr-media-query/create-stylesheet/create-stylesheet-mobile.js +56 -0
  28. package/lib/utils/ssr-media-query/create-stylesheet/index.android.js +10 -0
  29. package/lib/utils/ssr-media-query/create-stylesheet/index.ios.js +10 -0
  30. package/lib/utils/ssr-media-query/create-stylesheet/index.js +44 -0
  31. package/lib/utils/ssr-media-query/utils/create-media-query-styles.js +39 -6
  32. package/lib-module/Box/Box.js +17 -6
  33. package/lib-module/ColourToggle/ColourBubble.js +125 -0
  34. package/lib-module/ColourToggle/ColourToggle.js +92 -0
  35. package/lib-module/ColourToggle/index.js +2 -0
  36. package/lib-module/FlexGrid/Col/Col.js +42 -19
  37. package/lib-module/FlexGrid/FlexGrid.js +40 -17
  38. package/lib-module/FlexGrid/Row/Row.js +45 -22
  39. package/lib-module/Listbox/ListboxGroup.js +7 -1
  40. package/lib-module/Modal/ModalContent.js +4 -6
  41. package/lib-module/MultiSelectFilter/MultiSelectFilter.js +1 -0
  42. package/lib-module/Notification/Notification.js +13 -5
  43. package/lib-module/OrderedList/Item.js +171 -0
  44. package/lib-module/OrderedList/ItemBase.js +43 -0
  45. package/lib-module/OrderedList/OrderedList.js +61 -0
  46. package/lib-module/OrderedList/OrderedListBase.js +36 -0
  47. package/lib-module/OrderedList/index.js +2 -0
  48. package/lib-module/Responsive/Responsive.js +24 -15
  49. package/lib-module/Responsive/ResponsiveProp.js +39 -0
  50. package/lib-module/Responsive/ResponsiveWithMediaQueryStyleSheet.js +64 -0
  51. package/lib-module/ThemeProvider/ThemeProvider.js +5 -2
  52. package/lib-module/ThemeProvider/index.js +1 -0
  53. package/lib-module/ThemeProvider/useResponsiveThemeTokens.js +81 -0
  54. package/lib-module/Typography/Typography.js +50 -24
  55. package/lib-module/index.js +2 -0
  56. package/lib-module/server.js +4 -0
  57. package/lib-module/utils/ssr-media-query/create-stylesheet/create-stylesheet-mobile.js +48 -0
  58. package/lib-module/utils/ssr-media-query/create-stylesheet/index.android.js +2 -0
  59. package/lib-module/utils/ssr-media-query/create-stylesheet/index.ios.js +2 -0
  60. package/lib-module/utils/ssr-media-query/create-stylesheet/index.js +36 -0
  61. package/lib-module/utils/ssr-media-query/utils/create-media-query-styles.js +36 -6
  62. package/package.json +13 -2
  63. package/src/Box/Box.jsx +35 -17
  64. package/src/ColourToggle/ColourBubble.jsx +111 -0
  65. package/src/ColourToggle/ColourToggle.jsx +83 -0
  66. package/src/ColourToggle/index.js +3 -0
  67. package/src/FlexGrid/Col/Col.jsx +42 -13
  68. package/src/FlexGrid/FlexGrid.jsx +40 -11
  69. package/src/FlexGrid/Row/Row.jsx +40 -16
  70. package/src/Listbox/ListboxGroup.jsx +9 -2
  71. package/src/Modal/ModalContent.jsx +4 -6
  72. package/src/MultiSelectFilter/MultiSelectFilter.jsx +2 -0
  73. package/src/Notification/Notification.jsx +15 -3
  74. package/src/OrderedList/Item.jsx +152 -0
  75. package/src/OrderedList/ItemBase.jsx +43 -0
  76. package/src/OrderedList/OrderedList.jsx +61 -0
  77. package/src/OrderedList/OrderedListBase.jsx +33 -0
  78. package/src/OrderedList/index.js +3 -0
  79. package/src/Responsive/Responsive.jsx +24 -11
  80. package/src/Responsive/ResponsiveProp.jsx +33 -0
  81. package/src/Responsive/ResponsiveWithMediaQueryStyleSheet.jsx +58 -0
  82. package/src/ThemeProvider/ThemeProvider.jsx +5 -2
  83. package/src/ThemeProvider/index.js +1 -0
  84. package/src/ThemeProvider/useResponsiveThemeTokens.js +85 -0
  85. package/src/Typography/Typography.jsx +72 -24
  86. package/src/index.js +2 -0
  87. package/src/server.js +4 -0
  88. package/src/utils/ssr-media-query/create-stylesheet/create-stylesheet-mobile.js +41 -0
  89. package/src/utils/ssr-media-query/create-stylesheet/index.android.js +3 -0
  90. package/src/utils/ssr-media-query/create-stylesheet/index.ios.js +3 -0
  91. package/src/utils/ssr-media-query/create-stylesheet/index.js +33 -0
  92. package/src/utils/ssr-media-query/utils/create-media-query-styles.js +21 -6
  93. package/types/Badge.d.ts +28 -0
  94. package/types/Box.d.ts +52 -0
  95. package/types/ChevronLink.d.ts +47 -0
  96. package/types/Common.d.ts +106 -0
  97. package/types/Divider.d.ts +19 -0
  98. package/types/ExpandCollapse.d.ts +65 -0
  99. package/types/HorizontalScrollButton.d.ts +16 -0
  100. package/types/Icon.d.ts +21 -0
  101. package/types/Link.d.ts +48 -0
  102. package/types/List.d.ts +48 -0
  103. package/types/Search.d.ts +38 -0
  104. package/types/Select.d.ts +57 -0
  105. package/types/Spacer.d.ts +5 -0
  106. package/types/StackView.d.ts +28 -0
  107. package/types/Tabs.d.ts +46 -0
  108. package/types/TextButton.d.ts +11 -0
  109. package/types/ToggleSwitch.d.ts +54 -0
  110. package/types/ToolTip.d.ts +40 -0
  111. package/types/Typography.d.ts +39 -0
  112. package/types/index.d.ts +62 -0
  113. package/lib/utils/ssr-media-query/create-stylesheet.js +0 -76
  114. package/lib-module/utils/ssr-media-query/create-stylesheet.js +0 -68
  115. package/src/utils/ssr-media-query/create-stylesheet.js +0 -61
@@ -2,10 +2,10 @@ import React, { forwardRef } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import Text from "react-native-web/dist/exports/Text";
4
4
  import View from "react-native-web/dist/exports/View";
5
- import { useTheme, useThemeTokens } from '../ThemeProvider';
6
- import { useViewport } from '../ViewportProvider';
5
+ import { useResponsiveThemeTokens, useTheme, useThemeTokens } from '../ThemeProvider';
7
6
  import { applyTextStyles } from '../ThemeProvider/utils';
8
- import { a11yProps, variantProp, getTokensPropType, getMaxFontMultiplier, headingTags, selectSystemProps, textTags, textProps, viewProps, getA11yPropsFromHtmlTag } from '../utils';
7
+ import { a11yProps, variantProp, getTokensPropType, getMaxFontMultiplier, headingTags, selectSystemProps, textTags, textProps, viewProps, getA11yPropsFromHtmlTag, StyleSheet, createMediaQueryStyles } from '../utils';
8
+ import { useViewport } from '../ViewportProvider';
9
9
  /**
10
10
  * @typedef {import('../utils/a11y/semantics').TextTag} TextTag
11
11
  */
@@ -21,7 +21,8 @@ const selectTextStyles = (_ref, themeOptions) => {
21
21
  fontName,
22
22
  textAlign,
23
23
  textTransform,
24
- letterSpacing
24
+ letterSpacing,
25
+ textDecorationLine
25
26
  } = _ref;
26
27
  return applyTextStyles({
27
28
  fontWeight,
@@ -32,7 +33,8 @@ const selectTextStyles = (_ref, themeOptions) => {
32
33
  themeOptions,
33
34
  textAlign,
34
35
  textTransform,
35
- letterSpacing
36
+ letterSpacing,
37
+ textDecorationLine
36
38
  });
37
39
  };
38
40
 
@@ -52,23 +54,48 @@ const Typography = /*#__PURE__*/forwardRef((_ref2, ref) => {
52
54
  ...rest
53
55
  } = _ref2;
54
56
  const viewport = useViewport();
55
- const {
56
- superScriptFontSize,
57
- ...themeTokens
58
- } = useThemeTokens('Typography', tokens, variant, {
59
- viewport
60
- });
61
57
  const {
62
58
  themeOptions
63
59
  } = useTheme();
60
+ const {
61
+ enableMediaQueryStyleSheet
62
+ } = themeOptions;
63
+ const useTokens = enableMediaQueryStyleSheet ? useResponsiveThemeTokens : useThemeTokens;
64
+ const themeTokens = useTokens('Typography', tokens, variant);
65
+ const maxFontSizeMultiplier = enableMediaQueryStyleSheet ? getMaxFontMultiplier(themeTokens[viewport]) : getMaxFontMultiplier(themeTokens);
66
+ const textDecorationLine = strikeThrough ? 'line-through' : 'none';
67
+ let textStyles;
68
+ let mediaIds;
69
+ if (enableMediaQueryStyleSheet) {
70
+ const transformedThemeTokens = Object.entries(themeTokens).reduce((acc, _ref3) => {
71
+ let [vp, viewportTokens] = _ref3;
72
+ acc[vp] = selectTextStyles({
73
+ textAlign: align,
74
+ textDecorationLine,
75
+ ...viewportTokens
76
+ }, themeOptions);
77
+ return acc;
78
+ }, {});
79
+ const mediaQueryStyles = createMediaQueryStyles(transformedThemeTokens);
80
+ const {
81
+ ids,
82
+ styles
83
+ } = StyleSheet.create({
84
+ text: mediaQueryStyles
85
+ });
86
+ textStyles = styles.text;
87
+ mediaIds = ids.text;
88
+ } else {
89
+ textStyles = selectTextStyles({
90
+ textAlign: align,
91
+ textDecorationLine,
92
+ ...themeTokens
93
+ }, themeOptions);
94
+ }
64
95
  const resolvedTextProps = {
65
96
  ...selectTextProps(rest),
66
- style: selectTextStyles(align ? {
67
- ...themeTokens,
68
- textAlign: align
69
- } : themeTokens, themeOptions),
70
97
  dataSet,
71
- maxFontSizeMultiplier: getMaxFontMultiplier(themeTokens)
98
+ maxFontSizeMultiplier
72
99
  };
73
100
  const containerProps = {
74
101
  accessibilityRole,
@@ -79,7 +106,7 @@ const Typography = /*#__PURE__*/forwardRef((_ref2, ref) => {
79
106
  if (typeof child === 'object' && ((child === null || child === void 0 ? void 0 : child.type) === 'sub' || (child === null || child === void 0 ? void 0 : child.type) === 'sup')) {
80
107
  var _child$props;
81
108
  const childStyles = (child === null || child === void 0 ? void 0 : (_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.style) || {};
82
- const supFontSize = childStyles.fontSize ?? superScriptFontSize;
109
+ const supFontSize = childStyles.fontSize ?? themeTokens.superScriptFontSize;
83
110
  const sanitizedChild = /*#__PURE__*/React.cloneElement(child, {
84
111
  style: {
85
112
  ...childStyles,
@@ -99,19 +126,15 @@ const Typography = /*#__PURE__*/forwardRef((_ref2, ref) => {
99
126
  }
100
127
  return resetTagStyling(children);
101
128
  };
102
- const textDecorationLine = strikeThrough ? 'line-through' : 'none';
103
- const textStyles = resolvedTextProps.style ? {
104
- ...resolvedTextProps.style,
105
- textDecorationLine
106
- } : {
107
- textDecorationLine
108
- };
109
129
  return block ? /*#__PURE__*/_jsx(View, {
110
130
  ref: ref,
111
131
  ...containerProps,
112
132
  children: /*#__PURE__*/_jsx(Text, {
113
133
  ...resolvedTextProps,
114
134
  style: textStyles,
135
+ dataSet: mediaIds && {
136
+ media: mediaIds
137
+ },
115
138
  children: sanitizeChildren(children)
116
139
  })
117
140
  }) : /*#__PURE__*/_jsx(Text, {
@@ -119,6 +142,9 @@ const Typography = /*#__PURE__*/forwardRef((_ref2, ref) => {
119
142
  ...containerProps,
120
143
  ...resolvedTextProps,
121
144
  style: textStyles,
145
+ dataSet: mediaIds && {
146
+ media: mediaIds
147
+ },
122
148
  children: sanitizeChildren(children)
123
149
  });
124
150
  });
@@ -11,6 +11,7 @@ export { default as Checkbox } from './Checkbox';
11
11
  export * from './Checkbox';
12
12
  export { default as CheckboxCard } from './CheckboxCard';
13
13
  export { default as CheckboxCardGroup } from './CheckboxCardGroup';
14
+ export { default as ColourToggle } from './ColourToggle';
14
15
  export { default as Divider } from './Divider';
15
16
  export { default as ExpandCollapse, Accordion } from './ExpandCollapse';
16
17
  export { default as Feedback } from './Feedback';
@@ -28,6 +29,7 @@ export { default as List, ListItem, ListBase } from './List';
28
29
  export { default as Modal } from './Modal';
29
30
  export { default as MultiSelectFilter } from './MultiSelectFilter';
30
31
  export { default as Notification } from './Notification';
32
+ export { default as OrderedList } from './OrderedList';
31
33
  export { default as Pagination } from './Pagination';
32
34
  export { default as Progress } from './Progress';
33
35
  export { default as QuickLinks } from './QuickLinks';
@@ -0,0 +1,4 @@
1
+ export { default as selectSystemProps } from './utils/props/selectSystemProps';
2
+ export { getTokensPropType } from './utils/props/tokens';
3
+ export { default as htmlAttrs } from './utils/htmlAttrs';
4
+ export { getComponentTheme, getThemeTokens } from './ThemeProvider/utils/theme-tokens';
@@ -0,0 +1,48 @@
1
+ import mediaQuery from 'css-mediaquery';
2
+ import Dimensions from "react-native-web/dist/exports/Dimensions";
3
+ import { isMediaOrPseudo, isMedia } from '../utils/common';
4
+ const createStyleSheet = stylesWithQuery => {
5
+ if (!stylesWithQuery) return {
6
+ ids: {},
7
+ styles: {},
8
+ fullStyles: {}
9
+ };
10
+ let cleanStyles;
11
+ const ids = {};
12
+ Object.keys(stylesWithQuery).forEach(key => {
13
+ if (!(stylesWithQuery !== null && stylesWithQuery !== void 0 && stylesWithQuery[key])) return;
14
+ const mediaQueriesAndPseudoClasses = Object.keys(stylesWithQuery[key]).filter(isMediaOrPseudo);
15
+ cleanStyles = JSON.parse(JSON.stringify(stylesWithQuery));
16
+ mediaQueriesAndPseudoClasses.forEach(str => {
17
+ if (isMedia(str)) {
18
+ const mqStr = str.replace('@media', '');
19
+ const {
20
+ width,
21
+ height
22
+ } = Dimensions.get('window');
23
+ const isMatchingMediaQuery = mediaQuery.match(mqStr, {
24
+ width,
25
+ height,
26
+ orientation: width > height ? 'landscape' : 'portrait',
27
+ 'aspect-ratio': width / height
28
+ });
29
+ if (isMatchingMediaQuery) {
30
+ cleanStyles = {
31
+ ...cleanStyles,
32
+ [key]: {
33
+ ...cleanStyles[key],
34
+ ...stylesWithQuery[key][str]
35
+ }
36
+ };
37
+ }
38
+ }
39
+ delete cleanStyles[key][str];
40
+ });
41
+ });
42
+ return {
43
+ ids,
44
+ styles: cleanStyles,
45
+ fullStyles: stylesWithQuery
46
+ };
47
+ };
48
+ export default createStyleSheet;
@@ -0,0 +1,2 @@
1
+ import createStyleSheet from './create-stylesheet-mobile';
2
+ export default createStyleSheet;
@@ -0,0 +1,2 @@
1
+ import createStyleSheet from './create-stylesheet-mobile';
2
+ export default createStyleSheet;
@@ -0,0 +1,36 @@
1
+ import { addCss } from '../utils/inject';
2
+ import createDeclarationBlock from '../utils/create-declaration-block';
3
+ import hash from '../hash';
4
+ import { isMediaOrPseudo, deepClone, createCssRule } from '../utils/common';
5
+ const createStyleSheet = stylesWithQuery => {
6
+ if (!stylesWithQuery) return {
7
+ ids: {},
8
+ styles: {},
9
+ fullStyles: {}
10
+ };
11
+ let cleanStyles;
12
+ let ids = {};
13
+ Object.keys(stylesWithQuery).forEach(key => {
14
+ if (!(stylesWithQuery !== null && stylesWithQuery !== void 0 && stylesWithQuery[key])) return;
15
+ const mediaQueriesAndPseudoClasses = Object.keys(stylesWithQuery[key]).filter(isMediaOrPseudo);
16
+ cleanStyles = deepClone(stylesWithQuery);
17
+ mediaQueriesAndPseudoClasses.forEach(query => {
18
+ var _ids;
19
+ const css = createDeclarationBlock(stylesWithQuery[key][query]);
20
+ const stringHash = `rnmq-${hash(`${key}${query}${css}`)}`;
21
+ const rule = createCssRule(query, stringHash, css);
22
+ addCss(`${stringHash}`, rule);
23
+ delete cleanStyles[key][query];
24
+ ids = {
25
+ ...ids,
26
+ [key]: `${(_ids = ids) !== null && _ids !== void 0 && _ids[key] ? `${ids[key]} ` : ''}${stringHash}`
27
+ };
28
+ });
29
+ });
30
+ return {
31
+ ids,
32
+ styles: cleanStyles,
33
+ fullStyles: stylesWithQuery
34
+ };
35
+ };
36
+ export default createStyleSheet;
@@ -1,21 +1,51 @@
1
1
  import { viewports } from '@telus-uds/system-constants';
2
+ const inherit = _ref => {
3
+ let {
4
+ xs,
5
+ sm = xs,
6
+ md = sm,
7
+ lg = md,
8
+ xl = lg
9
+ } = _ref;
10
+ return {
11
+ xs,
12
+ sm,
13
+ md,
14
+ lg,
15
+ xl
16
+ };
17
+ };
2
18
 
3
19
  /**
4
20
  * @typedef { Object } CssStyles
5
- * @typedef { Record<"xs" | "sm" | "md" | "lg" | "xl", CssStyles> } ViewportStyles
21
+ */
22
+
23
+ /**
24
+ * @typedef { Object } ViewportStyles
25
+ * @property { CssStyles } xs - The CSS styles for the "xs" viewport (required).
26
+ * @property { CssStyles } [sm] - Optional styles for the "sm" viewport. Inherits from "xs" if not specified.
27
+ * @property { CssStyles } [md] - Optional styles for the "md" viewport. Inherits from "sm" if not specified.
28
+ * @property { CssStyles } [lg] - Optional styles for the "lg" viewport. Inherits from "md" if not specified.
29
+ * @property { CssStyles } [xl] - Optional styles for the "xl" viewport. Inherits from "lg" if not specified.
30
+ */
31
+
32
+ /**
6
33
  * @typedef { Record<String, CssStyles> } MediaQueryStyles
7
34
  */
8
35
 
9
36
  /**
10
37
  * Generates media query styles based on specified viewport styles.
11
- * @param {ViewportStyles} viewportStyles
12
- * @returns { MediaQueryStyles }
38
+ * @param { Object } viewportStyles - The styles for different viewports.
39
+ * @param { boolean } [shouldInherit=true] - Flag indicating whether to inherit styles.
40
+ * @returns { Object } - The media query styles.
13
41
  */
14
42
 
15
43
  function createMediaQueryStyles(viewportStyles) {
16
- const viewportsArray = Object.keys(viewportStyles);
17
- const mediaQueries = Object.entries(viewportStyles).reduce((acc, _ref) => {
18
- let [viewport, styles] = _ref;
44
+ let shouldInherit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
45
+ const effectiveStyles = shouldInherit ? inherit(viewportStyles) : viewportStyles;
46
+ const viewportsArray = viewports.keys;
47
+ const mediaQueries = Object.entries(effectiveStyles).reduce((acc, _ref2) => {
48
+ let [viewport, styles] = _ref2;
19
49
  const minWidth = viewports.map.get(viewport);
20
50
  const nextViewport = viewportsArray[viewportsArray.indexOf(viewport) + 1];
21
51
  const maxWidth = viewports.map.get(nextViewport);
package/package.json CHANGED
@@ -11,9 +11,10 @@
11
11
  "@floating-ui/react-native": "^0.8.1",
12
12
  "@gorhom/portal": "^1.0.14",
13
13
  "@telus-uds/system-constants": "^1.3.0",
14
- "@telus-uds/system-theme-tokens": "^2.47.0",
14
+ "@telus-uds/system-theme-tokens": "^2.49.0",
15
15
  "airbnb-prop-types": "^2.16.0",
16
16
  "css-mediaquery": "^0.1.2",
17
+ "expo-linear-gradient": "^12.5.0",
17
18
  "lodash.debounce": "^4.0.8",
18
19
  "lodash.merge": "^4.6.2",
19
20
  "lodash.throttle": "^4.1.1",
@@ -38,6 +39,16 @@
38
39
  "lib": "lib",
39
40
  "test": "__tests__"
40
41
  },
42
+ "exports": {
43
+ ".": {
44
+ "import": "./lib-module/index.js",
45
+ "require": "./lib/index.js"
46
+ },
47
+ "./server": {
48
+ "import": "./lib-module/server.js",
49
+ "require": "./lib/server.js"
50
+ }
51
+ },
41
52
  "homepage": "https://github.com/telus/universal-design-system#readme",
42
53
  "keywords": [
43
54
  "base"
@@ -74,5 +85,5 @@
74
85
  "standard-engine": {
75
86
  "skip": true
76
87
  },
77
- "version": "1.71.0"
88
+ "version": "1.73.0"
78
89
  }
package/src/Box/Box.jsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { View, ScrollView } from 'react-native'
3
+ import { View, ScrollView, Platform } from 'react-native'
4
4
  import { useThemeTokens } from '../ThemeProvider'
5
5
  import {
6
6
  a11yProps,
@@ -23,17 +23,20 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
23
23
  * @typedef {import('../utils/props/spacingProps.js').SpacingOptions} SpacingOptions
24
24
  */
25
25
 
26
- const selectBoxStyles = ({
27
- backgroundColor,
28
- gradient,
29
- borderWidth,
30
- borderColor,
31
- borderTopLeftRadius,
32
- borderTopRightRadius,
33
- borderBottomLeftRadius,
34
- borderBottomRightRadius,
35
- ...rest
36
- }) => {
26
+ const selectBoxStyles = (
27
+ {
28
+ backgroundColor,
29
+ gradient,
30
+ borderWidth,
31
+ borderColor,
32
+ borderTopLeftRadius,
33
+ borderTopRightRadius,
34
+ borderBottomLeftRadius,
35
+ borderBottomRightRadius,
36
+ ...rest
37
+ },
38
+ customGradient
39
+ ) => {
37
40
  const styles = {
38
41
  backgroundColor,
39
42
  borderWidth,
@@ -48,7 +51,12 @@ const selectBoxStyles = ({
48
51
  angle,
49
52
  stops: [stopOne, stopTwo]
50
53
  } = gradient
51
- styles.backgroundImage = `linear-gradient(${angle}deg, ${stopOne.color}, 75% , ${stopTwo.color})`
54
+
55
+ if (Platform.OS === 'web') {
56
+ styles.backgroundImage = `linear-gradient(${angle}deg, ${stopOne.color}, 75%, ${stopTwo.color})`
57
+ } else if (customGradient && Platform.OS !== 'web') {
58
+ styles.colors = [stopOne.color, stopTwo.color]
59
+ }
52
60
  }
53
61
 
54
62
  const paddings = ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom']
@@ -145,6 +153,7 @@ const Box = forwardRef(
145
153
  accessibilityRole,
146
154
  testID,
147
155
  dataSet,
156
+ customGradient,
148
157
  ...rest
149
158
  },
150
159
  ref
@@ -162,21 +171,26 @@ const Box = forwardRef(
162
171
  paddingRight: useSpacingScale(right),
163
172
  paddingTop: useSpacingScale(top),
164
173
  paddingBottom: useSpacingScale(bottom),
165
- ...selectBoxStyles(themeTokens)
174
+ ...selectBoxStyles(themeTokens, customGradient)
166
175
  }
167
176
 
177
+ const childrenToRender =
178
+ typeof customGradient === 'function'
179
+ ? customGradient(styles.colors, styles)(children)
180
+ : children
181
+
168
182
  if (scroll) {
169
183
  const scrollProps = typeof scroll === 'object' ? scroll : {}
170
184
  scrollProps.contentContainerStyle = [styles, scrollProps.contentContainerStyle]
171
185
  return (
172
186
  <ScrollView {...scrollProps} {...props} testID={testID} dataSet={dataSet} ref={ref}>
173
- {children}
187
+ {childrenToRender}
174
188
  </ScrollView>
175
189
  )
176
190
  }
177
191
  return (
178
192
  <View {...props} style={styles} testID={testID} dataSet={dataSet} ref={ref}>
179
- {children}
193
+ {childrenToRender}
180
194
  </View>
181
195
  )
182
196
  }
@@ -266,7 +280,11 @@ Box.propTypes = {
266
280
  /**
267
281
  * Box accepts any content as children.
268
282
  */
269
- children: PropTypes.node.isRequired
283
+ children: PropTypes.node.isRequired,
284
+ /**
285
+ Use this prop if need to add a custom gradient for mobile
286
+ */
287
+ customGradient: PropTypes.func
270
288
  }
271
289
 
272
290
  export default Box
@@ -0,0 +1,111 @@
1
+ import React, { forwardRef, useMemo } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { View, Pressable, Platform } from 'react-native'
5
+ import { resolvePressableTokens } from '../utils/pressability'
6
+ import { applyShadowToken } from '../ThemeProvider'
7
+
8
+ const selectGeneralBubbleTokens = ({
9
+ outerBubbleHeight,
10
+ outerBubbleWidth,
11
+ outerBubbleContentAlignItems,
12
+ outerBubbleJustifyContent,
13
+ bubbleBorderColor,
14
+ bubbleBorderWidth,
15
+ bubbleBorderRadius
16
+ }) => ({
17
+ height: outerBubbleHeight,
18
+ width: outerBubbleWidth,
19
+ justifyContent: outerBubbleContentAlignItems,
20
+ alignItems: outerBubbleJustifyContent,
21
+ borderColor: bubbleBorderColor,
22
+ borderWidth: bubbleBorderWidth,
23
+ borderRadius: bubbleBorderRadius,
24
+ ...Platform.select({ web: { outline: 'none' } })
25
+ })
26
+
27
+ const selectInnerBubbleTokens = ({
28
+ innerBubbleHeight,
29
+ innerBubbleWidth,
30
+ innerBubbleBorderRadius,
31
+ borderColor,
32
+ borderWidth,
33
+ shadow
34
+ }) => ({
35
+ height: innerBubbleHeight,
36
+ width: innerBubbleWidth,
37
+ borderRadius: innerBubbleBorderRadius,
38
+ borderColor,
39
+ borderWidth,
40
+ ...applyShadowToken(shadow)
41
+ })
42
+
43
+ const selectBorderBubbleTokens = ({
44
+ bubbleBorderColor,
45
+ bubbleBorderWidth,
46
+ bubbleBorderRadius
47
+ }) => ({
48
+ borderColor: bubbleBorderColor,
49
+ borderWidth: bubbleBorderWidth,
50
+ borderRadius: bubbleBorderRadius
51
+ })
52
+
53
+ const ColourBubble = forwardRef(
54
+ ({ tokens = {}, id, colourHexCode, colourName, isSelected, onPress }, ref) => {
55
+ const defaultTokens = tokens({ selected: isSelected })
56
+
57
+ const resolveColourBubbleTokens = (pressState) => resolvePressableTokens(tokens, pressState, {})
58
+
59
+ const themeTokens = useMemo(() => tokens(), [tokens])
60
+
61
+ return (
62
+ <Pressable
63
+ style={(state) => [
64
+ selectGeneralBubbleTokens(resolveColourBubbleTokens(state)),
65
+ isSelected && selectBorderBubbleTokens(defaultTokens)
66
+ ]}
67
+ onPress={onPress}
68
+ accessible
69
+ accessibilityRole="radio"
70
+ accessibilityLabel={colourName}
71
+ accessibilityState={{ checked: isSelected }}
72
+ ref={ref}
73
+ testID={id}
74
+ >
75
+ <View style={[selectInnerBubbleTokens(themeTokens), { backgroundColor: colourHexCode }]} />
76
+ </Pressable>
77
+ )
78
+ }
79
+ )
80
+ ColourBubble.displayName = 'ColourBubble'
81
+
82
+ ColourBubble.propTypes = {
83
+ /**
84
+ * Colour toggle tokens callback.
85
+ */
86
+ tokens: PropTypes.func,
87
+ /**
88
+ * ID of each colour bubble
89
+ */
90
+ id: PropTypes.string,
91
+ /**
92
+ * Hexadecimal code for the background of the colour bubble
93
+ */
94
+ colourHexCode: PropTypes.string,
95
+ /**
96
+ * Name of the colour bubble
97
+ */
98
+ colourName: PropTypes.string,
99
+ /**
100
+ * If the current colour bubble is selected
101
+ */
102
+ isSelected: PropTypes.bool,
103
+ /**
104
+ * If provided, this function is called when the current selection
105
+ * of the color is changed of all currently `items`.
106
+ * Receives two parameters: item object selected and the event
107
+ */
108
+ onPress: PropTypes.func
109
+ }
110
+
111
+ export default ColourBubble
@@ -0,0 +1,83 @@
1
+ import React, { forwardRef, useState } from 'react'
2
+ import { View } from 'react-native'
3
+ import PropTypes from 'prop-types'
4
+
5
+ import { useThemeTokensCallback } from '../ThemeProvider'
6
+ import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils'
7
+ import { StackWrap } from '../StackView'
8
+ import Typography from '../Typography'
9
+ import ColourBubble from './ColourBubble'
10
+
11
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
12
+
13
+ const ColourToggle = forwardRef(
14
+ ({ tokens, variant, defaultColourId, items, onChange, ...rest }, ref) => {
15
+ const [currentColourId, setCurrentColourId] = useState(defaultColourId)
16
+ const getTokens = useThemeTokensCallback('ColourToggle', tokens, variant)
17
+
18
+ const { space } = getTokens()
19
+ const { colourName: currentColourName = '' } =
20
+ items.find((item) => item.id === currentColourId) || ''
21
+
22
+ return (
23
+ <View ref={ref} {...selectProps(rest)}>
24
+ <Typography>{currentColourName}</Typography>
25
+ <StackWrap space={space} accessibilityRole="radiogroup">
26
+ {items.map(({ id, colourHexCode, colourName }, index) => {
27
+ const colourBubbleId = id || `ColourBubble[${index}]`
28
+
29
+ const handleChangeColour = (event) => {
30
+ setCurrentColourId(id)
31
+ onChange?.(event, { id, colourHexCode, colourName })
32
+ }
33
+
34
+ return (
35
+ <ColourBubble
36
+ key={colourBubbleId}
37
+ id={colourBubbleId}
38
+ tokens={getTokens}
39
+ isSelected={id === currentColourId}
40
+ colourHexCode={colourHexCode}
41
+ colourName={colourName}
42
+ onPress={handleChangeColour}
43
+ />
44
+ )
45
+ })}
46
+ </StackWrap>
47
+ </View>
48
+ )
49
+ }
50
+ )
51
+ ColourToggle.displayName = 'ColourToggle'
52
+
53
+ ColourToggle.propTypes = {
54
+ ...selectedSystemPropTypes,
55
+ /**
56
+ * Optional theme token overrides for the outer ColourToggle component
57
+ */
58
+ tokens: getTokensPropType('ColourToggle'),
59
+ /**
60
+ * Colour toggle variant.
61
+ */
62
+ variant: variantProp.propType,
63
+ /**
64
+ * Id of the selected color when component mounts
65
+ */
66
+ defaultColourId: PropTypes.string,
67
+ /**
68
+ * Array of objects containing specifics for each ColourBubble to be rendered in the group.
69
+ */
70
+ items: PropTypes.arrayOf(
71
+ PropTypes.exact({
72
+ colourHexCode: PropTypes.string,
73
+ colourName: PropTypes.string,
74
+ id: PropTypes.string
75
+ })
76
+ ),
77
+ /**
78
+ * If provided, this function is called when the current selection of the color is changed of all currently `items`. Receives two parameters: item object selected and the event
79
+ */
80
+ onChange: PropTypes.func
81
+ }
82
+
83
+ export default ColourToggle
@@ -0,0 +1,3 @@
1
+ import ColourToggle from './ColourToggle'
2
+
3
+ export default ColourToggle