@webority-technologies/mobile 0.0.21 → 0.0.23
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 +4 -2
- package/lib/commonjs/components/Avatar/Avatar.js +4 -2
- package/lib/commonjs/components/Badge/Badge.js +5 -5
- package/lib/commonjs/components/Banner/Banner.js +8 -4
- package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +6 -4
- package/lib/commonjs/components/BottomSheet/BottomSheet.js +69 -13
- package/lib/commonjs/components/BottomSheet/index.js +6 -0
- package/lib/commonjs/components/Box/Box.js +162 -0
- package/lib/commonjs/components/Box/index.js +37 -0
- package/lib/commonjs/components/Button/Button.js +7 -7
- package/lib/commonjs/components/Carousel/Carousel.js +4 -2
- package/lib/commonjs/components/Checkbox/Checkbox.js +14 -5
- package/lib/commonjs/components/DatePicker/DatePicker.js +9 -7
- package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +5 -2
- package/lib/commonjs/components/Dialog/Dialog.js +2 -2
- package/lib/commonjs/components/FieldBase/FieldBase.js +8 -4
- package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +13 -5
- package/lib/commonjs/components/FormField/FormField.js +61 -25
- package/lib/commonjs/components/Input/Input.js +41 -29
- package/lib/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +102 -0
- package/lib/commonjs/components/KeyboardAwareScrollView/index.js +13 -0
- package/lib/commonjs/components/KeyboardToolbar/KeyboardToolbar.js +130 -0
- package/lib/commonjs/components/KeyboardToolbar/index.js +13 -0
- package/lib/commonjs/components/Modal/Modal.js +17 -6
- package/lib/commonjs/components/NumberInput/NumberInput.js +35 -28
- package/lib/commonjs/components/OTPInput/OTPInput.js +33 -18
- package/lib/commonjs/components/Radio/Radio.js +7 -5
- package/lib/commonjs/components/Radio/RadioGroup.js +10 -3
- package/lib/commonjs/components/SearchBar/SearchBar.js +4 -2
- package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +20 -10
- package/lib/commonjs/components/Select/Select.js +33 -32
- package/lib/commonjs/components/Skeleton/SkeletonContent.js +5 -2
- package/lib/commonjs/components/Slider/Slider.js +42 -26
- package/lib/commonjs/components/Spinner/Spinner.js +5 -5
- package/lib/commonjs/components/Switch/Switch.js +29 -16
- package/lib/commonjs/components/Tabs/Tabs.js +4 -2
- package/lib/commonjs/components/Text/Text.js +142 -0
- package/lib/commonjs/components/Text/index.js +13 -0
- package/lib/commonjs/components/TimePicker/TimePicker.js +10 -7
- package/lib/commonjs/components/Toast/Toast.js +22 -10
- package/lib/commonjs/components/Tooltip/Tooltip.js +6 -2
- package/lib/commonjs/components/index.js +141 -89
- package/lib/commonjs/form/FormContext.js +40 -0
- package/lib/commonjs/form/index.js +68 -0
- package/lib/commonjs/form/path.js +79 -0
- package/lib/commonjs/form/rules.js +67 -0
- package/lib/commonjs/form/types.js +2 -0
- package/lib/commonjs/form/useField.js +54 -0
- package/lib/commonjs/form/useForm.js +316 -0
- package/lib/commonjs/hooks/index.js +14 -0
- package/lib/commonjs/hooks/useControllableState.js +30 -0
- package/lib/commonjs/hooks/useReducedMotion.js +31 -0
- package/lib/commonjs/index.js +96 -11
- package/lib/commonjs/theme/ThemeContext.js +30 -2
- package/lib/commonjs/theme/tokens.js +12 -0
- package/lib/module/components/Accordion/Accordion.js +4 -2
- package/lib/module/components/Avatar/Avatar.js +4 -2
- package/lib/module/components/Badge/Badge.js +5 -5
- package/lib/module/components/Banner/Banner.js +8 -4
- package/lib/module/components/BottomNavigation/BottomNavigation.js +6 -4
- package/lib/module/components/BottomSheet/BottomSheet.js +68 -13
- package/lib/module/components/BottomSheet/index.js +1 -1
- package/lib/module/components/Box/Box.js +156 -0
- package/lib/module/components/Box/index.js +4 -0
- package/lib/module/components/Button/Button.js +7 -7
- package/lib/module/components/Carousel/Carousel.js +4 -2
- package/lib/module/components/Checkbox/Checkbox.js +14 -5
- package/lib/module/components/DatePicker/DatePicker.js +9 -7
- package/lib/module/components/DateRangePicker/DateRangePicker.js +5 -2
- package/lib/module/components/Dialog/Dialog.js +2 -2
- package/lib/module/components/FieldBase/FieldBase.js +8 -4
- package/lib/module/components/FloatingActionButton/FloatingActionButton.js +13 -5
- package/lib/module/components/FormField/FormField.js +62 -26
- package/lib/module/components/Input/Input.js +41 -29
- package/lib/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +98 -0
- package/lib/module/components/KeyboardAwareScrollView/index.js +4 -0
- package/lib/module/components/KeyboardToolbar/KeyboardToolbar.js +125 -0
- package/lib/module/components/KeyboardToolbar/index.js +4 -0
- package/lib/module/components/Modal/Modal.js +17 -6
- package/lib/module/components/NumberInput/NumberInput.js +30 -23
- package/lib/module/components/OTPInput/OTPInput.js +30 -15
- package/lib/module/components/Radio/Radio.js +7 -5
- package/lib/module/components/Radio/RadioGroup.js +10 -3
- package/lib/module/components/SearchBar/SearchBar.js +4 -2
- package/lib/module/components/SegmentedControl/SegmentedControl.js +20 -10
- package/lib/module/components/Select/Select.js +33 -32
- package/lib/module/components/Skeleton/SkeletonContent.js +5 -2
- package/lib/module/components/Slider/Slider.js +42 -26
- package/lib/module/components/Spinner/Spinner.js +5 -5
- package/lib/module/components/Switch/Switch.js +29 -16
- package/lib/module/components/Tabs/Tabs.js +4 -2
- package/lib/module/components/Text/Text.js +138 -0
- package/lib/module/components/Text/index.js +4 -0
- package/lib/module/components/TimePicker/TimePicker.js +10 -7
- package/lib/module/components/Toast/Toast.js +22 -10
- package/lib/module/components/Tooltip/Tooltip.js +6 -2
- package/lib/module/components/index.js +5 -1
- package/lib/module/form/FormContext.js +32 -0
- package/lib/module/form/index.js +12 -0
- package/lib/module/form/path.js +72 -0
- package/lib/module/form/rules.js +52 -0
- package/lib/module/form/types.js +2 -0
- package/lib/module/form/useField.js +49 -0
- package/lib/module/form/useForm.js +312 -0
- package/lib/module/hooks/index.js +2 -0
- package/lib/module/hooks/useControllableState.js +26 -0
- package/lib/module/hooks/useReducedMotion.js +27 -0
- package/lib/module/index.js +3 -1
- package/lib/module/theme/ThemeContext.js +30 -2
- package/lib/module/theme/tokens.js +12 -0
- package/lib/typescript/commonjs/components/BottomNavigation/BottomNavigation.d.ts +1 -1
- package/lib/typescript/commonjs/components/BottomSheet/BottomSheet.d.ts +41 -0
- package/lib/typescript/commonjs/components/BottomSheet/index.d.ts +2 -2
- package/lib/typescript/commonjs/components/Box/Box.d.ts +60 -0
- package/lib/typescript/commonjs/components/Box/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/Button/Button.d.ts +1 -1
- package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +3 -2
- package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +3 -3
- package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +2 -2
- package/lib/typescript/commonjs/components/FormField/FormField.d.ts +13 -2
- package/lib/typescript/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
- package/lib/typescript/commonjs/components/KeyboardAwareScrollView/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
- package/lib/typescript/commonjs/components/KeyboardToolbar/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -2
- package/lib/typescript/commonjs/components/OTPInput/OTPInput.d.ts +3 -2
- package/lib/typescript/commonjs/components/Radio/Radio.d.ts +2 -2
- package/lib/typescript/commonjs/components/Radio/RadioGroup.d.ts +3 -2
- package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -2
- package/lib/typescript/commonjs/components/Slider/Slider.d.ts +6 -4
- package/lib/typescript/commonjs/components/Spinner/Spinner.d.ts +1 -1
- package/lib/typescript/commonjs/components/Switch/Switch.d.ts +3 -2
- package/lib/typescript/commonjs/components/Text/Text.d.ts +25 -0
- package/lib/typescript/commonjs/components/Text/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +3 -3
- package/lib/typescript/commonjs/components/index.d.ts +10 -2
- package/lib/typescript/commonjs/form/FormContext.d.ts +17 -0
- package/lib/typescript/commonjs/form/index.d.ts +9 -0
- package/lib/typescript/commonjs/form/path.d.ts +10 -0
- package/lib/typescript/commonjs/form/rules.d.ts +31 -0
- package/lib/typescript/commonjs/form/types.d.ts +94 -0
- package/lib/typescript/commonjs/form/useField.d.ts +27 -0
- package/lib/typescript/commonjs/form/useForm.d.ts +10 -0
- package/lib/typescript/commonjs/hooks/index.d.ts +3 -0
- package/lib/typescript/commonjs/hooks/useControllableState.d.ts +17 -0
- package/lib/typescript/commonjs/hooks/useReducedMotion.d.ts +8 -0
- package/lib/typescript/commonjs/index.d.ts +4 -2
- package/lib/typescript/commonjs/theme/types.d.ts +15 -0
- package/lib/typescript/module/components/BottomNavigation/BottomNavigation.d.ts +1 -1
- package/lib/typescript/module/components/BottomSheet/BottomSheet.d.ts +41 -0
- package/lib/typescript/module/components/BottomSheet/index.d.ts +2 -2
- package/lib/typescript/module/components/Box/Box.d.ts +60 -0
- package/lib/typescript/module/components/Box/index.d.ts +3 -0
- package/lib/typescript/module/components/Button/Button.d.ts +1 -1
- package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +3 -2
- package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +3 -3
- package/lib/typescript/module/components/Dialog/Dialog.d.ts +2 -2
- package/lib/typescript/module/components/FormField/FormField.d.ts +13 -2
- package/lib/typescript/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
- package/lib/typescript/module/components/KeyboardAwareScrollView/index.d.ts +3 -0
- package/lib/typescript/module/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
- package/lib/typescript/module/components/KeyboardToolbar/index.d.ts +3 -0
- package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -2
- package/lib/typescript/module/components/OTPInput/OTPInput.d.ts +3 -2
- package/lib/typescript/module/components/Radio/Radio.d.ts +2 -2
- package/lib/typescript/module/components/Radio/RadioGroup.d.ts +3 -2
- package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -2
- package/lib/typescript/module/components/Slider/Slider.d.ts +6 -4
- package/lib/typescript/module/components/Spinner/Spinner.d.ts +1 -1
- package/lib/typescript/module/components/Switch/Switch.d.ts +3 -2
- package/lib/typescript/module/components/Text/Text.d.ts +25 -0
- package/lib/typescript/module/components/Text/index.d.ts +3 -0
- package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +3 -3
- package/lib/typescript/module/components/index.d.ts +10 -2
- package/lib/typescript/module/form/FormContext.d.ts +17 -0
- package/lib/typescript/module/form/index.d.ts +9 -0
- package/lib/typescript/module/form/path.d.ts +10 -0
- package/lib/typescript/module/form/rules.d.ts +31 -0
- package/lib/typescript/module/form/types.d.ts +94 -0
- package/lib/typescript/module/form/useField.d.ts +27 -0
- package/lib/typescript/module/form/useForm.d.ts +10 -0
- package/lib/typescript/module/hooks/index.d.ts +3 -0
- package/lib/typescript/module/hooks/useControllableState.d.ts +17 -0
- package/lib/typescript/module/hooks/useReducedMotion.d.ts +8 -0
- package/lib/typescript/module/index.d.ts +4 -2
- package/lib/typescript/module/theme/types.d.ts +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { getPath, setPath } from "./path.js";
|
|
5
|
+
// Loosely typed (Values -> any) so the generic schema from any useForm<Values>
|
|
6
|
+
// instance flows in without variance friction; callers re-apply Values at use.
|
|
7
|
+
const rulesFor = (validate, name) => {
|
|
8
|
+
if (!validate || typeof validate === 'function') return [];
|
|
9
|
+
const r = validate[name];
|
|
10
|
+
if (!r) return [];
|
|
11
|
+
return Array.isArray(r) ? r : [r];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Dependency-free form engine. Tracks values/errors/touched/dirty, runs
|
|
16
|
+
* synchronous and async validation (per-field rule maps or a form-level
|
|
17
|
+
* function), gates error display behind touched/submit, and on a failed submit
|
|
18
|
+
* focuses the first errored field. The returned object is rebuilt every render
|
|
19
|
+
* so `<Form>` consumers re-render on state changes.
|
|
20
|
+
*/
|
|
21
|
+
export function useForm(config) {
|
|
22
|
+
const configRef = useRef(config);
|
|
23
|
+
configRef.current = config;
|
|
24
|
+
const initialRef = useRef(config.initialValues);
|
|
25
|
+
const [values, setValuesState] = useState(config.initialValues);
|
|
26
|
+
const [errors, setErrorsState] = useState({});
|
|
27
|
+
const [touched, setTouchedState] = useState({});
|
|
28
|
+
const [isSubmitting, setSubmitting] = useState(false);
|
|
29
|
+
const [isValidating, setValidating] = useState(false);
|
|
30
|
+
const [submitCount, setSubmitCount] = useState(0);
|
|
31
|
+
|
|
32
|
+
// Mirror of the latest state so handlers (incl. async) never read stale
|
|
33
|
+
// closures and sequential setFieldValue calls in one tick compound correctly.
|
|
34
|
+
const ref = useRef({
|
|
35
|
+
values,
|
|
36
|
+
errors,
|
|
37
|
+
touched,
|
|
38
|
+
submitCount
|
|
39
|
+
});
|
|
40
|
+
ref.current = {
|
|
41
|
+
values,
|
|
42
|
+
errors,
|
|
43
|
+
touched,
|
|
44
|
+
submitCount
|
|
45
|
+
};
|
|
46
|
+
const fieldNodes = useRef(new Map());
|
|
47
|
+
const fieldOrder = useRef([]);
|
|
48
|
+
const focusedFieldRef = useRef(null);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (!configRef.current.enableReinitialize) return;
|
|
51
|
+
const next = configRef.current.initialValues;
|
|
52
|
+
initialRef.current = next;
|
|
53
|
+
ref.current.values = next;
|
|
54
|
+
ref.current.errors = {};
|
|
55
|
+
ref.current.touched = {};
|
|
56
|
+
setValuesState(next);
|
|
57
|
+
setErrorsState({});
|
|
58
|
+
setTouchedState({});
|
|
59
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
60
|
+
}, [JSON.stringify(config.initialValues)]);
|
|
61
|
+
const validateField = useCallback(async name => {
|
|
62
|
+
const validate = configRef.current.validate;
|
|
63
|
+
const allValues = ref.current.values;
|
|
64
|
+
if (typeof validate === 'function') {
|
|
65
|
+
const map = (await validate(allValues)) ?? {};
|
|
66
|
+
return map[name] || undefined;
|
|
67
|
+
}
|
|
68
|
+
const value = getPath(allValues, name);
|
|
69
|
+
for (const rule of rulesFor(validate, name)) {
|
|
70
|
+
const res = await rule(value, allValues);
|
|
71
|
+
if (res) return res;
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}, []);
|
|
75
|
+
const runAll = useCallback(async vals => {
|
|
76
|
+
const validate = configRef.current.validate;
|
|
77
|
+
if (!validate) return {};
|
|
78
|
+
if (typeof validate === 'function') return (await validate(vals)) ?? {};
|
|
79
|
+
const out = {};
|
|
80
|
+
await Promise.all(Object.keys(validate).map(async name => {
|
|
81
|
+
const value = getPath(vals, name);
|
|
82
|
+
for (const rule of rulesFor(validate, name)) {
|
|
83
|
+
const res = await rule(value, vals);
|
|
84
|
+
if (res) {
|
|
85
|
+
out[name] = res;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
return out;
|
|
91
|
+
}, []);
|
|
92
|
+
const revalidateField = useCallback(async name => {
|
|
93
|
+
const err = await validateField(name);
|
|
94
|
+
setErrorsState(prev => {
|
|
95
|
+
if (prev[name] === err) return prev;
|
|
96
|
+
const next = {
|
|
97
|
+
...prev
|
|
98
|
+
};
|
|
99
|
+
if (err) next[name] = err;else delete next[name];
|
|
100
|
+
ref.current.errors = next;
|
|
101
|
+
return next;
|
|
102
|
+
});
|
|
103
|
+
}, [validateField]);
|
|
104
|
+
const validate = useCallback(async () => {
|
|
105
|
+
setValidating(true);
|
|
106
|
+
const errs = await runAll(ref.current.values);
|
|
107
|
+
setValidating(false);
|
|
108
|
+
ref.current.errors = errs;
|
|
109
|
+
setErrorsState(errs);
|
|
110
|
+
return errs;
|
|
111
|
+
}, [runAll]);
|
|
112
|
+
const setFieldValue = useCallback((name, value, shouldValidate) => {
|
|
113
|
+
const next = setPath(ref.current.values, name, value);
|
|
114
|
+
ref.current.values = next;
|
|
115
|
+
setValuesState(next);
|
|
116
|
+
const cfg = configRef.current;
|
|
117
|
+
const willValidate = shouldValidate ?? (ref.current.touched[name] || ref.current.submitCount > 0 || cfg.validateOn === 'change');
|
|
118
|
+
if (willValidate) void revalidateField(name);
|
|
119
|
+
}, [revalidateField]);
|
|
120
|
+
const handleBlur = useCallback(name => {
|
|
121
|
+
setTouchedState(prev => {
|
|
122
|
+
if (prev[name]) return prev;
|
|
123
|
+
const next = {
|
|
124
|
+
...prev,
|
|
125
|
+
[name]: true
|
|
126
|
+
};
|
|
127
|
+
ref.current.touched = next;
|
|
128
|
+
return next;
|
|
129
|
+
});
|
|
130
|
+
// Blur is the natural moment to surface a field's error.
|
|
131
|
+
void revalidateField(name);
|
|
132
|
+
}, [revalidateField]);
|
|
133
|
+
const setFieldTouched = useCallback((name, isTouched = true, shouldValidate) => {
|
|
134
|
+
const next = {
|
|
135
|
+
...ref.current.touched,
|
|
136
|
+
[name]: isTouched
|
|
137
|
+
};
|
|
138
|
+
ref.current.touched = next;
|
|
139
|
+
setTouchedState(next);
|
|
140
|
+
if (shouldValidate ?? isTouched) void revalidateField(name);
|
|
141
|
+
}, [revalidateField]);
|
|
142
|
+
const setFieldError = useCallback((name, error) => {
|
|
143
|
+
setErrorsState(prev => {
|
|
144
|
+
const next = {
|
|
145
|
+
...prev
|
|
146
|
+
};
|
|
147
|
+
if (error) next[name] = error;else delete next[name];
|
|
148
|
+
ref.current.errors = next;
|
|
149
|
+
return next;
|
|
150
|
+
});
|
|
151
|
+
}, []);
|
|
152
|
+
const setErrors = useCallback(errs => {
|
|
153
|
+
ref.current.errors = errs;
|
|
154
|
+
setErrorsState(errs);
|
|
155
|
+
}, []);
|
|
156
|
+
const setValues = useCallback((next, shouldValidate) => {
|
|
157
|
+
const resolved = typeof next === 'function' ? next(ref.current.values) : {
|
|
158
|
+
...ref.current.values,
|
|
159
|
+
...next
|
|
160
|
+
};
|
|
161
|
+
ref.current.values = resolved;
|
|
162
|
+
setValuesState(resolved);
|
|
163
|
+
if (shouldValidate) void validate();
|
|
164
|
+
}, [validate]);
|
|
165
|
+
const reset = useCallback(nextValues => {
|
|
166
|
+
const base = nextValues ? {
|
|
167
|
+
...initialRef.current,
|
|
168
|
+
...nextValues
|
|
169
|
+
} : initialRef.current;
|
|
170
|
+
initialRef.current = base;
|
|
171
|
+
ref.current.values = base;
|
|
172
|
+
ref.current.errors = {};
|
|
173
|
+
ref.current.touched = {};
|
|
174
|
+
ref.current.submitCount = 0;
|
|
175
|
+
setValuesState(base);
|
|
176
|
+
setErrorsState({});
|
|
177
|
+
setTouchedState({});
|
|
178
|
+
setSubmitCount(0);
|
|
179
|
+
}, []);
|
|
180
|
+
const registerField = useCallback((name, node) => {
|
|
181
|
+
if (node) {
|
|
182
|
+
fieldNodes.current.set(name, node);
|
|
183
|
+
if (!fieldOrder.current.includes(name)) fieldOrder.current.push(name);
|
|
184
|
+
} else {
|
|
185
|
+
fieldNodes.current.delete(name);
|
|
186
|
+
fieldOrder.current = fieldOrder.current.filter(n => n !== name);
|
|
187
|
+
}
|
|
188
|
+
}, []);
|
|
189
|
+
const handleFocus = useCallback(name => {
|
|
190
|
+
focusedFieldRef.current = name;
|
|
191
|
+
}, []);
|
|
192
|
+
const focusAdjacent = useCallback(direction => {
|
|
193
|
+
const order = fieldOrder.current;
|
|
194
|
+
const current = focusedFieldRef.current;
|
|
195
|
+
const index = current ? order.indexOf(current) : -1;
|
|
196
|
+
const target = order[index + direction];
|
|
197
|
+
if (!target) return;
|
|
198
|
+
focusedFieldRef.current = target;
|
|
199
|
+
fieldNodes.current.get(target)?.focus?.();
|
|
200
|
+
}, []);
|
|
201
|
+
const focusNext = useCallback(() => focusAdjacent(1), [focusAdjacent]);
|
|
202
|
+
const focusPrev = useCallback(() => focusAdjacent(-1), [focusAdjacent]);
|
|
203
|
+
const helpers = useMemo(() => ({
|
|
204
|
+
setErrors,
|
|
205
|
+
setFieldError,
|
|
206
|
+
reset,
|
|
207
|
+
setSubmitting
|
|
208
|
+
}), [setErrors, setFieldError, reset]);
|
|
209
|
+
const submit = useCallback(() => {
|
|
210
|
+
void (async () => {
|
|
211
|
+
const cfg = configRef.current;
|
|
212
|
+
const currentValues = ref.current.values;
|
|
213
|
+
ref.current.submitCount += 1;
|
|
214
|
+
setSubmitCount(c => c + 1);
|
|
215
|
+
setValidating(true);
|
|
216
|
+
const errs = await runAll(currentValues);
|
|
217
|
+
setValidating(false);
|
|
218
|
+
const keys = new Set([...fieldOrder.current, ...Object.keys(errs)]);
|
|
219
|
+
const nextTouched = {
|
|
220
|
+
...ref.current.touched
|
|
221
|
+
};
|
|
222
|
+
keys.forEach(k => {
|
|
223
|
+
nextTouched[k] = true;
|
|
224
|
+
});
|
|
225
|
+
ref.current.touched = nextTouched;
|
|
226
|
+
ref.current.errors = errs;
|
|
227
|
+
setTouchedState(nextTouched);
|
|
228
|
+
setErrorsState(errs);
|
|
229
|
+
const firstError = fieldOrder.current.find(n => errs[n]) ?? Object.keys(errs).find(n => errs[n]);
|
|
230
|
+
if (firstError) {
|
|
231
|
+
fieldNodes.current.get(firstError)?.focus?.();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
setSubmitting(true);
|
|
235
|
+
try {
|
|
236
|
+
await cfg.onSubmit(currentValues, helpers);
|
|
237
|
+
} finally {
|
|
238
|
+
setSubmitting(false);
|
|
239
|
+
}
|
|
240
|
+
})();
|
|
241
|
+
}, [runAll, helpers]);
|
|
242
|
+
const uiErrors = useMemo(() => {
|
|
243
|
+
const gated = {};
|
|
244
|
+
for (const k of Object.keys(errors)) {
|
|
245
|
+
if (errors[k] && (touched[k] || submitCount > 0)) gated[k] = errors[k];
|
|
246
|
+
}
|
|
247
|
+
return gated;
|
|
248
|
+
}, [errors, touched, submitCount]);
|
|
249
|
+
const isValid = useMemo(() => {
|
|
250
|
+
const validateCfg = configRef.current.validate;
|
|
251
|
+
if (!validateCfg) return true;
|
|
252
|
+
// Form-level async fn can't run synchronously — fall back to known errors.
|
|
253
|
+
if (typeof validateCfg === 'function') return Object.values(errors).every(e => !e);
|
|
254
|
+
for (const name of Object.keys(validateCfg)) {
|
|
255
|
+
const value = getPath(values, name);
|
|
256
|
+
for (const rule of rulesFor(validateCfg, name)) {
|
|
257
|
+
const res = rule(value, values);
|
|
258
|
+
if (typeof res === 'string' && res) return false; // async rules (Promise) are skipped here
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return true;
|
|
262
|
+
}, [values, errors]);
|
|
263
|
+
const dirty = useMemo(() => JSON.stringify(values) !== JSON.stringify(initialRef.current), [values]);
|
|
264
|
+
return {
|
|
265
|
+
values,
|
|
266
|
+
errors: uiErrors,
|
|
267
|
+
rawErrors: errors,
|
|
268
|
+
touched,
|
|
269
|
+
dirty,
|
|
270
|
+
isValid,
|
|
271
|
+
isSubmitting,
|
|
272
|
+
isValidating,
|
|
273
|
+
submitCount,
|
|
274
|
+
setFieldValue,
|
|
275
|
+
setFieldTouched,
|
|
276
|
+
setFieldError,
|
|
277
|
+
setValues,
|
|
278
|
+
setErrors,
|
|
279
|
+
reset,
|
|
280
|
+
validate,
|
|
281
|
+
validateField,
|
|
282
|
+
submit,
|
|
283
|
+
handleBlur,
|
|
284
|
+
focusNext,
|
|
285
|
+
focusPrev,
|
|
286
|
+
registerField,
|
|
287
|
+
getFieldState: name => {
|
|
288
|
+
const value = getPath(values, name);
|
|
289
|
+
const rawError = errors[name];
|
|
290
|
+
const isTouched = !!touched[name];
|
|
291
|
+
return {
|
|
292
|
+
value,
|
|
293
|
+
error: isTouched || submitCount > 0 ? rawError : undefined,
|
|
294
|
+
rawError,
|
|
295
|
+
touched: isTouched,
|
|
296
|
+
dirty: JSON.stringify(value) !== JSON.stringify(getPath(initialRef.current, name))
|
|
297
|
+
};
|
|
298
|
+
},
|
|
299
|
+
getFieldProps: name => ({
|
|
300
|
+
name,
|
|
301
|
+
value: getPath(values, name),
|
|
302
|
+
error: touched[name] || submitCount > 0 ? errors[name] : undefined,
|
|
303
|
+
touched: !!touched[name],
|
|
304
|
+
onChange: val => setFieldValue(name, val),
|
|
305
|
+
onChangeText: text => setFieldValue(name, text),
|
|
306
|
+
onBlur: () => handleBlur(name),
|
|
307
|
+
onFocus: () => handleFocus(name),
|
|
308
|
+
setValue: (val, sv) => setFieldValue(name, val, sv)
|
|
309
|
+
})
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=useForm.js.map
|
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
export { useToggle } from "./useToggle.js";
|
|
4
4
|
export { useDebounce } from "./useDebounce.js";
|
|
5
5
|
export { usePressAnimation } from "./usePressAnimation.js";
|
|
6
|
+
export { useReducedMotion } from "./useReducedMotion.js";
|
|
7
|
+
export { useControllableState } from "./useControllableState.js";
|
|
6
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useRef, useState } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Bridges controlled and uncontrolled usage for a value+onChange pair. When
|
|
6
|
+
* `value` is provided the component is controlled (the hook just forwards it
|
|
7
|
+
* and calls `onChange`); otherwise the hook owns the state, seeded from
|
|
8
|
+
* `defaultValue`. The controlled/uncontrolled decision is locked on first
|
|
9
|
+
* render so a component never flips modes mid-life.
|
|
10
|
+
*/
|
|
11
|
+
export function useControllableState({
|
|
12
|
+
value,
|
|
13
|
+
defaultValue,
|
|
14
|
+
onChange
|
|
15
|
+
}) {
|
|
16
|
+
const isControlledRef = useRef(value !== undefined);
|
|
17
|
+
const isControlled = isControlledRef.current;
|
|
18
|
+
const [internal, setInternal] = useState(defaultValue);
|
|
19
|
+
const current = isControlled ? value : internal;
|
|
20
|
+
const setValue = useCallback(next => {
|
|
21
|
+
if (!isControlled) setInternal(next);
|
|
22
|
+
onChange?.(next);
|
|
23
|
+
}, [isControlled, onChange]);
|
|
24
|
+
return [current, setValue];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=useControllableState.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { AccessibilityInfo } from 'react-native';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Tracks the OS "Reduce Motion" accessibility setting. The library's
|
|
8
|
+
* ThemeProvider uses this to collapse `theme.motion` (durations → 0, springs →
|
|
9
|
+
* near-instant) so animations don't trigger vestibular discomfort; consumers
|
|
10
|
+
* can also read it directly to swap an animated path for a static one.
|
|
11
|
+
*/
|
|
12
|
+
export const useReducedMotion = () => {
|
|
13
|
+
const [reduced, setReduced] = useState(false);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
let mounted = true;
|
|
16
|
+
AccessibilityInfo.isReduceMotionEnabled().then(value => {
|
|
17
|
+
if (mounted) setReduced(value);
|
|
18
|
+
});
|
|
19
|
+
const sub = AccessibilityInfo.addEventListener('reduceMotionChanged', value => setReduced(value));
|
|
20
|
+
return () => {
|
|
21
|
+
mounted = false;
|
|
22
|
+
sub.remove();
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
return reduced;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=useReducedMotion.js.map
|
package/lib/module/index.js
CHANGED
|
@@ -21,13 +21,15 @@ export { VersionCheck, useVersionCheck } from "./versionCheck/index.js";
|
|
|
21
21
|
// Theme
|
|
22
22
|
export { ThemeProvider, useTheme, useThemeMode, setTheme, setColorMode, getColorMode, getTheme, resetTheme, subscribeTheme, mergeTheme, lightTheme, darkTheme } from "./theme/index.js";
|
|
23
23
|
// Hooks
|
|
24
|
-
export { useToggle, useDebounce, usePressAnimation } from "./hooks/index.js";
|
|
24
|
+
export { useToggle, useDebounce, usePressAnimation, useReducedMotion, useControllableState } from "./hooks/index.js";
|
|
25
25
|
// Utils
|
|
26
26
|
export { ScreenDimensions, Breakpoints, Responsive, isScreenSize, isTablet, Spacing, Padding, Margin, triggerHaptic, setHapticImplementation, shadowStyle, compressImage } from "./utils/index.js";
|
|
27
27
|
// Formatters
|
|
28
28
|
export { formatDate, formatTime, formatDateTime, formatRelativeTime, formatPhone, normalizePhone, formatCurrency, formatNumber, formatPercent, formatCompactNumber, getInitials } from "./formatters/index.js";
|
|
29
29
|
// Validators
|
|
30
30
|
export { isNonEmpty, isEmail, isIndianMobile, isPhone, isUrl, isNumeric, isInteger, isAlphanumeric, isStrongPassword, isIndianPincode, isPan, isGstin, isAadhaar, isIfsc, isHexColor, isBetween, minLength, maxLength } from "./validators/index.js";
|
|
31
|
+
// Form engine (dependency-free; replaces Formik + Yup)
|
|
32
|
+
export { useForm, useField, useFieldArray, Form, useFormContext, useOptionalFormContext, rules, getPath, setPath, deletePath } from "./form/index.js";
|
|
31
33
|
// Network
|
|
32
34
|
export { useNetworkStatus, getNetworkStatus, addNetworkStatusListener, NetworkStatusBanner } from "./network/index.js";
|
|
33
35
|
// Permissions
|
|
@@ -4,7 +4,30 @@ import React, { createContext, useContext, useEffect, useMemo, useState } from '
|
|
|
4
4
|
import { Appearance } from 'react-native';
|
|
5
5
|
import { darkTheme, lightTheme } from "./tokens.js";
|
|
6
6
|
import { mergeTheme } from "./merge.js";
|
|
7
|
+
import { useReducedMotion } from "../hooks/useReducedMotion.js";
|
|
7
8
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
const REDUCED_SPRING = {
|
|
10
|
+
damping: 100,
|
|
11
|
+
stiffness: 1000,
|
|
12
|
+
mass: 1
|
|
13
|
+
};
|
|
14
|
+
// Reduce Motion: collapse timed animations to instant and make springs settle in
|
|
15
|
+
// ~1 frame, so vestibular-sensitive users aren't subjected to slides/scales/bounces.
|
|
16
|
+
const collapseMotion = motion => ({
|
|
17
|
+
...motion,
|
|
18
|
+
duration: {
|
|
19
|
+
instant: 0,
|
|
20
|
+
fast: 0,
|
|
21
|
+
normal: 0,
|
|
22
|
+
slow: 0,
|
|
23
|
+
slower: 0
|
|
24
|
+
},
|
|
25
|
+
spring: {
|
|
26
|
+
gentle: REDUCED_SPRING,
|
|
27
|
+
bouncy: REDUCED_SPRING,
|
|
28
|
+
snappy: REDUCED_SPRING
|
|
29
|
+
}
|
|
30
|
+
});
|
|
8
31
|
const defaultValue = {
|
|
9
32
|
theme: lightTheme,
|
|
10
33
|
mode: 'light',
|
|
@@ -30,11 +53,16 @@ export const ThemeProvider = ({
|
|
|
30
53
|
return () => sub.remove();
|
|
31
54
|
}, []);
|
|
32
55
|
const mode = preference === 'system' ? systemMode : preference;
|
|
56
|
+
const reduceMotion = useReducedMotion();
|
|
33
57
|
const theme = useMemo(() => {
|
|
34
58
|
const base = mode === 'dark' ? darkTheme : lightTheme;
|
|
35
59
|
const overrides = mode === 'dark' ? darkOverrides : lightOverrides;
|
|
36
|
-
|
|
37
|
-
|
|
60
|
+
const merged = overrides ? mergeTheme(base, overrides) : base;
|
|
61
|
+
return reduceMotion ? {
|
|
62
|
+
...merged,
|
|
63
|
+
motion: collapseMotion(merged.motion)
|
|
64
|
+
} : merged;
|
|
65
|
+
}, [mode, lightOverrides, darkOverrides, reduceMotion]);
|
|
38
66
|
const value = useMemo(() => ({
|
|
39
67
|
theme,
|
|
40
68
|
mode,
|
|
@@ -521,6 +521,12 @@ export const lightTheme = {
|
|
|
521
521
|
warning: '#F59E0B',
|
|
522
522
|
error: '#E5484D',
|
|
523
523
|
info: '#3B82F6',
|
|
524
|
+
onPrimary: '#FFFFFF',
|
|
525
|
+
onSecondary: '#0F0F1A',
|
|
526
|
+
onSuccess: '#FFFFFF',
|
|
527
|
+
onWarning: '#0F0F1A',
|
|
528
|
+
onError: '#FFFFFF',
|
|
529
|
+
onInfo: '#FFFFFF',
|
|
524
530
|
text: {
|
|
525
531
|
primary: '#0F0F1A',
|
|
526
532
|
secondary: '#52525B',
|
|
@@ -576,6 +582,12 @@ export const darkTheme = {
|
|
|
576
582
|
warning: '#FBBF24',
|
|
577
583
|
error: '#F87171',
|
|
578
584
|
info: '#60A5FA',
|
|
585
|
+
onPrimary: '#0F0F1A',
|
|
586
|
+
onSecondary: '#FAFAFA',
|
|
587
|
+
onSuccess: '#0F0F1A',
|
|
588
|
+
onWarning: '#0F0F1A',
|
|
589
|
+
onError: '#0F0F1A',
|
|
590
|
+
onInfo: '#0F0F1A',
|
|
579
591
|
text: {
|
|
580
592
|
primary: '#FAFAFA',
|
|
581
593
|
secondary: '#B4B4BB',
|
|
@@ -20,7 +20,7 @@ export interface TabConfig {
|
|
|
20
20
|
export interface BottomNavigationProps {
|
|
21
21
|
tabs: TabConfig[];
|
|
22
22
|
activeTab: string;
|
|
23
|
-
|
|
23
|
+
onChange: (tabKey: string) => void;
|
|
24
24
|
haptic?: HapticType | false;
|
|
25
25
|
showLabels?: boolean;
|
|
26
26
|
variant?: BottomNavigationVariant;
|
|
@@ -56,6 +56,23 @@ export interface BottomSheetProps {
|
|
|
56
56
|
mode?: BottomSheetMode;
|
|
57
57
|
handleIndicatorStyle?: StyleProp<ViewStyle>;
|
|
58
58
|
containerStyle?: StyleProp<ViewStyle>;
|
|
59
|
+
/**
|
|
60
|
+
* Sticky region rendered between the drag handle and the scrollable content.
|
|
61
|
+
* Does not scroll with `children`. Can call `useBottomSheet()` to read sheet
|
|
62
|
+
* state.
|
|
63
|
+
*/
|
|
64
|
+
header?: React.ReactNode;
|
|
65
|
+
/**
|
|
66
|
+
* Sticky region pinned to the bottom of the sheet, above the safe-area
|
|
67
|
+
* inset. Does not scroll with `children`, and rides up with the keyboard
|
|
68
|
+
* when `keyboardBehavior='shift'` (no extra wiring needed — the whole sheet
|
|
69
|
+
* shifts). Typical use: action button rows.
|
|
70
|
+
*/
|
|
71
|
+
footer?: React.ReactNode;
|
|
72
|
+
/** Style applied to the header region wrapper. */
|
|
73
|
+
headerStyle?: StyleProp<ViewStyle>;
|
|
74
|
+
/** Style applied to the footer region wrapper. */
|
|
75
|
+
footerStyle?: StyleProp<ViewStyle>;
|
|
59
76
|
children?: React.ReactNode;
|
|
60
77
|
accessibilityLabel?: string;
|
|
61
78
|
accessibilityViewIsModal?: boolean;
|
|
@@ -66,6 +83,30 @@ export interface BottomSheetRef {
|
|
|
66
83
|
collapse: () => void;
|
|
67
84
|
close: () => void;
|
|
68
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* State + actions exposed to anything rendered inside a `<BottomSheet>` —
|
|
88
|
+
* including the `header` and `footer` slots. Read via `useBottomSheet()`.
|
|
89
|
+
*
|
|
90
|
+
* `snapIndex` is the JS-thread mirror of the current snap point. -1 means the
|
|
91
|
+
* sheet is closed (mid-close-animation included). Use it to drive footer
|
|
92
|
+
* button enable state, conditional headers, etc. If you need per-frame
|
|
93
|
+
* progress (e.g. fade a header in as the sheet expands), reach for the
|
|
94
|
+
* animated value via a future enhancement — not exposed today to keep the
|
|
95
|
+
* surface minimal.
|
|
96
|
+
*/
|
|
97
|
+
export interface BottomSheetContextValue {
|
|
98
|
+
snapIndex: number;
|
|
99
|
+
snapPoints: number[];
|
|
100
|
+
expand: (index?: number) => void;
|
|
101
|
+
collapse: () => void;
|
|
102
|
+
close: () => void;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Access the enclosing `<BottomSheet>`'s state and imperative actions.
|
|
106
|
+
* Must be called from a component rendered inside a `<BottomSheet>` (as
|
|
107
|
+
* `children`, `header`, or `footer`).
|
|
108
|
+
*/
|
|
109
|
+
export declare const useBottomSheet: () => BottomSheetContextValue;
|
|
69
110
|
declare const BottomSheet: React.ForwardRefExoticComponent<BottomSheetProps & React.RefAttributes<BottomSheetRef>>;
|
|
70
111
|
export { BottomSheet };
|
|
71
112
|
export default BottomSheet;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { BottomSheet, default } from './BottomSheet';
|
|
2
|
-
export type { BottomSheetProps, BottomSheetRef, SnapPoint } from './BottomSheet';
|
|
1
|
+
export { BottomSheet, default, useBottomSheet } from './BottomSheet';
|
|
2
|
+
export type { BottomSheetContextValue, BottomSheetProps, BottomSheetRef, SnapPoint } from './BottomSheet';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import type { StyleProp, ViewProps, ViewStyle } from 'react-native';
|
|
4
|
+
import type { ColorPalette, RadiusScale, SpacingScale, Theme } from '../../theme/types';
|
|
5
|
+
export type SpacingToken = keyof SpacingScale;
|
|
6
|
+
export type RadiusToken = keyof RadiusScale;
|
|
7
|
+
export type BackgroundToken = keyof ColorPalette['background'];
|
|
8
|
+
export interface BoxProps extends ViewProps {
|
|
9
|
+
/** padding (all sides) */
|
|
10
|
+
p?: SpacingToken;
|
|
11
|
+
/** paddingHorizontal */
|
|
12
|
+
px?: SpacingToken;
|
|
13
|
+
/** paddingVertical */
|
|
14
|
+
py?: SpacingToken;
|
|
15
|
+
pt?: SpacingToken;
|
|
16
|
+
pr?: SpacingToken;
|
|
17
|
+
pb?: SpacingToken;
|
|
18
|
+
pl?: SpacingToken;
|
|
19
|
+
/** margin (all sides) */
|
|
20
|
+
m?: SpacingToken;
|
|
21
|
+
mx?: SpacingToken;
|
|
22
|
+
my?: SpacingToken;
|
|
23
|
+
mt?: SpacingToken;
|
|
24
|
+
mr?: SpacingToken;
|
|
25
|
+
mb?: SpacingToken;
|
|
26
|
+
ml?: SpacingToken;
|
|
27
|
+
/** Flexbox gap between children (spacing token). */
|
|
28
|
+
gap?: SpacingToken;
|
|
29
|
+
/** Background — a `colors.background.*` token or a raw colour string. */
|
|
30
|
+
bg?: BackgroundToken | (string & {});
|
|
31
|
+
radius?: RadiusToken;
|
|
32
|
+
/** Draw a hairline border in `colors.border.primary`. */
|
|
33
|
+
border?: boolean;
|
|
34
|
+
flex?: number;
|
|
35
|
+
align?: ViewStyle['alignItems'];
|
|
36
|
+
justify?: ViewStyle['justifyContent'];
|
|
37
|
+
direction?: ViewStyle['flexDirection'];
|
|
38
|
+
wrap?: boolean;
|
|
39
|
+
style?: StyleProp<ViewStyle>;
|
|
40
|
+
}
|
|
41
|
+
type LayoutProps = Omit<BoxProps, 'style' | 'children'>;
|
|
42
|
+
export declare const resolveBoxStyle: (theme: Theme, p: LayoutProps) => ViewStyle;
|
|
43
|
+
declare const Box: React.ForwardRefExoticComponent<BoxProps & React.RefAttributes<View>>;
|
|
44
|
+
export type StackProps = Omit<BoxProps, 'direction'>;
|
|
45
|
+
/** Vertical flex container with token spacing between children (default gap `md`). */
|
|
46
|
+
declare const Stack: React.ForwardRefExoticComponent<StackProps & React.RefAttributes<View>>;
|
|
47
|
+
export type RowProps = Omit<BoxProps, 'direction'>;
|
|
48
|
+
/** Horizontal flex container (default `align="center"`, gap `sm`). */
|
|
49
|
+
declare const Row: React.ForwardRefExoticComponent<RowProps & React.RefAttributes<View>>;
|
|
50
|
+
export interface SpacerProps {
|
|
51
|
+
/** Fixed spacer of this spacing token. Omit for a flexible spacer (`flex: 1`). */
|
|
52
|
+
size?: SpacingToken;
|
|
53
|
+
style?: StyleProp<ViewStyle>;
|
|
54
|
+
testID?: string;
|
|
55
|
+
}
|
|
56
|
+
/** Fixed gap (`size`) or a flexible push (`flex: 1`) between siblings. */
|
|
57
|
+
declare const Spacer: React.FC<SpacerProps>;
|
|
58
|
+
export { Box, Stack, Row, Spacer };
|
|
59
|
+
export default Box;
|
|
60
|
+
//# sourceMappingURL=Box.d.ts.map
|
|
@@ -4,7 +4,7 @@ import type { PressableProps, StyleProp, TextStyle, ViewStyle } from 'react-nati
|
|
|
4
4
|
import type { GradientDefinition } from '../../theme/types';
|
|
5
5
|
import type { HapticType } from '../../utils/hapticUtils';
|
|
6
6
|
export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'link';
|
|
7
|
-
export type ButtonTone = 'primary' | 'secondary' | 'success' | 'warning' | '
|
|
7
|
+
export type ButtonTone = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'neutral';
|
|
8
8
|
export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
9
9
|
export interface ButtonProps extends Omit<PressableProps, 'style' | 'children'> {
|
|
10
10
|
title?: string;
|
|
@@ -5,8 +5,9 @@ import type { HapticType } from '../../utils/hapticUtils';
|
|
|
5
5
|
export type CheckboxSize = 'sm' | 'md' | 'lg';
|
|
6
6
|
export type CheckboxTone = 'primary' | 'success' | 'warning' | 'error';
|
|
7
7
|
export interface CheckboxProps extends Omit<PressableProps, 'style' | 'children' | 'onPress'> {
|
|
8
|
-
checked
|
|
9
|
-
|
|
8
|
+
checked?: boolean;
|
|
9
|
+
defaultChecked?: boolean;
|
|
10
|
+
onChange?: (checked: boolean) => void;
|
|
10
11
|
indeterminate?: boolean;
|
|
11
12
|
disabled?: boolean;
|
|
12
13
|
label?: string;
|
|
@@ -6,21 +6,21 @@ export type WeekStart = 0 | 1 | 6;
|
|
|
6
6
|
/**
|
|
7
7
|
* DatePicker operates in two modes:
|
|
8
8
|
*
|
|
9
|
-
* 1. **Controlled-modal mode** — pass `visible` (plus `
|
|
9
|
+
* 1. **Controlled-modal mode** — pass `visible` (plus `onChange` / `onClose`)
|
|
10
10
|
* and own the open state externally. The component renders only the modal.
|
|
11
11
|
* 2. **Trigger mode** — omit `visible`. The component renders a built-in
|
|
12
12
|
* PickerTrigger field (label / value / placeholder / chevron / clear /
|
|
13
13
|
* helper / error / size / variant) and manages its own open state. The
|
|
14
14
|
* field opens the modal on press and closes it on confirm/cancel.
|
|
15
15
|
*
|
|
16
|
-
* `
|
|
16
|
+
* `onChange` / `onClose` are typed optional to support trigger-only usage
|
|
17
17
|
* where the consumer may not need either callback. In controlled-modal mode
|
|
18
18
|
* they remain semantically required.
|
|
19
19
|
*/
|
|
20
20
|
export interface DatePickerProps {
|
|
21
21
|
visible?: boolean;
|
|
22
22
|
value?: Date | null;
|
|
23
|
-
|
|
23
|
+
onChange?: (date: Date) => void;
|
|
24
24
|
onClose?: () => void;
|
|
25
25
|
minDate?: Date;
|
|
26
26
|
maxDate?: Date;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
|
|
3
|
-
export type DialogVariant = 'default' | 'success' | 'warning' | '
|
|
4
|
-
export type DialogActionTone = 'primary' | 'neutral' | '
|
|
3
|
+
export type DialogVariant = 'default' | 'success' | 'warning' | 'error' | 'info';
|
|
4
|
+
export type DialogActionTone = 'primary' | 'neutral' | 'error';
|
|
5
5
|
export interface DialogAction {
|
|
6
6
|
label: string;
|
|
7
7
|
onPress: () => void;
|