@ankhorage/surface 2.2.1 → 3.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 +1 -2
- package/dist/components/action-sheet/ActionSheet.d.ts.map +1 -1
- package/dist/components/action-sheet/ActionSheet.js +12 -7
- package/dist/components/action-sheet/ActionSheet.js.map +1 -1
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/Button.js +5 -7
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/button/types.d.ts +2 -5
- package/dist/components/button/types.d.ts.map +1 -1
- package/dist/components/button/types.js.map +1 -1
- package/dist/components/drawer/Drawer.d.ts.map +1 -1
- package/dist/components/drawer/Drawer.js +12 -7
- package/dist/components/drawer/Drawer.js.map +1 -1
- package/dist/components/icon-button/IconButton.d.ts.map +1 -1
- package/dist/components/icon-button/IconButton.js +1 -1
- package/dist/components/icon-button/IconButton.js.map +1 -1
- package/dist/components/icon-button/types.d.ts +2 -5
- package/dist/components/icon-button/types.d.ts.map +1 -1
- package/dist/components/icon-button/types.js.map +1 -1
- package/dist/components/menu/Menu.d.ts.map +1 -1
- package/dist/components/menu/Menu.js +12 -7
- package/dist/components/menu/Menu.js.map +1 -1
- package/dist/components/modal/Modal.d.ts.map +1 -1
- package/dist/components/modal/Modal.js +12 -7
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/navigation/NavigationItem.d.ts.map +1 -1
- package/dist/components/navigation/NavigationItem.js +1 -1
- package/dist/components/navigation/NavigationItem.js.map +1 -1
- package/dist/components/navigation/TabBarItem.d.ts.map +1 -1
- package/dist/components/navigation/TabBarItem.js +1 -1
- package/dist/components/navigation/TabBarItem.js.map +1 -1
- package/dist/components/navigation/types.d.ts +2 -2
- package/dist/components/navigation/types.d.ts.map +1 -1
- package/dist/components/navigation/types.js.map +1 -1
- package/dist/components/toast/ToastProvider.d.ts.map +1 -1
- package/dist/components/toast/ToastProvider.js +3 -2
- package/dist/components/toast/ToastProvider.js.map +1 -1
- package/dist/components/tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/tooltip/Tooltip.js +10 -5
- package/dist/components/tooltip/Tooltip.js.map +1 -1
- package/dist/context/TranslationContext.d.ts.map +1 -1
- package/dist/context/TranslationContext.js +3 -3
- package/dist/context/TranslationContext.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/overlay/OverlayProvider.d.ts.map +1 -1
- package/dist/internal/overlay/OverlayProvider.js +17 -16
- package/dist/internal/overlay/OverlayProvider.js.map +1 -1
- package/dist/internal/overlay/Portal.d.ts.map +1 -1
- package/dist/internal/overlay/Portal.js +2 -1
- package/dist/internal/overlay/Portal.js.map +1 -1
- package/dist/internal/resolvePointerEvents.d.ts +9 -0
- package/dist/internal/resolvePointerEvents.d.ts.map +1 -0
- package/dist/internal/resolvePointerEvents.js +17 -0
- package/dist/internal/resolvePointerEvents.js.map +1 -0
- package/dist/layout/AppBar.js +1 -1
- package/dist/layout/AppBar.js.map +1 -1
- package/dist/layout/Box.d.ts.map +1 -1
- package/dist/layout/Box.js +4 -22
- package/dist/layout/Box.js.map +1 -1
- package/dist/layout/Grid.js.map +1 -1
- package/dist/primitives/icon/Icon.d.ts +5 -12
- package/dist/primitives/icon/Icon.d.ts.map +1 -1
- package/dist/primitives/icon/Icon.js +5 -11
- package/dist/primitives/icon/Icon.js.map +1 -1
- package/dist/primitives/icon/PortableIcon.d.ts +51 -0
- package/dist/primitives/icon/PortableIcon.d.ts.map +1 -0
- package/dist/primitives/icon/PortableIcon.js +64 -0
- package/dist/primitives/icon/PortableIcon.js.map +1 -0
- package/dist/primitives/icon/index.d.ts +2 -1
- package/dist/primitives/icon/index.d.ts.map +1 -1
- package/dist/primitives/icon/index.js +1 -0
- package/dist/primitives/icon/index.js.map +1 -1
- package/dist/primitives/image/Image.d.ts.map +1 -1
- package/dist/primitives/image/Image.js +3 -5
- package/dist/primitives/image/Image.js.map +1 -1
- package/package.json +30 -27
- package/src/components/action-sheet/ActionSheet.tsx +14 -8
- package/src/components/button/Button.tsx +5 -17
- package/src/components/button/types.ts +2 -5
- package/src/components/drawer/Drawer.tsx +14 -8
- package/src/components/icon-button/IconButton.tsx +1 -6
- package/src/components/icon-button/types.ts +2 -5
- package/src/components/menu/Menu.tsx +14 -8
- package/src/components/modal/Modal.tsx +14 -8
- package/src/components/navigation/NavigationItem.tsx +1 -6
- package/src/components/navigation/TabBarItem.tsx +1 -6
- package/src/components/navigation/types.ts +2 -2
- package/src/components/toast/ToastProvider.tsx +3 -2
- package/src/components/tooltip/Tooltip.tsx +12 -6
- package/src/context/TranslationContext.tsx +12 -15
- package/src/index.test.ts +8 -0
- package/src/index.ts +2 -2
- package/src/internal/overlay/OverlayProvider.tsx +20 -20
- package/src/internal/overlay/Portal.tsx +2 -1
- package/src/internal/resolvePointerEvents.test.ts +19 -0
- package/src/internal/resolvePointerEvents.ts +29 -0
- package/src/layout/AppBar.tsx +1 -1
- package/src/layout/Box.tsx +5 -36
- package/src/layout/Grid.tsx +3 -3
- package/src/primitives/icon/Icon.tsx +9 -22
- package/src/primitives/icon/PortableIcon.tsx +112 -0
- package/src/primitives/icon/PortableIcon.web.test.tsx +119 -0
- package/src/primitives/icon/index.ts +2 -1
- package/src/primitives/image/Image.tsx +3 -6
- package/src/theme/colorEngine.test.ts +2 -2
- package/src/webAcceptance.test.tsx +84 -0
- package/dist/primitives/icon/resolveExpoIconComponent.d.ts +0 -11
- package/dist/primitives/icon/resolveExpoIconComponent.d.ts.map +0 -1
- package/dist/primitives/icon/resolveExpoIconComponent.js +0 -20
- package/dist/primitives/icon/resolveExpoIconComponent.js.map +0 -1
- package/src/primitives/icon/resolveExpoIconComponent.test.ts +0 -45
- package/src/primitives/icon/resolveExpoIconComponent.ts +0 -33
|
@@ -46,12 +46,7 @@ export function IconButton({
|
|
|
46
46
|
opacity: colors.opacity,
|
|
47
47
|
}}
|
|
48
48
|
>
|
|
49
|
-
<Icon
|
|
50
|
-
color={colors.contentColor}
|
|
51
|
-
name={icon.name}
|
|
52
|
-
provider={icon.provider}
|
|
53
|
-
size={resolveIconSize(theme, size)}
|
|
54
|
-
/>
|
|
49
|
+
<Icon {...icon} color={colors.contentColor} size={resolveIconSize(theme, size)} />
|
|
55
50
|
</Box>
|
|
56
51
|
);
|
|
57
52
|
}}
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import type { ControlSize } from '../../internal/resolvers/resolveControlSize';
|
|
2
2
|
import type { ButtonVariant } from '../../internal/resolvers/resolveInteractiveColors';
|
|
3
3
|
import type { ButtonBaseProps } from '../../primitives/button-base';
|
|
4
|
-
import type {
|
|
4
|
+
import type { IconSource } from '../../primitives/icon';
|
|
5
5
|
import type { SurfaceColor } from '../../surfaceColor';
|
|
6
6
|
|
|
7
7
|
export interface IconButtonProps extends Omit<
|
|
8
8
|
ButtonBaseProps,
|
|
9
9
|
'children' | 'style' | 'accessibilityLabel'
|
|
10
10
|
> {
|
|
11
|
-
icon:
|
|
12
|
-
name: IconProps['name'];
|
|
13
|
-
provider?: IconProps['provider'];
|
|
14
|
-
};
|
|
11
|
+
icon: IconSource;
|
|
15
12
|
accessibilityLabel: string;
|
|
16
13
|
variant?: ButtonVariant;
|
|
17
14
|
color?: SurfaceColor;
|
|
@@ -4,6 +4,7 @@ import { type LayoutRectangle, Pressable, View } from 'react-native';
|
|
|
4
4
|
import { FocusScope } from '../../internal/focus/FocusScope';
|
|
5
5
|
import { useFocusManager } from '../../internal/focus/useFocusManager';
|
|
6
6
|
import { Portal } from '../../internal/overlay/Portal';
|
|
7
|
+
import { resolvePointerEvents } from '../../internal/resolvePointerEvents';
|
|
7
8
|
import { resolveOverlayAnimation } from '../../internal/resolvers';
|
|
8
9
|
import { Box, Inline, Stack, Surface } from '../../layout';
|
|
9
10
|
import { ButtonBase } from '../../primitives/button-base';
|
|
@@ -12,6 +13,8 @@ import { useTheme } from '../../theme/ThemeContext';
|
|
|
12
13
|
import { resolveNextMenuIndex } from './navigation';
|
|
13
14
|
import type { MenuAction, MenuProps } from './types';
|
|
14
15
|
|
|
16
|
+
const boxNonePointerEvents = resolvePointerEvents('box-none');
|
|
17
|
+
|
|
15
18
|
interface MeasurableNode {
|
|
16
19
|
measureInWindow?: (
|
|
17
20
|
callback: (x: number, y: number, width: number, height: number) => void,
|
|
@@ -142,14 +145,17 @@ export function Menu({
|
|
|
142
145
|
</ButtonBase>
|
|
143
146
|
<Portal layer="menu" visible={open && Boolean(layout)}>
|
|
144
147
|
<View
|
|
145
|
-
|
|
146
|
-
style={
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
{...boxNonePointerEvents.props}
|
|
149
|
+
style={[
|
|
150
|
+
boxNonePointerEvents.style,
|
|
151
|
+
{
|
|
152
|
+
bottom: 0,
|
|
153
|
+
left: 0,
|
|
154
|
+
position: 'absolute',
|
|
155
|
+
right: 0,
|
|
156
|
+
top: 0,
|
|
157
|
+
},
|
|
158
|
+
]}
|
|
153
159
|
>
|
|
154
160
|
<Pressable
|
|
155
161
|
onPress={passive ? undefined : closeMenu}
|
|
@@ -3,11 +3,14 @@ import { Pressable, View } from 'react-native';
|
|
|
3
3
|
|
|
4
4
|
import { FocusScope } from '../../internal/focus/FocusScope';
|
|
5
5
|
import { Portal } from '../../internal/overlay/Portal';
|
|
6
|
+
import { resolvePointerEvents } from '../../internal/resolvePointerEvents';
|
|
6
7
|
import { resolveOverlayAnimation } from '../../internal/resolvers';
|
|
7
8
|
import { Center, Surface } from '../../layout';
|
|
8
9
|
import { useTheme } from '../../theme/ThemeContext';
|
|
9
10
|
import type { ModalProps } from './types';
|
|
10
11
|
|
|
12
|
+
const boxNonePointerEvents = resolvePointerEvents('box-none');
|
|
13
|
+
|
|
11
14
|
export function Modal({
|
|
12
15
|
visible,
|
|
13
16
|
onDismiss,
|
|
@@ -27,14 +30,17 @@ export function Modal({
|
|
|
27
30
|
return (
|
|
28
31
|
<Portal layer="modal" visible={visible}>
|
|
29
32
|
<View
|
|
30
|
-
|
|
31
|
-
style={
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
{...boxNonePointerEvents.props}
|
|
34
|
+
style={[
|
|
35
|
+
boxNonePointerEvents.style,
|
|
36
|
+
{
|
|
37
|
+
bottom: 0,
|
|
38
|
+
left: 0,
|
|
39
|
+
position: 'absolute',
|
|
40
|
+
right: 0,
|
|
41
|
+
top: 0,
|
|
42
|
+
},
|
|
43
|
+
]}
|
|
38
44
|
>
|
|
39
45
|
<Pressable
|
|
40
46
|
onPress={passive ? undefined : closeOnBackdrop ? onDismiss : undefined}
|
|
@@ -56,12 +56,7 @@ export function NavigationItem({
|
|
|
56
56
|
>
|
|
57
57
|
{item.icon ? (
|
|
58
58
|
<View style={{ marginRight: theme.spacing.s }}>
|
|
59
|
-
<Icon
|
|
60
|
-
color={presentation.contentColor}
|
|
61
|
-
name={item.icon.name}
|
|
62
|
-
provider={item.icon.provider}
|
|
63
|
-
size={compact ? 's' : 'm'}
|
|
64
|
-
/>
|
|
59
|
+
<Icon {...item.icon} color={presentation.contentColor} size={compact ? 's' : 'm'} />
|
|
65
60
|
</View>
|
|
66
61
|
) : null}
|
|
67
62
|
<Box flex={1}>
|
|
@@ -57,12 +57,7 @@ export function TabBarItem({ item, compact = false, testID, interactionPolicy }:
|
|
|
57
57
|
>
|
|
58
58
|
{item.icon ? (
|
|
59
59
|
<View style={{ marginBottom: item.label ? theme.spacing.xs : 0 }}>
|
|
60
|
-
<Icon
|
|
61
|
-
color={contentColor}
|
|
62
|
-
name={item.icon.name}
|
|
63
|
-
provider={item.icon.provider}
|
|
64
|
-
size={compact ? 's' : 'm'}
|
|
65
|
-
/>
|
|
60
|
+
<Icon {...item.icon} color={contentColor} size={compact ? 's' : 'm'} />
|
|
66
61
|
</View>
|
|
67
62
|
) : null}
|
|
68
63
|
{item.label ? (
|
|
@@ -2,9 +2,9 @@ import type React from 'react';
|
|
|
2
2
|
import type { AccessibilityRole, AccessibilityState } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import type { InteractionPolicy } from '../../interactionPolicy';
|
|
5
|
-
import type {
|
|
5
|
+
import type { IconSource } from '../../primitives/icon';
|
|
6
6
|
|
|
7
|
-
export type NavigationItemIcon =
|
|
7
|
+
export type NavigationItemIcon = IconSource;
|
|
8
8
|
|
|
9
9
|
export interface NavigationItemSpec {
|
|
10
10
|
id: string;
|
|
@@ -68,9 +68,10 @@ export function ToastProvider({
|
|
|
68
68
|
}, [defaultDuration, dismissToast, toasts]);
|
|
69
69
|
|
|
70
70
|
React.useEffect(() => {
|
|
71
|
+
const timers = timersRef.current;
|
|
71
72
|
return () => {
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
timers.forEach((timer) => clearTimeout(timer));
|
|
74
|
+
timers.clear();
|
|
74
75
|
};
|
|
75
76
|
}, []);
|
|
76
77
|
|
|
@@ -2,12 +2,15 @@ import React from 'react';
|
|
|
2
2
|
import { type LayoutRectangle, Platform, Pressable, View } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { Portal } from '../../internal/overlay/Portal';
|
|
5
|
+
import { resolvePointerEvents } from '../../internal/resolvePointerEvents';
|
|
5
6
|
import { resolveOverlayAnimation } from '../../internal/resolvers';
|
|
6
7
|
import { Surface } from '../../layout';
|
|
7
8
|
import { Text } from '../../primitives/text';
|
|
8
9
|
import { useTheme } from '../../theme/ThemeContext';
|
|
9
10
|
import type { TooltipProps } from './types';
|
|
10
11
|
|
|
12
|
+
const noPointerEvents = resolvePointerEvents('none');
|
|
13
|
+
|
|
11
14
|
interface MeasurableNode {
|
|
12
15
|
measureInWindow?: (
|
|
13
16
|
callback: (x: number, y: number, width: number, height: number) => void,
|
|
@@ -85,12 +88,15 @@ export function Tooltip({
|
|
|
85
88
|
</Pressable>
|
|
86
89
|
<Portal layer="tooltip" visible={visible && Boolean(layout)}>
|
|
87
90
|
<View
|
|
88
|
-
|
|
89
|
-
style={
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
{...noPointerEvents.props}
|
|
92
|
+
style={[
|
|
93
|
+
noPointerEvents.style,
|
|
94
|
+
{
|
|
95
|
+
left: tooltipLeft,
|
|
96
|
+
position: 'absolute',
|
|
97
|
+
top: tooltipTop,
|
|
98
|
+
},
|
|
99
|
+
]}
|
|
94
100
|
>
|
|
95
101
|
<Surface
|
|
96
102
|
p="s"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useContext
|
|
1
|
+
import React, { createContext, useContext } from 'react';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Minimal translation runtime surface.
|
|
@@ -31,20 +31,17 @@ export function TranslationProvider(props: {
|
|
|
31
31
|
}) {
|
|
32
32
|
const { t, i18n, children } = props;
|
|
33
33
|
|
|
34
|
-
const value =
|
|
35
|
-
() =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}),
|
|
46
|
-
[t, i18n, i18n?.language],
|
|
47
|
-
);
|
|
34
|
+
const value: TranslationRuntime = {
|
|
35
|
+
t: (key: string, options?: Record<string, unknown>) => {
|
|
36
|
+
if (i18n?.t) {
|
|
37
|
+
const result = i18n.t(key, options);
|
|
38
|
+
// If translation returns the key, it's missing in the current dictionary
|
|
39
|
+
if (result !== key) return result;
|
|
40
|
+
}
|
|
41
|
+
return t(key, options);
|
|
42
|
+
},
|
|
43
|
+
i18n: i18n ?? null,
|
|
44
|
+
};
|
|
48
45
|
|
|
49
46
|
return <TranslationContext.Provider value={value}>{children}</TranslationContext.Provider>;
|
|
50
47
|
}
|
package/src/index.test.ts
CHANGED
|
@@ -6,8 +6,10 @@ const indexSource = readFileSync(new URL('./index.ts', import.meta.url), 'utf8')
|
|
|
6
6
|
const packageJson = JSON.parse(
|
|
7
7
|
readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
|
|
8
8
|
) as {
|
|
9
|
+
devDependencies: Record<string, string>;
|
|
9
10
|
exports: Record<string, unknown>;
|
|
10
11
|
files: string[];
|
|
12
|
+
peerDependencies: Record<string, string>;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
const expectedRootExports = [
|
|
@@ -19,6 +21,7 @@ const expectedRootExports = [
|
|
|
19
21
|
"export { Field } from './components/field';",
|
|
20
22
|
"export { HelperText } from './components/helper-text';",
|
|
21
23
|
"export { IconButton } from './components/icon-button';",
|
|
24
|
+
"export { Icon, SUPPORTED_ICON_PROVIDERS } from './primitives/icon';",
|
|
22
25
|
"export type { InteractionPolicy, InteractionPolicyProps } from './interactionPolicy';",
|
|
23
26
|
"export { Label } from './components/label';",
|
|
24
27
|
"export { ListItem } from './components/list-item';",
|
|
@@ -67,4 +70,9 @@ describe('public package contract', () => {
|
|
|
67
70
|
'./package.json': './package.json',
|
|
68
71
|
});
|
|
69
72
|
});
|
|
73
|
+
|
|
74
|
+
it('supports RN 0.86 patches while validating the canonical RN 0.86.3 baseline', () => {
|
|
75
|
+
expect(packageJson.peerDependencies['react-native']).toBe('0.86.x');
|
|
76
|
+
expect(packageJson.devDependencies['react-native']).toBe('0.86.3');
|
|
77
|
+
});
|
|
70
78
|
});
|
package/src/index.ts
CHANGED
|
@@ -67,8 +67,8 @@ export type { ButtonBaseProps } from './primitives/button-base';
|
|
|
67
67
|
export { ButtonBase } from './primitives/button-base';
|
|
68
68
|
export type { HeadingLevel, HeadingProps } from './primitives/heading';
|
|
69
69
|
export { Heading } from './primitives/heading';
|
|
70
|
-
export type { IconProps, IconProvider } from './primitives/icon';
|
|
71
|
-
export { Icon } from './primitives/icon';
|
|
70
|
+
export type { IconProps, IconProvider, IconSource, IconVariant } from './primitives/icon';
|
|
71
|
+
export { Icon, SUPPORTED_ICON_PROVIDERS } from './primitives/icon';
|
|
72
72
|
export type { ImageFit, ImageProps, SurfaceImageSource } from './primitives/image';
|
|
73
73
|
export { Image } from './primitives/image';
|
|
74
74
|
export type { TextProps } from './primitives/text';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { View } from 'react-native';
|
|
2
|
+
import { StyleSheet, View, type ViewStyle } from 'react-native';
|
|
3
3
|
|
|
4
|
+
import { resolvePointerEvents } from '../resolvePointerEvents';
|
|
4
5
|
import {
|
|
5
6
|
createOverlayEntry,
|
|
6
7
|
type OverlayDescriptor,
|
|
@@ -10,6 +11,21 @@ import {
|
|
|
10
11
|
sortOverlayEntries,
|
|
11
12
|
} from './useOverlayStack';
|
|
12
13
|
|
|
14
|
+
const boxNonePointerEvents = resolvePointerEvents('box-none');
|
|
15
|
+
const styles = StyleSheet.create({
|
|
16
|
+
fill: {
|
|
17
|
+
bottom: 0,
|
|
18
|
+
left: 0,
|
|
19
|
+
position: 'absolute',
|
|
20
|
+
right: 0,
|
|
21
|
+
top: 0,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function overlayZIndex(zIndex: number): ViewStyle {
|
|
26
|
+
return { zIndex };
|
|
27
|
+
}
|
|
28
|
+
|
|
13
29
|
export function OverlayProvider({ children }: { children: React.ReactNode }) {
|
|
14
30
|
const orderRef = React.useRef(0);
|
|
15
31
|
const [overlays, setOverlays] = React.useState<OverlayEntry[]>([]);
|
|
@@ -52,28 +68,12 @@ export function OverlayProvider({ children }: { children: React.ReactNode }) {
|
|
|
52
68
|
<OverlayStackActionsContext.Provider value={actions}>
|
|
53
69
|
<OverlayStackContext.Provider value={value}>
|
|
54
70
|
{children}
|
|
55
|
-
<View
|
|
56
|
-
pointerEvents="box-none"
|
|
57
|
-
style={{
|
|
58
|
-
bottom: 0,
|
|
59
|
-
left: 0,
|
|
60
|
-
position: 'absolute',
|
|
61
|
-
right: 0,
|
|
62
|
-
top: 0,
|
|
63
|
-
}}
|
|
64
|
-
>
|
|
71
|
+
<View {...boxNonePointerEvents.props} style={[boxNonePointerEvents.style, styles.fill]}>
|
|
65
72
|
{overlays.map((overlay) => (
|
|
66
73
|
<View
|
|
74
|
+
{...boxNonePointerEvents.props}
|
|
67
75
|
key={overlay.id}
|
|
68
|
-
|
|
69
|
-
style={{
|
|
70
|
-
bottom: 0,
|
|
71
|
-
left: 0,
|
|
72
|
-
position: 'absolute',
|
|
73
|
-
right: 0,
|
|
74
|
-
top: 0,
|
|
75
|
-
zIndex: overlay.zIndex,
|
|
76
|
-
}}
|
|
76
|
+
style={[boxNonePointerEvents.style, styles.fill, overlayZIndex(overlay.zIndex)]}
|
|
77
77
|
>
|
|
78
78
|
{overlay.node}
|
|
79
79
|
</View>
|
|
@@ -19,9 +19,10 @@ export function Portal({ children, layer = 'modal', visible = true }: PortalProp
|
|
|
19
19
|
if (!overlayActions || !visible) {
|
|
20
20
|
return undefined;
|
|
21
21
|
}
|
|
22
|
+
const id = idRef.current;
|
|
22
23
|
|
|
23
24
|
return () => {
|
|
24
|
-
overlayActions.removeOverlay(
|
|
25
|
+
overlayActions.removeOverlay(id);
|
|
25
26
|
};
|
|
26
27
|
}, [overlayActions, visible]);
|
|
27
28
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { resolvePointerEventsForPlatform } from './resolvePointerEvents';
|
|
4
|
+
|
|
5
|
+
describe('resolvePointerEvents', () => {
|
|
6
|
+
test('moves React Native Web pointer events into style', () => {
|
|
7
|
+
expect(resolvePointerEventsForPlatform('box-none', 'web')).toEqual({
|
|
8
|
+
props: {},
|
|
9
|
+
style: { pointerEvents: 'box-none' },
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('preserves the native pointer-events prop', () => {
|
|
14
|
+
expect(resolvePointerEventsForPlatform('none', 'ios')).toEqual({
|
|
15
|
+
props: { pointerEvents: 'none' },
|
|
16
|
+
style: null,
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Platform, type StyleProp, type ViewProps, type ViewStyle } from 'react-native';
|
|
2
|
+
|
|
3
|
+
interface ResolvedPointerEvents {
|
|
4
|
+
props: Pick<ViewProps, 'pointerEvents'>;
|
|
5
|
+
style: StyleProp<ViewStyle>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function resolvePointerEvents(
|
|
9
|
+
pointerEvents: NonNullable<ViewProps['pointerEvents']>,
|
|
10
|
+
): ResolvedPointerEvents {
|
|
11
|
+
return resolvePointerEventsForPlatform(pointerEvents, Platform.OS);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function resolvePointerEventsForPlatform(
|
|
15
|
+
pointerEvents: NonNullable<ViewProps['pointerEvents']>,
|
|
16
|
+
platform: typeof Platform.OS,
|
|
17
|
+
): ResolvedPointerEvents {
|
|
18
|
+
if (platform === 'web') {
|
|
19
|
+
return {
|
|
20
|
+
props: {},
|
|
21
|
+
style: { pointerEvents },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
props: { pointerEvents },
|
|
27
|
+
style: null,
|
|
28
|
+
};
|
|
29
|
+
}
|
package/src/layout/AppBar.tsx
CHANGED
|
@@ -33,7 +33,7 @@ export function AppBar({
|
|
|
33
33
|
topInset === 0 ? undefined : { paddingTop: topInset };
|
|
34
34
|
|
|
35
35
|
return (
|
|
36
|
-
<Box {...props} bg={bg ?? theme.semantics.surface.default} style={
|
|
36
|
+
<Box {...props} bg={bg ?? theme.semantics.surface.default} style={style}>
|
|
37
37
|
<View style={safeAreaStyle}>
|
|
38
38
|
<View
|
|
39
39
|
style={[
|
package/src/layout/Box.tsx
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
Platform,
|
|
4
|
-
type StyleProp,
|
|
5
|
-
View,
|
|
6
|
-
type ViewProps as ReactNativeViewProps,
|
|
7
|
-
type ViewStyle,
|
|
8
|
-
} from 'react-native';
|
|
2
|
+
import { View, type ViewProps as ReactNativeViewProps } from 'react-native';
|
|
9
3
|
|
|
10
4
|
import { useResponsiveRuntime } from '../core/responsive';
|
|
5
|
+
import { resolvePointerEvents } from '../internal/resolvePointerEvents';
|
|
11
6
|
import { useTheme } from '../theme/ThemeContext';
|
|
12
7
|
import { type BoxStyleProps, resolveBoxStyles } from './helpers';
|
|
13
8
|
|
|
@@ -21,31 +16,6 @@ export interface BoxProps extends BoxStyleProps {
|
|
|
21
16
|
testID?: string;
|
|
22
17
|
}
|
|
23
18
|
|
|
24
|
-
function resolvePointerEventsStyle(
|
|
25
|
-
pointerEvents: ReactNativeViewProps['pointerEvents'] | undefined,
|
|
26
|
-
): StyleProp<ViewStyle> | null {
|
|
27
|
-
if (Platform.OS !== 'web' || pointerEvents === undefined) return null;
|
|
28
|
-
|
|
29
|
-
if (pointerEvents === 'auto' || pointerEvents === 'none') {
|
|
30
|
-
return { pointerEvents };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function resolveViewPointerEvents(
|
|
37
|
-
pointerEvents: ReactNativeViewProps['pointerEvents'] | undefined,
|
|
38
|
-
): ReactNativeViewProps['pointerEvents'] | undefined {
|
|
39
|
-
if (pointerEvents === undefined) return undefined;
|
|
40
|
-
if (Platform.OS !== 'web') return pointerEvents;
|
|
41
|
-
|
|
42
|
-
if (pointerEvents === 'box-none' || pointerEvents === 'box-only') {
|
|
43
|
-
return pointerEvents;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return undefined;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
19
|
export function Box({
|
|
50
20
|
accessible,
|
|
51
21
|
accessibilityLabel,
|
|
@@ -60,18 +30,17 @@ export function Box({
|
|
|
60
30
|
const { theme } = useTheme();
|
|
61
31
|
const { breakpoint } = useResponsiveRuntime();
|
|
62
32
|
const resolved = resolveBoxStyles(theme, breakpoint, props);
|
|
63
|
-
const
|
|
64
|
-
const viewPointerEvents = resolveViewPointerEvents(pointerEvents);
|
|
33
|
+
const resolvedPointerEvents = pointerEvents ? resolvePointerEvents(pointerEvents) : null;
|
|
65
34
|
|
|
66
35
|
return (
|
|
67
36
|
<View
|
|
37
|
+
{...resolvedPointerEvents?.props}
|
|
68
38
|
accessible={accessible}
|
|
69
39
|
accessibilityLabel={accessibilityLabel}
|
|
70
40
|
accessibilityRole={accessibilityRole}
|
|
71
41
|
accessibilityState={accessibilityState}
|
|
72
|
-
pointerEvents={viewPointerEvents}
|
|
73
42
|
testID={testID}
|
|
74
|
-
style={[resolved,
|
|
43
|
+
style={[resolved, resolvedPointerEvents?.style, style]}
|
|
75
44
|
>
|
|
76
45
|
{children}
|
|
77
46
|
</View>
|
package/src/layout/Grid.tsx
CHANGED
|
@@ -35,7 +35,7 @@ export function Grid({
|
|
|
35
35
|
const colSpacing = Number(resolveSpacing(theme, activeColGap) ?? 0);
|
|
36
36
|
const activeMinItemWidth = resolveResponsive(minItemWidth, breakpoint);
|
|
37
37
|
|
|
38
|
-
const basisPercent = `${100 / activeCols}%`;
|
|
38
|
+
const basisPercent: `${number}%` = `${100 / activeCols}%`;
|
|
39
39
|
const nodes = React.Children.toArray(children);
|
|
40
40
|
|
|
41
41
|
return (
|
|
@@ -58,8 +58,8 @@ export function Grid({
|
|
|
58
58
|
flexGrow: 1,
|
|
59
59
|
}
|
|
60
60
|
: {
|
|
61
|
-
width: basisPercent
|
|
62
|
-
flexBasis: basisPercent
|
|
61
|
+
width: basisPercent,
|
|
62
|
+
flexBasis: basisPercent,
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
return (
|
|
@@ -1,40 +1,27 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { type StyleProp, type TextStyle } from 'react-native';
|
|
3
2
|
|
|
4
3
|
import { resolveToken } from '../../theme/resolveToken';
|
|
5
4
|
import { useTheme } from '../../theme/ThemeContext';
|
|
6
5
|
import type { SurfaceTheme } from '../../theme/types';
|
|
7
|
-
import {
|
|
6
|
+
import { type IconSource, PortableIcon } from './PortableIcon';
|
|
8
7
|
|
|
9
|
-
export type IconProvider
|
|
8
|
+
export type { IconProvider, IconSource, IconVariant } from './PortableIcon';
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
name: string;
|
|
13
|
-
provider?: IconProvider;
|
|
10
|
+
interface IconPresentationProps {
|
|
14
11
|
size?: keyof SurfaceTheme['spacing'] | number;
|
|
15
12
|
color?: keyof SurfaceTheme['colors'] | string;
|
|
16
13
|
style?: StyleProp<TextStyle>;
|
|
17
14
|
testID?: string;
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
size = 'm',
|
|
24
|
-
color = 'text',
|
|
25
|
-
style,
|
|
26
|
-
testID,
|
|
27
|
-
}: IconProps) {
|
|
17
|
+
export type IconProps = IconSource & IconPresentationProps;
|
|
18
|
+
|
|
19
|
+
export function Icon(props: IconProps) {
|
|
28
20
|
const { theme } = useTheme();
|
|
29
|
-
const
|
|
21
|
+
const size = props.size ?? 'm';
|
|
22
|
+
const color = props.color ?? 'text';
|
|
30
23
|
const resolvedSize = typeof size === 'number' ? size : resolveToken(theme.spacing, size);
|
|
31
24
|
const resolvedColor = resolveToken(theme.colors, color);
|
|
32
25
|
|
|
33
|
-
return
|
|
34
|
-
color: resolvedColor,
|
|
35
|
-
name,
|
|
36
|
-
size: resolvedSize,
|
|
37
|
-
style,
|
|
38
|
-
testID,
|
|
39
|
-
});
|
|
26
|
+
return <PortableIcon {...props} color={resolvedColor} size={resolvedSize} />;
|
|
40
27
|
}
|