@forthtilliath/react-native-kit 0.18.0 → 0.20.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 +60 -16
- package/dist/components/picker/PhotoPicker.d.ts +22 -29
- package/dist/components/picker/PhotoPicker.d.ts.map +1 -1
- package/dist/components/picker/PhotoPicker.js +49 -81
- package/dist/components/picker/PhotoPicker.styles.d.ts +63 -0
- package/dist/components/picker/PhotoPicker.styles.d.ts.map +1 -0
- package/dist/components/picker/PhotoPicker.styles.js +59 -0
- package/dist/components/picker/QuantityStepper.d.ts +32 -31
- package/dist/components/picker/QuantityStepper.d.ts.map +1 -1
- package/dist/components/picker/QuantityStepper.js +39 -69
- package/dist/components/picker/QuantityStepper.styles.d.ts +59 -0
- package/dist/components/picker/QuantityStepper.styles.d.ts.map +1 -0
- package/dist/components/picker/QuantityStepper.styles.js +46 -0
- package/dist/components/settings/UpdateSettingsScreen.d.ts +5 -1
- package/dist/components/settings/UpdateSettingsScreen.d.ts.map +1 -1
- package/dist/components/settings/UpdateSettingsScreen.js +3 -3
- package/dist/components/settings/UpdateSettingsScreen.styles.d.ts +2 -0
- package/dist/components/settings/UpdateSettingsScreen.styles.d.ts.map +1 -1
- package/dist/components/theme/BackgroundPicker.d.ts +46 -0
- package/dist/components/theme/BackgroundPicker.d.ts.map +1 -0
- package/dist/components/theme/BackgroundPicker.js +79 -0
- package/dist/components/theme/findBackground.d.ts +20 -0
- package/dist/components/theme/findBackground.d.ts.map +1 -0
- package/dist/components/theme/findBackground.js +12 -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/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useViewShare.d.ts +39 -0
- package/dist/hooks/useViewShare.d.ts.map +1 -0
- package/dist/hooks/useViewShare.js +75 -0
- package/dist/utils/helpers/shareViewAsImage.d.ts +5 -3
- package/dist/utils/helpers/shareViewAsImage.d.ts.map +1 -1
- package/dist/utils/helpers/shareViewAsImage.js +3 -1
- package/package.json +8 -8
|
@@ -4,52 +4,7 @@ import { Pressable, Text, TextInput, View } from "react-native";
|
|
|
4
4
|
import { usePressRepeat } from "../../hooks/usePressRepeat.js";
|
|
5
5
|
import { useKitLocale } from "../../i18n/locale.js";
|
|
6
6
|
import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
|
|
7
|
-
|
|
8
|
-
fr: {
|
|
9
|
-
decrease: (label) => `Retirer : ${label}`,
|
|
10
|
-
increase: (label) => `Ajouter : ${label}`,
|
|
11
|
-
input: (label) => `Quantité : ${label}`,
|
|
12
|
-
},
|
|
13
|
-
en: {
|
|
14
|
-
decrease: (label) => `Decrease: ${label}`,
|
|
15
|
-
increase: (label) => `Increase: ${label}`,
|
|
16
|
-
input: (label) => `Quantity: ${label}`,
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
const defaultStyles = {
|
|
20
|
-
row: {
|
|
21
|
-
flexDirection: "row",
|
|
22
|
-
alignItems: "center",
|
|
23
|
-
gap: 6,
|
|
24
|
-
},
|
|
25
|
-
button: {
|
|
26
|
-
width: 40,
|
|
27
|
-
height: 40,
|
|
28
|
-
borderRadius: 20,
|
|
29
|
-
backgroundColor: "#2563eb",
|
|
30
|
-
alignItems: "center",
|
|
31
|
-
justifyContent: "center",
|
|
32
|
-
},
|
|
33
|
-
buttonDisabled: { opacity: 0.35 },
|
|
34
|
-
buttonText: {
|
|
35
|
-
color: "#ffffff",
|
|
36
|
-
fontSize: 22,
|
|
37
|
-
fontWeight: "700",
|
|
38
|
-
lineHeight: 26,
|
|
39
|
-
},
|
|
40
|
-
input: {
|
|
41
|
-
width: 52,
|
|
42
|
-
height: 40,
|
|
43
|
-
borderRadius: 8,
|
|
44
|
-
borderWidth: 1,
|
|
45
|
-
borderColor: "#d4d4d4",
|
|
46
|
-
color: "#111111",
|
|
47
|
-
fontSize: 18,
|
|
48
|
-
fontWeight: "700",
|
|
49
|
-
textAlign: "center",
|
|
50
|
-
padding: 0,
|
|
51
|
-
},
|
|
52
|
-
};
|
|
7
|
+
import { defaultA11yLabels, defaultStyles, } from "./QuantityStepper.styles.js";
|
|
53
8
|
/** Keeps the digits, and a leading "-" when negatives are allowed. */
|
|
54
9
|
function sanitize(text, allowsNegative) {
|
|
55
10
|
const digits = text.replace(/\D/g, "");
|
|
@@ -57,14 +12,21 @@ function sanitize(text, allowsNegative) {
|
|
|
57
12
|
? `-${digits}`
|
|
58
13
|
: digits;
|
|
59
14
|
}
|
|
15
|
+
/** Characters a bound takes in the field; 15 digits (+ "-") if unbounded. */
|
|
16
|
+
function lengthOf(bound) {
|
|
17
|
+
if (Number.isFinite(bound))
|
|
18
|
+
return String(bound).length;
|
|
19
|
+
return bound < 0 ? 16 : 15;
|
|
20
|
+
}
|
|
60
21
|
/**
|
|
61
|
-
* A whole-number counter from `min` (0) to `max`: −/+ buttons to adjust
|
|
62
|
-
* (optionally faster on long press, or repeating while held), and a
|
|
63
|
-
* field in the middle to type a large number in one go (other
|
|
64
|
-
* dropped, the result is clamped). A typed value that is not a
|
|
65
|
-
* below `min` (an empty field, a lone "-", the "2" of "25" with
|
|
66
|
-
* stays as typed until the field loses focus. A negative `min`
|
|
67
|
-
* negative values (penalties, defeat tokens…)
|
|
22
|
+
* A whole-number counter from `min` (0) to `max`: −/+ buttons to adjust by
|
|
23
|
+
* `step` (optionally faster on long press, or repeating while held), and a
|
|
24
|
+
* numeric field in the middle to type a large number in one go (other
|
|
25
|
+
* characters are dropped, the result is clamped). A typed value that is not a
|
|
26
|
+
* number yet or below `min` (an empty field, a lone "-", the "2" of "25" with
|
|
27
|
+
* `min={10}`) stays as typed until the field loses focus. A negative `min`
|
|
28
|
+
* allows negative values (penalties, defeat tokens…); `-Infinity`/`Infinity`
|
|
29
|
+
* remove a bound.
|
|
68
30
|
*
|
|
69
31
|
* @example
|
|
70
32
|
* ```tsx
|
|
@@ -72,10 +34,10 @@ function sanitize(text, allowsNegative) {
|
|
|
72
34
|
*
|
|
73
35
|
* <QuantityStepper value={count} onChange={setCount} label="Croissants" />
|
|
74
36
|
* <QuantityStepper value={bans} onChange={setBans} label="Bannissements" min={1} max={40} longPressStep={5} />
|
|
75
|
-
* <QuantityStepper value={score} onChange={setScore} label="Points" min={-
|
|
37
|
+
* <QuantityStepper value={score} onChange={setScore} label="Points" min={-Infinity} max={Infinity} step={4} repeatOnHold onStep={tapFeedback} />
|
|
76
38
|
* ```
|
|
77
39
|
*/
|
|
78
|
-
export function QuantityStepper({ value, onChange, label, min = 0, max = 999, longPressStep, repeatOnHold = false, locale, a11yLabels, styles, }) {
|
|
40
|
+
export function QuantityStepper({ value, onChange, label, min = 0, max = 999, step = 1, onStep, longPressStep, repeatOnHold = false, maxFontSizeMultiplier, locale, a11yLabels, styles, }) {
|
|
79
41
|
const labels = { ...defaultA11yLabels[useKitLocale(locale)], ...a11yLabels };
|
|
80
42
|
const merged = mergeSlotStyles(defaultStyles, styles);
|
|
81
43
|
const atMin = value <= min;
|
|
@@ -96,38 +58,46 @@ export function QuantityStepper({ value, onChange, label, min = 0, max = 999, lo
|
|
|
96
58
|
setDraft(null);
|
|
97
59
|
onChange(clamp(next));
|
|
98
60
|
}
|
|
61
|
+
/** A −/+ press: moves by `delta`; `false` when a bound stopped it. */
|
|
99
62
|
function stepBy(delta) {
|
|
100
63
|
const next = clamp(valueRef.current + delta);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
repeat.stop();
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
64
|
+
if (next === valueRef.current)
|
|
65
|
+
return false;
|
|
106
66
|
valueRef.current = next;
|
|
107
67
|
set(next);
|
|
68
|
+
onStep?.(next);
|
|
69
|
+
return true;
|
|
108
70
|
}
|
|
109
|
-
function startRepeat(
|
|
71
|
+
function startRepeat(direction) {
|
|
110
72
|
repeat.start(() => {
|
|
111
|
-
|
|
73
|
+
// A button disabled at its bound may never report the release.
|
|
74
|
+
if (!stepBy(direction * step))
|
|
75
|
+
repeat.stop();
|
|
112
76
|
});
|
|
113
77
|
}
|
|
114
78
|
// Held: repeat from press-in to press-out. Otherwise: one step per tap,
|
|
115
79
|
// and `longPressStep` on long press.
|
|
116
80
|
const tapsOnly = !repeatOnHold;
|
|
117
81
|
const jumps = tapsOnly && longPressStep !== undefined;
|
|
82
|
+
// A tap starts from the rendered value, even if the parent ignored the
|
|
83
|
+
// previous onChange.
|
|
84
|
+
function tap(delta) {
|
|
85
|
+
valueRef.current = value;
|
|
86
|
+
stepBy(delta);
|
|
87
|
+
}
|
|
118
88
|
return (_jsxs(View, { style: merged.row, children: [_jsx(Pressable, { style: [merged.button, atMin && merged.buttonDisabled], onPress: tapsOnly
|
|
119
89
|
? () => {
|
|
120
|
-
|
|
90
|
+
tap(-step);
|
|
121
91
|
}
|
|
122
92
|
: undefined, onLongPress: jumps
|
|
123
93
|
? () => {
|
|
124
|
-
|
|
94
|
+
tap(-longPressStep);
|
|
125
95
|
}
|
|
126
96
|
: undefined, onPressIn: repeatOnHold
|
|
127
97
|
? () => {
|
|
128
98
|
startRepeat(-1);
|
|
129
99
|
}
|
|
130
|
-
: undefined, onPressOut: repeatOnHold ? repeat.stop : undefined, 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) => {
|
|
100
|
+
: undefined, onPressOut: repeatOnHold ? repeat.stop : undefined, disabled: atMin, hitSlop: 6, accessibilityRole: "button", accessibilityLabel: labels.decrease(label), children: _jsx(Text, { style: merged.buttonText, maxFontSizeMultiplier: maxFontSizeMultiplier, children: "\u2212" }) }), _jsx(TextInput, { style: merged.input, value: draft ?? String(value), onChangeText: (text) => {
|
|
131
101
|
const cleaned = sanitize(text, allowsNegative);
|
|
132
102
|
const typed = Number(cleaned);
|
|
133
103
|
if (cleaned === "" || cleaned === "-" || typed < min) {
|
|
@@ -142,17 +112,17 @@ export function QuantityStepper({ value, onChange, label, min = 0, max = 999, lo
|
|
|
142
112
|
set(draft === "" || draft === "-" ? 0 : Number(draft));
|
|
143
113
|
},
|
|
144
114
|
// "number-pad" has no "-" key on Android.
|
|
145
|
-
keyboardType: allowsNegative ? "numeric" : "number-pad", selectTextOnFocus: true, maxLength: Math.max(
|
|
115
|
+
keyboardType: allowsNegative ? "numeric" : "number-pad", selectTextOnFocus: true, maxFontSizeMultiplier: maxFontSizeMultiplier, maxLength: Math.max(lengthOf(min), lengthOf(max)), accessibilityLabel: labels.input(label) }), _jsx(Pressable, { style: [merged.button, atMax && merged.buttonDisabled], onPress: tapsOnly
|
|
146
116
|
? () => {
|
|
147
|
-
|
|
117
|
+
tap(step);
|
|
148
118
|
}
|
|
149
119
|
: undefined, onLongPress: jumps
|
|
150
120
|
? () => {
|
|
151
|
-
|
|
121
|
+
tap(longPressStep);
|
|
152
122
|
}
|
|
153
123
|
: undefined, onPressIn: repeatOnHold
|
|
154
124
|
? () => {
|
|
155
125
|
startRepeat(1);
|
|
156
126
|
}
|
|
157
|
-
: undefined, onPressOut: repeatOnHold ? repeat.stop : undefined, disabled: atMax, hitSlop: 6, accessibilityRole: "button", accessibilityLabel: labels.increase(label), children: _jsx(Text, { style: merged.buttonText, children: "+" }) })] }));
|
|
127
|
+
: undefined, onPressOut: repeatOnHold ? repeat.stop : undefined, disabled: atMax, hitSlop: 6, accessibilityRole: "button", accessibilityLabel: labels.increase(label), children: _jsx(Text, { style: merged.buttonText, maxFontSizeMultiplier: maxFontSizeMultiplier, children: "+" }) })] }));
|
|
158
128
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
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 declare const defaultA11yLabels: Record<KitLocale, QuantityStepperA11yLabels>;
|
|
23
|
+
export declare const defaultStyles: {
|
|
24
|
+
row: {
|
|
25
|
+
flexDirection: "row";
|
|
26
|
+
alignItems: "center";
|
|
27
|
+
gap: number;
|
|
28
|
+
};
|
|
29
|
+
button: {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
borderRadius: number;
|
|
33
|
+
backgroundColor: string;
|
|
34
|
+
alignItems: "center";
|
|
35
|
+
justifyContent: "center";
|
|
36
|
+
};
|
|
37
|
+
buttonDisabled: {
|
|
38
|
+
opacity: number;
|
|
39
|
+
};
|
|
40
|
+
buttonText: {
|
|
41
|
+
color: string;
|
|
42
|
+
fontSize: number;
|
|
43
|
+
fontWeight: "700";
|
|
44
|
+
lineHeight: number;
|
|
45
|
+
};
|
|
46
|
+
input: {
|
|
47
|
+
width: number;
|
|
48
|
+
height: number;
|
|
49
|
+
borderRadius: number;
|
|
50
|
+
borderWidth: number;
|
|
51
|
+
borderColor: string;
|
|
52
|
+
color: string;
|
|
53
|
+
fontSize: number;
|
|
54
|
+
fontWeight: "700";
|
|
55
|
+
textAlign: "center";
|
|
56
|
+
padding: number;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=QuantityStepper.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuantityStepper.styles.d.ts","sourceRoot":"","sources":["../../../src/components/picker/QuantityStepper.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,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,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,yBAAyB,CAW1E,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCzB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const defaultA11yLabels = {
|
|
2
|
+
fr: {
|
|
3
|
+
decrease: (label) => `Retirer : ${label}`,
|
|
4
|
+
increase: (label) => `Ajouter : ${label}`,
|
|
5
|
+
input: (label) => `Quantité : ${label}`,
|
|
6
|
+
},
|
|
7
|
+
en: {
|
|
8
|
+
decrease: (label) => `Decrease: ${label}`,
|
|
9
|
+
increase: (label) => `Increase: ${label}`,
|
|
10
|
+
input: (label) => `Quantity: ${label}`,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export const defaultStyles = {
|
|
14
|
+
row: {
|
|
15
|
+
flexDirection: "row",
|
|
16
|
+
alignItems: "center",
|
|
17
|
+
gap: 6,
|
|
18
|
+
},
|
|
19
|
+
button: {
|
|
20
|
+
width: 40,
|
|
21
|
+
height: 40,
|
|
22
|
+
borderRadius: 20,
|
|
23
|
+
backgroundColor: "#2563eb",
|
|
24
|
+
alignItems: "center",
|
|
25
|
+
justifyContent: "center",
|
|
26
|
+
},
|
|
27
|
+
buttonDisabled: { opacity: 0.35 },
|
|
28
|
+
buttonText: {
|
|
29
|
+
color: "#ffffff",
|
|
30
|
+
fontSize: 22,
|
|
31
|
+
fontWeight: "700",
|
|
32
|
+
lineHeight: 26,
|
|
33
|
+
},
|
|
34
|
+
input: {
|
|
35
|
+
width: 52,
|
|
36
|
+
height: 40,
|
|
37
|
+
borderRadius: 8,
|
|
38
|
+
borderWidth: 1,
|
|
39
|
+
borderColor: "#d4d4d4",
|
|
40
|
+
color: "#111111",
|
|
41
|
+
fontSize: 18,
|
|
42
|
+
fontWeight: "700",
|
|
43
|
+
textAlign: "center",
|
|
44
|
+
padding: 0,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -7,7 +7,11 @@ export interface UpdateSettingsScreenProps {
|
|
|
7
7
|
checkForUpdate: () => Promise<UpdateSettingsScreenRelease | null>;
|
|
8
8
|
/** Positive when `a` is newer than `b`, e.g. semver comparison. */
|
|
9
9
|
compareVersions: (a: string, b: string) => number;
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Receives the release's `apkSha256`: pass it on as
|
|
12
|
+
* `expectedSha256` so a swapped or damaged APK is never installed.
|
|
13
|
+
*/
|
|
14
|
+
downloadAndInstallApk: (apkUrl: string, onProgress?: (fraction: number) => void, apkSha256?: string) => Promise<void>;
|
|
11
15
|
/** Omit to not show a version history section at all. */
|
|
12
16
|
fetchReleaseHistory?: () => Promise<UpdateSettingsScreenHistoryEntry[]>;
|
|
13
17
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UpdateSettingsScreen.d.ts","sourceRoot":"","sources":["../../../src/components/settings/UpdateSettingsScreen.tsx"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EACV,gCAAgC,EAChC,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC3B,MAAM,kCAAkC,CAAC;AAI1C,YAAY,EACV,gCAAgC,EAChC,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,kCAAkC,CAAC;AAU1C,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,cAAc,EAAE,MAAM,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CAAC;IAClE,mEAAmE;IACnE,eAAe,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,qBAAqB,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"UpdateSettingsScreen.d.ts","sourceRoot":"","sources":["../../../src/components/settings/UpdateSettingsScreen.tsx"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EACV,gCAAgC,EAChC,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC3B,MAAM,kCAAkC,CAAC;AAI1C,YAAY,EACV,gCAAgC,EAChC,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,kCAAkC,CAAC;AAU1C,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,cAAc,EAAE,MAAM,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CAAC;IAClE,mEAAmE;IACnE,eAAe,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD;;;OAGG;IACH,qBAAqB,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EACvC,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,yDAAyD;IACzD,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,gCAAgC,EAAE,CAAC,CAAC;IACxE;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,0BAA0B,CAAC;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,0BAA0B,CAAC;CACrC;AAQD,wBAAgB,oBAAoB,CAAC,EACnC,cAAc,EACd,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,UAAU,EAAE,gBAAgB,EAC5B,MAAM,EACN,MAAM,EACN,MAAM,GACP,EAAE,yBAAyB,+BA8J3B"}
|
|
@@ -52,12 +52,12 @@ export function UpdateSettingsScreen({ currentVersion, checkForUpdate, compareVe
|
|
|
52
52
|
void handleCheckForUpdate();
|
|
53
53
|
// eslint-disable-next-line @eslint-react/exhaustive-deps -- runs once on mount by design; handleCheckForUpdate is expected to be stable enough for the screen's lifetime.
|
|
54
54
|
}, []);
|
|
55
|
-
async function handleInstall(apkUrl) {
|
|
55
|
+
async function handleInstall({ apkUrl, apkSha256, }) {
|
|
56
56
|
setUpdateState({ status: "downloading", progress: 0 });
|
|
57
57
|
try {
|
|
58
58
|
await downloadAndInstallApk(apkUrl, (progress) => {
|
|
59
59
|
setUpdateState({ status: "downloading", progress });
|
|
60
|
-
});
|
|
60
|
+
}, apkSha256);
|
|
61
61
|
setUpdateState({ status: "idle" });
|
|
62
62
|
}
|
|
63
63
|
catch {
|
|
@@ -74,6 +74,6 @@ export function UpdateSettingsScreen({ currentVersion, checkForUpdate, compareVe
|
|
|
74
74
|
updateState.status !== "downloading" && (_jsx(Pressable, { style: [merged.button, isBusy && merged.buttonDisabled], onPress: () => {
|
|
75
75
|
void handleCheckForUpdate();
|
|
76
76
|
}, disabled: isBusy, accessibilityRole: "button", accessibilityLabel: t.checkButton, children: updateState.status === "checking" ? (_jsx(ActivityIndicator, { color: activityIndicatorColor })) : (_jsx(Text, { style: merged.buttonText, children: t.checkButton })) })), updateState.status === "up-to-date" && (_jsx(Text, { style: merged.helpText, children: t.upToDate })), updateState.status === "error" && (_jsx(Text, { style: merged.errorText, children: updateState.message })), updateState.status === "available" && (_jsxs(View, { style: merged.updateAvailableBox, children: [_jsx(Text, { style: merged.updateAvailableTitle, children: t.availableTitle(updateState.release.version) }), updateState.release.notes ? (_jsx(ChangelogNotes, { notes: updateState.release.notes, styles: merged.notes })) : null, _jsx(Pressable, { style: merged.button, onPress: () => {
|
|
77
|
-
void handleInstall(updateState.release
|
|
77
|
+
void handleInstall(updateState.release);
|
|
78
78
|
}, accessibilityRole: "button", accessibilityLabel: t.installButtonAccessibilityLabel(updateState.release.version), children: _jsx(Text, { style: merged.buttonText, children: t.installButton(updateState.release.version) }) })] })), updateState.status === "downloading" && (_jsxs(View, { style: merged.updateAvailableBox, children: [_jsx(Text, { style: merged.helpText, children: t.downloadingLabel(Math.round(updateState.progress * 100)) }), _jsx(Text, { style: merged.helpText, children: t.downloadingHint })] })), releaseHistory && releaseHistory.length > 0 && (_jsx(UpdateSettingsScreenHistory, { releaseHistory: releaseHistory, historyTitle: t.historyTitle, dateLocale: dateLocale, notesStyles: notesStyles, styles: merged }))] }));
|
|
79
79
|
}
|
|
@@ -4,6 +4,8 @@ export interface UpdateSettingsScreenRelease {
|
|
|
4
4
|
version: string;
|
|
5
5
|
notes: string;
|
|
6
6
|
apkUrl: string;
|
|
7
|
+
/** SHA-256 of the APK, handed back to `downloadAndInstallApk`. */
|
|
8
|
+
apkSha256?: string;
|
|
7
9
|
}
|
|
8
10
|
export interface UpdateSettingsScreenHistoryEntry {
|
|
9
11
|
version: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UpdateSettingsScreen.styles.d.ts","sourceRoot":"","sources":["../../../src/components/settings/UpdateSettingsScreen.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAInF,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"UpdateSettingsScreen.styles.d.ts","sourceRoot":"","sources":["../../../src/components/settings/UpdateSettingsScreen.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAInF,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,0BAA0B;IACzC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,+BAA+B,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9D,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC1C,oBAAoB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,oBAAoB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5C,gBAAgB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa;;;;;;;kCAOI,MAAM;;mDAEW,MAAM;oCAErB,MAAM;;;;;;;;;;kCAYR,MAAM;;mDAEW,MAAM;oCAErB,MAAM;;;;CAI6B,CAAC;AAEpE,eAAO,MAAM,aAAa,EAAE,QAAQ,CAClC,IAAI,CAAC,0BAA0B,EAAE,wBAAwB,GAAG,OAAO,CAAC,CACrE,GACC,IAAI,CAAC,0BAA0B,EAAE,wBAAwB,GAAG,OAAO,CA8DpE,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
2
|
+
import type { BackgroundOption } from "./findBackground.js";
|
|
3
|
+
export type { BackgroundOption } from "./findBackground.js";
|
|
4
|
+
export interface BackgroundPickerStyles {
|
|
5
|
+
/** The wrapping row of swatches. */
|
|
6
|
+
row?: StyleProp<ViewStyle>;
|
|
7
|
+
/** One option: swatch + label. */
|
|
8
|
+
option?: StyleProp<ViewStyle>;
|
|
9
|
+
swatch?: StyleProp<ViewStyle>;
|
|
10
|
+
/** Added on top of `swatch` for the chosen one. */
|
|
11
|
+
swatchSelected?: StyleProp<ViewStyle>;
|
|
12
|
+
card?: StyleProp<ViewStyle>;
|
|
13
|
+
/** The round badge holding the check mark. */
|
|
14
|
+
check?: StyleProp<ViewStyle>;
|
|
15
|
+
label?: StyleProp<TextStyle>;
|
|
16
|
+
labelSelected?: StyleProp<TextStyle>;
|
|
17
|
+
checkIconColor?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface BackgroundPickerProps<T extends BackgroundOption> {
|
|
20
|
+
options: readonly T[];
|
|
21
|
+
/** Id of the chosen option. */
|
|
22
|
+
value: string;
|
|
23
|
+
/** Receives the chosen option — add a haptic tick here if wanted. */
|
|
24
|
+
onChange: (option: T) => void;
|
|
25
|
+
styles?: BackgroundPickerStyles;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Radio group of background swatches: each one draws the page and a card in
|
|
29
|
+
* the colours on offer, the chosen one outlined with a check mark. Pair it
|
|
30
|
+
* with `findBackground` (`./findBackground`) to read the saved id, and check each palette's
|
|
31
|
+
* contrast with `contrastRatio` from `@forthtilliath/ts-kit/color`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* <BackgroundPicker
|
|
36
|
+
* options={[
|
|
37
|
+
* { id: "night", label: "Bleu nuit", page: "#0f172a", card: "#1e293b" },
|
|
38
|
+
* { id: "felt", label: "Tapis vert", page: "#0b1f15", card: "#112c1e" },
|
|
39
|
+
* ]}
|
|
40
|
+
* value={settings.background}
|
|
41
|
+
* onChange={(option) => { selectFeedback(); save(option.id); }}
|
|
42
|
+
* />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function BackgroundPicker<T extends BackgroundOption>({ options, value, onChange, styles, }: BackgroundPickerProps<T>): import("react").JSX.Element;
|
|
46
|
+
//# sourceMappingURL=BackgroundPicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackgroundPicker.d.ts","sourceRoot":"","sources":["../../../src/components/theme/BackgroundPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAMpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,WAAW,sBAAsB;IACrC,oCAAoC;IACpC,GAAG,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3B,kCAAkC;IAClC,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,mDAAmD;IACnD,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,gBAAgB;IAC/D,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IACtB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,sBAAsB,CAAC;CACjC;AAwCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,gBAAgB,EAAE,EAC3D,OAAO,EACP,KAAK,EACL,QAAQ,EACR,MAAM,GACP,EAAE,qBAAqB,CAAC,CAAC,CAAC,+BAoD1B"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Pressable, Text, View } from "react-native";
|
|
3
|
+
import { Ionicons } from "@expo/vector-icons";
|
|
4
|
+
import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
|
|
5
|
+
const defaultStyles = {
|
|
6
|
+
row: { flexDirection: "row", flexWrap: "wrap", gap: 8 },
|
|
7
|
+
option: {
|
|
8
|
+
flexGrow: 1,
|
|
9
|
+
flexBasis: "22%",
|
|
10
|
+
alignItems: "center",
|
|
11
|
+
gap: 4,
|
|
12
|
+
},
|
|
13
|
+
swatch: {
|
|
14
|
+
width: "100%",
|
|
15
|
+
aspectRatio: 1,
|
|
16
|
+
borderRadius: 12,
|
|
17
|
+
borderWidth: 2,
|
|
18
|
+
borderColor: "#d4d4d4",
|
|
19
|
+
padding: 8,
|
|
20
|
+
justifyContent: "flex-end",
|
|
21
|
+
},
|
|
22
|
+
swatchSelected: { borderColor: "#2563eb" },
|
|
23
|
+
card: { height: "45%", borderRadius: 6, borderWidth: 1 },
|
|
24
|
+
check: {
|
|
25
|
+
position: "absolute",
|
|
26
|
+
top: 4,
|
|
27
|
+
right: 4,
|
|
28
|
+
width: 22,
|
|
29
|
+
height: 22,
|
|
30
|
+
borderRadius: 11,
|
|
31
|
+
backgroundColor: "#2563eb",
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
},
|
|
35
|
+
label: {
|
|
36
|
+
color: "#6b7280",
|
|
37
|
+
fontSize: 13,
|
|
38
|
+
fontWeight: "600",
|
|
39
|
+
},
|
|
40
|
+
labelSelected: { color: "#111827" },
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Radio group of background swatches: each one draws the page and a card in
|
|
44
|
+
* the colours on offer, the chosen one outlined with a check mark. Pair it
|
|
45
|
+
* with `findBackground` (`./findBackground`) to read the saved id, and check each palette's
|
|
46
|
+
* contrast with `contrastRatio` from `@forthtilliath/ts-kit/color`.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* <BackgroundPicker
|
|
51
|
+
* options={[
|
|
52
|
+
* { id: "night", label: "Bleu nuit", page: "#0f172a", card: "#1e293b" },
|
|
53
|
+
* { id: "felt", label: "Tapis vert", page: "#0b1f15", card: "#112c1e" },
|
|
54
|
+
* ]}
|
|
55
|
+
* value={settings.background}
|
|
56
|
+
* onChange={(option) => { selectFeedback(); save(option.id); }}
|
|
57
|
+
* />
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function BackgroundPicker({ options, value, onChange, styles, }) {
|
|
61
|
+
const merged = mergeSlotStyles(defaultStyles, styles);
|
|
62
|
+
const checkIconColor = styles?.checkIconColor ?? "#ffffff";
|
|
63
|
+
return (_jsx(View, { style: merged.row, accessibilityRole: "radiogroup", children: options.map((option) => {
|
|
64
|
+
const selected = option.id === value;
|
|
65
|
+
return (_jsxs(Pressable, { style: merged.option, onPress: () => {
|
|
66
|
+
onChange(option);
|
|
67
|
+
}, accessibilityRole: "radio", accessibilityState: { checked: selected }, accessibilityLabel: option.label, children: [_jsxs(View, { style: [
|
|
68
|
+
merged.swatch,
|
|
69
|
+
{ backgroundColor: option.page },
|
|
70
|
+
selected && merged.swatchSelected,
|
|
71
|
+
], children: [_jsx(View, { style: [
|
|
72
|
+
merged.card,
|
|
73
|
+
{
|
|
74
|
+
backgroundColor: option.card,
|
|
75
|
+
borderColor: option.cardBorder ?? option.card,
|
|
76
|
+
},
|
|
77
|
+
] }), selected && (_jsx(View, { style: merged.check, children: _jsx(Ionicons, { name: "checkmark", size: 14, color: checkIconColor }) }))] }), _jsx(Text, { style: [merged.label, selected && merged.labelSelected], numberOfLines: 1, children: option.label })] }, option.id));
|
|
78
|
+
}) }));
|
|
79
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** One background on offer to `BackgroundPicker`, drawn as a page with a card on it. */
|
|
2
|
+
export interface BackgroundOption {
|
|
3
|
+
id: string;
|
|
4
|
+
/** Shown under the swatch and read by screen readers. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** The page colour. */
|
|
7
|
+
page: string;
|
|
8
|
+
/** The card drawn on the page. */
|
|
9
|
+
card: string;
|
|
10
|
+
/** The card's border. Defaults to `card`. */
|
|
11
|
+
cardBorder?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The option with this id, or the first one (the original background) if the
|
|
15
|
+
* id is unknown — a background removed since it was saved, or none saved yet.
|
|
16
|
+
*
|
|
17
|
+
* @throws {RangeError} If `options` is empty.
|
|
18
|
+
*/
|
|
19
|
+
export declare function findBackground<T extends BackgroundOption>(options: readonly T[], id: string | null | undefined): T;
|
|
20
|
+
//# sourceMappingURL=findBackground.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findBackground.d.ts","sourceRoot":"","sources":["../../../src/components/theme/findBackground.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,gBAAgB,EACvD,OAAO,EAAE,SAAS,CAAC,EAAE,EACrB,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC5B,CAAC,CAIH"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The option with this id, or the first one (the original background) if the
|
|
3
|
+
* id is unknown — a background removed since it was saved, or none saved yet.
|
|
4
|
+
*
|
|
5
|
+
* @throws {RangeError} If `options` is empty.
|
|
6
|
+
*/
|
|
7
|
+
export function findBackground(options, id) {
|
|
8
|
+
const found = options.find((option) => option.id === id) ?? options[0];
|
|
9
|
+
if (!found)
|
|
10
|
+
throw new RangeError("findBackground needs at least one option");
|
|
11
|
+
return found;
|
|
12
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/theme/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC"}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type View } from "react-native";
|
|
2
|
+
import { type ShareViewAsImageOptions } from "../utils/helpers/shareViewAsImage.js";
|
|
3
|
+
export interface UseViewShareOptions extends ShareViewAsImageOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Called when the capture or the share fails (capture missing from this
|
|
6
|
+
* binary, no share sheet…). Unset, an alert shows the error's message.
|
|
7
|
+
*/
|
|
8
|
+
onError?: (error: unknown) => void;
|
|
9
|
+
/** Title of the default error alert. */
|
|
10
|
+
errorTitle?: string;
|
|
11
|
+
/** Message of the default error alert, for an error without a message. */
|
|
12
|
+
errorMessage?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Shares as an image a view rendered on demand (a scoreboard, a summary card
|
|
16
|
+
* that isn't on screen): `capturing` is `true` while the capture runs — the
|
|
17
|
+
* screen mounts the view attached to `ref` (off screen, `collapsable={false}`)
|
|
18
|
+
* only meanwhile — and `share()` waits two frames for it to be drawn before
|
|
19
|
+
* capturing it with {@link shareViewAsImage}. A second `share()` while one is
|
|
20
|
+
* running is ignored.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* const ranking = useViewShare({ dialogTitle: "Partager le classement" });
|
|
25
|
+
*
|
|
26
|
+
* <Button title="Partager" onPress={() => void ranking.share()} />
|
|
27
|
+
* {ranking.capturing ? (
|
|
28
|
+
* <View ref={ranking.ref} collapsable={false} style={offScreen}>
|
|
29
|
+
* <RankingCard />
|
|
30
|
+
* </View>
|
|
31
|
+
* ) : null}
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function useViewShare({ onError, errorTitle, errorMessage, ...options }?: UseViewShareOptions): {
|
|
35
|
+
ref: import("react").RefObject<View | null>;
|
|
36
|
+
capturing: boolean;
|
|
37
|
+
share: () => Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=useViewShare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useViewShare.d.ts","sourceRoot":"","sources":["../../src/hooks/useViewShare.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,KAAK,IAAI,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,sCAAsC,CAAC;AAE9C,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IAClE;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA2BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,UAAU,EACV,YAAY,EACZ,GAAG,OAAO,EACX,GAAE,mBAAwB;;;;EA+B1B"}
|