@forthtilliath/react-native-kit 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -0
- package/dist/components/feedback/ErrorFallback.d.ts +63 -0
- package/dist/components/feedback/ErrorFallback.d.ts.map +1 -0
- package/dist/components/feedback/ErrorFallback.js +86 -0
- package/dist/components/feedback/index.d.ts +2 -0
- package/dist/components/feedback/index.d.ts.map +1 -0
- package/dist/components/feedback/index.js +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/list/AddButton.d.ts +27 -0
- package/dist/components/list/AddButton.d.ts.map +1 -0
- package/dist/components/list/AddButton.js +29 -0
- package/dist/components/list/DragHandle.d.ts +35 -0
- package/dist/components/list/DragHandle.d.ts.map +1 -0
- package/dist/components/list/DragHandle.js +31 -0
- package/dist/components/list/SwipeableRow.d.ts +18 -4
- package/dist/components/list/SwipeableRow.d.ts.map +1 -1
- package/dist/components/list/SwipeableRow.js +40 -13
- package/dist/components/list/index.d.ts +2 -0
- package/dist/components/list/index.d.ts.map +1 -1
- package/dist/components/list/index.js +2 -0
- package/dist/components/overlay/BottomSheet.d.ts +45 -0
- package/dist/components/overlay/BottomSheet.d.ts.map +1 -0
- package/dist/components/overlay/BottomSheet.js +48 -0
- package/dist/components/overlay/index.d.ts +2 -0
- package/dist/components/overlay/index.d.ts.map +1 -0
- package/dist/components/overlay/index.js +1 -0
- package/dist/components/picker/CheckboxGroup.d.ts +47 -0
- package/dist/components/picker/CheckboxGroup.d.ts.map +1 -0
- package/dist/components/picker/CheckboxGroup.js +50 -0
- package/dist/components/picker/MonthDayGrid.d.ts +58 -0
- package/dist/components/picker/MonthDayGrid.d.ts.map +1 -0
- package/dist/components/picker/MonthDayGrid.js +73 -0
- package/dist/components/picker/OptionsModal.d.ts +45 -0
- package/dist/components/picker/OptionsModal.d.ts.map +1 -0
- package/dist/components/picker/OptionsModal.js +45 -0
- package/dist/components/picker/QuantityStepper.d.ts +63 -0
- package/dist/components/picker/QuantityStepper.d.ts.map +1 -0
- package/dist/components/picker/QuantityStepper.js +101 -0
- package/dist/components/picker/SegmentedToggle.d.ts +52 -0
- package/dist/components/picker/SegmentedToggle.d.ts.map +1 -0
- package/dist/components/picker/SegmentedToggle.js +48 -0
- package/dist/components/picker/SelectField.d.ts +45 -0
- package/dist/components/picker/SelectField.d.ts.map +1 -0
- package/dist/components/picker/SelectField.js +54 -0
- package/dist/components/picker/index.d.ts +6 -0
- package/dist/components/picker/index.d.ts.map +1 -1
- package/dist/components/picker/index.js +6 -0
- package/dist/components/settings/SettingsCard.d.ts +63 -0
- package/dist/components/settings/SettingsCard.d.ts.map +1 -0
- package/dist/components/settings/SettingsCard.js +68 -0
- package/dist/components/settings/SwitchRow.d.ts +48 -0
- package/dist/components/settings/SwitchRow.d.ts.map +1 -0
- package/dist/components/settings/SwitchRow.js +44 -0
- package/dist/components/settings/index.d.ts +2 -0
- package/dist/components/settings/index.d.ts.map +1 -1
- package/dist/components/settings/index.js +2 -0
- package/dist/components/theme/ThemePreferenceProvider.d.ts +39 -0
- package/dist/components/theme/ThemePreferenceProvider.d.ts.map +1 -0
- package/dist/components/theme/ThemePreferenceProvider.js +53 -0
- package/dist/components/theme/index.d.ts +2 -0
- package/dist/components/theme/index.d.ts.map +1 -1
- package/dist/components/theme/index.js +2 -0
- package/dist/components/theme/themePreferenceContext.d.ts +20 -0
- package/dist/components/theme/themePreferenceContext.d.ts.map +1 -0
- package/dist/components/theme/themePreferenceContext.js +21 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -0
- package/dist/utils/calendar/index.d.ts +3 -0
- package/dist/utils/calendar/index.d.ts.map +1 -0
- package/dist/utils/calendar/index.js +2 -0
- package/dist/utils/calendar/syncDedicatedCalendar.d.ts +37 -0
- package/dist/utils/calendar/syncDedicatedCalendar.d.ts.map +1 -0
- package/dist/utils/calendar/syncDedicatedCalendar.js +42 -0
- package/dist/utils/calendar/toCalendarEventDetails.d.ts +32 -0
- package/dist/utils/calendar/toCalendarEventDetails.d.ts.map +1 -0
- package/dist/utils/calendar/toCalendarEventDetails.js +47 -0
- package/dist/utils/files/appFiles.d.ts +61 -0
- package/dist/utils/files/appFiles.d.ts.map +1 -0
- package/dist/utils/files/appFiles.js +126 -0
- package/dist/utils/files/imageThumbnail.d.ts +22 -0
- package/dist/utils/files/imageThumbnail.d.ts.map +1 -0
- package/dist/utils/files/imageThumbnail.js +28 -0
- package/dist/utils/files/index.d.ts +3 -0
- package/dist/utils/files/index.d.ts.map +1 -0
- package/dist/utils/files/index.js +2 -0
- package/dist/utils/helpers/haptics.d.ts +9 -0
- package/dist/utils/helpers/haptics.d.ts.map +1 -0
- package/dist/utils/helpers/haptics.js +28 -0
- package/dist/utils/helpers/index.d.ts +5 -0
- package/dist/utils/helpers/index.d.ts.map +1 -1
- package/dist/utils/helpers/index.js +5 -0
- package/dist/utils/helpers/isNativeModuleAvailable.d.ts +12 -0
- package/dist/utils/helpers/isNativeModuleAvailable.d.ts.map +1 -0
- package/dist/utils/helpers/isNativeModuleAvailable.js +15 -0
- package/dist/utils/helpers/shareFile.d.ts +23 -0
- package/dist/utils/helpers/shareFile.d.ts.map +1 -0
- package/dist/utils/helpers/shareFile.js +26 -0
- package/dist/utils/helpers/shareTextFile.d.ts +16 -0
- package/dist/utils/helpers/shareTextFile.d.ts.map +1 -0
- package/dist/utils/helpers/shareTextFile.js +23 -0
- package/dist/utils/helpers/shareViewAsImage.d.ts +21 -0
- package/dist/utils/helpers/shareViewAsImage.d.ts.map +1 -0
- package/dist/utils/helpers/shareViewAsImage.js +32 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/package.json +38 -6
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Modal, Pressable, ScrollView, View } from "react-native";
|
|
3
|
+
import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
|
|
4
|
+
const defaultStyles = {
|
|
5
|
+
overlay: {
|
|
6
|
+
flex: 1,
|
|
7
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
8
|
+
justifyContent: "flex-end",
|
|
9
|
+
},
|
|
10
|
+
sheet: {
|
|
11
|
+
backgroundColor: "#ffffff",
|
|
12
|
+
borderTopLeftRadius: 16,
|
|
13
|
+
borderTopRightRadius: 16,
|
|
14
|
+
paddingTop: 8,
|
|
15
|
+
paddingBottom: 24,
|
|
16
|
+
maxHeight: "85%",
|
|
17
|
+
},
|
|
18
|
+
// Without flexShrink the ScrollView takes its content's height, ignores the
|
|
19
|
+
// sheet's maxHeight, and the overflow is clipped instead of scrollable.
|
|
20
|
+
scroll: { flexShrink: 1 },
|
|
21
|
+
};
|
|
22
|
+
const backdropFill = {
|
|
23
|
+
position: "absolute",
|
|
24
|
+
top: 0,
|
|
25
|
+
right: 0,
|
|
26
|
+
bottom: 0,
|
|
27
|
+
left: 0,
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A modal panel sliding up from the bottom of the screen, its content
|
|
31
|
+
* scrollable past `maxHeight` — instead of inline content that shifts the
|
|
32
|
+
* layout. Tapping the backdrop or pressing back closes it.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* import { BottomSheet } from "@forthtilliath/react-native-kit/components/overlay/BottomSheet";
|
|
37
|
+
*
|
|
38
|
+
* const { bottom } = useSafeAreaInsets();
|
|
39
|
+
*
|
|
40
|
+
* <BottomSheet visible={open} onClose={() => setOpen(false)} bottomInset={bottom}>
|
|
41
|
+
* <DayDetails day={day} />
|
|
42
|
+
* </BottomSheet>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function BottomSheet({ visible, onClose, children, bottomInset = 0, styles, }) {
|
|
46
|
+
const merged = mergeSlotStyles(defaultStyles, styles);
|
|
47
|
+
return (_jsx(Modal, { visible: visible, transparent: true, animationType: "slide", onRequestClose: onClose, children: _jsxs(View, { style: merged.overlay, children: [_jsx(Pressable, { style: backdropFill, onPress: onClose }), _jsxs(View, { style: merged.sheet, children: [_jsx(ScrollView, { style: merged.scroll, children: children }), bottomInset > 0 && _jsx(View, { style: { height: bottomInset } })] })] }) }));
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/overlay/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./BottomSheet.js";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
2
|
+
/** Per-slot style overrides for {@link CheckboxGroup}, each merged after its default. */
|
|
3
|
+
export interface CheckboxGroupStyles {
|
|
4
|
+
/** The wrapping row holding the chips. */
|
|
5
|
+
row?: StyleProp<ViewStyle>;
|
|
6
|
+
/** Every chip. */
|
|
7
|
+
chip?: StyleProp<ViewStyle>;
|
|
8
|
+
/** Added on top of `chip` for the checked ones. */
|
|
9
|
+
chipChecked?: StyleProp<ViewStyle>;
|
|
10
|
+
/** Every chip's label. */
|
|
11
|
+
text?: StyleProp<TextStyle>;
|
|
12
|
+
/** Added on top of `text` for the checked ones. */
|
|
13
|
+
textChecked?: StyleProp<TextStyle>;
|
|
14
|
+
}
|
|
15
|
+
export interface CheckboxGroupOption<T extends string> {
|
|
16
|
+
value: T;
|
|
17
|
+
label: string;
|
|
18
|
+
}
|
|
19
|
+
export interface CheckboxGroupProps<T extends string> {
|
|
20
|
+
options: readonly CheckboxGroupOption<T>[];
|
|
21
|
+
/** The checked values, in the order they were checked. */
|
|
22
|
+
values: readonly T[];
|
|
23
|
+
/** Receives the new list: a tap adds the option at the end, or removes it. */
|
|
24
|
+
onChange: (values: T[]) => void;
|
|
25
|
+
/** What the choice is about, read by screen readers on the group. */
|
|
26
|
+
label?: string;
|
|
27
|
+
/** Per-slot style overrides — see {@link CheckboxGroupStyles}. */
|
|
28
|
+
styles?: CheckboxGroupStyles;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Chips that each check and uncheck independently (extensions, tags, days…),
|
|
32
|
+
* wrapping onto as many lines as needed. Each chip is announced as a checkbox.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* import { CheckboxGroup } from "@forthtilliath/react-native-kit/components/picker/CheckboxGroup";
|
|
37
|
+
*
|
|
38
|
+
* <CheckboxGroup
|
|
39
|
+
* label="Extensions"
|
|
40
|
+
* options={[{ value: "leaders", label: "Leaders" }, { value: "cities", label: "Cités" }]}
|
|
41
|
+
* values={extensions}
|
|
42
|
+
* onChange={setExtensions}
|
|
43
|
+
* />
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function CheckboxGroup<T extends string>({ options, values, onChange, label, styles, }: CheckboxGroupProps<T>): import("react").JSX.Element;
|
|
47
|
+
//# sourceMappingURL=CheckboxGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckboxGroup.d.ts","sourceRoot":"","sources":["../../../src/components/picker/CheckboxGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKpE,yFAAyF;AACzF,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3B,kBAAkB;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,mDAAmD;IACnD,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnC,0BAA0B;IAC1B,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,mDAAmD;IACnD,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM;IACnD,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,MAAM;IAClD,OAAO,EAAE,SAAS,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,0DAA0D;IAC1D,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAChC,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAuBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,EAC9C,OAAO,EACP,MAAM,EACN,QAAQ,EACR,KAAK,EACL,MAAM,GACP,EAAE,kBAAkB,CAAC,CAAC,CAAC,+BA8BvB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Pressable, Text, View } from "react-native";
|
|
3
|
+
import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
|
|
4
|
+
const defaultStyles = {
|
|
5
|
+
row: { flexDirection: "row", flexWrap: "wrap", gap: 8 },
|
|
6
|
+
chip: {
|
|
7
|
+
paddingVertical: 8,
|
|
8
|
+
paddingHorizontal: 12,
|
|
9
|
+
borderRadius: 999,
|
|
10
|
+
borderWidth: 1.5,
|
|
11
|
+
borderColor: "#d4d4d4",
|
|
12
|
+
},
|
|
13
|
+
chipChecked: {
|
|
14
|
+
backgroundColor: "#2563eb",
|
|
15
|
+
borderColor: "#2563eb",
|
|
16
|
+
},
|
|
17
|
+
text: {
|
|
18
|
+
fontSize: 13,
|
|
19
|
+
fontWeight: "600",
|
|
20
|
+
color: "#6b7280",
|
|
21
|
+
},
|
|
22
|
+
textChecked: { color: "#ffffff" },
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Chips that each check and uncheck independently (extensions, tags, days…),
|
|
26
|
+
* wrapping onto as many lines as needed. Each chip is announced as a checkbox.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* import { CheckboxGroup } from "@forthtilliath/react-native-kit/components/picker/CheckboxGroup";
|
|
31
|
+
*
|
|
32
|
+
* <CheckboxGroup
|
|
33
|
+
* label="Extensions"
|
|
34
|
+
* options={[{ value: "leaders", label: "Leaders" }, { value: "cities", label: "Cités" }]}
|
|
35
|
+
* values={extensions}
|
|
36
|
+
* onChange={setExtensions}
|
|
37
|
+
* />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function CheckboxGroup({ options, values, onChange, label, styles, }) {
|
|
41
|
+
const merged = mergeSlotStyles(defaultStyles, styles);
|
|
42
|
+
return (_jsx(View, { style: merged.row, accessibilityLabel: label, children: options.map((option) => {
|
|
43
|
+
const checked = values.includes(option.value);
|
|
44
|
+
return (_jsx(Pressable, { style: [merged.chip, checked && merged.chipChecked], accessibilityRole: "checkbox", accessibilityState: { checked }, accessibilityLabel: option.label, onPress: () => {
|
|
45
|
+
onChange(checked
|
|
46
|
+
? values.filter((v) => v !== option.value)
|
|
47
|
+
: [...values, option.value]);
|
|
48
|
+
}, children: _jsx(Text, { style: [merged.text, checked && merged.textChecked], children: option.label }) }, option.value));
|
|
49
|
+
}) }));
|
|
50
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
2
|
+
import { type KitLocale } from "../../i18n/locale.js";
|
|
3
|
+
/** Per-slot style overrides for {@link MonthDayGrid}, each merged after its default. */
|
|
4
|
+
export interface MonthDayGridStyles {
|
|
5
|
+
/** Wraps the weekday header row and the grid. */
|
|
6
|
+
container?: StyleProp<ViewStyle>;
|
|
7
|
+
/** The weekday header row. */
|
|
8
|
+
weekdayRow?: StyleProp<ViewStyle>;
|
|
9
|
+
/** Each weekday initial. */
|
|
10
|
+
weekdayText?: StyleProp<TextStyle>;
|
|
11
|
+
/** The wrapping grid of days. */
|
|
12
|
+
grid?: StyleProp<ViewStyle>;
|
|
13
|
+
/** One seventh of the width — headers, leading blanks, and days alike. */
|
|
14
|
+
cell?: StyleProp<ViewStyle>;
|
|
15
|
+
/** The round, tappable day. */
|
|
16
|
+
dayBox?: StyleProp<ViewStyle>;
|
|
17
|
+
/** Added on top of `dayBox` for a selected day. */
|
|
18
|
+
dayBoxSelected?: StyleProp<ViewStyle>;
|
|
19
|
+
/** The day number. */
|
|
20
|
+
dayText?: StyleProp<TextStyle>;
|
|
21
|
+
/** Added on top of `dayText` for a selected day. */
|
|
22
|
+
dayTextSelected?: StyleProp<TextStyle>;
|
|
23
|
+
}
|
|
24
|
+
export interface MonthDayGridProps {
|
|
25
|
+
/** The month's days in order, as `YYYY-MM-DD` dates. */
|
|
26
|
+
days: readonly string[];
|
|
27
|
+
/** The selected days, as `YYYY-MM-DD` dates. */
|
|
28
|
+
selected: ReadonlySet<string>;
|
|
29
|
+
/** Called with the tapped day; the host adds it to or removes it from `selected`. */
|
|
30
|
+
onToggle: (day: string) => void;
|
|
31
|
+
/** Seven column headers, Monday first. Defaults to the locale's initials. */
|
|
32
|
+
weekdayLabels?: readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* Language of the default `weekdayLabels` — French by default, or the
|
|
35
|
+
* nearest `KitLocaleProvider`'s.
|
|
36
|
+
*/
|
|
37
|
+
locale?: KitLocale;
|
|
38
|
+
/** Per-slot style overrides — see {@link MonthDayGridStyles}. */
|
|
39
|
+
styles?: MonthDayGridStyles;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A Monday-first month calendar where days are toggled on and off — public
|
|
43
|
+
* holidays, days off, availability… The first day is offset under its
|
|
44
|
+
* weekday column; the selection itself lives in the host.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* import { MonthDayGrid } from "@forthtilliath/react-native-kit/components/picker/MonthDayGrid";
|
|
49
|
+
*
|
|
50
|
+
* <MonthDayGrid
|
|
51
|
+
* days={daysOfMonth}
|
|
52
|
+
* selected={holidays}
|
|
53
|
+
* onToggle={(day) => setHolidays((prev) => toggleInSet(prev, day))}
|
|
54
|
+
* />
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function MonthDayGrid({ days, selected, onToggle, weekdayLabels, locale, styles, }: MonthDayGridProps): import("react").JSX.Element;
|
|
58
|
+
//# sourceMappingURL=MonthDayGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MonthDayGrid.d.ts","sourceRoot":"","sources":["../../../src/components/picker/MonthDayGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAMpE,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AAGpE,wFAAwF;AACxF,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,8BAA8B;IAC9B,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,4BAA4B;IAC5B,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnC,iCAAiC;IACjC,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,0EAA0E;IAC1E,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,mDAAmD;IACnD,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,sBAAsB;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,oDAAoD;IACpD,eAAe,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,qFAAqF;IACrF,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,iEAAiE;IACjE,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAuCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,MAAM,EACN,MAAM,GACP,EAAE,iBAAiB,+BA8CnB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Pressable, Text, View } from "react-native";
|
|
3
|
+
import { mondayFirstWeekday } from "@forthtilliath/ts-kit/date/mondayFirstWeekday";
|
|
4
|
+
import { parseIsoDate } from "@forthtilliath/ts-kit/date/parseIsoDate";
|
|
5
|
+
import { useKitLocale } from "../../i18n/locale.js";
|
|
6
|
+
import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
|
|
7
|
+
const defaultWeekdayLabels = {
|
|
8
|
+
fr: ["L", "M", "M", "J", "V", "S", "D"],
|
|
9
|
+
en: ["M", "T", "W", "T", "F", "S", "S"],
|
|
10
|
+
};
|
|
11
|
+
const defaultStyles = {
|
|
12
|
+
container: {},
|
|
13
|
+
weekdayRow: { flexDirection: "row" },
|
|
14
|
+
weekdayText: {
|
|
15
|
+
fontSize: 11,
|
|
16
|
+
fontWeight: "700",
|
|
17
|
+
opacity: 0.6,
|
|
18
|
+
color: "#111111",
|
|
19
|
+
},
|
|
20
|
+
grid: { flexDirection: "row", flexWrap: "wrap" },
|
|
21
|
+
cell: {
|
|
22
|
+
width: "14.28%",
|
|
23
|
+
alignItems: "center",
|
|
24
|
+
paddingVertical: 2,
|
|
25
|
+
},
|
|
26
|
+
dayBox: {
|
|
27
|
+
width: 32,
|
|
28
|
+
height: 32,
|
|
29
|
+
borderRadius: 16,
|
|
30
|
+
borderWidth: 1,
|
|
31
|
+
borderColor: "#d4d4d4",
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
},
|
|
35
|
+
dayBoxSelected: {
|
|
36
|
+
backgroundColor: "#dc2626",
|
|
37
|
+
borderColor: "#dc2626",
|
|
38
|
+
},
|
|
39
|
+
dayText: { fontSize: 12, color: "#111111" },
|
|
40
|
+
dayTextSelected: { color: "#ffffff", fontWeight: "700" },
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* A Monday-first month calendar where days are toggled on and off — public
|
|
44
|
+
* holidays, days off, availability… The first day is offset under its
|
|
45
|
+
* weekday column; the selection itself lives in the host.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* import { MonthDayGrid } from "@forthtilliath/react-native-kit/components/picker/MonthDayGrid";
|
|
50
|
+
*
|
|
51
|
+
* <MonthDayGrid
|
|
52
|
+
* days={daysOfMonth}
|
|
53
|
+
* selected={holidays}
|
|
54
|
+
* onToggle={(day) => setHolidays((prev) => toggleInSet(prev, day))}
|
|
55
|
+
* />
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function MonthDayGrid({ days, selected, onToggle, weekdayLabels, locale, styles, }) {
|
|
59
|
+
const resolvedLocale = useKitLocale(locale);
|
|
60
|
+
const headers = weekdayLabels ?? defaultWeekdayLabels[resolvedLocale];
|
|
61
|
+
const merged = mergeSlotStyles(defaultStyles, styles);
|
|
62
|
+
const firstDay = days[0];
|
|
63
|
+
const leadingBlanks = firstDay ? mondayFirstWeekday(firstDay) : 0;
|
|
64
|
+
return (_jsxs(View, { style: merged.container, children: [_jsx(View, { style: merged.weekdayRow, children: headers.map((header, i) => (
|
|
65
|
+
// Initials repeat (M, M / S, S): the column index is the identity.
|
|
66
|
+
// eslint-disable-next-line @eslint-react/no-array-index-key
|
|
67
|
+
_jsx(View, { style: merged.cell, children: _jsx(Text, { style: merged.weekdayText, children: header }) }, i))) }), _jsxs(View, { style: merged.grid, children: [Array.from({ length: leadingBlanks }, (_, i) => (_jsx(View, { style: merged.cell }, `blank-${String(i)}`))), days.map((day) => {
|
|
68
|
+
const isSelected = selected.has(day);
|
|
69
|
+
return (_jsx(View, { style: merged.cell, children: _jsx(Pressable, { style: [merged.dayBox, isSelected && merged.dayBoxSelected], accessibilityRole: "checkbox", accessibilityState: { checked: isSelected }, onPress: () => {
|
|
70
|
+
onToggle(day);
|
|
71
|
+
}, children: _jsx(Text, { style: [merged.dayText, isSelected && merged.dayTextSelected], children: parseIsoDate(day).getDate() }) }) }, day));
|
|
72
|
+
})] })] }));
|
|
73
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
2
|
+
/** One choice of an {@link OptionsModal} or a `SelectField`. */
|
|
3
|
+
export interface SelectOption<T extends string | number> {
|
|
4
|
+
value: T;
|
|
5
|
+
label: string;
|
|
6
|
+
}
|
|
7
|
+
/** Per-slot style overrides for {@link OptionsModal}, each merged after its default. */
|
|
8
|
+
export interface OptionsModalStyles {
|
|
9
|
+
/** The dimmed full-screen backdrop centering the card; tapping it closes. */
|
|
10
|
+
overlay?: StyleProp<ViewStyle>;
|
|
11
|
+
/** The card holding the scrollable list. */
|
|
12
|
+
card?: StyleProp<ViewStyle>;
|
|
13
|
+
/** Each option row. */
|
|
14
|
+
option?: StyleProp<ViewStyle>;
|
|
15
|
+
/** Each option's label. */
|
|
16
|
+
optionText?: StyleProp<TextStyle>;
|
|
17
|
+
}
|
|
18
|
+
export interface OptionsModalProps<T extends string | number> {
|
|
19
|
+
visible: boolean;
|
|
20
|
+
/** Called on a backdrop tap, on Android's back button, and after a choice. */
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
options: readonly SelectOption<T>[];
|
|
23
|
+
onSelect: (value: T) => void;
|
|
24
|
+
/** Per-slot style overrides — see {@link OptionsModalStyles}. */
|
|
25
|
+
styles?: OptionsModalStyles;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A centered popup listing options in a scrollable card: tapping one selects
|
|
29
|
+
* it and closes the popup. The building block of `SelectField`, usable on
|
|
30
|
+
* its own behind any custom trigger.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* import { OptionsModal } from "@forthtilliath/react-native-kit/components/picker/OptionsModal";
|
|
35
|
+
*
|
|
36
|
+
* <OptionsModal
|
|
37
|
+
* visible={open}
|
|
38
|
+
* onClose={() => setOpen(false)}
|
|
39
|
+
* options={[{ value: "a", label: "Option A" }, { value: "b", label: "Option B" }]}
|
|
40
|
+
* onSelect={setChoice}
|
|
41
|
+
* />
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function OptionsModal<T extends string | number>({ visible, onClose, options, onSelect, styles, }: OptionsModalProps<T>): import("react").JSX.Element;
|
|
45
|
+
//# sourceMappingURL=OptionsModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OptionsModal.d.ts","sourceRoot":"","sources":["../../../src/components/picker/OptionsModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKpE,gEAAgE;AAChE,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACrD,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wFAAwF;AACxF,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,uBAAuB;IACvB,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,2BAA2B;IAC3B,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,iEAAiE;IACjE,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAqBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,EACtD,OAAO,EACP,OAAO,EACP,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BA+BtB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Modal, Pressable, ScrollView, Text, View } from "react-native";
|
|
3
|
+
import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
|
|
4
|
+
const defaultStyles = {
|
|
5
|
+
overlay: {
|
|
6
|
+
flex: 1,
|
|
7
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
8
|
+
alignItems: "center",
|
|
9
|
+
justifyContent: "center",
|
|
10
|
+
padding: 24,
|
|
11
|
+
},
|
|
12
|
+
card: {
|
|
13
|
+
width: "100%",
|
|
14
|
+
maxHeight: "70%",
|
|
15
|
+
backgroundColor: "#ffffff",
|
|
16
|
+
borderRadius: 12,
|
|
17
|
+
paddingVertical: 8,
|
|
18
|
+
},
|
|
19
|
+
option: { paddingVertical: 14, paddingHorizontal: 20 },
|
|
20
|
+
optionText: { fontSize: 16, color: "#111111" },
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A centered popup listing options in a scrollable card: tapping one selects
|
|
24
|
+
* it and closes the popup. The building block of `SelectField`, usable on
|
|
25
|
+
* its own behind any custom trigger.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import { OptionsModal } from "@forthtilliath/react-native-kit/components/picker/OptionsModal";
|
|
30
|
+
*
|
|
31
|
+
* <OptionsModal
|
|
32
|
+
* visible={open}
|
|
33
|
+
* onClose={() => setOpen(false)}
|
|
34
|
+
* options={[{ value: "a", label: "Option A" }, { value: "b", label: "Option B" }]}
|
|
35
|
+
* onSelect={setChoice}
|
|
36
|
+
* />
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function OptionsModal({ visible, onClose, options, onSelect, styles, }) {
|
|
40
|
+
const merged = mergeSlotStyles(defaultStyles, styles);
|
|
41
|
+
return (_jsx(Modal, { visible: visible, transparent: true, animationType: "fade", onRequestClose: onClose, children: _jsx(Pressable, { style: merged.overlay, onPress: onClose, children: _jsx(View, { style: merged.card, children: _jsx(ScrollView, { children: options.map((option) => (_jsx(Pressable, { style: merged.option, accessibilityRole: "button", onPress: () => {
|
|
42
|
+
onSelect(option.value);
|
|
43
|
+
onClose();
|
|
44
|
+
}, children: _jsx(Text, { style: merged.optionText, children: option.label }) }, option.value))) }) }) }) }));
|
|
45
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
2
|
+
import { type KitLocale } from "../../i18n/locale.js";
|
|
3
|
+
/** Per-slot style overrides for {@link QuantityStepper}, each merged after its default. */
|
|
4
|
+
export interface QuantityStepperStyles {
|
|
5
|
+
/** The row: − button, field, + button. */
|
|
6
|
+
row?: StyleProp<ViewStyle>;
|
|
7
|
+
/** Both round buttons. */
|
|
8
|
+
button?: StyleProp<ViewStyle>;
|
|
9
|
+
/** Added on top of `button` for "−" at `min` and "+" at `max`. */
|
|
10
|
+
buttonDisabled?: StyleProp<ViewStyle>;
|
|
11
|
+
/** The "−" / "+" glyphs. */
|
|
12
|
+
buttonText?: StyleProp<TextStyle>;
|
|
13
|
+
/** The numeric field in the middle (its text color included). */
|
|
14
|
+
input?: StyleProp<TextStyle>;
|
|
15
|
+
}
|
|
16
|
+
/** Screen-reader labels of the three controls, built from the stepper's `label`. */
|
|
17
|
+
export interface QuantityStepperA11yLabels {
|
|
18
|
+
decrease: (label: string) => string;
|
|
19
|
+
increase: (label: string) => string;
|
|
20
|
+
input: (label: string) => string;
|
|
21
|
+
}
|
|
22
|
+
export interface QuantityStepperProps {
|
|
23
|
+
value: number;
|
|
24
|
+
/** Receives the new value, already clamped to `min…max`. */
|
|
25
|
+
onChange: (value: number) => void;
|
|
26
|
+
/** What is being counted — used in the screen-reader labels. */
|
|
27
|
+
label: string;
|
|
28
|
+
/** @defaultValue 0 */
|
|
29
|
+
min?: number;
|
|
30
|
+
/** @defaultValue 999 */
|
|
31
|
+
max?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Step applied by a long press on −/+, to reach large values quickly.
|
|
34
|
+
* Unset, a long press does nothing more than a tap.
|
|
35
|
+
*/
|
|
36
|
+
longPressStep?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Language of the default screen-reader labels — French by default, or the
|
|
39
|
+
* nearest `KitLocaleProvider`'s.
|
|
40
|
+
*/
|
|
41
|
+
locale?: KitLocale;
|
|
42
|
+
/** Overrides some or all of the screen-reader labels. */
|
|
43
|
+
a11yLabels?: Partial<QuantityStepperA11yLabels>;
|
|
44
|
+
/** Per-slot style overrides — see {@link QuantityStepperStyles}. */
|
|
45
|
+
styles?: QuantityStepperStyles;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A whole-number counter from `min` (0) to `max`: −/+ buttons to adjust
|
|
49
|
+
* (optionally faster on long press), and a numeric field in the middle to
|
|
50
|
+
* type a large number in one go (non-digits are dropped, the result is
|
|
51
|
+
* clamped). A typed value below `min` (an empty field, the "2" of "25" with
|
|
52
|
+
* `min={10}`) stays as typed until the field loses focus.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* import { QuantityStepper } from "@forthtilliath/react-native-kit/components/picker/QuantityStepper";
|
|
57
|
+
*
|
|
58
|
+
* <QuantityStepper value={count} onChange={setCount} label="Croissants" />
|
|
59
|
+
* <QuantityStepper value={bans} onChange={setBans} label="Bannissements" min={1} max={40} longPressStep={5} />
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function QuantityStepper({ value, onChange, label, min, max, longPressStep, locale, a11yLabels, styles, }: QuantityStepperProps): import("react").JSX.Element;
|
|
63
|
+
//# sourceMappingURL=QuantityStepper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuantityStepper.d.ts","sourceRoot":"","sources":["../../../src/components/picker/QuantityStepper.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGpE,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AAGpE,2FAA2F;AAC3F,MAAM,WAAW,qBAAqB;IACpC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3B,0BAA0B;IAC1B,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,kEAAkE;IAClE,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,4BAA4B;IAC5B,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,iEAAiE;IACjE,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,oFAAoF;AACpF,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAChD,oEAAoE;IACpE,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAkDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,GAAO,EACP,GAAS,EACT,aAAa,EACb,MAAM,EACN,UAAU,EACV,MAAM,GACP,EAAE,oBAAoB,+BAwEtB"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Pressable, Text, TextInput, View } from "react-native";
|
|
4
|
+
import { useKitLocale } from "../../i18n/locale.js";
|
|
5
|
+
import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
|
|
6
|
+
const defaultA11yLabels = {
|
|
7
|
+
fr: {
|
|
8
|
+
decrease: (label) => `Retirer : ${label}`,
|
|
9
|
+
increase: (label) => `Ajouter : ${label}`,
|
|
10
|
+
input: (label) => `Quantité : ${label}`,
|
|
11
|
+
},
|
|
12
|
+
en: {
|
|
13
|
+
decrease: (label) => `Decrease: ${label}`,
|
|
14
|
+
increase: (label) => `Increase: ${label}`,
|
|
15
|
+
input: (label) => `Quantity: ${label}`,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
const defaultStyles = {
|
|
19
|
+
row: {
|
|
20
|
+
flexDirection: "row",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
gap: 6,
|
|
23
|
+
},
|
|
24
|
+
button: {
|
|
25
|
+
width: 40,
|
|
26
|
+
height: 40,
|
|
27
|
+
borderRadius: 20,
|
|
28
|
+
backgroundColor: "#2563eb",
|
|
29
|
+
alignItems: "center",
|
|
30
|
+
justifyContent: "center",
|
|
31
|
+
},
|
|
32
|
+
buttonDisabled: { opacity: 0.35 },
|
|
33
|
+
buttonText: {
|
|
34
|
+
color: "#ffffff",
|
|
35
|
+
fontSize: 22,
|
|
36
|
+
fontWeight: "700",
|
|
37
|
+
lineHeight: 26,
|
|
38
|
+
},
|
|
39
|
+
input: {
|
|
40
|
+
width: 52,
|
|
41
|
+
height: 40,
|
|
42
|
+
borderRadius: 8,
|
|
43
|
+
borderWidth: 1,
|
|
44
|
+
borderColor: "#d4d4d4",
|
|
45
|
+
color: "#111111",
|
|
46
|
+
fontSize: 18,
|
|
47
|
+
fontWeight: "700",
|
|
48
|
+
textAlign: "center",
|
|
49
|
+
padding: 0,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* A whole-number counter from `min` (0) to `max`: −/+ buttons to adjust
|
|
54
|
+
* (optionally faster on long press), and a numeric field in the middle to
|
|
55
|
+
* type a large number in one go (non-digits are dropped, the result is
|
|
56
|
+
* clamped). A typed value below `min` (an empty field, the "2" of "25" with
|
|
57
|
+
* `min={10}`) stays as typed until the field loses focus.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { QuantityStepper } from "@forthtilliath/react-native-kit/components/picker/QuantityStepper";
|
|
62
|
+
*
|
|
63
|
+
* <QuantityStepper value={count} onChange={setCount} label="Croissants" />
|
|
64
|
+
* <QuantityStepper value={bans} onChange={setBans} label="Bannissements" min={1} max={40} longPressStep={5} />
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export function QuantityStepper({ value, onChange, label, min = 0, max = 999, longPressStep, locale, a11yLabels, styles, }) {
|
|
68
|
+
const labels = { ...defaultA11yLabels[useKitLocale(locale)], ...a11yLabels };
|
|
69
|
+
const merged = mergeSlotStyles(defaultStyles, styles);
|
|
70
|
+
const atMin = value <= min;
|
|
71
|
+
const atMax = value >= max;
|
|
72
|
+
// Field text not sent yet: clamping it to `min` on every keystroke would
|
|
73
|
+
// make any number starting below `min` impossible to type.
|
|
74
|
+
const [draft, setDraft] = useState(null);
|
|
75
|
+
function set(next) {
|
|
76
|
+
setDraft(null);
|
|
77
|
+
onChange(Math.min(max, Math.max(min, next)));
|
|
78
|
+
}
|
|
79
|
+
return (_jsxs(View, { style: merged.row, children: [_jsx(Pressable, { style: [merged.button, atMin && merged.buttonDisabled], onPress: () => {
|
|
80
|
+
set(value - 1);
|
|
81
|
+
}, onLongPress: longPressStep === undefined
|
|
82
|
+
? undefined
|
|
83
|
+
: () => {
|
|
84
|
+
set(value - longPressStep);
|
|
85
|
+
}, disabled: atMin, hitSlop: 6, accessibilityRole: "button", accessibilityLabel: labels.decrease(label), children: _jsx(Text, { style: merged.buttonText, children: "\u2212" }) }), _jsx(TextInput, { style: merged.input, value: draft ?? String(value), onChangeText: (text) => {
|
|
86
|
+
const digits = text.replace(/\D/g, "");
|
|
87
|
+
if (digits === "" || Number(digits) < min)
|
|
88
|
+
setDraft(digits);
|
|
89
|
+
else
|
|
90
|
+
set(Number(digits));
|
|
91
|
+
}, onBlur: () => {
|
|
92
|
+
if (draft !== null)
|
|
93
|
+
set(draft === "" ? min : Number(draft));
|
|
94
|
+
}, keyboardType: "number-pad", selectTextOnFocus: true, maxLength: String(max).length, accessibilityLabel: labels.input(label) }), _jsx(Pressable, { style: [merged.button, atMax && merged.buttonDisabled], onPress: () => {
|
|
95
|
+
set(value + 1);
|
|
96
|
+
}, onLongPress: longPressStep === undefined
|
|
97
|
+
? undefined
|
|
98
|
+
: () => {
|
|
99
|
+
set(value + longPressStep);
|
|
100
|
+
}, disabled: atMax, hitSlop: 6, accessibilityRole: "button", accessibilityLabel: labels.increase(label), children: _jsx(Text, { style: merged.buttonText, children: "+" }) })] }));
|
|
101
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
2
|
+
/** Per-slot style overrides for {@link SegmentedToggle}, each merged after its default. */
|
|
3
|
+
export interface SegmentedToggleStyles {
|
|
4
|
+
/** The row holding the buttons. */
|
|
5
|
+
row?: StyleProp<ViewStyle>;
|
|
6
|
+
/** Every button (equal widths through `flex: 1`). */
|
|
7
|
+
button?: StyleProp<ViewStyle>;
|
|
8
|
+
/** Added on top of `button` for the active one. */
|
|
9
|
+
buttonActive?: StyleProp<ViewStyle>;
|
|
10
|
+
/** Every button's label. */
|
|
11
|
+
text?: StyleProp<TextStyle>;
|
|
12
|
+
/** Added on top of `text` for the active one. */
|
|
13
|
+
textActive?: StyleProp<TextStyle>;
|
|
14
|
+
/** Every option's `hint` line. */
|
|
15
|
+
hint?: StyleProp<TextStyle>;
|
|
16
|
+
/** Added on top of `hint` for the active one. */
|
|
17
|
+
hintActive?: StyleProp<TextStyle>;
|
|
18
|
+
}
|
|
19
|
+
export interface SegmentedToggleOption<T extends string> {
|
|
20
|
+
value: T;
|
|
21
|
+
label: string;
|
|
22
|
+
/** A smaller line under the label (e.g. "2 × 2 joueurs"). */
|
|
23
|
+
hint?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface SegmentedToggleProps<T extends string> {
|
|
26
|
+
options: readonly SegmentedToggleOption<T>[];
|
|
27
|
+
/** The active option's value. */
|
|
28
|
+
value: T;
|
|
29
|
+
onChange: (value: T) => void;
|
|
30
|
+
/** What the choice is about, read by screen readers on the group. */
|
|
31
|
+
label?: string;
|
|
32
|
+
/** Per-slot style overrides — see {@link SegmentedToggleStyles}. */
|
|
33
|
+
styles?: SegmentedToggleStyles;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A row of equal-width buttons of which exactly one is active — a view
|
|
37
|
+
* switch such as Calendar / List. Announced as a radio group.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* import { SegmentedToggle } from "@forthtilliath/react-native-kit/components/picker/SegmentedToggle";
|
|
42
|
+
*
|
|
43
|
+
* <SegmentedToggle
|
|
44
|
+
* label="Affichage"
|
|
45
|
+
* options={[{ value: "calendar", label: "Calendrier" }, { value: "list", label: "Liste" }]}
|
|
46
|
+
* value={view}
|
|
47
|
+
* onChange={setView}
|
|
48
|
+
* />
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function SegmentedToggle<T extends string>({ options, value, onChange, label, styles, }: SegmentedToggleProps<T>): import("react").JSX.Element;
|
|
52
|
+
//# sourceMappingURL=SegmentedToggle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SegmentedToggle.d.ts","sourceRoot":"","sources":["../../../src/components/picker/SegmentedToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKpE,2FAA2F;AAC3F,MAAM,WAAW,qBAAqB;IACpC,mCAAmC;IACnC,GAAG,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3B,qDAAqD;IACrD,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,mDAAmD;IACnD,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,4BAA4B;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,iDAAiD;IACjD,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,kCAAkC;IAClC,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,iDAAiD;IACjD,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,MAAM;IACrD,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,MAAM;IACpD,OAAO,EAAE,SAAS,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7C,iCAAiC;IACjC,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAuBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,EAChD,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAK,EACL,MAAM,GACP,EAAE,oBAAoB,CAAC,CAAC,CAAC,+BAqCzB"}
|