@webority-technologies/mobile 0.0.15 → 0.0.21
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/lib/commonjs/components/Accordion/Accordion.js +60 -19
- package/lib/commonjs/components/AppBar/AppBar.js +29 -20
- package/lib/commonjs/components/Avatar/Avatar.js +38 -8
- package/lib/commonjs/components/Badge/Badge.js +66 -4
- package/lib/commonjs/components/Banner/Banner.js +146 -66
- package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +37 -15
- package/lib/commonjs/components/BottomSheet/BottomSheet.js +78 -53
- package/lib/commonjs/components/Button/Button.js +12 -5
- package/lib/commonjs/components/Card/Card.js +106 -16
- package/lib/commonjs/components/Carousel/Carousel.js +66 -12
- package/lib/commonjs/components/Checkbox/Checkbox.js +11 -7
- package/lib/commonjs/components/Chip/Chip.js +44 -12
- package/lib/commonjs/components/DatePicker/DatePicker.js +185 -76
- package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +133 -59
- package/lib/commonjs/components/Dialog/Dialog.js +16 -10
- package/lib/commonjs/components/Drawer/Drawer.js +13 -10
- package/lib/commonjs/components/FieldBase/FieldBase.js +494 -0
- package/lib/commonjs/components/FieldBase/index.js +32 -0
- package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +69 -44
- package/lib/commonjs/components/ForceUpdateDialog/ForceUpdateDialog.js +8 -2
- package/lib/commonjs/components/FormField/FormField.js +3 -2
- package/lib/commonjs/components/ImageGallery/ImageGallery.js +132 -44
- package/lib/commonjs/components/Input/Input.js +144 -181
- package/lib/commonjs/components/ListItem/ListItem.js +90 -11
- package/lib/commonjs/components/Modal/Modal.js +55 -27
- package/lib/commonjs/components/NumberInput/NumberInput.js +60 -106
- package/lib/commonjs/components/OTPInput/OTPInput.js +65 -58
- package/lib/commonjs/components/PickerTrigger/PickerTrigger.js +185 -0
- package/lib/commonjs/components/{AppIcon → PickerTrigger}/index.js +4 -4
- package/lib/commonjs/components/ProgressBar/ProgressBar.js +19 -11
- package/lib/commonjs/components/Radio/Radio.js +11 -6
- package/lib/commonjs/components/Rating/Rating.js +85 -19
- package/lib/commonjs/components/SearchBar/SearchBar.js +90 -107
- package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +22 -11
- package/lib/commonjs/components/Select/Select.js +62 -91
- package/lib/commonjs/components/Skeleton/Skeleton.js +131 -174
- package/lib/commonjs/components/Skeleton/SkeletonClock.js +117 -0
- package/lib/commonjs/components/Skeleton/SkeletonContent.js +164 -81
- package/lib/commonjs/components/Skeleton/SkeletonProvider.js +72 -10
- package/lib/commonjs/components/Skeleton/index.js +17 -16
- package/lib/commonjs/components/Slider/Slider.js +44 -25
- package/lib/commonjs/components/Stepper/Stepper.js +199 -29
- package/lib/commonjs/components/Swipeable/Swipeable.js +36 -19
- package/lib/commonjs/components/Switch/Switch.js +9 -2
- package/lib/commonjs/components/Tabs/Tabs.js +84 -21
- package/lib/commonjs/components/TimePicker/TimePicker.js +123 -45
- package/lib/commonjs/components/Toast/Toast.js +27 -16
- package/lib/commonjs/components/Tooltip/Tooltip.js +56 -32
- package/lib/commonjs/components/index.js +37 -37
- package/lib/commonjs/theme/tokens.js +55 -7
- package/lib/module/components/Accordion/Accordion.js +61 -20
- package/lib/module/components/AppBar/AppBar.js +29 -20
- package/lib/module/components/Avatar/Avatar.js +39 -9
- package/lib/module/components/Badge/Badge.js +67 -5
- package/lib/module/components/Banner/Banner.js +147 -67
- package/lib/module/components/BottomNavigation/BottomNavigation.js +37 -15
- package/lib/module/components/BottomSheet/BottomSheet.js +80 -55
- package/lib/module/components/Button/Button.js +12 -5
- package/lib/module/components/Card/Card.js +107 -17
- package/lib/module/components/Carousel/Carousel.js +67 -13
- package/lib/module/components/Checkbox/Checkbox.js +11 -7
- package/lib/module/components/Chip/Chip.js +45 -13
- package/lib/module/components/DatePicker/DatePicker.js +185 -76
- package/lib/module/components/DateRangePicker/DateRangePicker.js +134 -60
- package/lib/module/components/Dialog/Dialog.js +16 -10
- package/lib/module/components/Drawer/Drawer.js +13 -10
- package/lib/module/components/FieldBase/FieldBase.js +485 -0
- package/lib/module/components/FieldBase/index.js +4 -0
- package/lib/module/components/FloatingActionButton/FloatingActionButton.js +69 -44
- package/lib/module/components/ForceUpdateDialog/ForceUpdateDialog.js +8 -2
- package/lib/module/components/FormField/FormField.js +3 -2
- package/lib/module/components/ImageGallery/ImageGallery.js +128 -40
- package/lib/module/components/Input/Input.js +144 -179
- package/lib/module/components/ListItem/ListItem.js +91 -12
- package/lib/module/components/Modal/Modal.js +55 -27
- package/lib/module/components/NumberInput/NumberInput.js +60 -106
- package/lib/module/components/OTPInput/OTPInput.js +65 -58
- package/lib/module/components/PickerTrigger/PickerTrigger.js +181 -0
- package/lib/module/components/PickerTrigger/index.js +4 -0
- package/lib/module/components/ProgressBar/ProgressBar.js +19 -11
- package/lib/module/components/Radio/Radio.js +11 -6
- package/lib/module/components/Rating/Rating.js +86 -20
- package/lib/module/components/SearchBar/SearchBar.js +90 -107
- package/lib/module/components/SegmentedControl/SegmentedControl.js +22 -11
- package/lib/module/components/Select/Select.js +62 -91
- package/lib/module/components/Skeleton/Skeleton.js +135 -175
- package/lib/module/components/Skeleton/SkeletonClock.js +110 -0
- package/lib/module/components/Skeleton/SkeletonContent.js +167 -84
- package/lib/module/components/Skeleton/SkeletonProvider.js +71 -10
- package/lib/module/components/Skeleton/index.js +3 -2
- package/lib/module/components/Slider/Slider.js +44 -25
- package/lib/module/components/Stepper/Stepper.js +201 -31
- package/lib/module/components/Swipeable/Swipeable.js +36 -19
- package/lib/module/components/Switch/Switch.js +9 -2
- package/lib/module/components/Tabs/Tabs.js +84 -21
- package/lib/module/components/TimePicker/TimePicker.js +123 -45
- package/lib/module/components/Toast/Toast.js +27 -16
- package/lib/module/components/Tooltip/Tooltip.js +56 -32
- package/lib/module/components/index.js +2 -2
- package/lib/module/theme/tokens.js +55 -7
- package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +10 -5
- package/lib/typescript/commonjs/components/AppBar/AppBar.d.ts +8 -0
- package/lib/typescript/commonjs/components/Avatar/Avatar.d.ts +12 -6
- package/lib/typescript/commonjs/components/Badge/Badge.d.ts +7 -6
- package/lib/typescript/commonjs/components/Banner/Banner.d.ts +17 -6
- package/lib/typescript/commonjs/components/BottomSheet/BottomSheet.d.ts +7 -0
- package/lib/typescript/commonjs/components/Card/Card.d.ts +17 -6
- package/lib/typescript/commonjs/components/Carousel/Carousel.d.ts +7 -6
- package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +9 -1
- package/lib/typescript/commonjs/components/Chip/Chip.d.ts +13 -6
- package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +38 -3
- package/lib/typescript/commonjs/components/DateRangePicker/DateRangePicker.d.ts +36 -3
- package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +13 -1
- package/lib/typescript/commonjs/components/FieldBase/FieldBase.d.ts +172 -0
- package/lib/typescript/commonjs/components/FieldBase/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/FloatingActionButton/FloatingActionButton.d.ts +8 -6
- package/lib/typescript/commonjs/components/FloatingActionButton/index.d.ts +1 -1
- package/lib/typescript/commonjs/components/ForceUpdateDialog/ForceUpdateDialog.d.ts +7 -0
- package/lib/typescript/commonjs/components/FormField/FormField.d.ts +7 -0
- package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -4
- package/lib/typescript/commonjs/components/Input/Input.d.ts +7 -1
- package/lib/typescript/commonjs/components/ListItem/ListItem.d.ts +13 -6
- package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -0
- package/lib/typescript/commonjs/components/PickerTrigger/PickerTrigger.d.ts +57 -0
- package/lib/typescript/commonjs/components/PickerTrigger/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/ProgressBar/ProgressBar.d.ts +2 -0
- package/lib/typescript/commonjs/components/Radio/Radio.d.ts +3 -0
- package/lib/typescript/commonjs/components/Rating/Rating.d.ts +9 -6
- package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts +49 -20
- package/lib/typescript/commonjs/components/Skeleton/SkeletonClock.d.ts +60 -0
- package/lib/typescript/commonjs/components/Skeleton/SkeletonContent.d.ts +80 -19
- package/lib/typescript/commonjs/components/Skeleton/SkeletonProvider.d.ts +39 -5
- package/lib/typescript/commonjs/components/Skeleton/index.d.ts +6 -4
- package/lib/typescript/commonjs/components/Slider/Slider.d.ts +12 -1
- package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +18 -6
- package/lib/typescript/commonjs/components/Swipeable/Swipeable.d.ts +2 -0
- package/lib/typescript/commonjs/components/Switch/Switch.d.ts +1 -0
- package/lib/typescript/commonjs/components/Tabs/Tabs.d.ts +26 -2
- package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +36 -3
- package/lib/typescript/commonjs/components/Toast/Toast.d.ts +8 -0
- package/lib/typescript/commonjs/components/Tooltip/Tooltip.d.ts +7 -1
- package/lib/typescript/commonjs/components/index.d.ts +5 -5
- package/lib/typescript/commonjs/index.d.ts +1 -1
- package/lib/typescript/commonjs/theme/index.d.ts +1 -1
- package/lib/typescript/commonjs/theme/types.d.ts +578 -12
- package/lib/typescript/module/components/Accordion/Accordion.d.ts +10 -5
- package/lib/typescript/module/components/AppBar/AppBar.d.ts +8 -0
- package/lib/typescript/module/components/Avatar/Avatar.d.ts +12 -6
- package/lib/typescript/module/components/Badge/Badge.d.ts +7 -6
- package/lib/typescript/module/components/Banner/Banner.d.ts +17 -6
- package/lib/typescript/module/components/BottomSheet/BottomSheet.d.ts +7 -0
- package/lib/typescript/module/components/Card/Card.d.ts +17 -6
- package/lib/typescript/module/components/Carousel/Carousel.d.ts +7 -6
- package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +9 -1
- package/lib/typescript/module/components/Chip/Chip.d.ts +13 -6
- package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +38 -3
- package/lib/typescript/module/components/DateRangePicker/DateRangePicker.d.ts +36 -3
- package/lib/typescript/module/components/Dialog/Dialog.d.ts +13 -1
- package/lib/typescript/module/components/FieldBase/FieldBase.d.ts +172 -0
- package/lib/typescript/module/components/FieldBase/index.d.ts +3 -0
- package/lib/typescript/module/components/FloatingActionButton/FloatingActionButton.d.ts +8 -6
- package/lib/typescript/module/components/FloatingActionButton/index.d.ts +1 -1
- package/lib/typescript/module/components/ForceUpdateDialog/ForceUpdateDialog.d.ts +7 -0
- package/lib/typescript/module/components/FormField/FormField.d.ts +7 -0
- package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -4
- package/lib/typescript/module/components/Input/Input.d.ts +7 -1
- package/lib/typescript/module/components/ListItem/ListItem.d.ts +13 -6
- package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -0
- package/lib/typescript/module/components/PickerTrigger/PickerTrigger.d.ts +57 -0
- package/lib/typescript/module/components/PickerTrigger/index.d.ts +3 -0
- package/lib/typescript/module/components/ProgressBar/ProgressBar.d.ts +2 -0
- package/lib/typescript/module/components/Radio/Radio.d.ts +3 -0
- package/lib/typescript/module/components/Rating/Rating.d.ts +9 -6
- package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/lib/typescript/module/components/Skeleton/Skeleton.d.ts +49 -20
- package/lib/typescript/module/components/Skeleton/SkeletonClock.d.ts +60 -0
- package/lib/typescript/module/components/Skeleton/SkeletonContent.d.ts +80 -19
- package/lib/typescript/module/components/Skeleton/SkeletonProvider.d.ts +39 -5
- package/lib/typescript/module/components/Skeleton/index.d.ts +6 -4
- package/lib/typescript/module/components/Slider/Slider.d.ts +12 -1
- package/lib/typescript/module/components/Stepper/Stepper.d.ts +18 -6
- package/lib/typescript/module/components/Swipeable/Swipeable.d.ts +2 -0
- package/lib/typescript/module/components/Switch/Switch.d.ts +1 -0
- package/lib/typescript/module/components/Tabs/Tabs.d.ts +26 -2
- package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +36 -3
- package/lib/typescript/module/components/Toast/Toast.d.ts +8 -0
- package/lib/typescript/module/components/Tooltip/Tooltip.d.ts +7 -1
- package/lib/typescript/module/components/index.d.ts +5 -5
- package/lib/typescript/module/index.d.ts +1 -1
- package/lib/typescript/module/theme/index.d.ts +1 -1
- package/lib/typescript/module/theme/types.d.ts +578 -12
- package/package.json +2 -6
- package/lib/commonjs/components/AppIcon/AppIcon.js +0 -120
- package/lib/commonjs/types/vector-icons.d.js +0 -2
- package/lib/module/components/AppIcon/AppIcon.js +0 -111
- package/lib/module/components/AppIcon/index.js +0 -4
- package/lib/module/types/vector-icons.d.js +0 -2
- package/lib/typescript/commonjs/components/AppIcon/AppIcon.d.ts +0 -20
- package/lib/typescript/commonjs/components/AppIcon/index.d.ts +0 -3
- package/lib/typescript/module/components/AppIcon/AppIcon.d.ts +0 -20
- package/lib/typescript/module/components/AppIcon/index.d.ts +0 -3
|
@@ -10,9 +10,12 @@ var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
|
|
|
10
10
|
var _index = require("../../theme/index.js");
|
|
11
11
|
var _usePressAnimation = require("../../hooks/usePressAnimation.js");
|
|
12
12
|
var _hapticUtils = require("../../utils/hapticUtils.js");
|
|
13
|
-
var _index2 = require("../AppIcon/index.js");
|
|
14
13
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
14
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
15
|
+
// Local shape mirror — see types.ts FloatingActionButtonTokens for the canonical
|
|
16
|
+
// definition. Declared here so the component can read tokens before types.ts is
|
|
17
|
+
// regenerated; will collapse to a direct import once that lands.
|
|
18
|
+
|
|
16
19
|
const sizeMap = {
|
|
17
20
|
sm: {
|
|
18
21
|
diameter: 40,
|
|
@@ -52,9 +55,6 @@ const toneForeground = (theme, tone) => {
|
|
|
52
55
|
if (tone === 'neutral') return theme.colors.text.primary;
|
|
53
56
|
return theme.colors.text.inverse;
|
|
54
57
|
};
|
|
55
|
-
const isIconConfig = value => {
|
|
56
|
-
return typeof value === 'object' && value !== null && ! /*#__PURE__*/_react.default.isValidElement(value) && typeof value.name === 'string';
|
|
57
|
-
};
|
|
58
58
|
const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
59
59
|
const {
|
|
60
60
|
icon,
|
|
@@ -70,6 +70,8 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
|
|
|
70
70
|
accessibilityLabel,
|
|
71
71
|
accessibilityHint,
|
|
72
72
|
style,
|
|
73
|
+
containerStyle,
|
|
74
|
+
labelStyle,
|
|
73
75
|
testID
|
|
74
76
|
} = props;
|
|
75
77
|
const theme = (0, _index.useTheme)();
|
|
@@ -83,6 +85,10 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
|
|
|
83
85
|
} = (0, _usePressAnimation.usePressAnimation)({
|
|
84
86
|
enabled: !disabled
|
|
85
87
|
});
|
|
88
|
+
const fabTokens = theme.components.floatingActionButton;
|
|
89
|
+
const edgeOffset = fabTokens?.edgeOffset ?? 24;
|
|
90
|
+
const defaultBottomOffset = fabTokens?.bottomOffset ?? 24;
|
|
91
|
+
const pressHaptic = fabTokens?.pressHaptic ?? false;
|
|
86
92
|
const hideAnim = (0, _react.useRef)((0, _index.createAnimatedValue)(0)).current;
|
|
87
93
|
(0, _react.useEffect)(() => {
|
|
88
94
|
if (!hideOnScroll) {
|
|
@@ -98,7 +104,7 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
|
|
|
98
104
|
}, [hideOnScroll, isScrolling, hideAnim, theme.motion.duration.normal, theme.motion.easing.standard]);
|
|
99
105
|
const hideTranslateY = hideAnim.interpolate({
|
|
100
106
|
inputRange: [0, 1],
|
|
101
|
-
outputRange: [0, sizeStyles.diameter + (bottomOffset ??
|
|
107
|
+
outputRange: [0, sizeStyles.diameter + (bottomOffset ?? defaultBottomOffset) + insets.bottom + edgeOffset]
|
|
102
108
|
});
|
|
103
109
|
const hideOpacity = hideAnim.interpolate({
|
|
104
110
|
inputRange: [0, 1],
|
|
@@ -106,27 +112,22 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
|
|
|
106
112
|
});
|
|
107
113
|
const handlePress = _event => {
|
|
108
114
|
if (disabled) return;
|
|
109
|
-
(0, _hapticUtils.triggerHaptic)('impactLight');
|
|
115
|
+
if (pressHaptic) (0, _hapticUtils.triggerHaptic)('impactLight');
|
|
110
116
|
onPress();
|
|
111
117
|
};
|
|
112
|
-
const renderedIcon =
|
|
113
|
-
name: icon.name,
|
|
114
|
-
family: icon.family ?? 'feather',
|
|
115
|
-
size: sizeStyles.iconSize,
|
|
116
|
-
color: toneForeground(theme, tone)
|
|
117
|
-
}) : icon;
|
|
118
|
+
const renderedIcon = icon;
|
|
118
119
|
const isExtended = typeof label === 'string' && label.length > 0;
|
|
119
120
|
const backgroundColor = disabled ? theme.colors.surface.disabled : toneBackground(theme, tone);
|
|
120
121
|
const foregroundColor = disabled ? theme.colors.text.disabled : toneForeground(theme, tone);
|
|
121
122
|
const positionStyle = (0, _react.useMemo)(() => {
|
|
122
123
|
if (!position) return null;
|
|
123
|
-
const bottom = (bottomOffset ??
|
|
124
|
+
const bottom = (bottomOffset ?? defaultBottomOffset) + insets.bottom;
|
|
124
125
|
switch (position) {
|
|
125
126
|
case 'bottomLeft':
|
|
126
127
|
return {
|
|
127
128
|
position: 'absolute',
|
|
128
129
|
bottom,
|
|
129
|
-
left:
|
|
130
|
+
left: edgeOffset
|
|
130
131
|
};
|
|
131
132
|
case 'bottomCenter':
|
|
132
133
|
return {
|
|
@@ -139,10 +140,10 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
|
|
|
139
140
|
return {
|
|
140
141
|
position: 'absolute',
|
|
141
142
|
bottom,
|
|
142
|
-
right:
|
|
143
|
+
right: edgeOffset
|
|
143
144
|
};
|
|
144
145
|
}
|
|
145
|
-
}, [position, bottomOffset, insets.bottom]);
|
|
146
|
+
}, [position, bottomOffset, insets.bottom, defaultBottomOffset, edgeOffset]);
|
|
146
147
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
|
|
147
148
|
style: [positionStyle, {
|
|
148
149
|
transform: [{
|
|
@@ -151,7 +152,7 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
|
|
|
151
152
|
scale
|
|
152
153
|
}],
|
|
153
154
|
opacity: hideOpacity
|
|
154
|
-
}, style],
|
|
155
|
+
}, containerStyle, style],
|
|
155
156
|
pointerEvents: hideOnScroll && isScrolling ? 'none' : 'auto',
|
|
156
157
|
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
157
158
|
ref: ref,
|
|
@@ -188,7 +189,7 @@ const FloatingActionButton = exports.FloatingActionButton = /*#__PURE__*/(0, _re
|
|
|
188
189
|
fontSize: sizeStyles.fontSize,
|
|
189
190
|
fontWeight: theme.typography.fontWeight.semibold,
|
|
190
191
|
marginLeft: theme.spacing.sm
|
|
191
|
-
}],
|
|
192
|
+
}, labelStyle],
|
|
192
193
|
numberOfLines: 1,
|
|
193
194
|
children: label
|
|
194
195
|
}) : null]
|
|
@@ -214,8 +215,6 @@ const buildStyles = _theme => _reactNative.StyleSheet.create({
|
|
|
214
215
|
// so they remain smooth during JS thread work.
|
|
215
216
|
// =====================================================================
|
|
216
217
|
|
|
217
|
-
const SECONDARY_GAP = 16;
|
|
218
|
-
const STAGGER_MS = 50;
|
|
219
218
|
const FloatingActionButtonGroup = props => {
|
|
220
219
|
const {
|
|
221
220
|
primaryIcon,
|
|
@@ -228,28 +227,54 @@ const FloatingActionButtonGroup = props => {
|
|
|
228
227
|
bottomOffset,
|
|
229
228
|
size = 'md',
|
|
230
229
|
accessibilityLabel = 'Quick actions',
|
|
230
|
+
containerStyle,
|
|
231
|
+
secondaryActionStyle,
|
|
232
|
+
labelPillStyle,
|
|
233
|
+
labelStyle,
|
|
231
234
|
testID
|
|
232
235
|
} = props;
|
|
233
236
|
const theme = (0, _index.useTheme)();
|
|
234
237
|
const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
|
|
235
238
|
const sizeStyles = sizeMap[size];
|
|
236
239
|
const styles = (0, _react.useMemo)(() => buildGroupStyles(theme), [theme]);
|
|
240
|
+
const fabTokens = theme.components.floatingActionButton;
|
|
241
|
+
const edgeOffset = fabTokens?.edgeOffset ?? 24;
|
|
242
|
+
const defaultBottomOffset = fabTokens?.bottomOffset ?? 24;
|
|
243
|
+
const secondaryGap = fabTokens?.secondaryGap ?? 16;
|
|
244
|
+
const staggerMs = fabTokens?.staggerMs ?? 50;
|
|
245
|
+
const pressHaptic = fabTokens?.pressHaptic ?? false;
|
|
237
246
|
const isControlled = typeof controlledOpen === 'boolean';
|
|
238
247
|
const [internalOpen, setInternalOpen] = (0, _react.useState)(defaultOpen);
|
|
239
248
|
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
240
249
|
|
|
241
250
|
// Animation drivers
|
|
242
251
|
const progress = (0, _react.useRef)((0, _index.createAnimatedValue)(isOpen ? 1 : 0)).current;
|
|
252
|
+
// Stable refs for per-item Animated.Values. Reconciled inside useEffect — never
|
|
253
|
+
// mutated during render — so re-renders don't recreate Animated.Value instances
|
|
254
|
+
// (previous implementation leaked one Animated.Value per re-render when the
|
|
255
|
+
// actions array length changed).
|
|
243
256
|
const itemAnims = (0, _react.useRef)([]);
|
|
244
|
-
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
257
|
+
// Bump this when the underlying refs array is re-shaped so downstream effects
|
|
258
|
+
// and mapping reads see the new length.
|
|
259
|
+
const [itemAnimsVersion, setItemAnimsVersion] = (0, _react.useState)(0);
|
|
260
|
+
(0, _react.useEffect)(() => {
|
|
261
|
+
const current = itemAnims.current;
|
|
262
|
+
if (current.length === actions.length) return;
|
|
263
|
+
if (current.length < actions.length) {
|
|
264
|
+
const next = current.slice();
|
|
265
|
+
for (let i = current.length; i < actions.length; i += 1) {
|
|
266
|
+
next.push(new _reactNative.Animated.Value(isOpen ? 1 : 0));
|
|
267
|
+
}
|
|
268
|
+
itemAnims.current = next;
|
|
269
|
+
} else {
|
|
270
|
+
// Drop stale refs when actions array shrinks.
|
|
271
|
+
itemAnims.current = current.slice(0, actions.length);
|
|
250
272
|
}
|
|
251
|
-
|
|
252
|
-
|
|
273
|
+
setItemAnimsVersion(v => v + 1);
|
|
274
|
+
// isOpen intentionally not in deps — only used to seed brand-new values; the
|
|
275
|
+
// open/close effect below will animate them to the correct target anyway.
|
|
276
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
277
|
+
}, [actions.length]);
|
|
253
278
|
(0, _react.useEffect)(() => {
|
|
254
279
|
_reactNative.Animated.timing(progress, {
|
|
255
280
|
toValue: isOpen ? 1 : 0,
|
|
@@ -265,34 +290,34 @@ const FloatingActionButtonGroup = props => {
|
|
|
265
290
|
}));
|
|
266
291
|
// Reverse stagger order on close so items closest to primary collapse last
|
|
267
292
|
const ordered = isOpen ? animations : [...animations].reverse();
|
|
268
|
-
_reactNative.Animated.stagger(
|
|
269
|
-
}, [isOpen, progress, theme.motion.duration.normal, theme.motion.easing.standard, actions.length]);
|
|
293
|
+
_reactNative.Animated.stagger(staggerMs, ordered).start();
|
|
294
|
+
}, [isOpen, progress, theme.motion.duration.normal, theme.motion.easing.standard, actions.length, itemAnimsVersion, staggerMs]);
|
|
270
295
|
const setOpen = (0, _react.useCallback)(next => {
|
|
271
|
-
(0, _hapticUtils.triggerHaptic)('impactLight');
|
|
296
|
+
if (pressHaptic) (0, _hapticUtils.triggerHaptic)('impactLight');
|
|
272
297
|
if (!isControlled) setInternalOpen(next);
|
|
273
298
|
onOpenChange?.(next);
|
|
274
|
-
}, [isControlled, onOpenChange]);
|
|
299
|
+
}, [isControlled, onOpenChange, pressHaptic]);
|
|
275
300
|
const handlePrimaryPress = (0, _react.useCallback)(() => {
|
|
276
301
|
setOpen(!isOpen);
|
|
277
302
|
}, [isOpen, setOpen]);
|
|
278
303
|
const handleActionPress = (0, _react.useCallback)(action => {
|
|
279
|
-
(0, _hapticUtils.triggerHaptic)('selection');
|
|
304
|
+
if (pressHaptic) (0, _hapticUtils.triggerHaptic)('selection');
|
|
280
305
|
action.onPress();
|
|
281
306
|
// Close after action runs
|
|
282
307
|
if (!isControlled) setInternalOpen(false);
|
|
283
308
|
onOpenChange?.(false);
|
|
284
|
-
}, [isControlled, onOpenChange]);
|
|
309
|
+
}, [isControlled, onOpenChange, pressHaptic]);
|
|
285
310
|
const handleBackdropPress = (0, _react.useCallback)(() => {
|
|
286
311
|
if (isOpen) setOpen(false);
|
|
287
312
|
}, [isOpen, setOpen]);
|
|
288
313
|
const positionStyle = (0, _react.useMemo)(() => {
|
|
289
|
-
const bottom = (bottomOffset ??
|
|
314
|
+
const bottom = (bottomOffset ?? defaultBottomOffset) + insets.bottom;
|
|
290
315
|
switch (position) {
|
|
291
316
|
case 'bottomLeft':
|
|
292
317
|
return {
|
|
293
318
|
position: 'absolute',
|
|
294
319
|
bottom,
|
|
295
|
-
left:
|
|
320
|
+
left: edgeOffset,
|
|
296
321
|
alignItems: 'flex-start'
|
|
297
322
|
};
|
|
298
323
|
case 'bottomCenter':
|
|
@@ -307,14 +332,14 @@ const FloatingActionButtonGroup = props => {
|
|
|
307
332
|
return {
|
|
308
333
|
position: 'absolute',
|
|
309
334
|
bottom,
|
|
310
|
-
right:
|
|
335
|
+
right: edgeOffset,
|
|
311
336
|
alignItems: 'flex-end'
|
|
312
337
|
};
|
|
313
338
|
}
|
|
314
|
-
}, [position, bottomOffset, insets.bottom]);
|
|
339
|
+
}, [position, bottomOffset, insets.bottom, defaultBottomOffset, edgeOffset]);
|
|
315
340
|
|
|
316
341
|
// Vertical slot offset per index: secondary at index i sits (diameter + gap) * (i + 1) above primary
|
|
317
|
-
const slotOffset = index => -((sizeStyles.diameter +
|
|
342
|
+
const slotOffset = index => -((sizeStyles.diameter + secondaryGap) * (index + 1));
|
|
318
343
|
const backdropOpacity = progress.interpolate({
|
|
319
344
|
inputRange: [0, 1],
|
|
320
345
|
outputRange: [0, 0.4]
|
|
@@ -338,7 +363,7 @@ const FloatingActionButtonGroup = props => {
|
|
|
338
363
|
testID: testID ? `${testID}-backdrop` : undefined
|
|
339
364
|
})
|
|
340
365
|
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
341
|
-
style: positionStyle,
|
|
366
|
+
style: [positionStyle, containerStyle],
|
|
342
367
|
accessibilityRole: 'menu',
|
|
343
368
|
testID: testID,
|
|
344
369
|
children: [actions.map((action, index) => {
|
|
@@ -374,13 +399,13 @@ const FloatingActionButtonGroup = props => {
|
|
|
374
399
|
paddingVertical: theme.spacing.xs,
|
|
375
400
|
borderRadius: theme.radius.sm,
|
|
376
401
|
marginRight: theme.spacing.sm
|
|
377
|
-
}],
|
|
402
|
+
}, labelPillStyle],
|
|
378
403
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
379
|
-
style: {
|
|
404
|
+
style: [{
|
|
380
405
|
color: theme.colors.text.primary,
|
|
381
406
|
fontSize: theme.typography.fontSize.sm,
|
|
382
407
|
fontWeight: theme.typography.fontWeight.medium
|
|
383
|
-
},
|
|
408
|
+
}, labelStyle],
|
|
384
409
|
numberOfLines: 1,
|
|
385
410
|
children: action.label
|
|
386
411
|
})
|
|
@@ -397,7 +422,7 @@ const FloatingActionButtonGroup = props => {
|
|
|
397
422
|
height: secondaryDiameter,
|
|
398
423
|
borderRadius: secondaryDiameter / 2,
|
|
399
424
|
backgroundColor: itemBackground
|
|
400
|
-
}],
|
|
425
|
+
}, secondaryActionStyle],
|
|
401
426
|
testID: testID ? `${testID}-action-${action.key}` : undefined,
|
|
402
427
|
children: /*#__PURE__*/_react.default.isValidElement(action.icon) ? action.icon : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
403
428
|
style: {
|
|
@@ -32,7 +32,10 @@ const ForceUpdateDialog = ({
|
|
|
32
32
|
title = 'Update available',
|
|
33
33
|
message = 'A new version of the app is available. Please update to continue using the latest features and security improvements.',
|
|
34
34
|
updateLabel = 'Update now',
|
|
35
|
-
laterLabel = 'Later'
|
|
35
|
+
laterLabel = 'Later',
|
|
36
|
+
containerStyle,
|
|
37
|
+
titleStyle,
|
|
38
|
+
messageStyle
|
|
36
39
|
}) => {
|
|
37
40
|
const [updating, setUpdating] = (0, _react.useState)(false);
|
|
38
41
|
const handleUpdate = (0, _react.useCallback)(() => {
|
|
@@ -73,7 +76,10 @@ const ForceUpdateDialog = ({
|
|
|
73
76
|
message: message,
|
|
74
77
|
variant: "info",
|
|
75
78
|
actions: actions,
|
|
76
|
-
dismissOnAction: false
|
|
79
|
+
dismissOnAction: false,
|
|
80
|
+
containerStyle: containerStyle,
|
|
81
|
+
titleStyle: titleStyle,
|
|
82
|
+
messageStyle: messageStyle
|
|
77
83
|
});
|
|
78
84
|
};
|
|
79
85
|
exports.ForceUpdateDialog = ForceUpdateDialog;
|
|
@@ -21,6 +21,7 @@ const FormField = exports.FormField = /*#__PURE__*/(0, _react.forwardRef)((props
|
|
|
21
21
|
helperStyle,
|
|
22
22
|
errorStyle,
|
|
23
23
|
containerStyle,
|
|
24
|
+
inputContainerStyle: inputContainerStyleProp,
|
|
24
25
|
accessibilityLabel,
|
|
25
26
|
testID
|
|
26
27
|
} = props;
|
|
@@ -61,12 +62,12 @@ const FormField = exports.FormField = /*#__PURE__*/(0, _react.forwardRef)((props
|
|
|
61
62
|
testID: testID,
|
|
62
63
|
children: [layout === 'inline' ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
63
64
|
children: [labelNode, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
64
|
-
style: inputContainerStyle,
|
|
65
|
+
style: [inputContainerStyle, inputContainerStyleProp],
|
|
65
66
|
children: children
|
|
66
67
|
})]
|
|
67
68
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
68
69
|
children: [labelNode, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
69
|
-
style: inputContainerStyle,
|
|
70
|
+
style: [inputContainerStyle, inputContainerStyleProp],
|
|
70
71
|
children: children
|
|
71
72
|
})]
|
|
72
73
|
}), showHelper ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
@@ -9,10 +9,9 @@ var _reactNative = require("react-native");
|
|
|
9
9
|
var _reactNativeGestureHandler = require("react-native-gesture-handler");
|
|
10
10
|
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
|
|
11
11
|
var _index = require("../Carousel/index.js");
|
|
12
|
-
var _index2 = require("../
|
|
13
|
-
var _index3 = require("
|
|
14
|
-
var _index4 = require("../../
|
|
15
|
-
var _index5 = require("../../utils/index.js");
|
|
12
|
+
var _index2 = require("../Skeleton/index.js");
|
|
13
|
+
var _index3 = require("../../theme/index.js");
|
|
14
|
+
var _index4 = require("../../utils/index.js");
|
|
16
15
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
17
16
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
18
17
|
/**
|
|
@@ -34,9 +33,11 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
34
33
|
* />
|
|
35
34
|
*/
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
36
|
+
// Local shape mirror — see types.ts ImageGalleryTokens for the canonical definition.
|
|
37
|
+
|
|
38
|
+
const MAX_SCALE_FALLBACK = 4;
|
|
39
|
+
const MIN_SCALE_FALLBACK = 1;
|
|
40
|
+
const DOUBLE_TAP_SCALE_FALLBACK = 2;
|
|
40
41
|
const SPRING_CONFIG = {
|
|
41
42
|
damping: 18,
|
|
42
43
|
stiffness: 220,
|
|
@@ -55,8 +56,10 @@ const ImageGallery = ({
|
|
|
55
56
|
containerStyle,
|
|
56
57
|
testID
|
|
57
58
|
}) => {
|
|
58
|
-
const theme = (0,
|
|
59
|
+
const theme = (0, _index3.useTheme)();
|
|
59
60
|
const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
|
|
61
|
+
const galleryTokens = theme.components.imageGallery;
|
|
62
|
+
const pressHaptic = galleryTokens?.pressHaptic ?? false;
|
|
60
63
|
const [currentIndex, setCurrentIndex] = (0, _react.useState)(clamp(initialIndex, 0, Math.max(0, images.length - 1)));
|
|
61
64
|
const [lightboxOpen, setLightboxOpen] = (0, _react.useState)(false);
|
|
62
65
|
const handleIndexChange = (0, _react.useCallback)(idx => {
|
|
@@ -65,13 +68,13 @@ const ImageGallery = ({
|
|
|
65
68
|
}, [onIndexChange]);
|
|
66
69
|
const openLightbox = (0, _react.useCallback)(() => {
|
|
67
70
|
if (!enableLightbox) return;
|
|
68
|
-
(0,
|
|
71
|
+
if (pressHaptic) (0, _index4.triggerHaptic)('selection');
|
|
69
72
|
setLightboxOpen(true);
|
|
70
|
-
}, [enableLightbox]);
|
|
73
|
+
}, [enableLightbox, pressHaptic]);
|
|
71
74
|
const closeLightbox = (0, _react.useCallback)(() => {
|
|
72
|
-
(0,
|
|
75
|
+
if (pressHaptic) (0, _index4.triggerHaptic)('selection');
|
|
73
76
|
setLightboxOpen(false);
|
|
74
|
-
}, []);
|
|
77
|
+
}, [pressHaptic]);
|
|
75
78
|
const renderImage = (0, _react.useCallback)((image, idx) => {
|
|
76
79
|
const a11y = image.alt ?? `Image ${idx + 1} of ${images.length}`;
|
|
77
80
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
@@ -124,14 +127,17 @@ const ImageGallery = ({
|
|
|
124
127
|
enablePinchZoom: enablePinchZoom,
|
|
125
128
|
showCounter: showCounter,
|
|
126
129
|
onClose: closeLightbox,
|
|
127
|
-
onIndexChange: handleIndexChange
|
|
130
|
+
onIndexChange: handleIndexChange,
|
|
131
|
+
pressHaptic: pressHaptic
|
|
128
132
|
}) : null]
|
|
129
133
|
});
|
|
130
134
|
if (loading) {
|
|
131
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(ImageGallerySkeleton, {
|
|
136
|
+
images: images,
|
|
137
|
+
showThumbnails: showThumbnails,
|
|
138
|
+
showCounter: showCounter,
|
|
139
|
+
containerStyle: containerStyle,
|
|
140
|
+
testID: testID
|
|
135
141
|
});
|
|
136
142
|
}
|
|
137
143
|
return rendered;
|
|
@@ -139,6 +145,69 @@ const ImageGallery = ({
|
|
|
139
145
|
exports.ImageGallery = ImageGallery;
|
|
140
146
|
ImageGallery.displayName = 'ImageGallery';
|
|
141
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Placeholder shape for `<ImageGallery>`. Hero image block + optional
|
|
150
|
+
* counter pill + thumbnail strip. Heights are tuned to match the live
|
|
151
|
+
* component's defaults so the gallery doesn't reflow when ready.
|
|
152
|
+
*/
|
|
153
|
+
const ImageGallerySkeleton = ({
|
|
154
|
+
images,
|
|
155
|
+
showThumbnails = true,
|
|
156
|
+
showCounter = true,
|
|
157
|
+
containerStyle,
|
|
158
|
+
testID
|
|
159
|
+
}) => {
|
|
160
|
+
const thumbCount = Math.min(images?.length || 4, 6);
|
|
161
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
162
|
+
style: [{
|
|
163
|
+
width: '100%'
|
|
164
|
+
}, containerStyle],
|
|
165
|
+
testID: testID,
|
|
166
|
+
accessibilityRole: "progressbar",
|
|
167
|
+
accessibilityState: {
|
|
168
|
+
busy: true
|
|
169
|
+
},
|
|
170
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
171
|
+
style: {
|
|
172
|
+
position: 'relative'
|
|
173
|
+
},
|
|
174
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Skeleton, {
|
|
175
|
+
width: "100%",
|
|
176
|
+
height: 280,
|
|
177
|
+
radius: "lg"
|
|
178
|
+
}), showCounter ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
179
|
+
style: {
|
|
180
|
+
position: 'absolute',
|
|
181
|
+
top: 12,
|
|
182
|
+
right: 12
|
|
183
|
+
},
|
|
184
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Skeleton, {
|
|
185
|
+
width: 44,
|
|
186
|
+
height: 22,
|
|
187
|
+
radius: "full"
|
|
188
|
+
})
|
|
189
|
+
}) : null]
|
|
190
|
+
}), showThumbnails ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
191
|
+
style: {
|
|
192
|
+
flexDirection: 'row',
|
|
193
|
+
marginTop: 12
|
|
194
|
+
},
|
|
195
|
+
children: Array.from({
|
|
196
|
+
length: thumbCount
|
|
197
|
+
}).map((_, i) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Skeleton, {
|
|
198
|
+
width: 64,
|
|
199
|
+
height: 64,
|
|
200
|
+
radius: "md",
|
|
201
|
+
style: {
|
|
202
|
+
marginRight: 8
|
|
203
|
+
}
|
|
204
|
+
}, `sk-thumb-${i}`))
|
|
205
|
+
}) : null]
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
ImageGallerySkeleton.displayName = 'ImageGallerySkeleton';
|
|
209
|
+
ImageGallery.Skeleton = ImageGallerySkeleton;
|
|
210
|
+
|
|
142
211
|
// ───────── Lightbox ─────────
|
|
143
212
|
|
|
144
213
|
const Lightbox = ({
|
|
@@ -148,26 +217,35 @@ const Lightbox = ({
|
|
|
148
217
|
enablePinchZoom,
|
|
149
218
|
showCounter,
|
|
150
219
|
onClose,
|
|
151
|
-
onIndexChange
|
|
220
|
+
onIndexChange,
|
|
221
|
+
pressHaptic
|
|
152
222
|
}) => {
|
|
153
|
-
const theme = (0,
|
|
223
|
+
const theme = (0, _index3.useTheme)();
|
|
154
224
|
const styles = (0, _react.useMemo)(() => buildLightboxStyles(theme), [theme]);
|
|
225
|
+
const galleryTokens = theme.components.imageGallery;
|
|
226
|
+
const maxScale = galleryTokens?.maxScale ?? MAX_SCALE_FALLBACK;
|
|
227
|
+
const minScale = galleryTokens?.minScale ?? MIN_SCALE_FALLBACK;
|
|
228
|
+
const doubleTapScale = galleryTokens?.doubleTapScale ?? DOUBLE_TAP_SCALE_FALLBACK;
|
|
155
229
|
const carouselRef = (0, _react.useRef)(null);
|
|
156
230
|
const [activeIndex, setActiveIndex] = (0, _react.useState)(initialIndex);
|
|
157
231
|
const handleSwipe = (0, _react.useCallback)(idx => {
|
|
158
232
|
if (idx !== activeIndex) {
|
|
159
|
-
(0,
|
|
233
|
+
if (pressHaptic) (0, _index4.triggerHaptic)('selection');
|
|
160
234
|
setActiveIndex(idx);
|
|
161
235
|
onIndexChange(idx);
|
|
162
236
|
}
|
|
163
|
-
}, [activeIndex, onIndexChange]);
|
|
237
|
+
}, [activeIndex, onIndexChange, pressHaptic]);
|
|
164
238
|
const renderItem = (0, _react.useCallback)((image, idx) => /*#__PURE__*/(0, _jsxRuntime.jsx)(ZoomableImage, {
|
|
165
239
|
image: image,
|
|
166
240
|
index: idx,
|
|
167
241
|
total: images.length,
|
|
168
242
|
active: idx === activeIndex,
|
|
169
|
-
enabled: enablePinchZoom
|
|
170
|
-
|
|
243
|
+
enabled: enablePinchZoom,
|
|
244
|
+
maxScale: maxScale,
|
|
245
|
+
minScale: minScale,
|
|
246
|
+
doubleTapScale: doubleTapScale,
|
|
247
|
+
pressHaptic: pressHaptic
|
|
248
|
+
}), [activeIndex, enablePinchZoom, images.length, maxScale, minScale, doubleTapScale, pressHaptic]);
|
|
171
249
|
const caption = images[activeIndex]?.caption;
|
|
172
250
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
|
|
173
251
|
visible: visible,
|
|
@@ -203,11 +281,15 @@ const Lightbox = ({
|
|
|
203
281
|
accessibilityLabel: "Close gallery",
|
|
204
282
|
style: styles.closeButton,
|
|
205
283
|
hitSlop: 12,
|
|
206
|
-
children:
|
|
207
|
-
|
|
208
|
-
family: "feather",
|
|
209
|
-
size: "lg",
|
|
284
|
+
children: theme.icons?.close ? theme.icons.close({
|
|
285
|
+
size: 24,
|
|
210
286
|
color: theme.colors.text.inverse
|
|
287
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
288
|
+
style: {
|
|
289
|
+
fontSize: 24,
|
|
290
|
+
color: theme.colors.text.inverse
|
|
291
|
+
},
|
|
292
|
+
children: "\xD7"
|
|
211
293
|
})
|
|
212
294
|
}), caption ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
|
|
213
295
|
style: styles.captionWrap,
|
|
@@ -230,7 +312,11 @@ const ZoomableImage = ({
|
|
|
230
312
|
index,
|
|
231
313
|
total,
|
|
232
314
|
active,
|
|
233
|
-
enabled
|
|
315
|
+
enabled,
|
|
316
|
+
maxScale,
|
|
317
|
+
minScale,
|
|
318
|
+
doubleTapScale,
|
|
319
|
+
pressHaptic
|
|
234
320
|
}) => {
|
|
235
321
|
const screen = _reactNative.Dimensions.get('window');
|
|
236
322
|
const scale = (0, _reactNativeReanimated.useSharedValue)(1);
|
|
@@ -265,7 +351,9 @@ const ZoomableImage = ({
|
|
|
265
351
|
savedTranslateY.value = 0;
|
|
266
352
|
}
|
|
267
353
|
}, [active, scale, translateX, translateY, savedScale, savedTranslateX, savedTranslateY]);
|
|
268
|
-
const triggerImpact = (0, _react.useCallback)(() =>
|
|
354
|
+
const triggerImpact = (0, _react.useCallback)(() => {
|
|
355
|
+
if (pressHaptic) (0, _index4.triggerHaptic)('impactLight');
|
|
356
|
+
}, [pressHaptic]);
|
|
269
357
|
const pinch = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pinch().enabled(enabled).onStart(() => {
|
|
270
358
|
'worklet';
|
|
271
359
|
|
|
@@ -274,33 +362,33 @@ const ZoomableImage = ({
|
|
|
274
362
|
'worklet';
|
|
275
363
|
|
|
276
364
|
const next = savedScale.value * e.scale;
|
|
277
|
-
// Clamp
|
|
278
|
-
if (next <
|
|
279
|
-
scale.value =
|
|
280
|
-
} else if (next >
|
|
281
|
-
scale.value =
|
|
365
|
+
// Clamp minScale..maxScale on the UI thread so pinch feels rubbery at limits.
|
|
366
|
+
if (next < minScale) {
|
|
367
|
+
scale.value = minScale + (next - minScale) * 0.3;
|
|
368
|
+
} else if (next > maxScale) {
|
|
369
|
+
scale.value = maxScale + (next - maxScale) * 0.2;
|
|
282
370
|
} else {
|
|
283
371
|
scale.value = next;
|
|
284
372
|
}
|
|
285
373
|
}).onEnd(() => {
|
|
286
374
|
'worklet';
|
|
287
375
|
|
|
288
|
-
if (scale.value <
|
|
289
|
-
scale.value = (0, _reactNativeReanimated.withSpring)(
|
|
376
|
+
if (scale.value < minScale) {
|
|
377
|
+
scale.value = (0, _reactNativeReanimated.withSpring)(minScale, SPRING_CONFIG);
|
|
290
378
|
translateX.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
|
|
291
379
|
translateY.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
|
|
292
|
-
savedScale.value =
|
|
380
|
+
savedScale.value = minScale;
|
|
293
381
|
savedTranslateX.value = 0;
|
|
294
382
|
savedTranslateY.value = 0;
|
|
295
383
|
return;
|
|
296
384
|
}
|
|
297
|
-
if (scale.value >
|
|
298
|
-
scale.value = (0, _reactNativeReanimated.withSpring)(
|
|
299
|
-
savedScale.value =
|
|
385
|
+
if (scale.value > maxScale) {
|
|
386
|
+
scale.value = (0, _reactNativeReanimated.withSpring)(maxScale, SPRING_CONFIG);
|
|
387
|
+
savedScale.value = maxScale;
|
|
300
388
|
return;
|
|
301
389
|
}
|
|
302
390
|
savedScale.value = scale.value;
|
|
303
|
-
}), [enabled, scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY]);
|
|
391
|
+
}), [enabled, scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY, minScale, maxScale]);
|
|
304
392
|
|
|
305
393
|
// Pan only engages when zoomed in — otherwise the parent Carousel owns horizontal swipe.
|
|
306
394
|
const pan = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pan().minPointers(1).maxPointers(1).onStart(() => {
|
|
@@ -332,10 +420,10 @@ const ZoomableImage = ({
|
|
|
332
420
|
savedTranslateX.value = 0;
|
|
333
421
|
savedTranslateY.value = 0;
|
|
334
422
|
} else {
|
|
335
|
-
scale.value = (0, _reactNativeReanimated.withSpring)(
|
|
336
|
-
savedScale.value =
|
|
423
|
+
scale.value = (0, _reactNativeReanimated.withSpring)(doubleTapScale, SPRING_CONFIG);
|
|
424
|
+
savedScale.value = doubleTapScale;
|
|
337
425
|
}
|
|
338
|
-
}), [scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY, triggerImpact]);
|
|
426
|
+
}), [scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY, triggerImpact, doubleTapScale]);
|
|
339
427
|
|
|
340
428
|
// Race the gestures so they coordinate cleanly: a tap won't be misread as a tiny pan,
|
|
341
429
|
// and pan won't fire when the user actually starts a pinch.
|