@vellira-ui/react-native 2.53.0 → 2.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -110
- package/dist/index.d.ts +2 -0
- package/dist/index.js +360 -37
- package/package.json +14 -1
package/README.md
CHANGED
|
@@ -1,41 +1,24 @@
|
|
|
1
1
|
# @vellira-ui/react-native
|
|
2
2
|
|
|
3
|
-
React Native
|
|
3
|
+
React Native implementation of the Vellira design system.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- Button
|
|
10
|
-
- Checkbox
|
|
11
|
-
- Input
|
|
12
|
-
- FormField
|
|
13
|
-
- Radio
|
|
14
|
-
- RadioGroup
|
|
15
|
-
- Select
|
|
16
|
-
- Dropdown
|
|
17
|
-
- Tabs
|
|
18
|
-
- Tooltip
|
|
19
|
-
- Modal
|
|
20
|
-
|
|
21
|
-
Each public native component has React Native Storybook coverage and Vitest unit coverage.
|
|
22
|
-
|
|
23
|
-
For detailed props, shared types, examples, and compound component APIs, see
|
|
24
|
-
[Native Component API](./API.md).
|
|
5
|
+
It extends shared contracts from `@vellira-ui/types`, uses shared tokens from
|
|
6
|
+
`@vellira-ui/tokens`, shares renderer-neutral behavior through
|
|
7
|
+
`@vellira-ui/core`, and keeps native rendering, accessibility, layout, and
|
|
8
|
+
interaction behavior inside the React Native layer.
|
|
25
9
|
|
|
26
10
|
## Installation
|
|
27
11
|
|
|
12
|
+
Requires React and React Native.
|
|
13
|
+
|
|
28
14
|
```bash
|
|
29
15
|
pnpm add @vellira-ui/react-native
|
|
30
16
|
```
|
|
31
17
|
|
|
32
|
-
Peer dependencies:
|
|
33
|
-
|
|
34
|
-
- `react`
|
|
35
|
-
- `react-native`
|
|
36
|
-
|
|
37
18
|
## Usage
|
|
38
19
|
|
|
20
|
+
Use the components directly in your React Native application:
|
|
21
|
+
|
|
39
22
|
```tsx
|
|
40
23
|
import { Button, Checkbox, Input } from '@vellira-ui/react-native';
|
|
41
24
|
import { useState } from 'react';
|
|
@@ -47,7 +30,12 @@ export function Example() {
|
|
|
47
30
|
|
|
48
31
|
return (
|
|
49
32
|
<View style={{ gap: 16 }}>
|
|
50
|
-
<Input
|
|
33
|
+
<Input
|
|
34
|
+
label='Email'
|
|
35
|
+
value={email}
|
|
36
|
+
onValueChange={setEmail}
|
|
37
|
+
placeholder='name@example.com'
|
|
38
|
+
/>
|
|
51
39
|
<Checkbox
|
|
52
40
|
label='Accept terms'
|
|
53
41
|
description='Required to create an account.'
|
|
@@ -62,105 +50,56 @@ export function Example() {
|
|
|
62
50
|
}
|
|
63
51
|
```
|
|
64
52
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Use `accessibilityLabel` for icon-only native buttons:
|
|
68
|
-
|
|
69
|
-
```tsx
|
|
70
|
-
import { Search } from '@vellira-ui/icons';
|
|
71
|
-
|
|
72
|
-
<Button accessibilityLabel='Search' iconOnly iconStart={<Search />} />;
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Button icons are React elements from `@vellira-ui/icons`; the component injects
|
|
76
|
-
the current icon color and size. `loading` disables interaction and can replace
|
|
77
|
-
the visible label with `loadingText`.
|
|
78
|
-
|
|
79
|
-
### Checkbox Notes
|
|
80
|
-
|
|
81
|
-
Use `description` for settings-style helper text when the checkbox is not
|
|
82
|
-
wrapped in `FormField`. For checkbox rows without a visible label, provide
|
|
83
|
-
`accessibilityLabel`.
|
|
84
|
-
|
|
85
|
-
### Select Notes
|
|
53
|
+
## Components
|
|
86
54
|
|
|
87
|
-
|
|
88
|
-
visible choices, and `Dropdown` for action menus. Native `Select` opens a
|
|
89
|
-
sheet, modal, or popover and renders options with a FlatList-backed native
|
|
90
|
-
content surface.
|
|
55
|
+
### Inputs
|
|
91
56
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
57
|
+
- Button
|
|
58
|
+
- Checkbox
|
|
59
|
+
- Input
|
|
60
|
+
- Radio
|
|
61
|
+
- RadioGroup
|
|
62
|
+
- Select
|
|
95
63
|
|
|
96
|
-
|
|
97
|
-
const [role, setRole] = useState('editor');
|
|
64
|
+
### Overlays
|
|
98
65
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
onValueChange={(nextRole) => setRole(nextRole ?? '')}
|
|
104
|
-
searchable
|
|
105
|
-
clearable
|
|
106
|
-
>
|
|
107
|
-
<Select.Item value='admin' label='Admin' />
|
|
108
|
-
<Select.Item value='editor' label='Editor' />
|
|
109
|
-
<Select.Item value='viewer' label='Viewer' />
|
|
110
|
-
</Select>
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Dropdown Notes
|
|
66
|
+
- Dropdown
|
|
67
|
+
- Tooltip
|
|
68
|
+
- Popover
|
|
69
|
+
- Modal
|
|
116
70
|
|
|
117
|
-
|
|
118
|
-
menus with `Dropdown.Trigger`, `Dropdown.Content`, `Dropdown.Item`, groups,
|
|
119
|
-
labels, and separators. Use `open`, `defaultOpen`, and `onOpenChange` for menu
|
|
120
|
-
state. Use root `color` for the semantic trigger and menu palette, and
|
|
121
|
-
`Dropdown.Item danger` for destructive commands.
|
|
71
|
+
### Forms
|
|
122
72
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
<Dropdown color='primary' label='Actions'>
|
|
127
|
-
<Dropdown.Content>
|
|
128
|
-
<Dropdown.Label>File</Dropdown.Label>
|
|
129
|
-
<Dropdown.Item value='duplicate' onSelect={duplicate}>
|
|
130
|
-
Duplicate
|
|
131
|
-
</Dropdown.Item>
|
|
132
|
-
<Dropdown.Separator />
|
|
133
|
-
<Dropdown.Item value='delete' danger onSelect={deleteFile}>
|
|
134
|
-
Delete
|
|
135
|
-
</Dropdown.Item>
|
|
136
|
-
</Dropdown.Content>
|
|
137
|
-
</Dropdown>;
|
|
138
|
-
```
|
|
73
|
+
- FormField
|
|
74
|
+
- Tabs
|
|
139
75
|
|
|
140
|
-
|
|
76
|
+
Every public component includes React Native Storybook stories and Vitest unit
|
|
77
|
+
tests.
|
|
141
78
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
or `RadioGroup`. The wrapped control should provide its own
|
|
145
|
-
`accessibilityLabel`, role, disabled/editable state and interaction behavior.
|
|
146
|
-
`FormField` only provides layout, text styling, required mark, disabled root
|
|
147
|
-
state and polite error announcement.
|
|
79
|
+
For detailed props, shared types, examples, and compound component APIs, see
|
|
80
|
+
[Native Component API](./API.md).
|
|
148
81
|
|
|
149
|
-
##
|
|
82
|
+
## Infrastructure
|
|
150
83
|
|
|
151
|
-
|
|
84
|
+
The package also exports native infrastructure used by components and
|
|
85
|
+
applications:
|
|
152
86
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
87
|
+
- `Portal`
|
|
88
|
+
- `PortalProvider`
|
|
89
|
+
- `ThemeProvider`
|
|
90
|
+
- `useTheme`
|
|
91
|
+
- `nativeThemes`
|
|
156
92
|
|
|
157
|
-
|
|
93
|
+
## Documentation
|
|
158
94
|
|
|
159
|
-
|
|
95
|
+
- [Getting Started](https://docs.vellira.dev/start/getting-started)
|
|
96
|
+
- [React Native](https://docs.vellira.dev/react-native/)
|
|
97
|
+
- [Native Component API](./API.md)
|
|
160
98
|
|
|
161
99
|
## Storybook
|
|
162
100
|
|
|
163
|
-
Native stories live next to components as `*.stories.tsx` and are consumed by
|
|
101
|
+
Native stories live next to components as `*.stories.tsx` and are consumed by
|
|
102
|
+
`apps/native-storybook`.
|
|
164
103
|
|
|
165
104
|
Run on-device Storybook from the workspace root:
|
|
166
105
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ export { Dropdown } from './components/Dropdown';
|
|
|
2
2
|
export type { DropdownContentProps, DropdownEmptyProps, DropdownGroupProps, DropdownItemProps, DropdownLabelProps, DropdownPresentation, DropdownProps, DropdownSelectEvent, DropdownSeparatorProps, DropdownTriggerProps, } from './components/Dropdown/types';
|
|
3
3
|
export type { ModalProps } from './components/Modal';
|
|
4
4
|
export { Modal } from './components/Modal';
|
|
5
|
+
export type { PopoverAnchorProps, PopoverArrowProps, PopoverCloseProps, PopoverContentProps, PopoverDescriptionProps, PopoverProps, PopoverTitleProps, PopoverTriggerProps, } from './components/Popover';
|
|
6
|
+
export { Popover } from './components/Popover';
|
|
5
7
|
export type { RadioGroupProps } from './components/RadioGroup';
|
|
6
8
|
export { RadioGroup } from './components/RadioGroup';
|
|
7
9
|
export type { SelectOption, SelectProps } from './components/Select';
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,26 @@ import { Check, ChevronDown, Close, Search } from "@vellira-ui/icons";
|
|
|
3
3
|
import { AccessibilityInfo, ActivityIndicator, Animated, Dimensions, Easing, FlatList, Modal as Modal$1, Platform, Pressable, ScrollView, StyleSheet, Text, TextInput, View, findNodeHandle, useWindowDimensions } from "react-native";
|
|
4
4
|
import { darkTheme, highContrastTheme, lightTheme } from "@vellira-ui/tokens";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/theme/fontWeight.ts
|
|
7
|
+
const nativeFontWeights = /* @__PURE__ */ new Set([
|
|
8
|
+
"normal",
|
|
9
|
+
"bold",
|
|
10
|
+
"100",
|
|
11
|
+
"200",
|
|
12
|
+
"300",
|
|
13
|
+
"400",
|
|
14
|
+
"500",
|
|
15
|
+
"600",
|
|
16
|
+
"700",
|
|
17
|
+
"800",
|
|
18
|
+
"900"
|
|
19
|
+
]);
|
|
20
|
+
function toNativeFontWeight(weight) {
|
|
21
|
+
const normalizedWeight = String(weight);
|
|
22
|
+
if (!nativeFontWeights.has(normalizedWeight)) return "normal";
|
|
23
|
+
return normalizedWeight;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
6
26
|
//#region src/managers/FloatingManager/computeFloatingPosition.ts
|
|
7
27
|
function clamp(value, min, max) {
|
|
8
28
|
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
@@ -1882,6 +1902,338 @@ const Modal = Object.assign(ModalRoot, {
|
|
|
1882
1902
|
});
|
|
1883
1903
|
Modal.displayName = "Modal";
|
|
1884
1904
|
//#endregion
|
|
1905
|
+
//#region src/components/Popover/internal/PopoverContext.tsx
|
|
1906
|
+
const PopoverContext = createContext(null);
|
|
1907
|
+
function PopoverProvider({ children, value }) {
|
|
1908
|
+
return /* @__PURE__ */ jsx(PopoverContext.Provider, {
|
|
1909
|
+
value,
|
|
1910
|
+
children
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
function usePopoverContext(componentName) {
|
|
1914
|
+
const context = useContext(PopoverContext);
|
|
1915
|
+
if (!context) throw new Error(`${componentName} must be used within Popover.`);
|
|
1916
|
+
return context;
|
|
1917
|
+
}
|
|
1918
|
+
//#endregion
|
|
1919
|
+
//#region src/components/Popover/Anchor/PopoverAnchor.tsx
|
|
1920
|
+
function PopoverAnchor({ children, asChild = false, ...anchorProps }) {
|
|
1921
|
+
const { anchorRef } = usePopoverContext("Popover.Anchor");
|
|
1922
|
+
if (asChild) return cloneElement(children, { ref: anchorRef });
|
|
1923
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1924
|
+
...anchorProps,
|
|
1925
|
+
ref: anchorRef,
|
|
1926
|
+
children
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
PopoverAnchor.displayName = "Popover.Anchor";
|
|
1930
|
+
//#endregion
|
|
1931
|
+
//#region src/components/Popover/Arrow/PopoverArrow.styles.ts
|
|
1932
|
+
function createPopoverArrowStyles({ theme, side, arrowPosition }) {
|
|
1933
|
+
const tokens = theme.components.popover.arrow;
|
|
1934
|
+
const halfSize = tokens.size / 2;
|
|
1935
|
+
const position = side === "top" || side === "bottom" ? {
|
|
1936
|
+
left: arrowPosition.left ?? 0,
|
|
1937
|
+
transform: [{ translateX: -halfSize }, { rotate: "45deg" }]
|
|
1938
|
+
} : {
|
|
1939
|
+
top: arrowPosition.top ?? 0,
|
|
1940
|
+
transform: [{ translateY: -halfSize }, { rotate: "45deg" }]
|
|
1941
|
+
};
|
|
1942
|
+
const border = { borderColor: tokens.border };
|
|
1943
|
+
switch (side) {
|
|
1944
|
+
case "top":
|
|
1945
|
+
position.bottom = -halfSize;
|
|
1946
|
+
border.borderRightWidth = 1;
|
|
1947
|
+
border.borderBottomWidth = 1;
|
|
1948
|
+
break;
|
|
1949
|
+
case "bottom":
|
|
1950
|
+
position.top = -halfSize;
|
|
1951
|
+
border.borderLeftWidth = 1;
|
|
1952
|
+
border.borderTopWidth = 1;
|
|
1953
|
+
break;
|
|
1954
|
+
case "left":
|
|
1955
|
+
position.right = -halfSize;
|
|
1956
|
+
border.borderRightWidth = 1;
|
|
1957
|
+
border.borderTopWidth = 1;
|
|
1958
|
+
break;
|
|
1959
|
+
case "right":
|
|
1960
|
+
position.left = -halfSize;
|
|
1961
|
+
border.borderLeftWidth = 1;
|
|
1962
|
+
border.borderBottomWidth = 1;
|
|
1963
|
+
break;
|
|
1964
|
+
}
|
|
1965
|
+
return StyleSheet.create({ arrow: {
|
|
1966
|
+
position: "absolute",
|
|
1967
|
+
width: tokens.size,
|
|
1968
|
+
height: tokens.size,
|
|
1969
|
+
backgroundColor: tokens.bg,
|
|
1970
|
+
...position,
|
|
1971
|
+
...border
|
|
1972
|
+
} });
|
|
1973
|
+
}
|
|
1974
|
+
//#endregion
|
|
1975
|
+
//#region src/components/Popover/Arrow/PopoverArrow.tsx
|
|
1976
|
+
function PopoverArrow({ style }) {
|
|
1977
|
+
const { theme } = useTheme();
|
|
1978
|
+
const { placement, arrowPosition } = usePopoverContext("Popover.Arrow");
|
|
1979
|
+
const side = placement.split("-")[0];
|
|
1980
|
+
return /* @__PURE__ */ jsx(View, {
|
|
1981
|
+
accessible: false,
|
|
1982
|
+
pointerEvents: "none",
|
|
1983
|
+
style: [useMemo(() => createPopoverArrowStyles({
|
|
1984
|
+
theme,
|
|
1985
|
+
side,
|
|
1986
|
+
arrowPosition
|
|
1987
|
+
}), [
|
|
1988
|
+
theme,
|
|
1989
|
+
side,
|
|
1990
|
+
arrowPosition
|
|
1991
|
+
]).arrow, style]
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
PopoverArrow.displayName = "Popover.Arrow";
|
|
1995
|
+
//#endregion
|
|
1996
|
+
//#region src/components/Popover/Close/PopoverClose.tsx
|
|
1997
|
+
const PopoverClose = ({ children, asChild = false, onPress, ...closeProps }) => {
|
|
1998
|
+
const { setOpen } = usePopoverContext("Popover.Close");
|
|
1999
|
+
const handlePress = (event) => {
|
|
2000
|
+
children.props.onPress?.(event);
|
|
2001
|
+
onPress?.(event);
|
|
2002
|
+
if (event.defaultPrevented) return;
|
|
2003
|
+
setOpen(false, { reason: "close" });
|
|
2004
|
+
};
|
|
2005
|
+
if (asChild) return cloneElement(children, { onPress: handlePress });
|
|
2006
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
2007
|
+
...closeProps,
|
|
2008
|
+
onPress: handlePress,
|
|
2009
|
+
children
|
|
2010
|
+
});
|
|
2011
|
+
};
|
|
2012
|
+
PopoverClose.displayName = "PopoverClose";
|
|
2013
|
+
//#endregion
|
|
2014
|
+
//#region src/primitives/Portal/Portal.tsx
|
|
2015
|
+
const PortalContext = createContext(null);
|
|
2016
|
+
const styles$1 = StyleSheet.create({ host: { flex: 1 } });
|
|
2017
|
+
const PortalProvider = ({ children, container = null }) => /* @__PURE__ */ jsx(PortalContext.Provider, {
|
|
2018
|
+
value: container,
|
|
2019
|
+
children
|
|
2020
|
+
});
|
|
2021
|
+
const Portal = ({ children, visible = true, animationType = "none", hardwareAccelerated = true, navigationBarTranslucent = true, statusBarTranslucent = true, onDismiss, onRequestClose }) => {
|
|
2022
|
+
useContext(PortalContext);
|
|
2023
|
+
if (!visible) return null;
|
|
2024
|
+
return /* @__PURE__ */ jsx(Modal$1, {
|
|
2025
|
+
animationType,
|
|
2026
|
+
hardwareAccelerated,
|
|
2027
|
+
navigationBarTranslucent,
|
|
2028
|
+
onDismiss,
|
|
2029
|
+
onRequestClose,
|
|
2030
|
+
presentationStyle: "overFullScreen",
|
|
2031
|
+
statusBarTranslucent,
|
|
2032
|
+
transparent: true,
|
|
2033
|
+
visible: true,
|
|
2034
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
2035
|
+
pointerEvents: "box-none",
|
|
2036
|
+
style: styles$1.host,
|
|
2037
|
+
children
|
|
2038
|
+
})
|
|
2039
|
+
});
|
|
2040
|
+
};
|
|
2041
|
+
Portal.__velliraPortal = true;
|
|
2042
|
+
Portal.displayName = "Portal";
|
|
2043
|
+
PortalProvider.displayName = "PortalProvider";
|
|
2044
|
+
//#endregion
|
|
2045
|
+
//#region src/components/Popover/Content/PopoverContent.styles.ts
|
|
2046
|
+
const styles = StyleSheet.create({
|
|
2047
|
+
layer: { flex: 1 },
|
|
2048
|
+
backdrop: StyleSheet.absoluteFill,
|
|
2049
|
+
content: { position: "absolute" }
|
|
2050
|
+
});
|
|
2051
|
+
function createPopoverContentStyles(theme) {
|
|
2052
|
+
const tokens = theme.components.popover.content;
|
|
2053
|
+
const shadow = tokens.shadow.native;
|
|
2054
|
+
return StyleSheet.create({ content: {
|
|
2055
|
+
minWidth: tokens.minWidth,
|
|
2056
|
+
maxWidth: tokens.maxWidth,
|
|
2057
|
+
padding: tokens.padding,
|
|
2058
|
+
gap: tokens.gap,
|
|
2059
|
+
backgroundColor: tokens.bg,
|
|
2060
|
+
borderColor: tokens.border,
|
|
2061
|
+
borderWidth: tokens.borderWidth,
|
|
2062
|
+
borderRadius: tokens.radius,
|
|
2063
|
+
shadowColor: shadow.color,
|
|
2064
|
+
shadowOpacity: shadow.opacity,
|
|
2065
|
+
shadowRadius: shadow.blur,
|
|
2066
|
+
shadowOffset: {
|
|
2067
|
+
width: shadow.x,
|
|
2068
|
+
height: shadow.y
|
|
2069
|
+
},
|
|
2070
|
+
elevation: shadow.elevation
|
|
2071
|
+
} });
|
|
2072
|
+
}
|
|
2073
|
+
//#endregion
|
|
2074
|
+
//#region src/components/Popover/Content/PopoverContent.tsx
|
|
2075
|
+
function PopoverContent({ children, style, ...contentProps }) {
|
|
2076
|
+
const { theme } = useTheme();
|
|
2077
|
+
const layerRef = useRef(null);
|
|
2078
|
+
const themedStyles = useMemo(() => createPopoverContentStyles(theme), [theme]);
|
|
2079
|
+
const { open, position, onFloatingLayout, updatePosition, setOpen, closeOnOutsidePress } = usePopoverContext("Popover.Content");
|
|
2080
|
+
useEffect(() => {
|
|
2081
|
+
if (!open) return;
|
|
2082
|
+
requestAnimationFrame(() => {
|
|
2083
|
+
updatePosition(layerRef);
|
|
2084
|
+
});
|
|
2085
|
+
}, [open, updatePosition]);
|
|
2086
|
+
return /* @__PURE__ */ jsx(Portal, {
|
|
2087
|
+
visible: open,
|
|
2088
|
+
onRequestClose: () => {
|
|
2089
|
+
setOpen(false, { reason: "escape-key" });
|
|
2090
|
+
},
|
|
2091
|
+
children: /* @__PURE__ */ jsxs(View, {
|
|
2092
|
+
ref: layerRef,
|
|
2093
|
+
pointerEvents: "box-none",
|
|
2094
|
+
style: styles.layer,
|
|
2095
|
+
children: [/* @__PURE__ */ jsx(Pressable, {
|
|
2096
|
+
testID: "popover-backdrop",
|
|
2097
|
+
accessibilityLabel: closeOnOutsidePress ? "Close popover" : void 0,
|
|
2098
|
+
accessibilityRole: closeOnOutsidePress ? "button" : void 0,
|
|
2099
|
+
onPress: closeOnOutsidePress ? () => {
|
|
2100
|
+
setOpen(false, { reason: "outside-press" });
|
|
2101
|
+
} : void 0,
|
|
2102
|
+
style: styles.backdrop
|
|
2103
|
+
}), /* @__PURE__ */ jsx(View, {
|
|
2104
|
+
...contentProps,
|
|
2105
|
+
onLayout: onFloatingLayout,
|
|
2106
|
+
style: [
|
|
2107
|
+
styles.content,
|
|
2108
|
+
themedStyles.content,
|
|
2109
|
+
position,
|
|
2110
|
+
style
|
|
2111
|
+
],
|
|
2112
|
+
children
|
|
2113
|
+
})]
|
|
2114
|
+
})
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
//#endregion
|
|
2118
|
+
//#region src/components/Popover/Description/PopoverDescription.styles.ts
|
|
2119
|
+
function createPopoverDescriptionStyles(theme) {
|
|
2120
|
+
return StyleSheet.create({ description: {
|
|
2121
|
+
color: theme.components.popover.description.fg,
|
|
2122
|
+
fontSize: theme.tokens.typography.size.sm
|
|
2123
|
+
} });
|
|
2124
|
+
}
|
|
2125
|
+
//#endregion
|
|
2126
|
+
//#region src/components/Popover/Description/PopoverDescription.tsx
|
|
2127
|
+
const PopoverDescription = ({ children, style, ...descriptionProps }) => {
|
|
2128
|
+
const { theme } = useTheme();
|
|
2129
|
+
const styles = useMemo(() => createPopoverDescriptionStyles(theme), [theme]);
|
|
2130
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
2131
|
+
...descriptionProps,
|
|
2132
|
+
style: [styles.description, style],
|
|
2133
|
+
children
|
|
2134
|
+
});
|
|
2135
|
+
};
|
|
2136
|
+
PopoverDescription.displayName = "PopoverDescription";
|
|
2137
|
+
//#endregion
|
|
2138
|
+
//#region src/components/Popover/Root/PopoverRoot.tsx
|
|
2139
|
+
function getNativePlacement(side, align) {
|
|
2140
|
+
if (!side) return "bottom";
|
|
2141
|
+
if (!align || align === "center") return side;
|
|
2142
|
+
return `${side}-${align}`;
|
|
2143
|
+
}
|
|
2144
|
+
function PopoverRoot({ children, open: openProp, defaultOpen = false, onOpenChange, side = "bottom", align = "center", sideOffset = 8, closeOnOutsidePress = true }) {
|
|
2145
|
+
const triggerRef = useRef(null);
|
|
2146
|
+
const anchorRef = useRef(null);
|
|
2147
|
+
const getReferenceRef = useCallback(() => anchorRef.current ? anchorRef : triggerRef, []);
|
|
2148
|
+
const openChangeDetailsRef = useRef({ reason: "programmatic" });
|
|
2149
|
+
const [open, setOpenState] = useControllableState({
|
|
2150
|
+
value: openProp,
|
|
2151
|
+
defaultValue: defaultOpen,
|
|
2152
|
+
onChange: (nextOpen) => {
|
|
2153
|
+
onOpenChange?.(nextOpen, openChangeDetailsRef.current);
|
|
2154
|
+
}
|
|
2155
|
+
});
|
|
2156
|
+
const { position, arrowPosition, placement, updatePosition: updateFloatingPosition, onFloatingLayout } = useNativeFloatingPosition(getNativePlacement(side, align), sideOffset);
|
|
2157
|
+
const setOpen = useCallback((nextOpen, details) => {
|
|
2158
|
+
openChangeDetailsRef.current = details;
|
|
2159
|
+
setOpenState(nextOpen);
|
|
2160
|
+
}, [setOpenState]);
|
|
2161
|
+
return /* @__PURE__ */ jsx(PopoverProvider, {
|
|
2162
|
+
value: {
|
|
2163
|
+
open,
|
|
2164
|
+
closeOnOutsidePress,
|
|
2165
|
+
triggerRef,
|
|
2166
|
+
anchorRef,
|
|
2167
|
+
side,
|
|
2168
|
+
align,
|
|
2169
|
+
placement,
|
|
2170
|
+
position,
|
|
2171
|
+
arrowPosition,
|
|
2172
|
+
onFloatingLayout,
|
|
2173
|
+
updatePosition: useCallback((containerRef) => {
|
|
2174
|
+
updateFloatingPosition(getReferenceRef(), containerRef);
|
|
2175
|
+
}, [getReferenceRef, updateFloatingPosition]),
|
|
2176
|
+
setOpen
|
|
2177
|
+
},
|
|
2178
|
+
children
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
PopoverRoot.displayName = "Popover.Root";
|
|
2182
|
+
//#endregion
|
|
2183
|
+
//#region src/components/Popover/Title/PopoverTitle.styles.ts
|
|
2184
|
+
function createPopoverTitleStyles(theme) {
|
|
2185
|
+
return StyleSheet.create({ title: {
|
|
2186
|
+
color: theme.components.popover.title.fg,
|
|
2187
|
+
fontSize: theme.tokens.typography.size.md,
|
|
2188
|
+
fontWeight: toNativeFontWeight(theme.tokens.typography.weight.semibold)
|
|
2189
|
+
} });
|
|
2190
|
+
}
|
|
2191
|
+
//#endregion
|
|
2192
|
+
//#region src/components/Popover/Title/PopoverTitle.tsx
|
|
2193
|
+
const PopoverTitle = ({ children, style, ...titleProps }) => {
|
|
2194
|
+
const { theme } = useTheme();
|
|
2195
|
+
const styles = useMemo(() => createPopoverTitleStyles(theme), [theme]);
|
|
2196
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
2197
|
+
...titleProps,
|
|
2198
|
+
style: [styles.title, style],
|
|
2199
|
+
children
|
|
2200
|
+
});
|
|
2201
|
+
};
|
|
2202
|
+
PopoverTitle.displayName = "PopoverTitle";
|
|
2203
|
+
//#endregion
|
|
2204
|
+
//#region src/components/Popover/Trigger/PopoverTrigger.tsx
|
|
2205
|
+
function PopoverTrigger({ children, asChild = false, onPress, ...triggerProps }) {
|
|
2206
|
+
const { open, setOpen, triggerRef } = usePopoverContext("Popover.Trigger");
|
|
2207
|
+
const handlePress = (event) => {
|
|
2208
|
+
children.props.onPress?.(event);
|
|
2209
|
+
onPress?.(event);
|
|
2210
|
+
if (event.defaultPrevented) return;
|
|
2211
|
+
setOpen(!open, { reason: "trigger" });
|
|
2212
|
+
};
|
|
2213
|
+
if (asChild) return cloneElement(children, {
|
|
2214
|
+
ref: triggerRef,
|
|
2215
|
+
onPress: handlePress
|
|
2216
|
+
});
|
|
2217
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
2218
|
+
...triggerProps,
|
|
2219
|
+
ref: triggerRef,
|
|
2220
|
+
onPress: handlePress,
|
|
2221
|
+
children
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
//#endregion
|
|
2225
|
+
//#region src/components/Popover/Popover.tsx
|
|
2226
|
+
const Popover = Object.assign(PopoverRoot, {
|
|
2227
|
+
Anchor: PopoverAnchor,
|
|
2228
|
+
Trigger: PopoverTrigger,
|
|
2229
|
+
Content: PopoverContent,
|
|
2230
|
+
Arrow: PopoverArrow,
|
|
2231
|
+
Close: PopoverClose,
|
|
2232
|
+
Title: PopoverTitle,
|
|
2233
|
+
Description: PopoverDescription
|
|
2234
|
+
});
|
|
2235
|
+
Popover.displayName = "Popover";
|
|
2236
|
+
//#endregion
|
|
1885
2237
|
//#region src/components/RadioGroup/internal/RadioGroupContext.tsx
|
|
1886
2238
|
const RadioGroupContext = createContext(null);
|
|
1887
2239
|
const RadioGroupProvider = RadioGroupContext.Provider;
|
|
@@ -4807,10 +5159,10 @@ function InternalArrow() {
|
|
|
4807
5159
|
left: "right"
|
|
4808
5160
|
}[side];
|
|
4809
5161
|
const crossAxisStyle = side === "left" || side === "right" ? {
|
|
4810
|
-
top:
|
|
5162
|
+
top: tooltip.arrowPosition.top ?? 0,
|
|
4811
5163
|
marginTop: -size / 2
|
|
4812
5164
|
} : {
|
|
4813
|
-
left:
|
|
5165
|
+
left: tooltip.arrowPosition.left ?? 0,
|
|
4814
5166
|
marginLeft: -size / 2
|
|
4815
5167
|
};
|
|
4816
5168
|
return /* @__PURE__ */ jsx(View, {
|
|
@@ -4850,7 +5202,7 @@ const TooltipRoot = ({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
4850
5202
|
defaultValue: defaultOpen,
|
|
4851
5203
|
onChange: onOpenChange
|
|
4852
5204
|
});
|
|
4853
|
-
const { position, updatePosition, onFloatingLayout } = useNativeFloatingPosition(placement, offset);
|
|
5205
|
+
const { position, arrowPosition, placement: resolvedPlacement, updatePosition, onFloatingLayout } = useNativeFloatingPosition(placement, offset);
|
|
4854
5206
|
const clearCloseTimer = useCallback(() => {
|
|
4855
5207
|
if (closeTimerRef.current) {
|
|
4856
5208
|
clearTimeout(closeTimerRef.current);
|
|
@@ -4909,8 +5261,9 @@ const TooltipRoot = ({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
4909
5261
|
contentId,
|
|
4910
5262
|
open,
|
|
4911
5263
|
disabled,
|
|
4912
|
-
placement,
|
|
5264
|
+
placement: resolvedPlacement,
|
|
4913
5265
|
position,
|
|
5266
|
+
arrowPosition,
|
|
4914
5267
|
triggerRef,
|
|
4915
5268
|
setOpen,
|
|
4916
5269
|
show,
|
|
@@ -4919,13 +5272,14 @@ const TooltipRoot = ({ children, open: openProp, defaultOpen = false, onOpenChan
|
|
|
4919
5272
|
requestOutsideClose: dismiss.requestOutsideClose,
|
|
4920
5273
|
onFloatingLayout
|
|
4921
5274
|
}), [
|
|
5275
|
+
arrowPosition,
|
|
4922
5276
|
contentId,
|
|
4923
5277
|
disabled,
|
|
4924
5278
|
dismiss.requestClose,
|
|
4925
5279
|
dismiss.requestOutsideClose,
|
|
4926
5280
|
hide,
|
|
4927
5281
|
open,
|
|
4928
|
-
|
|
5282
|
+
resolvedPlacement,
|
|
4929
5283
|
position,
|
|
4930
5284
|
setOpen,
|
|
4931
5285
|
show,
|
|
@@ -5783,35 +6137,4 @@ const Input = forwardRef(({ label, description, value, defaultValue, onValueChan
|
|
|
5783
6137
|
});
|
|
5784
6138
|
Input.displayName = "Input";
|
|
5785
6139
|
//#endregion
|
|
5786
|
-
|
|
5787
|
-
const PortalContext = createContext(null);
|
|
5788
|
-
const styles = StyleSheet.create({ host: { flex: 1 } });
|
|
5789
|
-
const PortalProvider = ({ children, container = null }) => /* @__PURE__ */ jsx(PortalContext.Provider, {
|
|
5790
|
-
value: container,
|
|
5791
|
-
children
|
|
5792
|
-
});
|
|
5793
|
-
const Portal = ({ children, visible = true, animationType = "none", hardwareAccelerated = true, navigationBarTranslucent = true, statusBarTranslucent = true, onDismiss, onRequestClose }) => {
|
|
5794
|
-
useContext(PortalContext);
|
|
5795
|
-
if (!visible) return null;
|
|
5796
|
-
return /* @__PURE__ */ jsx(Modal$1, {
|
|
5797
|
-
animationType,
|
|
5798
|
-
hardwareAccelerated,
|
|
5799
|
-
navigationBarTranslucent,
|
|
5800
|
-
onDismiss,
|
|
5801
|
-
onRequestClose,
|
|
5802
|
-
presentationStyle: "overFullScreen",
|
|
5803
|
-
statusBarTranslucent,
|
|
5804
|
-
transparent: true,
|
|
5805
|
-
visible: true,
|
|
5806
|
-
children: /* @__PURE__ */ jsx(View, {
|
|
5807
|
-
pointerEvents: "box-none",
|
|
5808
|
-
style: styles.host,
|
|
5809
|
-
children
|
|
5810
|
-
})
|
|
5811
|
-
});
|
|
5812
|
-
};
|
|
5813
|
-
Portal.__velliraPortal = true;
|
|
5814
|
-
Portal.displayName = "Portal";
|
|
5815
|
-
PortalProvider.displayName = "PortalProvider";
|
|
5816
|
-
//#endregion
|
|
5817
|
-
export { Button, Checkbox, Dropdown, FormField, Input, Modal, Portal, PortalProvider, Radio, RadioGroup, Select, Tabs, ThemeProvider, Tooltip, nativeThemes, useTheme };
|
|
6140
|
+
export { Button, Checkbox, Dropdown, FormField, Input, Modal, Popover, Portal, PortalProvider, Radio, RadioGroup, Select, Tabs, ThemeProvider, Tooltip, nativeThemes, useTheme };
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellira-ui/react-native",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.55.0",
|
|
4
4
|
"description": "React Native components for Vellira Design System",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vellira",
|
|
7
|
+
"react-native",
|
|
8
|
+
"ui",
|
|
9
|
+
"components",
|
|
10
|
+
"design-system",
|
|
11
|
+
"typescript",
|
|
12
|
+
"mobile"
|
|
13
|
+
],
|
|
5
14
|
"author": "Roman Bakurov",
|
|
6
15
|
"license": "MIT",
|
|
7
16
|
"repository": {
|
|
@@ -9,6 +18,10 @@
|
|
|
9
18
|
"url": "git+https://github.com/vellira-dev/vellira.git",
|
|
10
19
|
"directory": "packages/react-native"
|
|
11
20
|
},
|
|
21
|
+
"homepage": "https://vellira.dev",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/vellira-dev/vellira/issues"
|
|
24
|
+
},
|
|
12
25
|
"private": false,
|
|
13
26
|
"type": "module",
|
|
14
27
|
"sideEffects": false,
|