@utilitywarehouse/hearth-react-native 0.2.0 → 0.3.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +3 -1
- package/CHANGELOG.md +34 -0
- package/build/components/Alert/AlertCloseButton.js +25 -3
- package/build/components/Alert/AlertIcon.js +17 -1
- package/build/components/Alert/AlertIconButton.js +27 -1
- package/build/components/Alert/AlertLink.js +47 -1
- package/build/components/Alert/AlertText.d.ts +1 -1
- package/build/components/Alert/AlertText.js +26 -2
- package/build/components/Alert/AlertTitle.d.ts +1 -1
- package/build/components/Alert/AlertTitle.js +26 -2
- package/build/components/Badge/Badge.js +101 -14
- package/build/components/Badge/Badge.props.d.ts +2 -2
- package/build/components/Badge/BadgeIcon.js +27 -29
- package/build/components/Badge/BadgeText.js +29 -31
- package/build/components/Button/Button.d.ts +2 -2
- package/build/components/Button/ButtonGroupRoot.d.ts +3 -2
- package/build/components/Button/ButtonGroupRoot.js +9 -0
- package/build/components/Button/ButtonRoot.js +1 -0
- package/build/components/Card/Card.props.d.ts +2 -2
- package/build/components/Checkbox/Checkbox.d.ts +2 -2
- package/build/components/Checkbox/Checkbox.js +11 -10
- package/build/components/Checkbox/Checkbox.props.d.ts +3 -1
- package/build/components/Checkbox/CheckboxIcon.js +1 -1
- package/build/components/Checkbox/CheckboxImage.d.ts +6 -0
- package/build/components/Checkbox/CheckboxImage.js +5 -0
- package/build/components/Checkbox/CheckboxTileRoot.js +1 -1
- package/build/components/Checkbox/index.d.ts +3 -2
- package/build/components/Checkbox/index.js +2 -1
- package/build/components/CurrencyInput/CurrencyInput.d.ts +6 -0
- package/build/components/CurrencyInput/CurrencyInput.js +47 -0
- package/build/components/CurrencyInput/CurrencyInput.props.d.ts +14 -0
- package/build/components/CurrencyInput/CurrencyInput.props.js +1 -0
- package/build/components/CurrencyInput/index.d.ts +1 -0
- package/build/components/CurrencyInput/index.js +1 -0
- package/build/components/DescriptionList/DescriptionList.context.d.ts +6 -0
- package/build/components/DescriptionList/DescriptionList.context.js +9 -0
- package/build/components/DescriptionList/DescriptionList.d.ts +6 -0
- package/build/components/DescriptionList/DescriptionList.js +25 -0
- package/build/components/DescriptionList/DescriptionList.props.d.ts +18 -0
- package/build/components/DescriptionList/DescriptionList.props.js +1 -0
- package/build/components/DescriptionList/DescriptionListItem.d.ts +6 -0
- package/build/components/DescriptionList/DescriptionListItem.js +49 -0
- package/build/components/DescriptionList/DescriptionListItem.props.d.ts +17 -0
- package/build/components/DescriptionList/DescriptionListItem.props.js +1 -0
- package/build/components/DescriptionList/index.d.ts +4 -0
- package/build/components/DescriptionList/index.js +2 -0
- package/build/components/Divider/Divider.js +46 -0
- package/build/components/Divider/Divider.props.d.ts +2 -2
- package/build/components/Flex/Flex.props.d.ts +3 -2
- package/build/components/Grid/Grid.props.d.ts +2 -2
- package/build/components/IconContainer/IconContainer.d.ts +5 -0
- package/build/components/IconContainer/IconContainer.js +161 -0
- package/build/components/IconContainer/IconContainer.props.d.ts +15 -0
- package/build/components/IconContainer/IconContainer.props.js +1 -0
- package/build/components/IconContainer/index.d.ts +2 -0
- package/build/components/IconContainer/index.js +1 -0
- package/build/components/Icons/CircleIcon.js +3 -3
- package/build/components/Input/Input.js +2 -34
- package/build/components/Input/Input.props.d.ts +1 -17
- package/build/components/Input/InputField.js +0 -7
- package/build/components/Link/Link.d.ts +1 -1
- package/build/components/Link/Link.js +4 -4
- package/build/components/Link/Link.props.d.ts +3 -0
- package/build/components/Modal/Modal.js +17 -1
- package/build/components/Radio/Radio.d.ts +2 -2
- package/build/components/Radio/Radio.js +9 -8
- package/build/components/Radio/Radio.props.d.ts +3 -1
- package/build/components/Radio/RadioImage.d.ts +6 -0
- package/build/components/Radio/RadioImage.js +5 -0
- package/build/components/Radio/RadioTileRoot.js +1 -1
- package/build/components/Radio/index.d.ts +3 -2
- package/build/components/Radio/index.js +2 -1
- package/build/components/SectionHeader/SectionHeader.js +1 -0
- package/build/components/Select/SelectOption.js +1 -7
- package/build/components/Tabs/Tab.d.ts +18 -0
- package/build/components/Tabs/Tab.js +74 -0
- package/build/components/Tabs/Tab.props.d.ts +14 -0
- package/build/components/Tabs/Tab.props.js +1 -0
- package/build/components/Tabs/TabPanel.d.ts +3 -0
- package/build/components/Tabs/TabPanel.js +34 -0
- package/build/components/Tabs/TabPanel.props.d.ts +8 -0
- package/build/components/Tabs/TabPanel.props.js +1 -0
- package/build/components/Tabs/Tabs.context.d.ts +23 -0
- package/build/components/Tabs/Tabs.context.js +8 -0
- package/build/components/Tabs/Tabs.d.ts +6 -0
- package/build/components/Tabs/Tabs.js +114 -0
- package/build/components/Tabs/Tabs.props.d.ts +19 -0
- package/build/components/Tabs/Tabs.props.js +1 -0
- package/build/components/Tabs/TabsList.d.ts +6 -0
- package/build/components/Tabs/TabsList.js +112 -0
- package/build/components/Tabs/TabsList.props.d.ts +6 -0
- package/build/components/Tabs/TabsList.props.js +1 -0
- package/build/components/Tabs/index.d.ts +8 -0
- package/build/components/Tabs/index.js +4 -0
- package/build/components/UnstyledIconButton/UnstyledIconButton.d.ts +1 -1
- package/build/components/UnstyledIconButton/UnstyledIconButton.js +4 -4
- package/build/components/UnstyledIconButton/UnstyledIconButton.props.d.ts +2 -1
- package/build/components/index.d.ts +4 -0
- package/build/components/index.js +4 -0
- package/build/core/themes.d.ts +428 -160
- package/build/core/themes.js +57 -1
- package/build/tokens/color.d.ts +88 -80
- package/build/tokens/color.js +44 -40
- package/build/tokens/components/dark/alert.d.ts +13 -0
- package/build/tokens/components/dark/alert.js +13 -0
- package/build/tokens/components/dark/button.d.ts +1 -0
- package/build/tokens/components/dark/button.js +1 -0
- package/build/tokens/components/dark/checkbox.d.ts +4 -1
- package/build/tokens/components/dark/checkbox.js +4 -1
- package/build/tokens/components/dark/icon-button.d.ts +10 -3
- package/build/tokens/components/dark/icon-button.js +10 -3
- package/build/tokens/components/dark/index.d.ts +1 -0
- package/build/tokens/components/dark/index.js +1 -0
- package/build/tokens/components/dark/link.d.ts +5 -0
- package/build/tokens/components/dark/link.js +5 -0
- package/build/tokens/components/dark/progress-bar.d.ts +41 -0
- package/build/tokens/components/dark/progress-bar.js +40 -0
- package/build/tokens/components/dark/radio.d.ts +1 -1
- package/build/tokens/components/dark/radio.js +1 -1
- package/build/tokens/components/dark/tabs.d.ts +2 -0
- package/build/tokens/components/dark/tabs.js +2 -0
- package/build/tokens/components/light/alert.d.ts +13 -0
- package/build/tokens/components/light/alert.js +13 -0
- package/build/tokens/components/light/badge.d.ts +1 -1
- package/build/tokens/components/light/badge.js +1 -1
- package/build/tokens/components/light/button.d.ts +1 -0
- package/build/tokens/components/light/button.js +1 -0
- package/build/tokens/components/light/checkbox.d.ts +6 -3
- package/build/tokens/components/light/checkbox.js +6 -3
- package/build/tokens/components/light/icon-button.d.ts +8 -1
- package/build/tokens/components/light/icon-button.js +8 -1
- package/build/tokens/components/light/index.d.ts +1 -0
- package/build/tokens/components/light/index.js +1 -0
- package/build/tokens/components/light/link.d.ts +5 -0
- package/build/tokens/components/light/link.js +5 -0
- package/build/tokens/components/light/progress-bar.d.ts +41 -0
- package/build/tokens/components/light/progress-bar.js +40 -0
- package/build/tokens/components/light/radio.d.ts +3 -3
- package/build/tokens/components/light/radio.js +3 -3
- package/build/tokens/components/light/tabs.d.ts +2 -0
- package/build/tokens/components/light/tabs.js +2 -0
- package/build/tokens/index.d.ts +1 -0
- package/build/tokens/index.js +1 -0
- package/build/tokens/layout.d.ts +48 -30
- package/build/tokens/layout.js +24 -15
- package/build/tokens/motion.d.ts +23 -0
- package/build/tokens/motion.js +22 -0
- package/build/tokens/primitive.d.ts +19 -0
- package/build/tokens/primitive.js +19 -0
- package/build/tokens/semantic-dark.d.ts +26 -24
- package/build/tokens/semantic-dark.js +26 -24
- package/build/tokens/semantic-light.d.ts +18 -16
- package/build/tokens/semantic-light.js +18 -16
- package/build/types/values.d.ts +2 -1
- package/build/utils/formatThousands.d.ts +2 -0
- package/build/utils/formatThousands.js +16 -0
- package/build/utils/index.d.ts +1 -0
- package/build/utils/index.js +1 -0
- package/docs/assets/bank-logo.png +0 -0
- package/docs/assets/bank-logo1.png +0 -0
- package/docs/components/AllComponents.web.tsx +97 -8
- package/docs/components/NextPrevPage.tsx +11 -3
- package/docs/components/UsageWrap.tsx +2 -2
- package/docs/components/index.ts +6 -7
- package/docs/heplers/addReactNativePrefix.ts +8 -0
- package/docs/heplers/index.ts +1 -0
- package/docs/introduction.mdx +3 -3
- package/docs/theme-tokens.mdx +42 -0
- package/package.json +13 -13
- package/src/components/Alert/AlertCloseButton.tsx +33 -5
- package/src/components/Alert/AlertIcon.tsx +17 -1
- package/src/components/Alert/AlertIconButton.tsx +37 -4
- package/src/components/Alert/AlertLink.tsx +52 -1
- package/src/components/Alert/AlertText.tsx +28 -3
- package/src/components/Alert/AlertTitle.tsx +28 -3
- package/src/components/Badge/Badge.docs.mdx +7 -7
- package/src/components/Badge/Badge.props.ts +3 -2
- package/src/components/Badge/Badge.stories.tsx +81 -92
- package/src/components/Badge/Badge.tsx +101 -14
- package/src/components/Badge/BadgeIcon.tsx +27 -29
- package/src/components/Badge/BadgeText.tsx +29 -31
- package/src/components/Button/ButtonGroupRoot.tsx +12 -2
- package/src/components/Button/ButtonRoot.tsx +1 -0
- package/src/components/Card/Card.docs.mdx +1 -1
- package/src/components/Card/Card.props.ts +2 -2
- package/src/components/Checkbox/Checkbox.docs.mdx +45 -7
- package/src/components/Checkbox/Checkbox.props.ts +3 -1
- package/src/components/Checkbox/Checkbox.stories.tsx +37 -1
- package/src/components/Checkbox/Checkbox.tsx +12 -9
- package/src/components/Checkbox/CheckboxIcon.tsx +1 -1
- package/src/components/Checkbox/CheckboxImage.tsx +9 -0
- package/src/components/Checkbox/CheckboxTileRoot.tsx +1 -1
- package/src/components/Checkbox/index.ts +3 -2
- package/src/components/CurrencyInput/CurrencyInput.docs.mdx +120 -0
- package/src/components/CurrencyInput/CurrencyInput.props.ts +19 -0
- package/src/components/CurrencyInput/CurrencyInput.stories.tsx +116 -0
- package/src/components/CurrencyInput/CurrencyInput.tsx +91 -0
- package/src/components/CurrencyInput/index.ts +1 -0
- package/src/components/DescriptionList/DescriptionList.context.ts +18 -0
- package/src/components/DescriptionList/DescriptionList.docs.mdx +98 -0
- package/src/components/DescriptionList/DescriptionList.props.ts +20 -0
- package/src/components/DescriptionList/DescriptionList.stories.tsx +154 -0
- package/src/components/DescriptionList/DescriptionList.tsx +64 -0
- package/src/components/DescriptionList/DescriptionListItem.props.ts +19 -0
- package/src/components/DescriptionList/DescriptionListItem.tsx +101 -0
- package/src/components/DescriptionList/index.ts +4 -0
- package/src/components/Divider/Divider.props.ts +2 -2
- package/src/components/Divider/Divider.stories.tsx +3 -3
- package/src/components/Divider/Divider.tsx +46 -0
- package/src/components/Flex/Flex.docs.mdx +4 -4
- package/src/components/Flex/Flex.props.ts +3 -2
- package/src/components/Flex/Flex.stories.tsx +1 -1
- package/src/components/Grid/Grid.docs.mdx +12 -12
- package/src/components/Grid/Grid.props.ts +2 -2
- package/src/components/Grid/Grid.stories.tsx +2 -2
- package/src/components/IconContainer/IconContainer.docs.mdx +90 -0
- package/src/components/IconContainer/IconContainer.props.ts +17 -0
- package/src/components/IconContainer/IconContainer.stories.tsx +130 -0
- package/src/components/IconContainer/IconContainer.tsx +180 -0
- package/src/components/IconContainer/index.tsx +2 -0
- package/src/components/Icons/CircleIcon.tsx +9 -11
- package/src/components/Input/Input.docs.mdx +3 -3
- package/src/components/Input/Input.props.ts +0 -20
- package/src/components/Input/Input.stories.tsx +0 -6
- package/src/components/Input/Input.tsx +2 -49
- package/src/components/Input/InputField.tsx +0 -7
- package/src/components/Link/Link.props.ts +3 -0
- package/src/components/Link/Link.tsx +12 -6
- package/src/components/List/List.docs.mdx +24 -23
- package/src/components/Modal/Modal.tsx +18 -0
- package/src/components/Radio/Radio.docs.mdx +96 -124
- package/src/components/Radio/Radio.props.ts +3 -1
- package/src/components/Radio/Radio.stories.tsx +47 -0
- package/src/components/Radio/Radio.tsx +10 -7
- package/src/components/Radio/RadioImage.tsx +9 -0
- package/src/components/Radio/RadioTileRoot.tsx +1 -1
- package/src/components/Radio/index.ts +3 -2
- package/src/components/SectionHeader/SectionHeader.tsx +1 -0
- package/src/components/Select/Select.docs.mdx +6 -6
- package/src/components/Select/Select.stories.tsx +7 -7
- package/src/components/Select/SelectOption.tsx +4 -10
- package/src/components/Tabs/Tab.props.ts +16 -0
- package/src/components/Tabs/Tab.tsx +113 -0
- package/src/components/Tabs/TabPanel.props.ts +10 -0
- package/src/components/Tabs/TabPanel.tsx +46 -0
- package/src/components/Tabs/Tabs.context.ts +26 -0
- package/src/components/Tabs/Tabs.docs.mdx +214 -0
- package/src/components/Tabs/Tabs.props.ts +21 -0
- package/src/components/Tabs/Tabs.stories.tsx +270 -0
- package/src/components/Tabs/Tabs.tsx +139 -0
- package/src/components/Tabs/TabsList.props.ts +8 -0
- package/src/components/Tabs/TabsList.tsx +194 -0
- package/src/components/Tabs/index.ts +8 -0
- package/src/components/UnstyledIconButton/UnstyledIconButton.props.ts +2 -1
- package/src/components/UnstyledIconButton/UnstyledIconButton.tsx +9 -3
- package/src/components/index.ts +4 -0
- package/src/core/themes.ts +57 -1
- package/src/tokens/color.ts +44 -40
- package/src/tokens/components/dark/alert.ts +13 -0
- package/src/tokens/components/dark/button.ts +1 -0
- package/src/tokens/components/dark/checkbox.ts +4 -1
- package/src/tokens/components/dark/icon-button.ts +10 -3
- package/src/tokens/components/dark/index.ts +1 -0
- package/src/tokens/components/dark/link.ts +5 -0
- package/src/tokens/components/dark/progress-bar.ts +41 -0
- package/src/tokens/components/dark/radio.ts +1 -1
- package/src/tokens/components/dark/tabs.ts +2 -0
- package/src/tokens/components/light/alert.ts +13 -0
- package/src/tokens/components/light/badge.ts +1 -1
- package/src/tokens/components/light/button.ts +1 -0
- package/src/tokens/components/light/checkbox.ts +6 -3
- package/src/tokens/components/light/icon-button.ts +8 -1
- package/src/tokens/components/light/index.ts +1 -0
- package/src/tokens/components/light/link.ts +5 -0
- package/src/tokens/components/light/progress-bar.ts +41 -0
- package/src/tokens/components/light/radio.ts +3 -3
- package/src/tokens/components/light/tabs.ts +2 -0
- package/src/tokens/index.ts +1 -0
- package/src/tokens/layout.ts +24 -15
- package/src/tokens/motion.ts +23 -0
- package/src/tokens/primitive.ts +19 -0
- package/src/tokens/semantic-dark.ts +26 -24
- package/src/tokens/semantic-light.ts +18 -16
- package/src/types/values.ts +3 -1
- package/src/utils/formatThousands.ts +14 -0
- package/src/utils/index.ts +1 -0
- package/docs/assets/react-native-pig.png +0 -0
- package/docs/components/AdvancedRadioExample.tsx +0 -126
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
|
+
import { Platform, Pressable, View } from 'react-native';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
import { DetailText } from '../DetailText';
|
|
5
|
+
import { Icon } from '../Icon';
|
|
6
|
+
import type TabProps from './Tab.props';
|
|
7
|
+
import { useTabsContext } from './Tabs.context';
|
|
8
|
+
|
|
9
|
+
import { createPressable } from '@gluestack-ui/pressable';
|
|
10
|
+
|
|
11
|
+
const Tab = ({
|
|
12
|
+
value,
|
|
13
|
+
children,
|
|
14
|
+
icon,
|
|
15
|
+
disabled,
|
|
16
|
+
style,
|
|
17
|
+
states,
|
|
18
|
+
...props
|
|
19
|
+
}: TabProps & { states?: { active?: boolean; disabled?: boolean } }) => {
|
|
20
|
+
const {
|
|
21
|
+
value: active,
|
|
22
|
+
select,
|
|
23
|
+
size,
|
|
24
|
+
disabled: allDisabled,
|
|
25
|
+
registerTabLayout,
|
|
26
|
+
} = useTabsContext();
|
|
27
|
+
const { active: pressed } = states || { active: false };
|
|
28
|
+
const isActive = active === value;
|
|
29
|
+
styles.useVariants({ size, pressed });
|
|
30
|
+
const ref = useRef<View | null>(null);
|
|
31
|
+
const handlePress = () => {
|
|
32
|
+
if (disabled || allDisabled) return;
|
|
33
|
+
select(value);
|
|
34
|
+
};
|
|
35
|
+
const handleLayout = useCallback(
|
|
36
|
+
(e: any) => {
|
|
37
|
+
const { x, y, width, height } = e.nativeEvent.layout;
|
|
38
|
+
registerTabLayout(value, { x, y, width, height });
|
|
39
|
+
},
|
|
40
|
+
[value, registerTabLayout]
|
|
41
|
+
);
|
|
42
|
+
return (
|
|
43
|
+
<Pressable
|
|
44
|
+
ref={ref}
|
|
45
|
+
accessibilityRole="tab"
|
|
46
|
+
accessibilityState={{ selected: isActive, disabled: !!(disabled || allDisabled) }}
|
|
47
|
+
onPress={handlePress}
|
|
48
|
+
onLayout={handleLayout}
|
|
49
|
+
style={[styles.tab, style]}
|
|
50
|
+
{...(Platform.OS === 'web'
|
|
51
|
+
? { id: `tab-${value}`, 'aria-controls': `tabpanel-${value}` }
|
|
52
|
+
: null)}
|
|
53
|
+
{...props}
|
|
54
|
+
>
|
|
55
|
+
<View style={styles.content}>
|
|
56
|
+
{icon ? <Icon as={icon} /> : null}
|
|
57
|
+
<DetailText size={size}>{children}</DetailText>
|
|
58
|
+
</View>
|
|
59
|
+
</Pressable>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
Tab.displayName = 'Tab';
|
|
64
|
+
|
|
65
|
+
const styles = StyleSheet.create(theme => ({
|
|
66
|
+
tab: {
|
|
67
|
+
position: 'relative',
|
|
68
|
+
backgroundColor: 'transparent',
|
|
69
|
+
alignItems: 'center',
|
|
70
|
+
justifyContent: 'center',
|
|
71
|
+
paddingHorizontal: theme.components.tabs.item.paddingHorizontal,
|
|
72
|
+
paddingVertical: theme.components.tabs.item.paddingVertical,
|
|
73
|
+
_web: {
|
|
74
|
+
_hover: {
|
|
75
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.hover,
|
|
76
|
+
},
|
|
77
|
+
'_focus-visible': {
|
|
78
|
+
...theme.helpers.focusVisible,
|
|
79
|
+
outlineOffset: -2,
|
|
80
|
+
borderRadius: theme.borderRadius.sm,
|
|
81
|
+
},
|
|
82
|
+
_active: {
|
|
83
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
variants: {
|
|
87
|
+
size: {
|
|
88
|
+
md: { height: theme.components.tabs.md.height },
|
|
89
|
+
lg: { height: theme.components.tabs.lg.height },
|
|
90
|
+
},
|
|
91
|
+
pressed: {
|
|
92
|
+
true: {
|
|
93
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
|
|
94
|
+
},
|
|
95
|
+
false: {},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
content: {
|
|
100
|
+
flexDirection: 'row',
|
|
101
|
+
alignItems: 'center',
|
|
102
|
+
gap: theme.components.tabs.item.gap,
|
|
103
|
+
},
|
|
104
|
+
badge: {
|
|
105
|
+
marginLeft: theme.space[25],
|
|
106
|
+
},
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
const PressableTab = createPressable({ Root: Tab });
|
|
110
|
+
|
|
111
|
+
PressableTab.displayName = 'Tab';
|
|
112
|
+
|
|
113
|
+
export default PressableTab;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
import { Platform, View } from 'react-native';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
import type TabPanelProps from './TabPanel.props';
|
|
5
|
+
import { useTabsContext } from './Tabs.context';
|
|
6
|
+
|
|
7
|
+
const TabPanel = ({ value, children, keepMounted, style, ...rest }: TabPanelProps) => {
|
|
8
|
+
const { value: active } = useTabsContext();
|
|
9
|
+
const isActive = active === value;
|
|
10
|
+
if (!isActive && !keepMounted) return null;
|
|
11
|
+
styles.useVariants({ active: isActive });
|
|
12
|
+
return (
|
|
13
|
+
<View
|
|
14
|
+
{...(Platform.OS === 'web'
|
|
15
|
+
? {
|
|
16
|
+
id: `tabpanel-${value}`,
|
|
17
|
+
role: 'tabpanel',
|
|
18
|
+
'aria-labelledby': `tab-${value}`,
|
|
19
|
+
hidden: !isActive || undefined,
|
|
20
|
+
}
|
|
21
|
+
: { accessibilityRole: 'summary' })}
|
|
22
|
+
importantForAccessibility={isActive ? undefined : 'no-hide-descendants'}
|
|
23
|
+
accessibilityElementsHidden={isActive ? undefined : true}
|
|
24
|
+
style={[styles.panel, style]}
|
|
25
|
+
{...rest}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</View>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const styles = StyleSheet.create(theme => ({
|
|
33
|
+
panel: {
|
|
34
|
+
flex: 1,
|
|
35
|
+
width: '100%',
|
|
36
|
+
paddingTop: theme.space[100],
|
|
37
|
+
variants: {
|
|
38
|
+
active: {
|
|
39
|
+
true: { display: 'flex' },
|
|
40
|
+
false: { display: 'none' },
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
export default memo(TabPanel);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import { SharedValue } from 'react-native-reanimated';
|
|
3
|
+
|
|
4
|
+
export interface TabsContextValue {
|
|
5
|
+
value: string | undefined;
|
|
6
|
+
size: 'md' | 'lg';
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
select: (value: string) => void;
|
|
9
|
+
registerTabLayout: (
|
|
10
|
+
value: string,
|
|
11
|
+
layout: { x: number; y: number; width: number; height: number }
|
|
12
|
+
) => void;
|
|
13
|
+
getTabLayout: (
|
|
14
|
+
value: string
|
|
15
|
+
) => { x: number; y: number; width: number; height: number } | undefined;
|
|
16
|
+
indicatorXSV: SharedValue<number>;
|
|
17
|
+
indicatorSizeSV: SharedValue<number>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const TabsContext = createContext<TabsContextValue | undefined>(undefined);
|
|
21
|
+
|
|
22
|
+
export const useTabsContext = () => {
|
|
23
|
+
const ctx = useContext(TabsContext);
|
|
24
|
+
if (!ctx) throw new Error('Tab / TabPanel must be used within Tabs');
|
|
25
|
+
return ctx;
|
|
26
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { Canvas, Controls, Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { Badge, BodyText, Tab, TabPanel, Tabs, TabsList } from '../../';
|
|
3
|
+
import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
|
|
4
|
+
import * as Stories from './Tabs.stories';
|
|
5
|
+
|
|
6
|
+
<BackToTopButton />
|
|
7
|
+
|
|
8
|
+
<ViewFigmaButton url="https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=6463-1113" />
|
|
9
|
+
|
|
10
|
+
<Meta title="Components / Tabs" />
|
|
11
|
+
|
|
12
|
+
# Tabs
|
|
13
|
+
|
|
14
|
+
Tabs are a navigational component that allows users to move easily between groups of related content.
|
|
15
|
+
|
|
16
|
+
- [Playground](#playground)
|
|
17
|
+
- [Usage](#usage)
|
|
18
|
+
- [Examples](#examples)
|
|
19
|
+
- [Controlled](#controlled)
|
|
20
|
+
- [Overflow & Scrolling](#overflow--scrolling)
|
|
21
|
+
- [With Icons](#with-icons)
|
|
22
|
+
- [Props](#props)
|
|
23
|
+
- [Size Variants](#size-variants)
|
|
24
|
+
- [Accessibility](#accessibility)
|
|
25
|
+
|
|
26
|
+
## Playground
|
|
27
|
+
|
|
28
|
+
<Canvas of={Stories.Playground} />
|
|
29
|
+
<Controls of={Stories.Playground} />
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
<UsageWrap>
|
|
34
|
+
<Tabs defaultValue="account">
|
|
35
|
+
<TabsList>
|
|
36
|
+
<Tab value="account">Account</Tab>
|
|
37
|
+
<Tab value="billing">Billing</Tab>
|
|
38
|
+
<Tab value="usage">Usage</Tab>
|
|
39
|
+
</TabsList>
|
|
40
|
+
<TabPanel value="account">
|
|
41
|
+
<BodyText>Account content</BodyText>
|
|
42
|
+
</TabPanel>
|
|
43
|
+
<TabPanel value="billing">
|
|
44
|
+
<BodyText>Billing content</BodyText>
|
|
45
|
+
</TabPanel>
|
|
46
|
+
<TabPanel value="usage">
|
|
47
|
+
<BodyText>Usage metrics content</BodyText>
|
|
48
|
+
</TabPanel>
|
|
49
|
+
</Tabs>
|
|
50
|
+
</UsageWrap>
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { Tabs, TabsList, Tab, TabPanel } from '@utilitywarehouse/hearth-react-native';
|
|
54
|
+
|
|
55
|
+
<Tabs defaultValue="account">
|
|
56
|
+
<TabsList>
|
|
57
|
+
<Tab value="account">Account</Tab>
|
|
58
|
+
<Tab value="billing">Billing</Tab>
|
|
59
|
+
<Tab value="usage">Usage</Tab>
|
|
60
|
+
</TabsList>
|
|
61
|
+
<TabPanel value="account">
|
|
62
|
+
<BodyText>Account content</BodyText>
|
|
63
|
+
</TabPanel>
|
|
64
|
+
<TabPanel value="billing">
|
|
65
|
+
<BodyText>Billing content</BodyText>
|
|
66
|
+
</TabPanel>
|
|
67
|
+
<TabPanel value="usage">
|
|
68
|
+
<BodyText>Usage metrics content</BodyText>
|
|
69
|
+
</TabPanel>
|
|
70
|
+
</Tabs>;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Examples
|
|
74
|
+
|
|
75
|
+
### Controlled
|
|
76
|
+
|
|
77
|
+
Tabs can be controlled by passing `value` and `onValueChange` props to the `Tabs` component.
|
|
78
|
+
This allows you to manage the active tab state externally.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
const [tab, setTab] = useState('account');
|
|
82
|
+
<Tabs value={tab} onValueChange={setTab}>
|
|
83
|
+
<TabsList>
|
|
84
|
+
<Tab value="account">Account</Tab>
|
|
85
|
+
<Tab value="billing">Billing</Tab>
|
|
86
|
+
<Tab value="usage">Usage</Tab>
|
|
87
|
+
</TabsList>
|
|
88
|
+
<TabPanel value="account">
|
|
89
|
+
<BodyText>Account content</BodyText>
|
|
90
|
+
</TabPanel>
|
|
91
|
+
<TabPanel value="billing">
|
|
92
|
+
<BodyText>Billing content</BodyText>
|
|
93
|
+
</TabPanel>
|
|
94
|
+
<TabPanel value="usage">
|
|
95
|
+
<BodyText>Usage metrics content</BodyText>
|
|
96
|
+
</TabPanel>
|
|
97
|
+
</Tabs>;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Overflow & Scrolling
|
|
101
|
+
|
|
102
|
+
<Canvas of={Stories.WithScrolling} />
|
|
103
|
+
|
|
104
|
+
When the combined tab labels exceed the horizontal space, the list becomes horizontally scrollable.
|
|
105
|
+
Contextual navigation buttons (previous / next) appear just outside the scrollable area. They:
|
|
106
|
+
|
|
107
|
+
- Scroll by ~60% of the visible width per press (for efficient paging)
|
|
108
|
+
- Are hidden from assistive technology (screen readers) - users rely on the tab structure itself
|
|
109
|
+
- Only render when further scrolling in that direction is possible
|
|
110
|
+
- Honor reduced motion: only the indicator animation is affected (system reduced motion will minimise excessive transitions)
|
|
111
|
+
|
|
112
|
+
### With Icons
|
|
113
|
+
|
|
114
|
+
You can add icons to each `Tab` by passing an icon component to the `icon` prop. The icon will be placed to the left of the tab label.
|
|
115
|
+
|
|
116
|
+
<Canvas of={Stories.WithIcons} />
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { Tabs, TabsList, Tab, TabPanel } from '@utilitywarehouse/hearth-react-native';
|
|
120
|
+
import {
|
|
121
|
+
ElectricityMediumIcon,
|
|
122
|
+
MobileMediumIcon,
|
|
123
|
+
InsuranceMediumIcon,
|
|
124
|
+
} from '@utilitywarehouse/hearth-react-native-icons';
|
|
125
|
+
|
|
126
|
+
const MyComponent = () => (
|
|
127
|
+
<Tabs defaultValue="one">
|
|
128
|
+
<TabsList>
|
|
129
|
+
<Tab value="one" icon={ElectricityMediumIcon}>
|
|
130
|
+
Energy
|
|
131
|
+
</Tab>
|
|
132
|
+
<Tab value="two" icon={BroadbandMediumIcon}>
|
|
133
|
+
Broadband
|
|
134
|
+
</Tab>
|
|
135
|
+
<Tab value="three" icon={MobileMediumIcon}>
|
|
136
|
+
Mobile
|
|
137
|
+
</Tab>
|
|
138
|
+
<Tab value="four" icon={InsuranceMediumIcon}>
|
|
139
|
+
Insurance
|
|
140
|
+
</Tab>
|
|
141
|
+
</TabsList>
|
|
142
|
+
<TabPanel value="one">
|
|
143
|
+
<BodyText>One panel</BodyText>
|
|
144
|
+
</TabPanel>
|
|
145
|
+
<TabPanel value="two">
|
|
146
|
+
<BodyText>Two panel</BodyText>
|
|
147
|
+
</TabPanel>
|
|
148
|
+
<TabPanel value="three">
|
|
149
|
+
<BodyText>Three panel</BodyText>
|
|
150
|
+
</TabPanel>
|
|
151
|
+
<TabPanel value="four">
|
|
152
|
+
<BodyText>Four panel</BodyText>
|
|
153
|
+
</TabPanel>
|
|
154
|
+
</Tabs>
|
|
155
|
+
);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Props
|
|
159
|
+
|
|
160
|
+
### Tabs
|
|
161
|
+
|
|
162
|
+
| Prop | Type | Description | Default |
|
|
163
|
+
| --------------- | ------------------------- | ------------------------------------------------------------------- | ---------- |
|
|
164
|
+
| `value` | `string` | Controlled active tab value | - |
|
|
165
|
+
| `defaultValue` | `string` | Uncontrolled initial tab value | first Tab |
|
|
166
|
+
| `onValueChange` | `(value: string) => void` | Change handler | - |
|
|
167
|
+
| `size` | `'md' \| 'lg'` | Size variant (affects tab height & list padding) | `md` |
|
|
168
|
+
| `disabled` | `boolean` | Disables all interaction | `false` |
|
|
169
|
+
| `withPanels` | `boolean` | If true, expects sibling `TabPanel` elements and wires ARIA linkage | `true`\* |
|
|
170
|
+
| `children` | `ReactNode` | Composition (typically `TabsList` + `TabPanel` children) | (required) |
|
|
171
|
+
|
|
172
|
+
\*If omitted you can still compose panels manually, but accessibility linkage (`aria-controls` / `id`) is provided when `withPanels` is true.
|
|
173
|
+
|
|
174
|
+
### TabsList / Tab / TabPanel
|
|
175
|
+
|
|
176
|
+
#### TabsList
|
|
177
|
+
|
|
178
|
+
| Prop | Type | Description | Default |
|
|
179
|
+
| ---------- | ----------- | -------------------------- | ---------- |
|
|
180
|
+
| `children` | `ReactNode` | One or more `Tab` elements | (required) |
|
|
181
|
+
|
|
182
|
+
#### Tab
|
|
183
|
+
|
|
184
|
+
| Prop | Type | Description | Default |
|
|
185
|
+
| ---------- | --------------- | --------------------------------- | ---------- |
|
|
186
|
+
| `value` | `string` | Unique tab value | (required) |
|
|
187
|
+
| `children` | `ReactNode` | Label content (can include badge) | (required) |
|
|
188
|
+
| `icon` | `ComponentType` | Optional leading icon | - |
|
|
189
|
+
| `disabled` | `boolean` | Disabled state | `false` |
|
|
190
|
+
|
|
191
|
+
#### TabPanel
|
|
192
|
+
|
|
193
|
+
| Prop | Type | Description | Default |
|
|
194
|
+
| ------------- | ----------- | ------------------------------------------- | ---------- |
|
|
195
|
+
| `value` | `string` | Matches a `Tab` value | (required) |
|
|
196
|
+
| `children` | `ReactNode` | Panel content | (required) |
|
|
197
|
+
| `keepMounted` | `boolean` | Keep hidden panels in tree (preserve state) | `false` |
|
|
198
|
+
|
|
199
|
+
## Size Variants
|
|
200
|
+
|
|
201
|
+
<Canvas of={Stories.Sizes} />
|
|
202
|
+
|
|
203
|
+
## Accessibility
|
|
204
|
+
|
|
205
|
+
| Element | Role | Notes |
|
|
206
|
+
| ----------- | --------------------------------------- | ----------------------------------------------- |
|
|
207
|
+
| `Tabs` root | `tablist` | Container for related `tab` elements |
|
|
208
|
+
| `Tab` | `tab` | Uses `accessibilityState.selected` & `disabled` |
|
|
209
|
+
| `TabPanel` | `tabpanel` (web) / hidden view (native) | Inactive panels removed from a11y tree |
|
|
210
|
+
|
|
211
|
+
Selection state is communicated through `accessibilityState`. Provide concise labels (children text) for best screen reader clarity.
|
|
212
|
+
Any extra content you compose is read in order unless you explicitly hide it. The animated indicator reflects the active tab;
|
|
213
|
+
reduced motion preferences are respected. Hidden panels are removed from the accessibility tree.
|
|
214
|
+
Overflow scroll buttons are hidden from assistive tech and only appear visually when scrolling is possible.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ViewProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface TabsProps extends ViewProps {
|
|
5
|
+
/** Controlled active tab value */
|
|
6
|
+
value?: string;
|
|
7
|
+
/** Uncontrolled initial value */
|
|
8
|
+
defaultValue?: string;
|
|
9
|
+
/** Callback when active tab changes */
|
|
10
|
+
onValueChange?: (value: string) => void;
|
|
11
|
+
/** Size variant */
|
|
12
|
+
size?: 'md' | 'lg';
|
|
13
|
+
/** Tabs (Tab components) */
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/** Disable all tabs */
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/** If true, expect sibling TabPanel components and manage their rendering/ARIA linkage */
|
|
18
|
+
withPanels?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default TabsProps;
|