@webority-technologies/mobile 0.0.24 → 0.0.25

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.
Files changed (53) hide show
  1. package/lib/commonjs/components/Autocomplete/Autocomplete.js +204 -0
  2. package/lib/commonjs/components/Autocomplete/index.js +13 -0
  3. package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +1 -1
  4. package/lib/commonjs/components/Confetti/Confetti.js +170 -0
  5. package/lib/commonjs/components/Confetti/index.js +13 -0
  6. package/lib/commonjs/components/FieldBase/FieldBase.js +0 -2
  7. package/lib/commonjs/components/IconButton/IconButton.js +176 -0
  8. package/lib/commonjs/components/IconButton/index.js +13 -0
  9. package/lib/commonjs/components/Modal/Modal.js +0 -1
  10. package/lib/commonjs/components/ProgressBar/ProgressBar.js +32 -4
  11. package/lib/commonjs/components/SlideToConfirm/SlideToConfirm.js +224 -0
  12. package/lib/commonjs/components/SlideToConfirm/index.js +13 -0
  13. package/lib/commonjs/components/index.js +142 -114
  14. package/lib/commonjs/hooks/usePressAnimation.js +0 -1
  15. package/lib/module/components/Autocomplete/Autocomplete.js +199 -0
  16. package/lib/module/components/Autocomplete/index.js +4 -0
  17. package/lib/module/components/BottomNavigation/BottomNavigation.js +1 -1
  18. package/lib/module/components/Confetti/Confetti.js +166 -0
  19. package/lib/module/components/Confetti/index.js +4 -0
  20. package/lib/module/components/FieldBase/FieldBase.js +0 -2
  21. package/lib/module/components/IconButton/IconButton.js +172 -0
  22. package/lib/module/components/IconButton/index.js +4 -0
  23. package/lib/module/components/Modal/Modal.js +0 -1
  24. package/lib/module/components/ProgressBar/ProgressBar.js +33 -5
  25. package/lib/module/components/SlideToConfirm/SlideToConfirm.js +220 -0
  26. package/lib/module/components/SlideToConfirm/index.js +4 -0
  27. package/lib/module/components/index.js +4 -0
  28. package/lib/module/hooks/usePressAnimation.js +0 -1
  29. package/lib/typescript/commonjs/components/Autocomplete/Autocomplete.d.ts +53 -0
  30. package/lib/typescript/commonjs/components/Autocomplete/index.d.ts +3 -0
  31. package/lib/typescript/commonjs/components/Confetti/Confetti.d.ts +41 -0
  32. package/lib/typescript/commonjs/components/Confetti/index.d.ts +3 -0
  33. package/lib/typescript/commonjs/components/IconButton/IconButton.d.ts +34 -0
  34. package/lib/typescript/commonjs/components/IconButton/index.d.ts +3 -0
  35. package/lib/typescript/commonjs/components/ProgressBar/ProgressBar.d.ts +12 -0
  36. package/lib/typescript/commonjs/components/ProgressBar/index.d.ts +1 -1
  37. package/lib/typescript/commonjs/components/SlideToConfirm/SlideToConfirm.d.ts +34 -0
  38. package/lib/typescript/commonjs/components/SlideToConfirm/index.d.ts +3 -0
  39. package/lib/typescript/commonjs/components/index.d.ts +9 -1
  40. package/lib/typescript/commonjs/hooks/usePressAnimation.d.ts +1 -2
  41. package/lib/typescript/module/components/Autocomplete/Autocomplete.d.ts +53 -0
  42. package/lib/typescript/module/components/Autocomplete/index.d.ts +3 -0
  43. package/lib/typescript/module/components/Confetti/Confetti.d.ts +41 -0
  44. package/lib/typescript/module/components/Confetti/index.d.ts +3 -0
  45. package/lib/typescript/module/components/IconButton/IconButton.d.ts +34 -0
  46. package/lib/typescript/module/components/IconButton/index.d.ts +3 -0
  47. package/lib/typescript/module/components/ProgressBar/ProgressBar.d.ts +12 -0
  48. package/lib/typescript/module/components/ProgressBar/index.d.ts +1 -1
  49. package/lib/typescript/module/components/SlideToConfirm/SlideToConfirm.d.ts +34 -0
  50. package/lib/typescript/module/components/SlideToConfirm/index.d.ts +3 -0
  51. package/lib/typescript/module/components/index.d.ts +9 -1
  52. package/lib/typescript/module/hooks/usePressAnimation.d.ts +1 -2
  53. package/package.json +1 -1
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
4
+ import { Keyboard, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
5
+ import { useTheme } from "../../theme/index.js";
6
+ import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
7
+ import { useControllableState } from "../../hooks/index.js";
8
+ import { Input } from "../Input/index.js";
9
+ import { Spinner } from "../Spinner/index.js";
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const defaultGetLabel = o => typeof o === 'string' ? o : String(o);
12
+ function Autocomplete(props) {
13
+ const {
14
+ options,
15
+ value,
16
+ defaultValue,
17
+ onChangeText,
18
+ onSelect,
19
+ getOptionLabel,
20
+ getOptionKey,
21
+ filter,
22
+ minChars = 1,
23
+ maxResults = 8,
24
+ emptyText = 'No matches',
25
+ loading = false,
26
+ filterMode = 'client',
27
+ loadingText = 'Searching…',
28
+ placeholder,
29
+ label,
30
+ error,
31
+ helperText,
32
+ disabled = false,
33
+ size = 'md',
34
+ variant,
35
+ haptic,
36
+ style,
37
+ listStyle,
38
+ optionTextStyle,
39
+ testID
40
+ } = props;
41
+ const theme = useTheme();
42
+ const styles = useMemo(() => buildStyles(theme), [theme]);
43
+ const [text, setText] = useControllableState({
44
+ value,
45
+ defaultValue: defaultValue ?? '',
46
+ onChange: onChangeText
47
+ });
48
+ const [focused, setFocused] = useState(false);
49
+ const [fieldHeight, setFieldHeight] = useState(0);
50
+ const blurTimer = useRef(null);
51
+ const labelOf = useCallback(o => getOptionLabel ? getOptionLabel(o) : defaultGetLabel(o), [getOptionLabel]);
52
+ const filtered = useMemo(() => {
53
+ // Server-side search: trust the provided options, don't re-filter them away.
54
+ if (filterMode === 'none') return options.slice(0, maxResults);
55
+ const q = text.trim();
56
+ if (q.length < minChars) return [];
57
+ const lower = q.toLowerCase();
58
+ const match = filter ? o => filter(o, q) : o => labelOf(o).toLowerCase().includes(lower);
59
+ return options.filter(match).slice(0, maxResults);
60
+ }, [options, text, minChars, maxResults, filter, labelOf, filterMode]);
61
+ const showList = focused && (loading || text.trim().length >= minChars);
62
+ const handleSelect = useCallback(o => {
63
+ const h = resolveHaptic(haptic, 'selection');
64
+ if (h) triggerHaptic(h);
65
+ if (blurTimer.current) clearTimeout(blurTimer.current);
66
+ setText(labelOf(o));
67
+ setFocused(false);
68
+ Keyboard.dismiss();
69
+ onSelect(o);
70
+ }, [haptic, setText, labelOf, onSelect]);
71
+ React.useEffect(() => () => {
72
+ if (blurTimer.current) clearTimeout(blurTimer.current);
73
+ }, []);
74
+ const onFieldLayout = useCallback(e => {
75
+ setFieldHeight(e.nativeEvent.layout.height);
76
+ }, []);
77
+ return /*#__PURE__*/_jsxs(View, {
78
+ style: [styles.container, style],
79
+ testID: testID,
80
+ children: [/*#__PURE__*/_jsx(View, {
81
+ onLayout: onFieldLayout,
82
+ children: /*#__PURE__*/_jsx(Input, {
83
+ value: text,
84
+ onChangeText: setText,
85
+ onFocus: () => {
86
+ if (blurTimer.current) clearTimeout(blurTimer.current);
87
+ setFocused(true);
88
+ },
89
+ onBlur: () => {
90
+ blurTimer.current = setTimeout(() => setFocused(false), 120);
91
+ },
92
+ placeholder: placeholder,
93
+ label: label,
94
+ error: error,
95
+ helperText: helperText,
96
+ editable: !disabled,
97
+ size: size,
98
+ variant: variant,
99
+ autoCorrect: false,
100
+ autoCapitalize: "none"
101
+ })
102
+ }), showList ? /*#__PURE__*/_jsx(View, {
103
+ style: [styles.list, {
104
+ top: fieldHeight,
105
+ backgroundColor: theme.colors.background.elevated,
106
+ borderColor: theme.colors.border.primary,
107
+ borderRadius: theme.radius.md,
108
+ ...theme.shadows.lg
109
+ }, listStyle],
110
+ children: loading ? /*#__PURE__*/_jsxs(View, {
111
+ style: styles.loadingRow,
112
+ children: [/*#__PURE__*/_jsx(Spinner, {
113
+ size: "sm"
114
+ }), /*#__PURE__*/_jsx(Text, {
115
+ style: [styles.loadingText, {
116
+ color: theme.colors.text.secondary,
117
+ fontSize: theme.typography.fontSize.sm
118
+ }],
119
+ children: loadingText
120
+ })]
121
+ }) : filtered.length === 0 ? /*#__PURE__*/_jsx(Text, {
122
+ style: [styles.empty, {
123
+ color: theme.colors.text.tertiary,
124
+ fontSize: theme.typography.fontSize.sm
125
+ }],
126
+ children: emptyText
127
+ }) : /*#__PURE__*/_jsx(ScrollView, {
128
+ keyboardShouldPersistTaps: "handled",
129
+ style: styles.scroll,
130
+ children: filtered.map((o, i) => /*#__PURE__*/_jsx(Pressable, {
131
+ onPress: () => handleSelect(o),
132
+ android_ripple: {
133
+ color: theme.colors.surface.pressed
134
+ },
135
+ style: ({
136
+ pressed
137
+ }) => [styles.option, {
138
+ paddingHorizontal: theme.spacing.md,
139
+ paddingVertical: theme.spacing.sm,
140
+ backgroundColor: pressed ? theme.colors.surface.pressed : 'transparent'
141
+ }],
142
+ accessibilityRole: "button",
143
+ accessibilityLabel: labelOf(o),
144
+ children: /*#__PURE__*/_jsx(Text, {
145
+ style: [styles.optionText, {
146
+ color: theme.colors.text.primary,
147
+ fontSize: theme.typography.fontSize.base
148
+ }, optionTextStyle],
149
+ numberOfLines: 1,
150
+ children: labelOf(o)
151
+ })
152
+ }, getOptionKey ? getOptionKey(o) : `${labelOf(o)}-${i}`))
153
+ })
154
+ }) : null]
155
+ });
156
+ }
157
+ Autocomplete.displayName = 'Autocomplete';
158
+ const buildStyles = theme => StyleSheet.create({
159
+ container: {
160
+ width: '100%',
161
+ position: 'relative',
162
+ zIndex: 10
163
+ },
164
+ list: {
165
+ position: 'absolute',
166
+ left: 0,
167
+ right: 0,
168
+ borderWidth: StyleSheet.hairlineWidth,
169
+ overflow: 'hidden',
170
+ zIndex: 20,
171
+ maxHeight: 240
172
+ },
173
+ scroll: {
174
+ maxHeight: 240
175
+ },
176
+ option: {
177
+ width: '100%'
178
+ },
179
+ optionText: {
180
+ includeFontPadding: false
181
+ },
182
+ empty: {
183
+ padding: theme.spacing.md,
184
+ textAlign: 'center',
185
+ includeFontPadding: false
186
+ },
187
+ loadingRow: {
188
+ flexDirection: 'row',
189
+ alignItems: 'center',
190
+ gap: theme.spacing.sm,
191
+ padding: theme.spacing.md
192
+ },
193
+ loadingText: {
194
+ includeFontPadding: false
195
+ }
196
+ });
197
+ export { Autocomplete };
198
+ export default Autocomplete;
199
+ //# sourceMappingURL=Autocomplete.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { Autocomplete } from "./Autocomplete.js";
4
+ //# sourceMappingURL=index.js.map
@@ -154,7 +154,7 @@ const BottomNavigation = /*#__PURE__*/forwardRef((props, ref) => {
154
154
  translateX: indicatorTranslateX
155
155
  }]
156
156
  }, indicatorStyle]
157
- }) : null, tabs.map((tab, index) => {
157
+ }) : null, tabs.map(tab => {
158
158
  const isActive = tab.key === activeTab;
159
159
  const color = isActive ? theme.colors.primary : theme.colors.text.tertiary;
160
160
  const renderIcon = isActive && tab.activeIcon ? tab.activeIcon : tab.icon;
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+
3
+ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react';
4
+ import { StyleSheet, View, useWindowDimensions } from 'react-native';
5
+ import Animated, { Easing, cancelAnimation, runOnJS, useAnimatedStyle, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated';
6
+ import { useTheme } from "../../theme/index.js";
7
+ import { useReducedMotion } from "../../hooks/index.js";
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const TAU = Math.PI * 2;
10
+ const rand = (min, max) => min + Math.random() * (max - min);
11
+ const buildPieces = (count, colors, mode, baseSize) => Array.from({
12
+ length: count
13
+ }, (_, i) => {
14
+ const isCannon = mode === 'cannon';
15
+ return {
16
+ color: colors[i % colors.length] ?? colors[0],
17
+ size: baseSize * rand(0.6, 1.4),
18
+ isCircle: Math.random() < 0.35,
19
+ baseXFrac: isCannon ? 0.5 : Math.random(),
20
+ vxFrac: isCannon ? rand(-0.7, 0.7) : rand(-0.15, 0.15),
21
+ vy0Frac: isCannon ? rand(-1.5, -1.0) : rand(0, 0.15),
22
+ rotations: rand(1, 5),
23
+ rotateDir: Math.random() < 0.5 ? 1 : -1,
24
+ swayAmp: rand(8, 28),
25
+ swayFreq: rand(1, 3),
26
+ flutterFreq: rand(2, 5)
27
+ };
28
+ });
29
+ const ConfettiPiece = ({
30
+ piece,
31
+ progress,
32
+ width,
33
+ height,
34
+ originX,
35
+ originY,
36
+ mode,
37
+ fadeOut
38
+ }) => {
39
+ const animStyle = useAnimatedStyle(() => {
40
+ const t = progress.value;
41
+ const startX = mode === 'cannon' ? originX : piece.baseXFrac * width;
42
+ const startY = mode === 'cannon' ? originY : -piece.size * 2;
43
+ const gravity = height * (mode === 'cannon' ? 1.8 : 1.5);
44
+ const x = startX + piece.vxFrac * width * t + Math.sin(t * piece.swayFreq * TAU) * piece.swayAmp;
45
+ const y = startY + piece.vy0Frac * height * t + gravity * t * t;
46
+ const rotate = piece.rotateDir * piece.rotations * 360 * t;
47
+ // Paper-flutter: oscillate scaleX so pieces read as thin spinning paper.
48
+ const flutter = 0.35 + 0.65 * Math.abs(Math.cos(t * piece.flutterFreq * TAU));
49
+ const opacity = fadeOut ? Math.max(0, 1 - Math.max(0, t - 0.8) / 0.2) : 1;
50
+ return {
51
+ opacity,
52
+ transform: [{
53
+ translateX: x
54
+ }, {
55
+ translateY: y
56
+ }, {
57
+ rotate: `${rotate}deg`
58
+ }, {
59
+ scaleX: flutter
60
+ }]
61
+ };
62
+ });
63
+ return /*#__PURE__*/_jsx(Animated.View, {
64
+ style: [{
65
+ position: 'absolute',
66
+ width: piece.size,
67
+ height: piece.isCircle ? piece.size : piece.size * 0.5,
68
+ borderRadius: piece.isCircle ? piece.size / 2 : 1,
69
+ backgroundColor: piece.color
70
+ }, animStyle]
71
+ });
72
+ };
73
+ const Confetti = /*#__PURE__*/forwardRef(({
74
+ count = 80,
75
+ colors,
76
+ mode = 'rain',
77
+ origin,
78
+ duration = 2800,
79
+ fadeOut = true,
80
+ autoStart = false,
81
+ recycle = false,
82
+ size = 10,
83
+ onComplete,
84
+ style,
85
+ testID
86
+ }, ref) => {
87
+ const theme = useTheme();
88
+ const reduceMotion = useReducedMotion();
89
+ const window = useWindowDimensions();
90
+ const [layout, setLayout] = useState({
91
+ width: window.width,
92
+ height: window.height
93
+ });
94
+ const [active, setActive] = useState(false);
95
+ const [pieces, setPieces] = useState([]);
96
+ const palette = useMemo(() => colors ?? [theme.colors.primary, theme.colors.secondary, theme.colors.success, theme.colors.warning, theme.colors.error, theme.colors.info], [colors, theme.colors]);
97
+ const progress = useSharedValue(0);
98
+ const finish = useCallback(() => {
99
+ setActive(false);
100
+ onComplete?.();
101
+ }, [onComplete]);
102
+ const start = useCallback(() => {
103
+ if (reduceMotion) {
104
+ onComplete?.();
105
+ return;
106
+ }
107
+ cancelAnimation(progress);
108
+ progress.value = 0;
109
+ setPieces(buildPieces(count, palette, mode, size));
110
+ setActive(true);
111
+ const tween = withTiming(1, {
112
+ duration,
113
+ easing: Easing.linear
114
+ }, finished => {
115
+ 'worklet';
116
+
117
+ if (finished && !recycle) runOnJS(finish)();
118
+ });
119
+ progress.value = recycle ? withRepeat(tween, -1, false) : tween;
120
+ }, [reduceMotion, progress, duration, recycle, finish, onComplete, count, palette, mode, size]);
121
+ const stop = useCallback(() => {
122
+ cancelAnimation(progress);
123
+ setActive(false);
124
+ }, [progress]);
125
+ useImperativeHandle(ref, () => ({
126
+ start,
127
+ stop
128
+ }), [start, stop]);
129
+ useEffect(() => {
130
+ if (autoStart) start();
131
+ return () => cancelAnimation(progress);
132
+ // eslint-disable-next-line react-hooks/exhaustive-deps
133
+ }, []);
134
+ const onLayout = useCallback(e => {
135
+ const {
136
+ width,
137
+ height
138
+ } = e.nativeEvent.layout;
139
+ if (width > 0 && height > 0) setLayout({
140
+ width,
141
+ height
142
+ });
143
+ }, []);
144
+ const originX = origin?.x ?? layout.width / 2;
145
+ const originY = origin?.y ?? layout.height;
146
+ return /*#__PURE__*/_jsx(View, {
147
+ style: [StyleSheet.absoluteFill, style],
148
+ pointerEvents: "none",
149
+ onLayout: onLayout,
150
+ testID: testID,
151
+ children: active ? pieces.map((piece, i) => /*#__PURE__*/_jsx(ConfettiPiece, {
152
+ piece: piece,
153
+ progress: progress,
154
+ width: layout.width,
155
+ height: layout.height,
156
+ originX: originX,
157
+ originY: originY,
158
+ mode: mode,
159
+ fadeOut: fadeOut
160
+ }, i)) : null
161
+ });
162
+ });
163
+ Confetti.displayName = 'Confetti';
164
+ export { Confetti };
165
+ export default Confetti;
166
+ //# sourceMappingURL=Confetti.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { Confetti } from "./Confetti.js";
4
+ //# sourceMappingURL=index.js.map
@@ -28,8 +28,6 @@ import React, { useEffect, useMemo, useRef } from 'react';
28
28
  import { Animated, Easing, Pressable, StyleSheet, View } from 'react-native';
29
29
  import { useTheme, createAnimatedValue, fontFor } from "../../theme/index.js";
30
30
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
31
- const SIDES = ['top', 'right', 'bottom', 'left'];
32
-
33
31
  /** Map a single colour string to all four sides (shorthand expansion). */
34
32
  const expandColorSides = value => {
35
33
  if (typeof value === 'string') {
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+
3
+ import React, { forwardRef } from 'react';
4
+ import { Animated, Pressable, StyleSheet } from 'react-native';
5
+ import { useTheme } from "../../theme/index.js";
6
+ import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
+ import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
8
+ import { Spinner } from "../Spinner/index.js";
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ const SIZE_MAP = {
11
+ sm: {
12
+ diameter: 32,
13
+ icon: 16
14
+ },
15
+ md: {
16
+ diameter: 40,
17
+ icon: 20
18
+ },
19
+ lg: {
20
+ diameter: 48,
21
+ icon: 24
22
+ }
23
+ };
24
+ const toneFor = (theme, tone) => {
25
+ switch (tone) {
26
+ case 'secondary':
27
+ return {
28
+ base: theme.colors.secondary,
29
+ on: theme.colors.onSecondary,
30
+ fg: theme.colors.secondary
31
+ };
32
+ case 'success':
33
+ return {
34
+ base: theme.colors.success,
35
+ on: theme.colors.onSuccess,
36
+ fg: theme.colors.success
37
+ };
38
+ case 'warning':
39
+ return {
40
+ base: theme.colors.warning,
41
+ on: theme.colors.onWarning,
42
+ fg: theme.colors.warning
43
+ };
44
+ case 'error':
45
+ return {
46
+ base: theme.colors.error,
47
+ on: theme.colors.onError,
48
+ fg: theme.colors.error
49
+ };
50
+ case 'neutral':
51
+ return {
52
+ base: theme.colors.background.tertiary,
53
+ on: theme.colors.text.primary,
54
+ fg: theme.colors.text.primary
55
+ };
56
+ case 'primary':
57
+ default:
58
+ return {
59
+ base: theme.colors.primary,
60
+ on: theme.colors.onPrimary,
61
+ fg: theme.colors.primary
62
+ };
63
+ }
64
+ };
65
+ const IconButton = /*#__PURE__*/forwardRef((props, ref) => {
66
+ const {
67
+ icon,
68
+ onPress,
69
+ accessibilityLabel,
70
+ tone = 'primary',
71
+ variant = 'solid',
72
+ size = 'md',
73
+ shape = 'circle',
74
+ active = false,
75
+ disabled = false,
76
+ loading = false,
77
+ haptic,
78
+ style,
79
+ testID
80
+ } = props;
81
+ const theme = useTheme();
82
+ const sizeCfg = SIZE_MAP[size];
83
+ const isDisabled = disabled || loading;
84
+ const {
85
+ scale,
86
+ pressIn,
87
+ pressOut
88
+ } = usePressAnimation({
89
+ scaleTo: 0.92,
90
+ enabled: !isDisabled
91
+ });
92
+ const {
93
+ base,
94
+ on,
95
+ fg
96
+ } = toneFor(theme, tone);
97
+ const effectiveVariant = active ? 'solid' : variant;
98
+ let backgroundColor = 'transparent';
99
+ let borderColor = 'transparent';
100
+ let borderWidth = 0;
101
+ let iconColor = isDisabled ? theme.colors.text.disabled : fg;
102
+ if (effectiveVariant === 'solid') {
103
+ backgroundColor = isDisabled ? theme.colors.surface.disabled : base;
104
+ iconColor = isDisabled ? theme.colors.text.disabled : on;
105
+ } else if (effectiveVariant === 'soft') {
106
+ backgroundColor = isDisabled ? theme.colors.surface.disabled : `${base}22`;
107
+ } else if (effectiveVariant === 'outline') {
108
+ borderColor = isDisabled ? theme.colors.border.primary : base;
109
+ borderWidth = theme.colors.border.width;
110
+ }
111
+ const radius = shape === 'circle' ? sizeCfg.diameter / 2 : theme.radius.md;
112
+ const handlePress = e => {
113
+ if (isDisabled) return;
114
+ const h = resolveHaptic(haptic, 'selection');
115
+ if (h) triggerHaptic(h);
116
+ onPress?.(e);
117
+ };
118
+ return /*#__PURE__*/_jsx(Pressable, {
119
+ ref: ref,
120
+ onPress: handlePress,
121
+ onPressIn: pressIn,
122
+ onPressOut: pressOut,
123
+ disabled: isDisabled,
124
+ accessibilityRole: "button",
125
+ accessibilityLabel: accessibilityLabel,
126
+ accessibilityState: {
127
+ disabled: isDisabled,
128
+ selected: active
129
+ },
130
+ hitSlop: 6,
131
+ testID: testID,
132
+ style: ({
133
+ pressed
134
+ }) => [styles.base, {
135
+ width: sizeCfg.diameter,
136
+ height: sizeCfg.diameter,
137
+ borderRadius: radius,
138
+ backgroundColor,
139
+ borderColor,
140
+ borderWidth,
141
+ opacity: pressed && effectiveVariant !== 'solid' ? 0.7 : 1
142
+ }, style],
143
+ children: /*#__PURE__*/_jsx(Animated.View, {
144
+ style: [styles.content, {
145
+ transform: [{
146
+ scale
147
+ }]
148
+ }],
149
+ children: loading ? /*#__PURE__*/_jsx(Spinner, {
150
+ size: "sm",
151
+ color: iconColor
152
+ }) : typeof icon === 'function' ? icon({
153
+ color: iconColor,
154
+ size: sizeCfg.icon
155
+ }) : icon
156
+ })
157
+ });
158
+ });
159
+ IconButton.displayName = 'IconButton';
160
+ const styles = StyleSheet.create({
161
+ base: {
162
+ alignItems: 'center',
163
+ justifyContent: 'center'
164
+ },
165
+ content: {
166
+ alignItems: 'center',
167
+ justifyContent: 'center'
168
+ }
169
+ });
170
+ export { IconButton };
171
+ export default IconButton;
172
+ //# sourceMappingURL=IconButton.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { IconButton } from "./IconButton.js";
4
+ //# sourceMappingURL=index.js.map
@@ -13,7 +13,6 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
13
13
  visible,
14
14
  onRequestClose,
15
15
  presentation = 'centered',
16
- backdropOpacity = 0.5,
17
16
  backdropPressClose = true,
18
17
  animationDuration,
19
18
  accessibilityLabel,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, Easing, StyleSheet, View } from 'react-native';
5
- import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
5
+ import { useTheme, createAnimatedValue, setNativeValue, Gradient } from "../../theme/index.js";
6
6
  import { jsx as _jsx } from "react/jsx-runtime";
7
7
  const toneColor = (theme, tone) => {
8
8
  switch (tone) {
@@ -33,6 +33,8 @@ const ProgressBar = /*#__PURE__*/forwardRef((props, ref) => {
33
33
  tone = 'primary',
34
34
  trackColor,
35
35
  barColor,
36
+ gradient,
37
+ segments,
36
38
  animated = true,
37
39
  style,
38
40
  containerStyle,
@@ -53,6 +55,12 @@ const ProgressBar = /*#__PURE__*/forwardRef((props, ref) => {
53
55
  const resolvedRadius = radius ?? theme.radius.full;
54
56
  const resolvedTrack = trackColor ?? theme.colors.surface.disabled;
55
57
  const resolvedBar = barColor ?? toneColor(theme, tone);
58
+ const resolvedGradient = useMemo(() => {
59
+ if (!gradient) return null;
60
+ if (typeof gradient === 'string') return theme.gradients[gradient] ?? null;
61
+ return gradient;
62
+ }, [gradient, theme.gradients]);
63
+ const hasSegments = Array.isArray(segments) && segments.length > 0;
56
64
  useEffect(() => {
57
65
  if (isIndeterminate) return;
58
66
  if (!animated) {
@@ -111,7 +119,18 @@ const ProgressBar = /*#__PURE__*/forwardRef((props, ref) => {
111
119
  borderRadius: resolvedRadius,
112
120
  backgroundColor: resolvedTrack
113
121
  }, style, containerStyle],
114
- children: isIndeterminate ? /*#__PURE__*/_jsx(Animated.View, {
122
+ children: hasSegments ? /*#__PURE__*/_jsx(View, {
123
+ style: [styles.segments, {
124
+ height
125
+ }],
126
+ children: (segments ?? []).map((s, i) => /*#__PURE__*/_jsx(View, {
127
+ style: {
128
+ width: `${clampProgress(s.value) * 100}%`,
129
+ height,
130
+ backgroundColor: s.color ?? toneColor(theme, s.tone ?? 'primary')
131
+ }
132
+ }, i))
133
+ }) : isIndeterminate ? /*#__PURE__*/_jsx(Animated.View, {
115
134
  style: [styles.indeterminateBar, {
116
135
  height,
117
136
  borderRadius: resolvedRadius,
@@ -125,9 +144,14 @@ const ProgressBar = /*#__PURE__*/forwardRef((props, ref) => {
125
144
  style: [styles.determinateBar, {
126
145
  height,
127
146
  borderRadius: resolvedRadius,
128
- backgroundColor: resolvedBar,
129
- width: determinateWidth
130
- }, barStyle]
147
+ backgroundColor: resolvedGradient ? 'transparent' : resolvedBar,
148
+ width: determinateWidth,
149
+ overflow: resolvedGradient ? 'hidden' : undefined
150
+ }, barStyle],
151
+ children: resolvedGradient ? /*#__PURE__*/_jsx(Gradient, {
152
+ gradient: resolvedGradient,
153
+ style: StyleSheet.absoluteFill
154
+ }) : null
131
155
  })
132
156
  });
133
157
  });
@@ -146,6 +170,10 @@ const buildStyles = _theme => StyleSheet.create({
146
170
  position: 'absolute',
147
171
  left: 0,
148
172
  top: 0
173
+ },
174
+ segments: {
175
+ flexDirection: 'row',
176
+ width: '100%'
149
177
  }
150
178
  });
151
179
  export { ProgressBar };