@telus-uds/components-base 1.12.1 → 1.14.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.
- package/CHANGELOG.md +41 -2
- package/component-docs.json +888 -66
- package/lib/Button/ButtonBase.js +36 -7
- package/lib/Button/ButtonGroup.js +7 -0
- package/lib/Button/propTypes.js +18 -0
- package/lib/Carousel/Carousel.js +69 -12
- package/lib/Carousel/CarouselContext.js +17 -11
- package/lib/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +73 -0
- package/lib/Carousel/CarouselTabs/CarouselTabs.js +70 -0
- package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +95 -0
- package/lib/Carousel/CarouselTabs/CarouselTabsPanelItem.js +148 -0
- package/lib/Carousel/CarouselTabs/index.js +13 -0
- package/lib/Carousel/CarouselThumbnail.js +99 -0
- package/lib/Carousel/CarouselThumbnailNavigation.js +87 -0
- package/lib/Carousel/dictionary.js +4 -2
- package/lib/Carousel/index.js +10 -1
- package/lib/Checkbox/CheckboxGroup.js +7 -0
- package/lib/Icon/IconText.js +1 -1
- package/lib/Link/InlinePressable.js +1 -8
- package/lib/Link/LinkBase.js +6 -7
- package/lib/List/ListItem.js +1 -1
- package/lib/Notification/Notification.js +37 -22
- package/lib/Radio/RadioGroup.js +8 -0
- package/lib/RadioCard/RadioCardGroup.js +7 -0
- package/lib/SkipLink/SkipLink.js +216 -0
- package/lib/SkipLink/index.js +13 -0
- package/lib/ThemeProvider/ThemeProvider.js +6 -1
- package/lib/ToggleSwitch/ToggleSwitchGroup.js +7 -0
- package/lib/index.js +9 -0
- package/lib-module/Button/ButtonBase.js +35 -7
- package/lib-module/Button/ButtonGroup.js +7 -0
- package/lib-module/Button/propTypes.js +17 -0
- package/lib-module/Carousel/Carousel.js +66 -11
- package/lib-module/Carousel/CarouselContext.js +17 -11
- package/lib-module/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +51 -0
- package/lib-module/Carousel/CarouselTabs/CarouselTabs.js +50 -0
- package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +76 -0
- package/lib-module/Carousel/CarouselTabs/CarouselTabsPanelItem.js +126 -0
- package/lib-module/Carousel/CarouselTabs/index.js +2 -0
- package/lib-module/Carousel/CarouselThumbnail.js +85 -0
- package/lib-module/Carousel/CarouselThumbnailNavigation.js +66 -0
- package/lib-module/Carousel/dictionary.js +4 -2
- package/lib-module/Carousel/index.js +2 -1
- package/lib-module/Checkbox/CheckboxGroup.js +7 -0
- package/lib-module/Icon/IconText.js +1 -1
- package/lib-module/Link/InlinePressable.js +1 -8
- package/lib-module/Link/LinkBase.js +6 -7
- package/lib-module/List/ListItem.js +1 -1
- package/lib-module/Notification/Notification.js +38 -23
- package/lib-module/Radio/RadioGroup.js +8 -0
- package/lib-module/RadioCard/RadioCardGroup.js +7 -0
- package/lib-module/SkipLink/SkipLink.js +188 -0
- package/lib-module/SkipLink/index.js +2 -0
- package/lib-module/ThemeProvider/ThemeProvider.js +5 -1
- package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +7 -0
- package/lib-module/index.js +1 -0
- package/package.json +46 -47
- package/src/Button/ButtonBase.jsx +28 -9
- package/src/Button/ButtonGroup.jsx +6 -0
- package/src/Button/propTypes.js +14 -0
- package/src/Carousel/Carousel.jsx +68 -10
- package/src/Carousel/CarouselContext.jsx +22 -9
- package/src/Carousel/CarouselFirstFocus/CarouselFirstFocus.jsx +49 -0
- package/src/Carousel/CarouselTabs/CarouselTabs.jsx +37 -0
- package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +69 -0
- package/src/Carousel/CarouselTabs/CarouselTabsPanelItem.jsx +119 -0
- package/src/Carousel/CarouselTabs/index.js +3 -0
- package/src/Carousel/CarouselThumbnail.jsx +77 -0
- package/src/Carousel/CarouselThumbnailNavigation.jsx +53 -0
- package/src/Carousel/dictionary.js +4 -2
- package/src/Carousel/index.js +1 -0
- package/src/Checkbox/CheckboxGroup.jsx +7 -0
- package/src/Icon/IconText.jsx +1 -1
- package/src/Link/InlinePressable.jsx +2 -8
- package/src/Link/LinkBase.jsx +8 -17
- package/src/List/ListItem.jsx +1 -1
- package/src/Notification/Notification.jsx +35 -20
- package/src/Radio/RadioGroup.jsx +7 -0
- package/src/RadioCard/RadioCardGroup.jsx +6 -0
- package/src/SkipLink/SkipLink.jsx +179 -0
- package/src/SkipLink/index.js +3 -0
- package/src/ThemeProvider/ThemeProvider.jsx +7 -1
- package/src/ToggleSwitch/ToggleSwitchGroup.jsx +6 -0
- package/src/index.js +1 -0
|
@@ -6,22 +6,26 @@ const CarouselContext = /*#__PURE__*/React.createContext();
|
|
|
6
6
|
|
|
7
7
|
const CarouselProvider = _ref => {
|
|
8
8
|
let {
|
|
9
|
-
children,
|
|
10
9
|
activeIndex,
|
|
11
|
-
|
|
12
|
-
width,
|
|
10
|
+
children,
|
|
13
11
|
goTo,
|
|
14
12
|
getCopyWithPlaceholders,
|
|
15
|
-
|
|
13
|
+
itemLabel,
|
|
14
|
+
refocus = false,
|
|
15
|
+
themeTokens,
|
|
16
|
+
totalItems,
|
|
17
|
+
width
|
|
16
18
|
} = _ref;
|
|
17
19
|
const value = React.useMemo(() => ({
|
|
18
20
|
activeIndex,
|
|
19
|
-
totalItems,
|
|
20
|
-
width,
|
|
21
21
|
goTo,
|
|
22
22
|
getCopyWithPlaceholders,
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
itemLabel,
|
|
24
|
+
refocus,
|
|
25
|
+
themeTokens,
|
|
26
|
+
totalItems,
|
|
27
|
+
width
|
|
28
|
+
}), [activeIndex, goTo, getCopyWithPlaceholders, itemLabel, refocus, totalItems, themeTokens, width]);
|
|
25
29
|
return /*#__PURE__*/_jsx(CarouselContext.Provider, {
|
|
26
30
|
value: value,
|
|
27
31
|
children: children
|
|
@@ -41,10 +45,12 @@ function useCarousel() {
|
|
|
41
45
|
CarouselProvider.propTypes = {
|
|
42
46
|
children: PropTypes.arrayOf(PropTypes.element).isRequired,
|
|
43
47
|
activeIndex: PropTypes.number.isRequired,
|
|
44
|
-
totalItems: PropTypes.number.isRequired,
|
|
45
|
-
width: PropTypes.number.isRequired,
|
|
46
48
|
goTo: PropTypes.func.isRequired,
|
|
47
49
|
getCopyWithPlaceholders: PropTypes.func.isRequired,
|
|
48
|
-
|
|
50
|
+
itemLabel: PropTypes.string.isRequired,
|
|
51
|
+
refocus: PropTypes.bool,
|
|
52
|
+
themeTokens: getTokensPropType('Carousel'),
|
|
53
|
+
totalItems: PropTypes.number.isRequired,
|
|
54
|
+
width: PropTypes.number.isRequired
|
|
49
55
|
};
|
|
50
56
|
export { CarouselProvider, useCarousel };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import Pressable from "react-native-web/dist/exports/Pressable";
|
|
3
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
4
|
+
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
5
|
+
import { PropTypes } from 'prop-types';
|
|
6
|
+
import { useCarousel } from '../CarouselContext';
|
|
7
|
+
/**
|
|
8
|
+
* Focus target so that when a new slide is shown, the user can tab into
|
|
9
|
+
* its content using the keyboard.
|
|
10
|
+
*
|
|
11
|
+
* @TODO rework this after integrating with SkipLink when available.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
15
|
+
const CarouselFirstFocus = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
16
|
+
let {
|
|
17
|
+
title
|
|
18
|
+
} = _ref;
|
|
19
|
+
const {
|
|
20
|
+
getCopyWithPlaceholders
|
|
21
|
+
} = useCarousel(); // TODO: integrate skip link description if behaving as skip link.
|
|
22
|
+
// Consider moving this content to aria-live area while only the skip link is focused.
|
|
23
|
+
|
|
24
|
+
const accessibilityLabel = "".concat(title, ", ").concat(getCopyWithPlaceholders('stepTrackerLabel'));
|
|
25
|
+
const accessibilityRole = Platform.select({
|
|
26
|
+
web: 'link',
|
|
27
|
+
// The focused item will ultimately be a skip link.
|
|
28
|
+
default: 'button' // 'link' role usually denotes opening browser on Native.
|
|
29
|
+
|
|
30
|
+
});
|
|
31
|
+
return /*#__PURE__*/_jsx(Pressable // TODO: integrate skip link functionality, jump focus to after Carousel
|
|
32
|
+
, {
|
|
33
|
+
onPress: undefined,
|
|
34
|
+
ref: ref,
|
|
35
|
+
accessibilityLabel: accessibilityLabel,
|
|
36
|
+
accessibilityRole: accessibilityRole,
|
|
37
|
+
style: StyleSheet.absoluteFill,
|
|
38
|
+
focusable: true
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
CarouselFirstFocus.displayName = 'CarouselFirstFocus';
|
|
42
|
+
CarouselFirstFocus.propTypes = {
|
|
43
|
+
/**
|
|
44
|
+
* Simple description of this carousel for screenreaders, to be read before
|
|
45
|
+
* "{itemLabel} {index} of {count}.
|
|
46
|
+
*
|
|
47
|
+
* For example, "Summer offers" in "Summer offers, offer 1 of 3"
|
|
48
|
+
*/
|
|
49
|
+
title: PropTypes.string
|
|
50
|
+
};
|
|
51
|
+
export default CarouselFirstFocus;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
var _CarouselTabs$propTyp, _CarouselTabs$propTyp2;
|
|
2
|
+
|
|
3
|
+
import React, { forwardRef } from 'react';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { useResponsiveProp } from '../../utils';
|
|
6
|
+
import Carousel from '../Carousel';
|
|
7
|
+
import CarouselTabsPanel from './CarouselTabsPanel';
|
|
8
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
const CarouselTabs = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
10
|
+
let {
|
|
11
|
+
items,
|
|
12
|
+
refocus = true,
|
|
13
|
+
...carouselProps
|
|
14
|
+
} = _ref;
|
|
15
|
+
const panelNavigation = useResponsiveProp({
|
|
16
|
+
md: /*#__PURE__*/_jsx(CarouselTabsPanel, {
|
|
17
|
+
items: items
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
return /*#__PURE__*/_jsx(Carousel, {
|
|
21
|
+
refocus: refocus,
|
|
22
|
+
...carouselProps,
|
|
23
|
+
ref: ref,
|
|
24
|
+
panelNavigation: panelNavigation,
|
|
25
|
+
children: items.map(_ref2 => {
|
|
26
|
+
let {
|
|
27
|
+
title,
|
|
28
|
+
content
|
|
29
|
+
} = _ref2;
|
|
30
|
+
return /*#__PURE__*/_jsx(React.Fragment, {
|
|
31
|
+
children: content
|
|
32
|
+
}, title);
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
CarouselTabs.displayName = 'CarouselTabs';
|
|
37
|
+
CarouselTabs.propTypes = {
|
|
38
|
+
/**
|
|
39
|
+
* An array of objects where title is the string shown in the slide's tab and content is the JSX for the slide itself
|
|
40
|
+
*/
|
|
41
|
+
items: PropTypes.arrayOf(PropTypes.shape({
|
|
42
|
+
title: PropTypes.string.isRequired,
|
|
43
|
+
content: PropTypes.node.isRequired
|
|
44
|
+
})),
|
|
45
|
+
...Carousel.propTypes
|
|
46
|
+
}; // CarouselTabs doesn't require `children` prop, it uses `items` instead.
|
|
47
|
+
// eslint-disable-next-line react/forbid-foreign-prop-types
|
|
48
|
+
|
|
49
|
+
if ((_CarouselTabs$propTyp = CarouselTabs.propTypes) !== null && _CarouselTabs$propTyp !== void 0 && _CarouselTabs$propTyp.children) (_CarouselTabs$propTyp2 = CarouselTabs.propTypes) === null || _CarouselTabs$propTyp2 === void 0 ? true : delete _CarouselTabs$propTyp2.children;
|
|
50
|
+
export default CarouselTabs;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React, { forwardRef, useRef } from 'react';
|
|
2
|
+
import View from "react-native-web/dist/exports/View";
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import StackView from '../../StackView';
|
|
5
|
+
import { useCarousel } from '../CarouselContext';
|
|
6
|
+
import CarouselTabsPanelItem from './CarouselTabsPanelItem';
|
|
7
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
9
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
const CarouselTabsPanel = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
11
|
+
let {
|
|
12
|
+
items
|
|
13
|
+
} = _ref;
|
|
14
|
+
const {
|
|
15
|
+
activeIndex,
|
|
16
|
+
goTo
|
|
17
|
+
} = useCarousel();
|
|
18
|
+
const nextFocusRef = useRef();
|
|
19
|
+
const firstTabRef = useRef(); // TODO: figure out a better cross-brand way to specify subcomponent variants.
|
|
20
|
+
// For now, this picks an Allium variant, and does nothing in brands that lack it.
|
|
21
|
+
// See similar comment in Carousel and https://github.com/telus/universal-design-system/issues/1549
|
|
22
|
+
|
|
23
|
+
const dividerVariant = {
|
|
24
|
+
decorative: true
|
|
25
|
+
};
|
|
26
|
+
const lastTabSelected = activeIndex === items.length - 1;
|
|
27
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
28
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
29
|
+
focusable: true,
|
|
30
|
+
accessible: true,
|
|
31
|
+
onFocus: event => {
|
|
32
|
+
// When user forward-tabs into this section, focus the next tab; if they backwards-tab
|
|
33
|
+
// (shift-tab) back into the carousel content, don't interfere.
|
|
34
|
+
const previousWebFocus = event.relatedTarget;
|
|
35
|
+
if (previousWebFocus !== firstTabRef.current) nextFocusRef.current.focus();
|
|
36
|
+
}
|
|
37
|
+
}), /*#__PURE__*/_jsx(StackView, {
|
|
38
|
+
direction: "row",
|
|
39
|
+
space: 3,
|
|
40
|
+
divider: {
|
|
41
|
+
variant: dividerVariant
|
|
42
|
+
},
|
|
43
|
+
ref: ref,
|
|
44
|
+
children: items.map((_ref2, index) => {
|
|
45
|
+
let {
|
|
46
|
+
title,
|
|
47
|
+
onPress,
|
|
48
|
+
...panelItemProps
|
|
49
|
+
} = _ref2;
|
|
50
|
+
const selected = index === activeIndex;
|
|
51
|
+
const isNext = index === activeIndex + 1; // Selected item should be always unfocusable and unpressable
|
|
52
|
+
|
|
53
|
+
const handlePress = selected ? undefined : event => {
|
|
54
|
+
if (typeof onPress === 'function') onPress(event, index);
|
|
55
|
+
goTo(index);
|
|
56
|
+
};
|
|
57
|
+
return /*#__PURE__*/_jsx(CarouselTabsPanelItem, {
|
|
58
|
+
ref: isNext && nextFocusRef || index === 0 && firstTabRef || null,
|
|
59
|
+
title: title,
|
|
60
|
+
selected: selected,
|
|
61
|
+
onPress: handlePress,
|
|
62
|
+
...panelItemProps
|
|
63
|
+
}, title);
|
|
64
|
+
})
|
|
65
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
66
|
+
focusable: true,
|
|
67
|
+
accessible: true,
|
|
68
|
+
ref: lastTabSelected ? nextFocusRef : null
|
|
69
|
+
})]
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
CarouselTabsPanel.displayName = 'CarouselTabsPanel';
|
|
73
|
+
CarouselTabsPanel.propTypes = {
|
|
74
|
+
items: PropTypes.arrayOf(PropTypes.shape(CarouselTabsPanelItem.propTypes || {}))
|
|
75
|
+
};
|
|
76
|
+
export default CarouselTabsPanel;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import React, { forwardRef, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Pressable from "react-native-web/dist/exports/Pressable";
|
|
4
|
+
import Text from "react-native-web/dist/exports/Text";
|
|
5
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
6
|
+
import { applyTextStyles, useThemeTokensCallback } from '../../ThemeProvider';
|
|
7
|
+
import { selectSystemProps, a11yProps, pressProps, viewProps, textProps, getTokensPropType, variantProp, resolvePressableState } from '../../utils';
|
|
8
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
const [selectPressProps, pressPropTypes] = selectSystemProps([a11yProps, pressProps, viewProps]);
|
|
10
|
+
const [selectTextProps, textPropTypes] = selectSystemProps([textProps]);
|
|
11
|
+
|
|
12
|
+
const selectContainerStyles = _ref => {
|
|
13
|
+
let {
|
|
14
|
+
paddingLeft,
|
|
15
|
+
paddingRight,
|
|
16
|
+
paddingTop,
|
|
17
|
+
paddingBottom = 0,
|
|
18
|
+
borderBottomColor,
|
|
19
|
+
borderBottomWidth = 0,
|
|
20
|
+
borderBottomStyle,
|
|
21
|
+
flex,
|
|
22
|
+
alignItems,
|
|
23
|
+
justifyContent
|
|
24
|
+
} = _ref;
|
|
25
|
+
return {
|
|
26
|
+
paddingLeft,
|
|
27
|
+
paddingRight,
|
|
28
|
+
paddingTop,
|
|
29
|
+
paddingBottom: paddingBottom - borderBottomWidth,
|
|
30
|
+
borderBottomColor,
|
|
31
|
+
borderBottomWidth,
|
|
32
|
+
borderBottomStyle,
|
|
33
|
+
flex,
|
|
34
|
+
alignItems,
|
|
35
|
+
justifyContent,
|
|
36
|
+
...Platform.select({
|
|
37
|
+
// Removes the default browser :focus outline
|
|
38
|
+
web: {
|
|
39
|
+
outline: 'none'
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const selectTextStyles = _ref2 => {
|
|
46
|
+
let {
|
|
47
|
+
fontSize,
|
|
48
|
+
fontScaleCap,
|
|
49
|
+
lineHeight,
|
|
50
|
+
letterSpacing,
|
|
51
|
+
fontWeight,
|
|
52
|
+
fontName,
|
|
53
|
+
color
|
|
54
|
+
} = _ref2;
|
|
55
|
+
return applyTextStyles({
|
|
56
|
+
fontSize,
|
|
57
|
+
fontScaleCap,
|
|
58
|
+
lineHeight,
|
|
59
|
+
letterSpacing,
|
|
60
|
+
fontWeight,
|
|
61
|
+
fontName,
|
|
62
|
+
color
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const CarouselTabsPanelItem = /*#__PURE__*/forwardRef((_ref3, ref) => {
|
|
67
|
+
let {
|
|
68
|
+
title,
|
|
69
|
+
selected,
|
|
70
|
+
inactive,
|
|
71
|
+
variant,
|
|
72
|
+
tokens,
|
|
73
|
+
accessibilityRole = 'tab',
|
|
74
|
+
...rest
|
|
75
|
+
} = _ref3;
|
|
76
|
+
// Workaround for React Native Web https://github.com/necolas/react-native-web/issues/2357
|
|
77
|
+
// Don't allow disabled to be set while focus is true else focus state gets locked `true`
|
|
78
|
+
// (must refocus _after_ calling `goTo`, else focus target content is not up to date)
|
|
79
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
80
|
+
const disabled = (inactive || selected) && !isFocused;
|
|
81
|
+
const getTokens = useThemeTokensCallback('CarouselTabsPanelItem', tokens, variant);
|
|
82
|
+
|
|
83
|
+
const resolveTokens = pressState => getTokens(resolvePressableState(pressState, {
|
|
84
|
+
selected
|
|
85
|
+
}));
|
|
86
|
+
|
|
87
|
+
const getContainerStyle = pressState => selectContainerStyles(resolveTokens(pressState));
|
|
88
|
+
|
|
89
|
+
const getTextStyle = pressState => selectTextStyles(resolveTokens(pressState));
|
|
90
|
+
|
|
91
|
+
const {
|
|
92
|
+
onPress,
|
|
93
|
+
...selectedPressProps
|
|
94
|
+
} = selectPressProps(rest);
|
|
95
|
+
|
|
96
|
+
const handleKeyDown = event => {
|
|
97
|
+
// Allow using the spacebar for navigation
|
|
98
|
+
if ((event === null || event === void 0 ? void 0 : event.key) === ' ') onPress(event);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return /*#__PURE__*/_jsx(Pressable, {
|
|
102
|
+
onPress: onPress,
|
|
103
|
+
style: getContainerStyle,
|
|
104
|
+
accessibilityRole: accessibilityRole,
|
|
105
|
+
ref: ref,
|
|
106
|
+
onKeyDown: handleKeyDown,
|
|
107
|
+
onFocus: () => setIsFocused(true),
|
|
108
|
+
onBlur: () => setIsFocused(false),
|
|
109
|
+
disabled: disabled,
|
|
110
|
+
...selectedPressProps,
|
|
111
|
+
children: pressState => /*#__PURE__*/_jsx(Text, {
|
|
112
|
+
style: getTextStyle(pressState),
|
|
113
|
+
...selectTextProps(rest),
|
|
114
|
+
children: title
|
|
115
|
+
})
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
CarouselTabsPanelItem.displayName = 'CarouselTabsPanelItem';
|
|
119
|
+
CarouselTabsPanelItem.propTypes = { ...pressPropTypes,
|
|
120
|
+
...textPropTypes,
|
|
121
|
+
title: PropTypes.string.isRequired,
|
|
122
|
+
selected: PropTypes.bool,
|
|
123
|
+
tokens: getTokensPropType('CarouselTabsPanelItem'),
|
|
124
|
+
variant: variantProp.propType
|
|
125
|
+
};
|
|
126
|
+
export default CarouselTabsPanelItem;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import Pressable from "react-native-web/dist/exports/Pressable";
|
|
4
|
+
import Image from "react-native-web/dist/exports/Image";
|
|
5
|
+
import { useCarousel } from './CarouselContext';
|
|
6
|
+
/**
|
|
7
|
+
* `Carousel.Thumbnail` is used to wrap the content of an individual slide and is suppsoed to be the
|
|
8
|
+
* only top-level component passed to the `Carousel`
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
|
|
13
|
+
const CarouselThumbnail = _ref => {
|
|
14
|
+
let {
|
|
15
|
+
accessibilityLabel,
|
|
16
|
+
alt,
|
|
17
|
+
index,
|
|
18
|
+
src
|
|
19
|
+
} = _ref;
|
|
20
|
+
const {
|
|
21
|
+
activeIndex,
|
|
22
|
+
itemLabel,
|
|
23
|
+
totalItems,
|
|
24
|
+
getCopyWithPlaceholders,
|
|
25
|
+
goTo,
|
|
26
|
+
themeTokens
|
|
27
|
+
} = useCarousel();
|
|
28
|
+
const thumbnailTitle = alt !== null && alt !== void 0 ? alt : getCopyWithPlaceholders('stepTrackerLabel').replace(/%\{itemLabel\}/g, itemLabel).replace(/%\{stepNumber\}/g, index).replace(/%\{stepCount\}/g, totalItems);
|
|
29
|
+
|
|
30
|
+
const handlePress = () => goTo(index);
|
|
31
|
+
|
|
32
|
+
const handleKeyDown = event => {
|
|
33
|
+
// Allow using the spacebar for navigation
|
|
34
|
+
if ((event === null || event === void 0 ? void 0 : event.key) === ' ') goTo(index);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const {
|
|
38
|
+
thumbnailBorderColor,
|
|
39
|
+
thumbnailBorderRadius,
|
|
40
|
+
thumbnailBorderWidth,
|
|
41
|
+
thumbnailMargin,
|
|
42
|
+
thumbnailPadding,
|
|
43
|
+
thumbnailSelectedBorderColor,
|
|
44
|
+
thumbnailSelectedBorderWidth,
|
|
45
|
+
thumbnailSize
|
|
46
|
+
} = themeTokens;
|
|
47
|
+
const styles = {
|
|
48
|
+
pressable: {
|
|
49
|
+
borderColor: thumbnailBorderColor,
|
|
50
|
+
borderRadius: thumbnailBorderRadius,
|
|
51
|
+
borderWidth: thumbnailBorderWidth,
|
|
52
|
+
margin: thumbnailMargin,
|
|
53
|
+
padding: thumbnailPadding
|
|
54
|
+
},
|
|
55
|
+
image: {
|
|
56
|
+
height: thumbnailSize,
|
|
57
|
+
width: thumbnailSize
|
|
58
|
+
},
|
|
59
|
+
selected: {
|
|
60
|
+
borderColor: thumbnailSelectedBorderColor,
|
|
61
|
+
borderWidth: thumbnailSelectedBorderWidth,
|
|
62
|
+
padding: thumbnailPadding - thumbnailSelectedBorderWidth + thumbnailBorderWidth
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
return /*#__PURE__*/_jsx(Pressable, {
|
|
66
|
+
onKeyDown: handleKeyDown,
|
|
67
|
+
onPress: handlePress,
|
|
68
|
+
style: [styles.pressable, index === activeIndex && styles.selected],
|
|
69
|
+
children: /*#__PURE__*/_jsx(Image, {
|
|
70
|
+
accessibilityIgnoresInvertColors: true,
|
|
71
|
+
accessibilityLabel: accessibilityLabel !== null && accessibilityLabel !== void 0 ? accessibilityLabel : alt,
|
|
72
|
+
source: src,
|
|
73
|
+
style: styles.image,
|
|
74
|
+
title: thumbnailTitle
|
|
75
|
+
})
|
|
76
|
+
}, src);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
CarouselThumbnail.propTypes = {
|
|
80
|
+
accessibilityLabel: PropTypes.string,
|
|
81
|
+
alt: PropTypes.string,
|
|
82
|
+
index: PropTypes.number,
|
|
83
|
+
src: PropTypes.string
|
|
84
|
+
};
|
|
85
|
+
export default CarouselThumbnail;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import View from "react-native-web/dist/exports/View";
|
|
4
|
+
import { useCarousel } from './CarouselContext';
|
|
5
|
+
import CarouselThumbnail from './CarouselThumbnail';
|
|
6
|
+
import { StackWrap } from '../StackView';
|
|
7
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
const CarouselThumbnailNavigation = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
9
|
+
let {
|
|
10
|
+
thumbnails = []
|
|
11
|
+
} = _ref;
|
|
12
|
+
const {
|
|
13
|
+
totalItems,
|
|
14
|
+
themeTokens
|
|
15
|
+
} = useCarousel();
|
|
16
|
+
|
|
17
|
+
if (thumbnails.length !== totalItems) {
|
|
18
|
+
throw new Error('Thumbnail set provided does not match the number of slides in the carousel');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
thumbnailContainerPaddingTop,
|
|
23
|
+
thumbnailMargin
|
|
24
|
+
} = themeTokens;
|
|
25
|
+
const stackWrapTokens = {
|
|
26
|
+
justifyContent: 'flex-start'
|
|
27
|
+
};
|
|
28
|
+
const containerStyles = {
|
|
29
|
+
justifyContent: 'center',
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
paddingTop: thumbnailContainerPaddingTop - thumbnailMargin
|
|
32
|
+
};
|
|
33
|
+
return /*#__PURE__*/_jsx(View, {
|
|
34
|
+
style: containerStyles,
|
|
35
|
+
children: /*#__PURE__*/_jsx(StackWrap, {
|
|
36
|
+
direction: "row",
|
|
37
|
+
tokens: stackWrapTokens,
|
|
38
|
+
ref: ref,
|
|
39
|
+
children: thumbnails.map((_ref2, index) => {
|
|
40
|
+
let {
|
|
41
|
+
accessibilityLabel,
|
|
42
|
+
alt,
|
|
43
|
+
src
|
|
44
|
+
} = _ref2;
|
|
45
|
+
return /*#__PURE__*/_jsx(CarouselThumbnail, {
|
|
46
|
+
accessibilityLabel: accessibilityLabel,
|
|
47
|
+
alt: alt,
|
|
48
|
+
index: index,
|
|
49
|
+
src: src
|
|
50
|
+
}, src);
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
CarouselThumbnailNavigation.displayName = 'CarouselThumbnailNavigation';
|
|
56
|
+
CarouselThumbnailNavigation.propTypes = {
|
|
57
|
+
/**
|
|
58
|
+
* An array of objects containing information on the thumbnail images.
|
|
59
|
+
*/
|
|
60
|
+
thumbnails: PropTypes.arrayOf(PropTypes.shape({
|
|
61
|
+
accessibilityLabel: PropTypes.string,
|
|
62
|
+
alt: PropTypes.string,
|
|
63
|
+
src: PropTypes.string
|
|
64
|
+
})).isRequired
|
|
65
|
+
};
|
|
66
|
+
export default CarouselThumbnailNavigation;
|
|
@@ -4,13 +4,15 @@ export default {
|
|
|
4
4
|
carouselLabel: '%{stepCount} items',
|
|
5
5
|
iconButtonLabel: 'Show %{itemLabel} %{targetStep} of %{stepCount}',
|
|
6
6
|
stepLabel: '%{itemLabel} %{stepNumber}',
|
|
7
|
-
stepTrackerLabel: '%{itemLabel} %{stepNumber} of %{stepCount}'
|
|
7
|
+
stepTrackerLabel: '%{itemLabel} %{stepNumber} of %{stepCount}',
|
|
8
|
+
skipLink: 'Skip %{title}'
|
|
8
9
|
},
|
|
9
10
|
fr: {
|
|
10
11
|
// TODO: French translations here
|
|
11
12
|
carouselLabel: '(fr) %{stepCount} items',
|
|
12
13
|
iconButtonLabel: '(fr) Show %{itemLabel} %{targetStep} of %{stepCount}',
|
|
13
14
|
stepLabel: '(fr) %{itemLabel} %{stepNumber}',
|
|
14
|
-
stepTrackerLabel: '(fr) %{itemLabel} %{stepNumber} of %{stepCount}'
|
|
15
|
+
stepTrackerLabel: '(fr) %{itemLabel} %{stepNumber} of %{stepCount}',
|
|
16
|
+
skipLink: '(fr) Skip %{title}'
|
|
15
17
|
}
|
|
16
18
|
};
|
|
@@ -67,6 +67,7 @@ const CheckboxGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
67
67
|
legend,
|
|
68
68
|
tooltip,
|
|
69
69
|
hint,
|
|
70
|
+
hintPosition = 'inline',
|
|
70
71
|
validation,
|
|
71
72
|
feedback,
|
|
72
73
|
initialCheckedIds,
|
|
@@ -133,6 +134,7 @@ const CheckboxGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
133
134
|
legend: legend,
|
|
134
135
|
tooltip: tooltip,
|
|
135
136
|
hint: hint,
|
|
137
|
+
hintPosition: hintPosition,
|
|
136
138
|
space: fieldSpace,
|
|
137
139
|
feedback: feedback,
|
|
138
140
|
inactive: inactive,
|
|
@@ -182,6 +184,11 @@ CheckboxGroup.propTypes = { ...selectedSystemPropTypes,
|
|
|
182
184
|
*/
|
|
183
185
|
hint: PropTypes.string,
|
|
184
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Position of the hint relative to label. Use `below` to display a larger hint below the label.
|
|
189
|
+
*/
|
|
190
|
+
hintPosition: PropTypes.oneOf(['inline', 'below']),
|
|
191
|
+
|
|
185
192
|
/**
|
|
186
193
|
* Optional tooltip text content to include alongside the legend and hint.
|
|
187
194
|
*/
|
|
@@ -9,8 +9,6 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
|
9
9
|
* InlinePressable is an alternative to React Native's Pressable that works better when nested
|
|
10
10
|
* inline inside Text. It accepts the same props as React Native's Pressable.
|
|
11
11
|
*
|
|
12
|
-
* On Web it simply passes its props to Pressable and defaults to `inline-flex` instead of `flex`.
|
|
13
|
-
*
|
|
14
12
|
* @param {PressableProps} PressableProps
|
|
15
13
|
*/
|
|
16
14
|
// React Native exports prop Types but not propTypes, use JSDoc types here rather than duplicate RN
|
|
@@ -21,12 +19,11 @@ const InlinePressable = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
21
19
|
let {
|
|
22
20
|
children,
|
|
23
21
|
style,
|
|
24
|
-
inline = false,
|
|
25
22
|
...props
|
|
26
23
|
} = _ref;
|
|
27
24
|
return /*#__PURE__*/_jsx(Pressable, {
|
|
28
25
|
ref: ref,
|
|
29
|
-
style: pressState => [staticStyles
|
|
26
|
+
style: pressState => [staticStyles.inline, typeof style === 'function' ? style(pressState) : style],
|
|
30
27
|
...props,
|
|
31
28
|
children: pressState => typeof children === 'function' ? children(pressState) : children
|
|
32
29
|
});
|
|
@@ -34,11 +31,7 @@ const InlinePressable = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
34
31
|
InlinePressable.displayName = 'InlinePressable';
|
|
35
32
|
const staticStyles = StyleSheet.create({
|
|
36
33
|
inline: {
|
|
37
|
-
// Stop Pressable defaulting to (block) flex
|
|
38
34
|
display: 'inline'
|
|
39
|
-
},
|
|
40
|
-
inlineFlex: {
|
|
41
|
-
display: 'inline-flex'
|
|
42
35
|
}
|
|
43
36
|
});
|
|
44
37
|
export default InlinePressable;
|
|
@@ -12,7 +12,7 @@ import { IconText, iconComponentPropTypes } from '../Icon';
|
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
13
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps]);
|
|
14
14
|
|
|
15
|
-
const selectOuterBorderStyles = _ref => {
|
|
15
|
+
const selectOuterBorderStyles = (_ref, hasIcon) => {
|
|
16
16
|
let {
|
|
17
17
|
outerBorderColor,
|
|
18
18
|
outerBorderWidth,
|
|
@@ -33,7 +33,8 @@ const selectOuterBorderStyles = _ref => {
|
|
|
33
33
|
}),
|
|
34
34
|
// Stops focus ring stretching horizontally if parent has display: block
|
|
35
35
|
// width: fit-content isn't supported on Firefox; can't cascade props like CSS `width: fit-content; width: --moz-fit-content;`
|
|
36
|
-
display: 'inline-flex'
|
|
36
|
+
display: hasIcon ? 'inline-flex' : 'inline' // Stop Pressable defaulting to (block) flex
|
|
37
|
+
|
|
37
38
|
} : {}
|
|
38
39
|
);
|
|
39
40
|
};
|
|
@@ -169,14 +170,12 @@ const LinkBase = /*#__PURE__*/forwardRef((_ref6, ref) => {
|
|
|
169
170
|
themeOptions
|
|
170
171
|
} = useTheme();
|
|
171
172
|
return /*#__PURE__*/_jsx(InlinePressable, { ...selectedProps,
|
|
172
|
-
inline: hasIcon // assuming links without icons should be inline (even if they are long)
|
|
173
|
-
,
|
|
174
173
|
ref: ref,
|
|
175
174
|
style: linkState => {
|
|
176
175
|
const themeTokens = resolveLinkTokens(linkState);
|
|
177
|
-
const outerBorderStyles = selectOuterBorderStyles(themeTokens);
|
|
176
|
+
const outerBorderStyles = selectOuterBorderStyles(themeTokens, hasIcon);
|
|
178
177
|
const decorationStyles = selectDecorationStyles(themeTokens);
|
|
179
|
-
return [outerBorderStyles, blockLeftStyle, decorationStyles,
|
|
178
|
+
return [outerBorderStyles, blockLeftStyle, decorationStyles, staticStyles.rowContainer];
|
|
180
179
|
},
|
|
181
180
|
children: linkState => {
|
|
182
181
|
const themeTokens = resolveLinkTokens(linkState);
|
|
@@ -218,7 +217,7 @@ LinkBase.propTypes = { ...selectedSystemPropTypes,
|
|
|
218
217
|
* A function component for an SVG icon to render inside the link. Inherits size and color from
|
|
219
218
|
* the link and any Typography the link is nested inside.
|
|
220
219
|
*/
|
|
221
|
-
icon: PropTypes.
|
|
220
|
+
icon: PropTypes.elementType,
|
|
222
221
|
|
|
223
222
|
/**
|
|
224
223
|
* When `icon` is provided, use `iconPosition` to place the Icon to the left or right side of Link.
|