@ankhorage/surface 4.4.1 → 5.0.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 +12 -0
- package/README.md +2 -2
- package/dist/features/bottom-sheet/BottomSheetProvider.js +8 -6
- package/dist/features/bottom-sheet/BottomSheetProvider.js.map +1 -1
- package/dist/features/bottom-sheet/public.d.ts +2 -1
- package/dist/features/bottom-sheet/public.d.ts.map +1 -1
- package/dist/features/bottom-sheet/public.js +1 -0
- package/dist/features/bottom-sheet/public.js.map +1 -1
- package/dist/{components/modal → features/modal/adapters/inbound}/Modal.d.ts +2 -1
- package/dist/features/modal/adapters/inbound/Modal.d.ts.map +1 -0
- package/dist/features/modal/adapters/inbound/Modal.js +51 -0
- package/dist/features/modal/adapters/inbound/Modal.js.map +1 -0
- package/dist/features/modal/public.d.ts +3 -0
- package/dist/features/modal/public.d.ts.map +1 -0
- package/dist/features/modal/public.js +2 -0
- package/dist/features/modal/public.js.map +1 -0
- package/dist/features/popover-menu/adapters/inbound/PopoverMenu.d.ts +5 -0
- package/dist/features/popover-menu/adapters/inbound/PopoverMenu.d.ts.map +1 -0
- package/dist/features/popover-menu/adapters/inbound/PopoverMenu.js +85 -0
- package/dist/features/popover-menu/adapters/inbound/PopoverMenu.js.map +1 -0
- package/dist/features/popover-menu/composition/usePopoverMenuController.d.ts +19 -0
- package/dist/features/popover-menu/composition/usePopoverMenuController.d.ts.map +1 -0
- package/dist/features/popover-menu/composition/usePopoverMenuController.js +35 -0
- package/dist/features/popover-menu/composition/usePopoverMenuController.js.map +1 -0
- package/dist/features/popover-menu/public.d.ts +3 -0
- package/dist/features/popover-menu/public.d.ts.map +1 -0
- package/dist/features/popover-menu/public.js +2 -0
- package/dist/features/popover-menu/public.js.map +1 -0
- package/dist/features/popover-menu/utils/resolveNextMenuIndex.d.ts +5 -0
- package/dist/features/popover-menu/utils/resolveNextMenuIndex.d.ts.map +1 -0
- package/dist/features/popover-menu/utils/resolveNextMenuIndex.js +18 -0
- package/dist/features/popover-menu/utils/resolveNextMenuIndex.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tab.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/Tab.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tab.js +33 -0
- package/dist/features/tabs/adapters/inbound/Tab.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabList.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/TabList.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabList.js +42 -0
- package/dist/features/tabs/adapters/inbound/TabList.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.js +14 -0
- package/dist/features/tabs/adapters/inbound/TabPanel.js.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tabs.d.ts +5 -0
- package/dist/features/tabs/adapters/inbound/Tabs.d.ts.map +1 -0
- package/dist/features/tabs/adapters/inbound/Tabs.js +12 -0
- package/dist/features/tabs/adapters/inbound/Tabs.js.map +1 -0
- package/dist/features/tabs/composition/TabsContext.d.ts +4 -0
- package/dist/features/tabs/composition/TabsContext.d.ts.map +1 -0
- package/dist/features/tabs/composition/TabsContext.js +3 -0
- package/dist/features/tabs/composition/TabsContext.js.map +1 -0
- package/dist/features/tabs/composition/useTabRegistration.d.ts +7 -0
- package/dist/features/tabs/composition/useTabRegistration.d.ts.map +1 -0
- package/dist/features/tabs/composition/useTabRegistration.js +20 -0
- package/dist/features/tabs/composition/useTabRegistration.js.map +1 -0
- package/dist/features/tabs/composition/useTabsContext.d.ts +4 -0
- package/dist/features/tabs/composition/useTabsContext.d.ts.map +1 -0
- package/dist/{components/tabs/context.js → features/tabs/composition/useTabsContext.js} +4 -4
- package/dist/features/tabs/composition/useTabsContext.js.map +1 -0
- package/dist/features/tabs/composition/useTabsController.d.ts +4 -0
- package/dist/features/tabs/composition/useTabsController.d.ts.map +1 -0
- package/dist/features/tabs/composition/useTabsController.js +43 -0
- package/dist/features/tabs/composition/useTabsController.js.map +1 -0
- package/dist/features/tabs/public.d.ts +6 -0
- package/dist/features/tabs/public.d.ts.map +1 -0
- package/dist/features/tabs/public.js +5 -0
- package/dist/features/tabs/public.js.map +1 -0
- package/dist/features/tabs/utils/resolveNextTabValue.d.ts +4 -0
- package/dist/features/tabs/utils/resolveNextTabValue.d.ts.map +1 -0
- package/dist/{components/tabs/navigation.js → features/tabs/utils/resolveNextTabValue.js} +10 -13
- package/dist/features/tabs/utils/resolveNextTabValue.js.map +1 -0
- package/dist/features/tabs/utils/resolveTabElementId.d.ts +3 -0
- package/dist/features/tabs/utils/resolveTabElementId.d.ts.map +1 -0
- package/dist/features/tabs/utils/resolveTabElementId.js +10 -0
- package/dist/features/tabs/utils/resolveTabElementId.js.map +1 -0
- package/dist/features/tooltip/adapters/inbound/Tooltip.d.ts +5 -0
- package/dist/features/tooltip/adapters/inbound/Tooltip.d.ts.map +1 -0
- package/dist/features/tooltip/adapters/inbound/Tooltip.js +25 -0
- package/dist/features/tooltip/adapters/inbound/Tooltip.js.map +1 -0
- package/dist/features/tooltip/composition/useTooltipVisibility.d.ts +9 -0
- package/dist/features/tooltip/composition/useTooltipVisibility.d.ts.map +1 -0
- package/dist/features/tooltip/composition/useTooltipVisibility.js +25 -0
- package/dist/features/tooltip/composition/useTooltipVisibility.js.map +1 -0
- package/dist/features/tooltip/public.d.ts +3 -0
- package/dist/features/tooltip/public.d.ts.map +1 -0
- package/dist/features/tooltip/public.js +2 -0
- package/dist/features/tooltip/public.js.map +1 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/types/bottomSheet.d.ts +3 -0
- package/dist/types/bottomSheet.d.ts.map +1 -1
- package/dist/types/bottomSheet.js.map +1 -1
- package/dist/{components/modal/types.d.ts → types/modal.d.ts} +2 -2
- package/dist/types/modal.d.ts.map +1 -0
- package/dist/types/modal.js +2 -0
- package/dist/types/modal.js.map +1 -0
- package/dist/types/popoverMenu.d.ts +24 -0
- package/dist/types/popoverMenu.d.ts.map +1 -0
- package/dist/types/popoverMenu.js +2 -0
- package/dist/types/popoverMenu.js.map +1 -0
- package/dist/types/tabs.d.ts +43 -0
- package/dist/types/tabs.d.ts.map +1 -0
- package/dist/types/tabs.js +2 -0
- package/dist/types/tabs.js.map +1 -0
- package/dist/{components/tooltip/types.d.ts → types/tooltip.d.ts} +2 -2
- package/dist/types/tooltip.d.ts.map +1 -0
- package/dist/types/tooltip.js +2 -0
- package/dist/types/tooltip.js.map +1 -0
- package/package.json +1 -1
- package/src/features/bottom-sheet/BottomSheetProvider.tsx +13 -8
- package/src/features/bottom-sheet/public.test.ts +23 -0
- package/src/features/bottom-sheet/public.ts +12 -1
- package/src/features/modal/adapters/inbound/Modal.tsx +74 -0
- package/src/features/modal/public.ts +2 -0
- package/src/features/popover-menu/adapters/inbound/PopoverMenu.tsx +201 -0
- package/src/features/popover-menu/composition/usePopoverMenuController.ts +55 -0
- package/src/features/popover-menu/public.test.ts +13 -0
- package/src/features/popover-menu/public.ts +6 -0
- package/src/{components/menu/navigation.test.ts → features/popover-menu/utils/resolveNextMenuIndex.test.ts} +4 -4
- package/src/features/popover-menu/utils/resolveNextMenuIndex.ts +21 -0
- package/src/features/tabs/adapters/inbound/Tab.tsx +67 -0
- package/src/features/tabs/adapters/inbound/TabList.tsx +50 -0
- package/src/{components/tabs → features/tabs/adapters/inbound}/TabPanel.tsx +6 -10
- package/src/features/tabs/adapters/inbound/Tabs.tsx +17 -0
- package/src/features/tabs/composition/TabsContext.tsx +5 -0
- package/src/features/tabs/composition/useTabRegistration.ts +27 -0
- package/src/features/tabs/composition/useTabsContext.ts +13 -0
- package/src/features/tabs/composition/useTabsController.ts +55 -0
- package/src/features/tabs/public.ts +5 -0
- package/src/{components/tabs/navigation.test.ts → features/tabs/utils/resolveNextTabValue.test.ts} +2 -2
- package/src/features/tabs/utils/resolveNextTabValue.ts +24 -0
- package/src/features/tabs/utils/resolveTabElementId.test.ts +19 -0
- package/src/features/tabs/utils/resolveTabElementId.ts +14 -0
- package/src/features/tooltip/adapters/inbound/Tooltip.tsx +56 -0
- package/src/features/tooltip/composition/useTooltipVisibility.ts +29 -0
- package/src/features/tooltip/public.test.ts +11 -0
- package/src/features/tooltip/public.ts +2 -0
- package/src/index.test.ts +12 -5
- package/src/index.ts +12 -8
- package/src/types/bottomSheet.ts +4 -0
- package/src/{components/modal/types.ts → types/modal.ts} +1 -1
- package/src/types/popoverMenu.ts +27 -0
- package/src/types/tabs.ts +51 -0
- package/src/{components/tooltip/types.ts → types/tooltip.ts} +1 -1
- package/dist/components/menu/Menu.d.ts +0 -4
- package/dist/components/menu/Menu.d.ts.map +0 -1
- package/dist/components/menu/Menu.js +0 -152
- package/dist/components/menu/Menu.js.map +0 -1
- package/dist/components/menu/index.d.ts +0 -3
- package/dist/components/menu/index.d.ts.map +0 -1
- package/dist/components/menu/index.js +0 -2
- package/dist/components/menu/index.js.map +0 -1
- package/dist/components/menu/navigation.d.ts +0 -4
- package/dist/components/menu/navigation.d.ts.map +0 -1
- package/dist/components/menu/navigation.js +0 -25
- package/dist/components/menu/navigation.js.map +0 -1
- package/dist/components/menu/types.d.ts +0 -23
- package/dist/components/menu/types.d.ts.map +0 -1
- package/dist/components/menu/types.js +0 -2
- package/dist/components/menu/types.js.map +0 -1
- package/dist/components/modal/Modal.d.ts.map +0 -1
- package/dist/components/modal/Modal.js +0 -59
- package/dist/components/modal/Modal.js.map +0 -1
- package/dist/components/modal/index.d.ts +0 -3
- package/dist/components/modal/index.d.ts.map +0 -1
- package/dist/components/modal/index.js +0 -2
- package/dist/components/modal/index.js.map +0 -1
- package/dist/components/modal/types.d.ts.map +0 -1
- package/dist/components/modal/types.js +0 -2
- package/dist/components/modal/types.js.map +0 -1
- package/dist/components/tabs/Tab.d.ts +0 -4
- package/dist/components/tabs/Tab.d.ts.map +0 -1
- package/dist/components/tabs/Tab.js +0 -48
- package/dist/components/tabs/Tab.js.map +0 -1
- package/dist/components/tabs/TabList.d.ts +0 -4
- package/dist/components/tabs/TabList.d.ts.map +0 -1
- package/dist/components/tabs/TabList.js +0 -37
- package/dist/components/tabs/TabList.js.map +0 -1
- package/dist/components/tabs/TabPanel.d.ts +0 -4
- package/dist/components/tabs/TabPanel.d.ts.map +0 -1
- package/dist/components/tabs/TabPanel.js +0 -16
- package/dist/components/tabs/TabPanel.js.map +0 -1
- package/dist/components/tabs/Tabs.d.ts +0 -4
- package/dist/components/tabs/Tabs.d.ts.map +0 -1
- package/dist/components/tabs/Tabs.js +0 -54
- package/dist/components/tabs/Tabs.js.map +0 -1
- package/dist/components/tabs/a11y.d.ts +0 -3
- package/dist/components/tabs/a11y.d.ts.map +0 -1
- package/dist/components/tabs/a11y.js +0 -13
- package/dist/components/tabs/a11y.js.map +0 -1
- package/dist/components/tabs/context.d.ts +0 -20
- package/dist/components/tabs/context.d.ts.map +0 -1
- package/dist/components/tabs/context.js.map +0 -1
- package/dist/components/tabs/index.d.ts +0 -6
- package/dist/components/tabs/index.d.ts.map +0 -1
- package/dist/components/tabs/index.js +0 -5
- package/dist/components/tabs/index.js.map +0 -1
- package/dist/components/tabs/navigation.d.ts +0 -3
- package/dist/components/tabs/navigation.d.ts.map +0 -1
- package/dist/components/tabs/navigation.js.map +0 -1
- package/dist/components/tabs/types.d.ts +0 -26
- package/dist/components/tabs/types.d.ts.map +0 -1
- package/dist/components/tabs/types.js +0 -2
- package/dist/components/tabs/types.js.map +0 -1
- package/dist/components/tooltip/Tooltip.d.ts +0 -4
- package/dist/components/tooltip/Tooltip.d.ts.map +0 -1
- package/dist/components/tooltip/Tooltip.js +0 -75
- package/dist/components/tooltip/Tooltip.js.map +0 -1
- package/dist/components/tooltip/index.d.ts +0 -3
- package/dist/components/tooltip/index.d.ts.map +0 -1
- package/dist/components/tooltip/index.js +0 -2
- package/dist/components/tooltip/index.js.map +0 -1
- package/dist/components/tooltip/types.d.ts.map +0 -1
- package/dist/components/tooltip/types.js +0 -2
- package/dist/components/tooltip/types.js.map +0 -1
- package/src/components/menu/Menu.tsx +0 -228
- package/src/components/menu/index.ts +0 -2
- package/src/components/menu/navigation.ts +0 -34
- package/src/components/menu/types.ts +0 -26
- package/src/components/modal/Modal.tsx +0 -96
- package/src/components/modal/index.ts +0 -2
- package/src/components/tabs/Tab.tsx +0 -89
- package/src/components/tabs/TabList.tsx +0 -51
- package/src/components/tabs/Tabs.tsx +0 -67
- package/src/components/tabs/a11y.test.ts +0 -15
- package/src/components/tabs/a11y.ts +0 -15
- package/src/components/tabs/context.tsx +0 -31
- package/src/components/tabs/index.ts +0 -5
- package/src/components/tabs/navigation.ts +0 -32
- package/src/components/tabs/types.ts +0 -30
- package/src/components/tooltip/Tooltip.tsx +0 -117
- package/src/components/tooltip/index.ts +0 -2
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*** Resolves the next enabled action index for standard menu keyboard navigation. */
|
|
2
|
+
export function resolveNextMenuIndex(
|
|
3
|
+
items: readonly { disabled?: boolean }[],
|
|
4
|
+
currentIndex: number,
|
|
5
|
+
key: string,
|
|
6
|
+
): number {
|
|
7
|
+
const enabledIndexes = items.flatMap((item, index) => (item.disabled ? [] : [index]));
|
|
8
|
+
if (enabledIndexes.length === 0) return -1;
|
|
9
|
+
if (key === 'Home') return enabledIndexes.at(0) ?? -1;
|
|
10
|
+
if (key === 'End') return enabledIndexes.at(-1) ?? -1;
|
|
11
|
+
|
|
12
|
+
const activeEnabledIndex = enabledIndexes.indexOf(currentIndex);
|
|
13
|
+
const nextEnabledIndex =
|
|
14
|
+
activeEnabledIndex === -1
|
|
15
|
+
? 0
|
|
16
|
+
: key === 'ArrowUp'
|
|
17
|
+
? (activeEnabledIndex - 1 + enabledIndexes.length) % enabledIndexes.length
|
|
18
|
+
: (activeEnabledIndex + 1) % enabledIndexes.length;
|
|
19
|
+
|
|
20
|
+
return enabledIndexes.at(nextEnabledIndex) ?? -1;
|
|
21
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Pressable, type ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '../../../../theme/ThemeContext';
|
|
5
|
+
import type { TabProps } from '../../../../types/tabs';
|
|
6
|
+
import { Box } from '../../../layout/public';
|
|
7
|
+
import { Text } from '../../../typography/public';
|
|
8
|
+
import { useTabRegistration } from '../../composition/useTabRegistration';
|
|
9
|
+
import { useTabsContext } from '../../composition/useTabsContext';
|
|
10
|
+
|
|
11
|
+
/*** Renders one accessible selectable tab inside a Tabs context. */
|
|
12
|
+
export function Tab({
|
|
13
|
+
value,
|
|
14
|
+
children,
|
|
15
|
+
disabled = false,
|
|
16
|
+
interactionPolicy = 'enabled',
|
|
17
|
+
testID,
|
|
18
|
+
}: TabProps) {
|
|
19
|
+
const { theme } = useTheme();
|
|
20
|
+
const { activeValue, getPanelId, getTabId, setActiveValue, setFocusedValue } = useTabsContext();
|
|
21
|
+
const pressableRef = useTabRegistration({ disabled, value });
|
|
22
|
+
const selected = activeValue === value;
|
|
23
|
+
const passive = interactionPolicy === 'passive';
|
|
24
|
+
const onPress = passive || disabled ? undefined : () => setActiveValue(value);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Pressable
|
|
28
|
+
accessibilityLabel={undefined}
|
|
29
|
+
accessibilityRole="tab"
|
|
30
|
+
accessibilityState={{ disabled, selected }}
|
|
31
|
+
aria-controls={getPanelId(value)}
|
|
32
|
+
disabled={disabled}
|
|
33
|
+
nativeID={getTabId(value)}
|
|
34
|
+
onBlur={() => setFocusedValue(undefined)}
|
|
35
|
+
onFocus={() => setFocusedValue(value)}
|
|
36
|
+
onPress={onPress}
|
|
37
|
+
ref={pressableRef}
|
|
38
|
+
testID={testID}
|
|
39
|
+
>
|
|
40
|
+
<Box
|
|
41
|
+
px="m"
|
|
42
|
+
py="s"
|
|
43
|
+
style={resolveTabStyle({
|
|
44
|
+
borderColor: selected
|
|
45
|
+
? theme.semantics.action.primary.base
|
|
46
|
+
: theme.semantics.border.default,
|
|
47
|
+
disabled,
|
|
48
|
+
})}
|
|
49
|
+
>
|
|
50
|
+
<Text color={selected ? 'primary' : undefined} variant="label" weight="medium">
|
|
51
|
+
{children}
|
|
52
|
+
</Text>
|
|
53
|
+
</Box>
|
|
54
|
+
</Pressable>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*** Resolves active and disabled visual state without inline JSX styles. */
|
|
59
|
+
function resolveTabStyle({
|
|
60
|
+
borderColor,
|
|
61
|
+
disabled,
|
|
62
|
+
}: {
|
|
63
|
+
borderColor: string;
|
|
64
|
+
disabled: boolean;
|
|
65
|
+
}): ViewStyle {
|
|
66
|
+
return { borderBottomColor: borderColor, borderBottomWidth: 2, opacity: disabled ? 0.64 : 1 };
|
|
67
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useFocusManager } from '../../../../internal/focus/useFocusManager';
|
|
5
|
+
import type { TabListProps, TabNavigationKey } from '../../../../types/tabs';
|
|
6
|
+
import { Box } from '../../../layout/public';
|
|
7
|
+
import { useTabsContext } from '../../composition/useTabsContext';
|
|
8
|
+
import { resolveNextTabValue } from '../../utils/resolveNextTabValue';
|
|
9
|
+
|
|
10
|
+
const navigationKeys: readonly string[] = [
|
|
11
|
+
'ArrowLeft',
|
|
12
|
+
'ArrowRight',
|
|
13
|
+
'ArrowUp',
|
|
14
|
+
'ArrowDown',
|
|
15
|
+
'Home',
|
|
16
|
+
'End',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/*** Renders the accessible tab list and owns keyboard focus navigation. */
|
|
20
|
+
export function TabList({ children, testID }: TabListProps) {
|
|
21
|
+
const { bindKeydown } = useFocusManager();
|
|
22
|
+
const { focusedValue, setActiveValue, tabs } = useTabsContext();
|
|
23
|
+
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
if (!focusedValue) return undefined;
|
|
26
|
+
|
|
27
|
+
return bindKeydown((event) => {
|
|
28
|
+
if (!isTabNavigationKey(event.key)) return;
|
|
29
|
+
const nextValue = resolveNextTabValue(tabs, focusedValue, event.key);
|
|
30
|
+
if (!nextValue) return;
|
|
31
|
+
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
tabs.find((tab) => tab.value === nextValue)?.focus();
|
|
34
|
+
setActiveValue(nextValue);
|
|
35
|
+
});
|
|
36
|
+
}, [bindKeydown, focusedValue, setActiveValue, tabs]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Box accessibilityRole="tablist" style={styles.list} testID={testID}>
|
|
40
|
+
{children}
|
|
41
|
+
</Box>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/*** Narrows keyboard event keys to the tab navigation key contract. */
|
|
46
|
+
function isTabNavigationKey(key: string | undefined): key is TabNavigationKey {
|
|
47
|
+
return key !== undefined && navigationKeys.includes(key);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const styles = StyleSheet.create({ list: { flexDirection: 'row' } });
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import type { TabPanelProps } from '../../../../types/tabs';
|
|
5
|
+
import { useTabsContext } from '../../composition/useTabsContext';
|
|
6
6
|
|
|
7
7
|
const TAB_PANEL_ROLE = 'tabpanel' as React.ComponentProps<typeof View>['accessibilityRole'];
|
|
8
8
|
|
|
9
|
+
/*** Renders the content panel associated with the active tab value. */
|
|
9
10
|
export function TabPanel({ value, children, testID }: TabPanelProps) {
|
|
10
11
|
const { activeValue, getPanelId, getTabId } = useTabsContext();
|
|
11
12
|
|
|
12
|
-
if (activeValue !== value)
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const tabId = getTabId(value);
|
|
17
|
-
const panelId = getPanelId(value);
|
|
13
|
+
if (activeValue !== value) return null;
|
|
18
14
|
|
|
19
15
|
return (
|
|
20
16
|
<View
|
|
21
|
-
accessibilityLabelledBy={
|
|
17
|
+
accessibilityLabelledBy={getTabId(value)}
|
|
22
18
|
accessibilityRole={TAB_PANEL_ROLE}
|
|
23
|
-
nativeID={
|
|
19
|
+
nativeID={getPanelId(value)}
|
|
24
20
|
testID={testID}
|
|
25
21
|
>
|
|
26
22
|
{children}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { TabsProps } from '../../../../types/tabs';
|
|
4
|
+
import { Box } from '../../../layout/public';
|
|
5
|
+
import { TabsContext } from '../../composition/TabsContext';
|
|
6
|
+
import { useTabsController } from '../../composition/useTabsController';
|
|
7
|
+
|
|
8
|
+
/*** Provides accessible tab selection state to TabList, Tab, and TabPanel children. */
|
|
9
|
+
export function Tabs({ children, ...props }: TabsProps) {
|
|
10
|
+
const contextValue = useTabsController(props);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<TabsContext value={contextValue}>
|
|
14
|
+
<Box testID={props.testID}>{children}</Box>
|
|
15
|
+
</TabsContext>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Pressable } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTabsContext } from './useTabsContext';
|
|
5
|
+
|
|
6
|
+
/*** Registers one focusable tab with the owning Tabs context. */
|
|
7
|
+
export function useTabRegistration({ disabled, value }: { disabled: boolean; value: string }) {
|
|
8
|
+
const { registerTab, unregisterTab } = useTabsContext();
|
|
9
|
+
const pressableRef = React.useRef<React.ElementRef<typeof Pressable> | null>(null);
|
|
10
|
+
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
registerTab({
|
|
13
|
+
disabled,
|
|
14
|
+
focus: () => {
|
|
15
|
+
const focusable = pressableRef.current as unknown as {
|
|
16
|
+
focus?: (() => void) | undefined;
|
|
17
|
+
} | null;
|
|
18
|
+
focusable?.focus?.();
|
|
19
|
+
},
|
|
20
|
+
value,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return () => unregisterTab(value);
|
|
24
|
+
}, [disabled, registerTab, unregisterTab, value]);
|
|
25
|
+
|
|
26
|
+
return pressableRef;
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { TabsContextValue } from '../../../types/tabs';
|
|
4
|
+
import { TabsContext } from './TabsContext';
|
|
5
|
+
|
|
6
|
+
/*** Returns the active Tabs feature context. */
|
|
7
|
+
export function useTabsContext(): TabsContextValue {
|
|
8
|
+
const value = React.use(TabsContext);
|
|
9
|
+
|
|
10
|
+
if (!value) throw new Error('Tabs components must be used within <Tabs>.');
|
|
11
|
+
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useControllableState } from '../../../internal/useControllableState';
|
|
4
|
+
import type { TabRegistration, TabsContextValue, TabsProps } from '../../../types/tabs';
|
|
5
|
+
import { resolveTabElementId } from '../utils/resolveTabElementId';
|
|
6
|
+
|
|
7
|
+
/*** Owns controlled state, registration, focus state, and ids for one Tabs instance. */
|
|
8
|
+
export function useTabsController({
|
|
9
|
+
defaultValue,
|
|
10
|
+
onValueChange,
|
|
11
|
+
testID,
|
|
12
|
+
value,
|
|
13
|
+
}: Pick<TabsProps, 'defaultValue' | 'onValueChange' | 'testID' | 'value'>): TabsContextValue {
|
|
14
|
+
const [activeValue, setActiveValue] = useControllableState<string | undefined>({
|
|
15
|
+
defaultValue,
|
|
16
|
+
onChange: (nextValue) => {
|
|
17
|
+
if (nextValue !== undefined) onValueChange?.(nextValue);
|
|
18
|
+
},
|
|
19
|
+
value,
|
|
20
|
+
});
|
|
21
|
+
const [focusedValue, setFocusedValue] = React.useState<string | undefined>(undefined);
|
|
22
|
+
const [tabs, setTabs] = React.useState<readonly TabRegistration[]>([]);
|
|
23
|
+
|
|
24
|
+
const registerTab = React.useCallback((tab: TabRegistration) => {
|
|
25
|
+
setTabs((current) =>
|
|
26
|
+
current.some((entry) => entry.value === tab.value)
|
|
27
|
+
? current.map((entry) => (entry.value === tab.value ? tab : entry))
|
|
28
|
+
: [...current, tab],
|
|
29
|
+
);
|
|
30
|
+
}, []);
|
|
31
|
+
const unregisterTab = React.useCallback((valueToRemove: string) => {
|
|
32
|
+
setTabs((current) => current.filter((entry) => entry.value !== valueToRemove));
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (activeValue !== undefined) return;
|
|
37
|
+
const firstEnabledTab = tabs.find((entry) => !entry.disabled);
|
|
38
|
+
if (firstEnabledTab) setActiveValue(firstEnabledTab.value);
|
|
39
|
+
}, [activeValue, setActiveValue, tabs]);
|
|
40
|
+
|
|
41
|
+
return React.useMemo(
|
|
42
|
+
() => ({
|
|
43
|
+
activeValue,
|
|
44
|
+
focusedValue,
|
|
45
|
+
getPanelId: (tabValue: string) => resolveTabElementId('panel', testID, tabValue),
|
|
46
|
+
getTabId: (tabValue: string) => resolveTabElementId('tab', testID, tabValue),
|
|
47
|
+
registerTab,
|
|
48
|
+
setActiveValue: (nextValue: string) => setActiveValue(nextValue),
|
|
49
|
+
setFocusedValue,
|
|
50
|
+
tabs,
|
|
51
|
+
unregisterTab,
|
|
52
|
+
}),
|
|
53
|
+
[activeValue, focusedValue, registerTab, setActiveValue, tabs, testID, unregisterTab],
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { TabListProps, TabPanelProps, TabProps, TabsProps } from '../../types/tabs';
|
|
2
|
+
export { Tab } from './adapters/inbound/Tab';
|
|
3
|
+
export { TabList } from './adapters/inbound/TabList';
|
|
4
|
+
export { TabPanel } from './adapters/inbound/TabPanel';
|
|
5
|
+
export { Tabs } from './adapters/inbound/Tabs';
|
package/src/{components/tabs/navigation.test.ts → features/tabs/utils/resolveNextTabValue.test.ts}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test';
|
|
2
2
|
|
|
3
|
-
import { resolveNextTabValue } from './
|
|
3
|
+
import { resolveNextTabValue } from './resolveNextTabValue';
|
|
4
4
|
|
|
5
5
|
const tabs = [
|
|
6
6
|
{ disabled: false, focus: () => undefined, value: 'overview' },
|
|
7
7
|
{ disabled: true, focus: () => undefined, value: 'disabled' },
|
|
8
8
|
{ disabled: false, focus: () => undefined, value: 'details' },
|
|
9
|
-
];
|
|
9
|
+
] as const;
|
|
10
10
|
|
|
11
11
|
describe('resolveNextTabValue', () => {
|
|
12
12
|
it('skips disabled tabs when cycling', () => {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TabNavigationKey, TabRegistration } from '../../../types/tabs';
|
|
2
|
+
|
|
3
|
+
/*** Resolves the next enabled tab for keyboard focus navigation. */
|
|
4
|
+
export function resolveNextTabValue(
|
|
5
|
+
tabs: readonly TabRegistration[],
|
|
6
|
+
currentValue: string | undefined,
|
|
7
|
+
key: TabNavigationKey,
|
|
8
|
+
): string | undefined {
|
|
9
|
+
const enabledTabs = tabs.filter((tab) => !tab.disabled);
|
|
10
|
+
if (enabledTabs.length === 0) return undefined;
|
|
11
|
+
|
|
12
|
+
if (key === 'Home') return enabledTabs.at(0)?.value;
|
|
13
|
+
if (key === 'End') return enabledTabs.at(-1)?.value;
|
|
14
|
+
|
|
15
|
+
const currentIndex = enabledTabs.findIndex((tab) => tab.value === currentValue);
|
|
16
|
+
if (currentIndex === -1) return enabledTabs.at(0)?.value;
|
|
17
|
+
|
|
18
|
+
const nextIndex =
|
|
19
|
+
key === 'ArrowLeft' || key === 'ArrowUp'
|
|
20
|
+
? (currentIndex - 1 + enabledTabs.length) % enabledTabs.length
|
|
21
|
+
: (currentIndex + 1) % enabledTabs.length;
|
|
22
|
+
|
|
23
|
+
return enabledTabs.at(nextIndex)?.value;
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { resolveTabElementId } from './resolveTabElementId';
|
|
4
|
+
|
|
5
|
+
describe('resolveTabElementId', () => {
|
|
6
|
+
it('creates stable ids from tab values', () => {
|
|
7
|
+
expect(resolveTabElementId('tab', undefined, 'Account Settings')).toBe(
|
|
8
|
+
'tabs-tab-Account-Settings',
|
|
9
|
+
);
|
|
10
|
+
expect(resolveTabElementId('panel', undefined, 'Account Settings')).toBe(
|
|
11
|
+
'tabs-panel-Account-Settings',
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('namespaces ids by tabs testID when provided', () => {
|
|
16
|
+
expect(resolveTabElementId('tab', 'settings', 'billing')).toBe('settings-tabs-tab-billing');
|
|
17
|
+
expect(resolveTabElementId('panel', 'settings', 'billing')).toBe('settings-tabs-panel-billing');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*** Creates a stable tab or tab-panel id from a Tabs test id and tab value. */
|
|
2
|
+
export function resolveTabElementId(
|
|
3
|
+
kind: 'tab' | 'panel',
|
|
4
|
+
testID: string | undefined,
|
|
5
|
+
value: string,
|
|
6
|
+
): string {
|
|
7
|
+
const base = testID ? `${testID}-tabs` : 'tabs';
|
|
8
|
+
return `${base}-${kind}-${sanitizeTabValue(value)}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/*** Normalizes a tab value for use inside an accessibility id. */
|
|
12
|
+
function sanitizeTabValue(value: string): string {
|
|
13
|
+
return value.trim().replace(/[^a-zA-Z0-9_-]+/g, '-');
|
|
14
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Platform, Pressable, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '../../../../theme/ThemeContext';
|
|
5
|
+
import type { TooltipProps } from '../../../../types/tooltip';
|
|
6
|
+
import { Popover } from '../../../popover/public';
|
|
7
|
+
import { Surface } from '../../../surface/public';
|
|
8
|
+
import { Text } from '../../../typography/public';
|
|
9
|
+
import { useTooltipVisibility } from '../../composition/useTooltipVisibility';
|
|
10
|
+
|
|
11
|
+
/*** Presents delayed hover/focus help through the shared Popover foundation. */
|
|
12
|
+
export function Tooltip({
|
|
13
|
+
children,
|
|
14
|
+
content,
|
|
15
|
+
delay = 150,
|
|
16
|
+
interactionPolicy = 'enabled',
|
|
17
|
+
placement = 'top',
|
|
18
|
+
testID,
|
|
19
|
+
}: TooltipProps) {
|
|
20
|
+
const { theme } = useTheme();
|
|
21
|
+
const passive = interactionPolicy === 'passive';
|
|
22
|
+
const { hide, setVisible, show, visible } = useTooltipVisibility(delay, passive);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Popover
|
|
26
|
+
closeOnOutsidePress={false}
|
|
27
|
+
interactionPolicy={interactionPolicy}
|
|
28
|
+
onOpenChange={setVisible}
|
|
29
|
+
open={visible}
|
|
30
|
+
placement={placement}
|
|
31
|
+
testID={testID}
|
|
32
|
+
anchor={() => (
|
|
33
|
+
<Pressable
|
|
34
|
+
onBlur={passive ? undefined : hide}
|
|
35
|
+
onFocus={passive ? undefined : show}
|
|
36
|
+
onHoverIn={Platform.OS === 'web' && !passive ? show : undefined}
|
|
37
|
+
onHoverOut={Platform.OS === 'web' && !passive ? hide : undefined}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</Pressable>
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
<View pointerEvents="none">
|
|
44
|
+
<Surface
|
|
45
|
+
p="s"
|
|
46
|
+
style={{ backgroundColor: theme.semantics.surface.inverse }}
|
|
47
|
+
variant="raised"
|
|
48
|
+
>
|
|
49
|
+
<Text emphasis="inverse" variant="caption">
|
|
50
|
+
{content}
|
|
51
|
+
</Text>
|
|
52
|
+
</Surface>
|
|
53
|
+
</View>
|
|
54
|
+
</Popover>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
/*** Manages delayed tooltip visibility and timer cleanup. */
|
|
4
|
+
export function useTooltipVisibility(delay: number, passive: boolean) {
|
|
5
|
+
const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
6
|
+
const [visible, setVisible] = React.useState(false);
|
|
7
|
+
|
|
8
|
+
const clearTimer = React.useCallback(() => {
|
|
9
|
+
if (timeoutRef.current) {
|
|
10
|
+
clearTimeout(timeoutRef.current);
|
|
11
|
+
timeoutRef.current = null;
|
|
12
|
+
}
|
|
13
|
+
}, []);
|
|
14
|
+
|
|
15
|
+
const show = React.useCallback(() => {
|
|
16
|
+
if (passive) return;
|
|
17
|
+
clearTimer();
|
|
18
|
+
timeoutRef.current = setTimeout(() => setVisible(true), delay);
|
|
19
|
+
}, [clearTimer, delay, passive]);
|
|
20
|
+
|
|
21
|
+
const hide = React.useCallback(() => {
|
|
22
|
+
clearTimer();
|
|
23
|
+
setVisible(false);
|
|
24
|
+
}, [clearTimer]);
|
|
25
|
+
|
|
26
|
+
React.useEffect(() => clearTimer, [clearTimer]);
|
|
27
|
+
|
|
28
|
+
return { hide, setVisible, show, visible } as const;
|
|
29
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
test('Tooltip delegates anchored positioning and portal ownership to Popover', async () => {
|
|
4
|
+
const source = await Bun.file('src/features/tooltip/adapters/inbound/Tooltip.tsx').text();
|
|
5
|
+
|
|
6
|
+
expect(source).toContain("import { Popover } from '../../../popover/public';");
|
|
7
|
+
expect(source).toContain('<Popover');
|
|
8
|
+
expect(source).not.toContain('measureInWindow');
|
|
9
|
+
expect(source).not.toContain('internal/overlay');
|
|
10
|
+
expect(source).not.toContain('<Portal');
|
|
11
|
+
});
|
package/src/index.test.ts
CHANGED
|
@@ -28,8 +28,12 @@ const expectedFeatureRootExports = [
|
|
|
28
28
|
"export { Image } from './features/image/public';",
|
|
29
29
|
"export { KeyboardAvoidingView } from './features/keyboard-avoiding-view/public';",
|
|
30
30
|
"export { Box, Container, Divider, Grid, Stack } from './features/layout/public';",
|
|
31
|
+
"export { Modal } from './features/modal/public';",
|
|
32
|
+
"export { PopoverMenu } from './features/popover-menu/public';",
|
|
31
33
|
"export { Popover } from './features/popover/public';",
|
|
32
34
|
"export { Surface } from './features/surface/public';",
|
|
35
|
+
"export { Tab, TabList, TabPanel, Tabs } from './features/tabs/public';",
|
|
36
|
+
"export { Tooltip } from './features/tooltip/public';",
|
|
33
37
|
"export { Toast, ToastProvider, useToast } from './features/toast/public';",
|
|
34
38
|
"export { Heading, Text } from './features/typography/public';",
|
|
35
39
|
] as const;
|
|
@@ -39,12 +43,8 @@ const expectedLegacyRootExports = [
|
|
|
39
43
|
"export { HelperText } from './components/helper-text';",
|
|
40
44
|
"export { Label } from './components/label';",
|
|
41
45
|
"export { ListItem } from './components/list-item';",
|
|
42
|
-
"export { Menu } from './components/menu';",
|
|
43
|
-
"export { Modal } from './components/modal';",
|
|
44
46
|
"export { Switch } from './components/switch';",
|
|
45
|
-
"export { Tab, TabList, TabPanel, Tabs } from './components/tabs';",
|
|
46
47
|
"export { Textarea } from './components/textarea';",
|
|
47
|
-
"export { Tooltip } from './components/tooltip';",
|
|
48
48
|
"export type { InteractionPolicy, InteractionPolicyProps } from './interactionPolicy';",
|
|
49
49
|
"export * from './core/responsive';",
|
|
50
50
|
"export * from './layout';",
|
|
@@ -62,9 +62,13 @@ describe('feature-owned root barrel contract', () => {
|
|
|
62
62
|
'./components/card',
|
|
63
63
|
'./components/checkbox',
|
|
64
64
|
'./components/icon-button',
|
|
65
|
+
'./components/menu',
|
|
66
|
+
'./components/modal',
|
|
65
67
|
'./components/radio',
|
|
68
|
+
'./components/tabs',
|
|
66
69
|
'./components/text-input',
|
|
67
70
|
'./components/toast',
|
|
71
|
+
'./components/tooltip',
|
|
68
72
|
'./primitives/heading',
|
|
69
73
|
'./primitives/icon',
|
|
70
74
|
'./primitives/image',
|
|
@@ -94,12 +98,15 @@ describe('remaining root barrel contract', () => {
|
|
|
94
98
|
expectedLegacyRootExports.forEach((line) => expect(indexSource).toContain(line));
|
|
95
99
|
});
|
|
96
100
|
|
|
97
|
-
it('does not retain obsolete action-sheet, drawer, or navigation chrome', () => {
|
|
101
|
+
it('does not retain obsolete action-sheet, drawer, menu aliases, or navigation chrome', () => {
|
|
98
102
|
expect(indexSource).not.toContain('ActionSheet');
|
|
99
103
|
expect(indexSource).not.toContain("'./components/action-sheet'");
|
|
100
104
|
expect(indexSource).not.toContain("'./components/drawer'");
|
|
101
105
|
expect(indexSource).not.toContain("'./components/navigation'");
|
|
102
106
|
expect(indexSource).not.toContain('DrawerNavigation');
|
|
107
|
+
expect(indexSource).not.toMatch(/\bMenuProps\b/u);
|
|
108
|
+
expect(indexSource).not.toMatch(/\bMenuAction\b/u);
|
|
109
|
+
expect(indexSource).not.toMatch(/export\s*\{\s*Menu\s*\}/u);
|
|
103
110
|
expect(indexSource).not.toContain('NavigationItem');
|
|
104
111
|
expect(indexSource).not.toContain('NavigationList');
|
|
105
112
|
expect(indexSource).not.toContain('TabBar');
|
package/src/index.ts
CHANGED
|
@@ -6,18 +6,10 @@ export type { LabelProps } from './components/label';
|
|
|
6
6
|
export { Label } from './components/label';
|
|
7
7
|
export type { ListItemProps } from './components/list-item';
|
|
8
8
|
export { ListItem } from './components/list-item';
|
|
9
|
-
export type { MenuAction, MenuActionIntent, MenuItem, MenuProps } from './components/menu';
|
|
10
|
-
export { Menu } from './components/menu';
|
|
11
|
-
export type { ModalProps } from './components/modal';
|
|
12
|
-
export { Modal } from './components/modal';
|
|
13
9
|
export type { SwitchProps } from './components/switch';
|
|
14
10
|
export { Switch } from './components/switch';
|
|
15
|
-
export type { TabListProps, TabPanelProps, TabProps, TabsProps } from './components/tabs';
|
|
16
|
-
export { Tab, TabList, TabPanel, Tabs } from './components/tabs';
|
|
17
11
|
export type { TextareaProps } from './components/textarea';
|
|
18
12
|
export { Textarea } from './components/textarea';
|
|
19
|
-
export type { TooltipProps } from './components/tooltip';
|
|
20
|
-
export { Tooltip } from './components/tooltip';
|
|
21
13
|
export type { FontRuntime } from './context/FontContext';
|
|
22
14
|
export { FontProvider, useFontContext } from './context/FontContext';
|
|
23
15
|
export type { I18nInstance, TranslationRuntime, Translator } from './context/TranslationContext';
|
|
@@ -74,14 +66,24 @@ export type {
|
|
|
74
66
|
StackProps,
|
|
75
67
|
} from './features/layout/public';
|
|
76
68
|
export { Box, Container, Divider, Grid, Stack } from './features/layout/public';
|
|
69
|
+
export type { ModalProps } from './features/modal/public';
|
|
70
|
+
export { Modal } from './features/modal/public';
|
|
77
71
|
export type {
|
|
78
72
|
PopoverAnchorRenderProps,
|
|
79
73
|
PopoverPlacement,
|
|
80
74
|
PopoverProps,
|
|
81
75
|
} from './features/popover/public';
|
|
82
76
|
export { Popover } from './features/popover/public';
|
|
77
|
+
export type {
|
|
78
|
+
PopoverMenuAction,
|
|
79
|
+
PopoverMenuActionIntent,
|
|
80
|
+
PopoverMenuProps,
|
|
81
|
+
} from './features/popover-menu/public';
|
|
82
|
+
export { PopoverMenu } from './features/popover-menu/public';
|
|
83
83
|
export type { SurfaceProps, SurfaceVariant } from './features/surface/public';
|
|
84
84
|
export { Surface } from './features/surface/public';
|
|
85
|
+
export type { TabListProps, TabPanelProps, TabProps, TabsProps } from './features/tabs/public';
|
|
86
|
+
export { Tab, TabList, TabPanel, Tabs } from './features/tabs/public';
|
|
85
87
|
export type {
|
|
86
88
|
ToastController,
|
|
87
89
|
ToastOptions,
|
|
@@ -90,6 +92,8 @@ export type {
|
|
|
90
92
|
ToastStatus,
|
|
91
93
|
} from './features/toast/public';
|
|
92
94
|
export { Toast, ToastProvider, useToast } from './features/toast/public';
|
|
95
|
+
export type { TooltipProps } from './features/tooltip/public';
|
|
96
|
+
export { Tooltip } from './features/tooltip/public';
|
|
93
97
|
export type { HeadingLevel, HeadingProps, TextProps } from './features/typography/public';
|
|
94
98
|
export { Heading, Text } from './features/typography/public';
|
|
95
99
|
export type { InteractionPolicy, InteractionPolicyProps } from './interactionPolicy';
|
package/src/types/bottomSheet.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
|
|
3
|
+
export type BottomSheetContentMode = 'view' | 'direct';
|
|
4
|
+
|
|
3
5
|
export interface BottomSheetPresentOptions {
|
|
4
6
|
content: React.ReactNode;
|
|
7
|
+
contentMode?: BottomSheetContentMode;
|
|
5
8
|
snapPoints?: readonly (number | string)[];
|
|
6
9
|
initialIndex?: number;
|
|
7
10
|
enableDynamicSizing?: boolean;
|
|
11
|
+
maxDynamicContentSize?: number;
|
|
8
12
|
enablePanDownToClose?: boolean;
|
|
9
13
|
dismissOnBackdropPress?: boolean;
|
|
10
14
|
keyboardBehavior?: 'extend' | 'fillParent' | 'interactive';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { InteractionPolicy } from '../interactionPolicy';
|
|
4
|
+
import type { PopoverAnchorRenderProps } from './popover';
|
|
5
|
+
|
|
6
|
+
export type PopoverMenuActionIntent = 'default' | 'danger';
|
|
7
|
+
|
|
8
|
+
export interface PopoverMenuAction {
|
|
9
|
+
id: string;
|
|
10
|
+
title: React.ReactNode;
|
|
11
|
+
description?: React.ReactNode;
|
|
12
|
+
leading?: React.ReactNode;
|
|
13
|
+
trailing?: React.ReactNode;
|
|
14
|
+
intent?: PopoverMenuActionIntent;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
selected?: boolean;
|
|
17
|
+
activate?: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PopoverMenuProps {
|
|
21
|
+
trigger: (controls: PopoverAnchorRenderProps) => React.ReactNode;
|
|
22
|
+
actions: readonly PopoverMenuAction[];
|
|
23
|
+
dismiss?: () => void;
|
|
24
|
+
closeOnSelect?: boolean;
|
|
25
|
+
interactionPolicy?: InteractionPolicy;
|
|
26
|
+
testID?: string;
|
|
27
|
+
}
|