@forthtilliath/react-native-kit 0.14.8 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +39 -17
  2. package/dist/components/index.d.ts +4 -4
  3. package/dist/components/index.d.ts.map +1 -1
  4. package/dist/components/index.js +4 -4
  5. package/dist/components/list/SwipeableRow.d.ts +14 -1
  6. package/dist/components/list/SwipeableRow.d.ts.map +1 -1
  7. package/dist/components/list/SwipeableRow.js +18 -16
  8. package/dist/components/list/Thumbnail.d.ts.map +1 -1
  9. package/dist/components/list/Thumbnail.js +2 -6
  10. package/dist/components/list/UndoToast.d.ts +10 -4
  11. package/dist/components/list/UndoToast.d.ts.map +1 -1
  12. package/dist/components/list/UndoToast.js +11 -8
  13. package/dist/components/list/index.d.ts +4 -4
  14. package/dist/components/list/index.d.ts.map +1 -1
  15. package/dist/components/list/index.js +4 -4
  16. package/dist/components/picker/PhotoPicker.d.ts +12 -1
  17. package/dist/components/picker/PhotoPicker.d.ts.map +1 -1
  18. package/dist/components/picker/PhotoPicker.js +32 -33
  19. package/dist/components/picker/PickerModal.d.ts +7 -1
  20. package/dist/components/picker/PickerModal.d.ts.map +1 -1
  21. package/dist/components/picker/PickerModal.js +8 -28
  22. package/dist/components/picker/PickerModal.styles.d.ts +18 -1
  23. package/dist/components/picker/PickerModal.styles.d.ts.map +1 -1
  24. package/dist/components/picker/PickerModal.styles.js +16 -6
  25. package/dist/components/picker/VoiceSearchButton.d.ts +13 -2
  26. package/dist/components/picker/VoiceSearchButton.d.ts.map +1 -1
  27. package/dist/components/picker/VoiceSearchButton.js +18 -1
  28. package/dist/components/picker/index.d.ts +3 -3
  29. package/dist/components/picker/index.d.ts.map +1 -1
  30. package/dist/components/picker/index.js +3 -3
  31. package/dist/components/settings/AboutSettingsScreen.d.ts +7 -1
  32. package/dist/components/settings/AboutSettingsScreen.d.ts.map +1 -1
  33. package/dist/components/settings/AboutSettingsScreen.js +13 -13
  34. package/dist/components/settings/BackupSettingsScreen.d.ts +9 -59
  35. package/dist/components/settings/BackupSettingsScreen.d.ts.map +1 -1
  36. package/dist/components/settings/BackupSettingsScreen.js +32 -141
  37. package/dist/components/settings/BackupSettingsScreen.styles.d.ts +173 -0
  38. package/dist/components/settings/BackupSettingsScreen.styles.d.ts.map +1 -0
  39. package/dist/components/settings/BackupSettingsScreen.styles.js +98 -0
  40. package/dist/components/settings/ContactSettingsScreen.d.ts +7 -1
  41. package/dist/components/settings/ContactSettingsScreen.d.ts.map +1 -1
  42. package/dist/components/settings/ContactSettingsScreen.js +15 -14
  43. package/dist/components/settings/PrivacySettingsScreen.d.ts +7 -1
  44. package/dist/components/settings/PrivacySettingsScreen.d.ts.map +1 -1
  45. package/dist/components/settings/PrivacySettingsScreen.js +50 -28
  46. package/dist/components/settings/SettingsMenu.d.ts.map +1 -1
  47. package/dist/components/settings/SettingsMenu.js +2 -9
  48. package/dist/components/settings/ThemeSettingsScreen.d.ts +7 -1
  49. package/dist/components/settings/ThemeSettingsScreen.d.ts.map +1 -1
  50. package/dist/components/settings/ThemeSettingsScreen.js +17 -19
  51. package/dist/components/settings/UpdateSettingsScreen.d.ts +11 -2
  52. package/dist/components/settings/UpdateSettingsScreen.d.ts.map +1 -1
  53. package/dist/components/settings/UpdateSettingsScreen.js +7 -31
  54. package/dist/components/settings/UpdateSettingsScreen.styles.d.ts +28 -1
  55. package/dist/components/settings/UpdateSettingsScreen.styles.d.ts.map +1 -1
  56. package/dist/components/settings/UpdateSettingsScreen.styles.js +26 -11
  57. package/dist/components/settings/index.d.ts +7 -7
  58. package/dist/components/settings/index.d.ts.map +1 -1
  59. package/dist/components/settings/index.js +7 -7
  60. package/dist/components/theme/ThemeOptionList.d.ts +7 -1
  61. package/dist/components/theme/ThemeOptionList.d.ts.map +1 -1
  62. package/dist/components/theme/ThemeOptionList.js +6 -17
  63. package/dist/components/theme/ThemeToggle.d.ts +7 -1
  64. package/dist/components/theme/ThemeToggle.d.ts.map +1 -1
  65. package/dist/components/theme/ThemeToggle.js +6 -20
  66. package/dist/components/theme/index.d.ts +2 -2
  67. package/dist/components/theme/index.d.ts.map +1 -1
  68. package/dist/components/theme/index.js +2 -2
  69. package/dist/components/theme/themeLabels.d.ts +14 -0
  70. package/dist/components/theme/themeLabels.d.ts.map +1 -0
  71. package/dist/components/theme/themeLabels.js +5 -0
  72. package/dist/hooks/index.d.ts +3 -3
  73. package/dist/hooks/index.d.ts.map +1 -1
  74. package/dist/hooks/index.js +3 -3
  75. package/dist/hooks/useDebouncedChange.d.ts.map +1 -1
  76. package/dist/hooks/useDebouncedChange.js +6 -7
  77. package/dist/hooks/useSubmitGuard.d.ts.map +1 -1
  78. package/dist/hooks/useSubmitGuard.js +9 -5
  79. package/dist/i18n/KitLocaleProvider.d.ts +19 -0
  80. package/dist/i18n/KitLocaleProvider.d.ts.map +1 -0
  81. package/dist/i18n/KitLocaleProvider.js +16 -0
  82. package/dist/i18n/index.d.ts +3 -0
  83. package/dist/i18n/index.d.ts.map +1 -0
  84. package/dist/i18n/index.js +2 -0
  85. package/dist/i18n/locale.d.ts +14 -0
  86. package/dist/i18n/locale.d.ts.map +1 -0
  87. package/dist/i18n/locale.js +18 -0
  88. package/dist/index.d.ts +5 -2
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +5 -2
  91. package/dist/utils/helpers/confirmDestructive.d.ts +6 -0
  92. package/dist/utils/helpers/confirmDestructive.d.ts.map +1 -1
  93. package/dist/utils/helpers/confirmDestructive.js +20 -6
  94. package/dist/utils/helpers/index.d.ts +1 -0
  95. package/dist/utils/helpers/index.d.ts.map +1 -1
  96. package/dist/utils/helpers/index.js +1 -0
  97. package/dist/utils/helpers/mergeSlotStyles.d.ts +20 -0
  98. package/dist/utils/helpers/mergeSlotStyles.d.ts.map +1 -0
  99. package/dist/utils/helpers/mergeSlotStyles.js +26 -0
  100. package/dist/utils/index.d.ts +1 -1
  101. package/dist/utils/index.d.ts.map +1 -1
  102. package/dist/utils/index.js +1 -1
  103. package/package.json +14 -10
package/README.md CHANGED
@@ -18,7 +18,7 @@ Or, from within this monorepo, as a workspace dependency:
18
18
  }
19
19
  ```
20
20
 
21
- `react` and `react-native` are peer dependencies — install them in the consuming app if not already present. `@expo/vector-icons`, `expo-image-picker`, `expo-speech-recognition`, and `react-native-gesture-handler` are also peer dependencies, needed only if you import the components that use them (`Thumbnail`/`PickerModal`/`SwipeableRow`, `PhotoPicker`, `VoiceSearchButton`/`PickerModal`, `SwipeableRow`, respectively).
21
+ `react` and `react-native` are peer dependencies — install them in the consuming app if not already present. `@expo/vector-icons`, `expo-image-picker`, `expo-speech-recognition`, `react-native-gesture-handler` and `react-native-reanimated` are also peer dependencies, needed only if you import the components that use them (`Thumbnail`/`PickerModal`/`SwipeableRow`, `PhotoPicker`, `VoiceSearchButton`/`PickerModal`, `SwipeableRow`, `SwipeableRow`, respectively).
22
22
 
23
23
  ## Usage
24
24
 
@@ -38,6 +38,23 @@ import { PhotoPicker, useSubmitGuard } from "@forthtilliath/react-native-kit";
38
38
 
39
39
  **Avoid the barrel under Jest (or any other CommonJS `require` consumer).** `export * from` re-exports are evaluated eagerly on `require()` — unlike Metro's ESM bundling, there's no tree-shaking to skip the unused ones. Requiring the barrel from _any_ file, even one that only wants a framework-agnostic util like `getMostRecentIds`, pulls in every component's module graph, including native-module imports (`expo-speech-recognition` via `VoiceSearchButton`/`PickerModal`) that don't exist in a Jest environment — this throws `Cannot find native module '...'` at require time, not just at runtime for an unrendered component. Deep imports only ever load the one module you asked for, so they don't have this problem in any environment.
40
40
 
41
+ ### Languages (`locale`)
42
+
43
+ Every component with built-in copy (labels, hints, accessibility labels, default sections…) ships it in **French** (default) and **English**. Pick the language:
44
+
45
+ - per component, with a `locale` prop: `<UndoToast locale="en" … />`;
46
+ - or once for a whole tree — handy for a bilingual app — with `KitLocaleProvider`:
47
+
48
+ ```tsx
49
+ import { KitLocaleProvider } from "@forthtilliath/react-native-kit/i18n/KitLocaleProvider";
50
+
51
+ <KitLocaleProvider locale={userLanguage /* "fr" | "en" */}>
52
+ <App />
53
+ </KitLocaleProvider>;
54
+ ```
55
+
56
+ A component's own `locale` prop wins over the provider, and its `labels` prop still overrides individual strings on top of either. The locale also drives `VoiceSearchButton`'s speech-recognition language (`fr-FR` / `en-US`) and `UpdateSettingsScreen`'s date format, unless `lang` / `dateLocale` are passed. `confirmDestructive`, being a plain function, can't read the provider: pass it `{ locale }`.
57
+
41
58
  ### `<Thumbnail photoUri={...} placeholderIcon="..." />`
42
59
 
43
60
  List-row thumbnail: the photo if there is one, otherwise a placeholder icon.
@@ -54,7 +71,7 @@ import { Thumbnail } from "@forthtilliath/react-native-kit/components/list/Thumb
54
71
 
55
72
  ### `<SwipeableRow onDelete={...} deleteLabel="...">`
56
73
 
57
- Swipe a list row left to reveal a delete button, on top of a tap to edit it.
74
+ Swipe a list row left to reveal a delete button, on top of a tap to edit it. Built on react-native-gesture-handler's `ReanimatedSwipeable`, so it needs `react-native-reanimated` installed. The text under the trash icon defaults to "Supprimer" ("Delete" in English), overridable with `deleteText`.
58
75
 
59
76
  ```tsx
60
77
  import { SwipeableRow } from "@forthtilliath/react-native-kit/components/list/SwipeableRow";
@@ -119,12 +136,13 @@ import { UndoToast } from "@forthtilliath/react-native-kit/components/list/UndoT
119
136
  }
120
137
  ```
121
138
 
122
- | Prop | Type | Default | Notes |
123
- | ------------- | ----------------- | -------- | ----------------------------------------------------------------------------------- |
124
- | `message` | `string` | — | Past tense; single line, truncated with an ellipsis. |
125
- | `actionLabel` | `string` | `"Undo"` | The tappable label on the right. |
126
- | `onAction` | `() => void` | — | Reverse the change here. The host then hides the toast. |
127
- | `styles` | `UndoToastStyles` | — | Per-slot overrides (`toast` / `message` / `action`), each merged after its default. |
139
+ | Prop | Type | Default | Notes |
140
+ | ------------- | ----------------- | --------------------------------- | ----------------------------------------------------------------------------------- |
141
+ | `message` | `string` | — | Past tense; single line, truncated with an ellipsis. |
142
+ | `actionLabel` | `string` | `"Annuler"` (`"Undo"` in English) | The tappable label on the right. |
143
+ | `locale` | `KitLocale` | `"fr"` | Language of the default `actionLabel` (see [Languages](#languages-locale)). |
144
+ | `onAction` | `() => void` | — | Reverse the change here. The host then hides the toast. |
145
+ | `styles` | `UndoToastStyles` | — | Per-slot overrides (`toast` / `message` / `action`), each merged after its default. |
128
146
 
129
147
  Full pattern — commit for good after 5s, localized label, re-themed:
130
148
 
@@ -171,13 +189,17 @@ Microphone button to dictate a search instead of typing it. Safe to mount more t
171
189
  ```tsx
172
190
  import { VoiceSearchButton } from "@forthtilliath/react-native-kit/components/picker/VoiceSearchButton";
173
191
 
174
- <VoiceSearchButton onResult={setQuery} lang="en-US" />;
192
+ <VoiceSearchButton onResult={setQuery} />;
175
193
  ```
176
194
 
195
+ Recognizes French by default (`fr-FR`, or `en-US` with `locale="en"`); pass `lang` for any other BCP 47 language.
196
+
177
197
  ### `<PhotoPicker photoUri={...} onChange={...} savePhoto={...} photoLabel="..." />`
178
198
 
179
199
  Photo picker (camera or library) with a preview and a remove link. `savePhoto` is injected rather than hard-coded, so where/how the picked image gets persisted is entirely up to the caller.
180
200
 
201
+ Only the camera asks for a permission: the library opens the system photo picker, which needs none — the app can block `READ_EXTERNAL_STORAGE` / `WRITE_EXTERNAL_STORAGE` / `READ_MEDIA_IMAGES` (e.g. `android.blockedPermissions` in `app.json`).
202
+
181
203
  ```tsx
182
204
  import { PhotoPicker } from "@forthtilliath/react-native-kit/components/picker/PhotoPicker";
183
205
 
@@ -220,7 +242,7 @@ import {
220
242
 
221
243
  Groups results into sections via each item's `group` (e.g. food groups, ingredients vs recipes) — ignored while searching, where the best global matches are shown instead. Pass `filterItems` for custom ranking (e.g. `rankByNameMatch` from this same package's `utils/`) instead of the default case-insensitive substring match.
222
244
 
223
- For all 5 components above, styling and (where relevant) copy work the same way as `ChangelogNotes`: an optional `styles` prop (all fields optional, neutral defaults) and, for `PhotoPicker`/`PickerModal`, an optional `labels` prop for the built-in French copy.
245
+ For all 5 components above, styling and (where relevant) copy work the same way as `ChangelogNotes`: an optional `styles` prop (all fields optional, neutral defaults) and, for `PhotoPicker`/`PickerModal`, an optional `labels` prop over the built-in French or English copy (see [Languages](#languages-locale)).
224
246
 
225
247
  ### `useSubmitGuard()`
226
248
 
@@ -257,15 +279,14 @@ useDebouncedChange([settingsData, itemsData], 5 * 60 * 1000, () => {
257
279
 
258
280
  ### `confirmDestructive(title, onConfirm, options?)`
259
281
 
260
- Generic destructive-action confirmation (title + message + Cancel/Confirm), for anything irreversible (delete, reset...). Ships with French defaults (`message`, `cancelLabel`, `confirmLabel` all overridable).
282
+ Generic destructive-action confirmation (title + message + Cancel/Confirm), for anything irreversible (delete, reset...). Ships with French defaults, or English ones with `{ locale: "en" }` (`message`, `cancelLabel`, `confirmLabel` all overridable).
261
283
 
262
284
  ```ts
263
285
  import { confirmDestructive } from "@forthtilliath/react-native-kit/utils/helpers/confirmDestructive";
264
286
 
265
287
  confirmDestructive("Delete this item?", () => deleteItem(id), {
266
- message: "This cannot be undone.",
267
- cancelLabel: "Cancel",
268
- confirmLabel: "Delete",
288
+ locale: "en",
289
+ confirmLabel: "Remove",
269
290
  });
270
291
  ```
271
292
 
@@ -568,11 +589,12 @@ import { PrivacySettingsScreen } from "@forthtilliath/react-native-kit/component
568
589
  />;
569
590
  ```
570
591
 
571
- For all 7 components above, styling works the same way as `ChangelogNotes`: an optional `styles` prop (all fields optional, neutral defaults), and where relevant an optional `labels` prop for the built-in French copy.
592
+ For all 7 components above, styling works the same way as `ChangelogNotes`: an optional `styles` prop (all fields optional, neutral defaults), and where relevant an optional `labels` prop over the built-in French or English copy (see [Languages](#languages-locale)).
572
593
 
573
594
  ### Utils (`utils/helpers/`)
574
595
 
575
- `confirmDestructive` is the only remaining util here — it wraps React Native's `Alert`, so it isn't framework-agnostic (see its own section above).
596
+ - `confirmDestructive` — wraps React Native's `Alert`, so it isn't framework-agnostic (see its own section above).
597
+ - `mergeSlotStyles(defaultStyles, styles)` — merges a component's per-slot `styles` overrides onto its defaults as `[default, override]` style arrays, so overriding one property of a slot keeps the rest of its default. Every component of this package uses it; handy for your own components following the same `styles` convention.
576
598
 
577
599
  The framework-agnostic helpers that used to live here (`getPeriodStartMs`, `getMostRecentIds`, `nextInCycle`, `normalizeForSearch`, `rankByNameMatch`, `escapeCsvField`, `formatCsvNumber`, `escapeHtml`) moved to [`@forthtilliath/ts-kit`](../ts-kit#readme) — no React Native dependency on them, so they're usable from Node/web too. They're still re-exported from this package's root barrel for convenience:
578
600
 
@@ -600,4 +622,4 @@ Built to `dist/` (see the `exports` field in `package.json`), so run `pnpm run b
600
622
 
601
623
  ### Testing note
602
624
 
603
- `react-native`'s package entry uses Flow syntax that `@babel/parser`'s flow plugin can't parse (`as Cast` casts aren't supported there), so Vitest can never load the real package directly. Tests alias `react-native` to a minimal stub (`src/__mocks__/react-native.tsx`) instead — see that file for details. `react-native-gesture-handler` ships the same kind of Flow syntax, and `@expo/vector-icons` has its own unrelated ESM-resolution issue under Vite/Rollup — both are stubbed the same way (`src/__mocks__/react-native-gesture-handler.tsx`, `src/__mocks__/expo-vector-icons.tsx`). `expo-speech-recognition` and `expo-image-picker` wrap native modules unavailable under Vitest regardless, so they're mocked with plain spies (`src/__mocks__/expo-speech-recognition.tsx`, `src/__mocks__/expo-image-picker.ts`).
625
+ `react-native`'s package entry uses Flow syntax that `@babel/parser`'s flow plugin can't parse (`as Cast` casts aren't supported there), so Vitest can never load the real package directly. Tests alias `react-native` to a minimal stub (`src/__mocks__/react-native.tsx`) instead — see that file for details. `react-native-gesture-handler` ships the same kind of Flow syntax, and `@expo/vector-icons` has its own unrelated ESM-resolution issue under Vite/Rollup — both are stubbed the same way (`src/__mocks__/react-native-gesture-handler.tsx`, `src/__mocks__/expo-vector-icons.tsx`). `react-native-gesture-handler/ReanimatedSwipeable` needs Reanimated's native runtime, so it gets its own stub too (`src/__mocks__/react-native-gesture-handler-reanimated-swipeable.tsx`). `expo-speech-recognition` and `expo-image-picker` wrap native modules unavailable under Vitest regardless, so they're mocked with plain spies (`src/__mocks__/expo-speech-recognition.tsx`, `src/__mocks__/expo-image-picker.ts`).
@@ -1,5 +1,5 @@
1
- export * from "./list";
2
- export * from "./picker";
3
- export * from "./settings";
4
- export * from "./theme";
1
+ export * from "./list/index.js";
2
+ export * from "./picker/index.js";
3
+ export * from "./settings/index.js";
4
+ export * from "./theme/index.js";
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC"}
@@ -1,4 +1,4 @@
1
- export * from "./list";
2
- export * from "./picker";
3
- export * from "./settings";
4
- export * from "./theme";
1
+ export * from "./list/index.js";
2
+ export * from "./picker/index.js";
3
+ export * from "./settings/index.js";
4
+ export * from "./theme/index.js";
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { StyleProp, TextStyle, ViewStyle } from "react-native";
3
+ import { type KitLocale } from "../../i18n/locale.js";
3
4
  export interface SwipeableRowStyles {
4
5
  deleteAction?: StyleProp<ViewStyle>;
5
6
  deleteActionText?: StyleProp<TextStyle>;
@@ -8,9 +9,21 @@ export interface SwipeableRowStyles {
8
9
  export interface SwipeableRowProps {
9
10
  children: ReactNode;
10
11
  onDelete: () => void;
12
+ /** Accessibility label of the delete button, e.g. `"Delete « Marie »"`. */
11
13
  deleteLabel: string;
14
+ /** Text under the trash icon. Defaults to "Supprimer" (`"Delete"` with `locale="en"`). */
12
15
  deleteText?: string;
16
+ /**
17
+ * Language of the default `deleteText` — French by default, or the
18
+ * nearest `KitLocaleProvider`'s.
19
+ */
20
+ locale?: KitLocale;
13
21
  styles?: SwipeableRowStyles;
14
22
  }
15
- export declare function SwipeableRow({ children, onDelete, deleteLabel, deleteText, styles, }: SwipeableRowProps): import("react").JSX.Element;
23
+ /**
24
+ * Swipe a list row left to reveal a delete button, on top of a tap to edit it.
25
+ * Built on react-native-gesture-handler's `ReanimatedSwipeable`, so the app
26
+ * needs `react-native-reanimated` (a peer dependency).
27
+ */
28
+ export declare function SwipeableRow({ children, onDelete, deleteLabel, deleteText, locale, styles, }: SwipeableRowProps): import("react").JSX.Element;
16
29
  //# sourceMappingURL=SwipeableRow.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SwipeableRow.d.ts","sourceRoot":"","sources":["../../../src/components/list/SwipeableRow.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKpE,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,gBAAgB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAiBD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,UAAqB,EACrB,MAAM,GACP,EAAE,iBAAiB,+BAuCnB"}
1
+ {"version":3,"file":"SwipeableRow.d.ts","sourceRoot":"","sources":["../../../src/components/list/SwipeableRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKpE,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AAGpE,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,gBAAgB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAqBD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,UAAU,EACV,MAAM,EACN,MAAM,GACP,EAAE,iBAAiB,+BAiCnB"}
@@ -1,8 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef } from "react";
3
2
  import { Pressable, Text } from "react-native";
4
- import { Swipeable } from "react-native-gesture-handler";
3
+ import ReanimatedSwipeable from "react-native-gesture-handler/ReanimatedSwipeable";
5
4
  import { Ionicons } from "@expo/vector-icons";
5
+ import { useKitLocale } from "../../i18n/locale.js";
6
+ import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
7
+ const defaultDeleteTexts = {
8
+ fr: "Supprimer",
9
+ en: "Delete",
10
+ };
6
11
  const defaultStyles = {
7
12
  deleteAction: {
8
13
  backgroundColor: "#dc2626",
@@ -16,22 +21,19 @@ const defaultStyles = {
16
21
  deleteActionText: { color: "#ffffff", fontSize: 11, fontWeight: "600" },
17
22
  deleteIconColor: "#ffffff",
18
23
  };
19
- // Swipe a list row left to reveal a delete button, on top of a tap to edit it.
20
- export function SwipeableRow({ children, onDelete, deleteLabel, deleteText = "Delete", styles, }) {
21
- // Style fields are merged as arrays (default, then override) so a partial
22
- // override (e.g. just backgroundColor) doesn't drop the default's
23
- // width/borderRadius/marginBottom/gap too.
24
+ /**
25
+ * Swipe a list row left to reveal a delete button, on top of a tap to edit it.
26
+ * Built on react-native-gesture-handler's `ReanimatedSwipeable`, so the app
27
+ * needs `react-native-reanimated` (a peer dependency).
28
+ */
29
+ export function SwipeableRow({ children, onDelete, deleteLabel, deleteText, locale, styles, }) {
30
+ const resolvedLocale = useKitLocale(locale);
24
31
  const merged = {
25
- deleteAction: [defaultStyles.deleteAction, styles?.deleteAction],
26
- deleteActionText: [
27
- defaultStyles.deleteActionText,
28
- styles?.deleteActionText,
29
- ],
32
+ ...mergeSlotStyles(defaultStyles, styles),
30
33
  deleteIconColor: styles?.deleteIconColor ?? defaultStyles.deleteIconColor,
31
34
  };
32
- const swipeableRef = useRef(null);
33
- return (_jsx(Swipeable, { ref: swipeableRef, renderRightActions: () => (_jsxs(Pressable, { style: merged.deleteAction, onPress: () => {
34
- swipeableRef.current?.close();
35
+ return (_jsx(ReanimatedSwipeable, { renderRightActions: (_progress, _translation, swipeable) => (_jsxs(Pressable, { style: merged.deleteAction, onPress: () => {
36
+ swipeable.close();
35
37
  onDelete();
36
- }, accessibilityRole: "button", accessibilityLabel: deleteLabel, children: [_jsx(Ionicons, { name: "trash-outline", size: 22, color: merged.deleteIconColor }), _jsx(Text, { style: merged.deleteActionText, children: deleteText })] })), children: children }));
38
+ }, accessibilityRole: "button", accessibilityLabel: deleteLabel, children: [_jsx(Ionicons, { name: "trash-outline", size: 22, color: merged.deleteIconColor }), _jsx(Text, { style: merged.deleteActionText, children: deleteText ?? defaultDeleteTexts[resolvedLocale] })] })), children: children }));
37
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Thumbnail.d.ts","sourceRoot":"","sources":["../../../src/components/list/Thumbnail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAErE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IAClC,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iFAAiF;IACjF,eAAe,EAAE,MAAM,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAgBD,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,eAAe,EACf,IAAmB,EACnB,MAAM,GACP,EAAE,cAAc,+BA+BhB"}
1
+ {"version":3,"file":"Thumbnail.d.ts","sourceRoot":"","sources":["../../../src/components/list/Thumbnail.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAErE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAI9C,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IAClC,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iFAAiF;IACjF,eAAe,EAAE,MAAM,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAgBD,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,eAAe,EACf,IAAmB,EACnB,MAAM,GACP,EAAE,cAAc,+BA0BhB"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Image, View } from "react-native";
3
3
  import { Ionicons } from "@expo/vector-icons";
4
+ import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
4
5
  const DEFAULT_SIZE = 48;
5
6
  const defaultStyles = {
6
7
  thumbnail: { borderRadius: 10, backgroundColor: "#f3f4f6" },
@@ -14,13 +15,8 @@ const defaultStyles = {
14
15
  };
15
16
  // List-row thumbnail (photo, or a placeholder icon when there is none).
16
17
  export function Thumbnail({ photoUri, placeholderIcon, size = DEFAULT_SIZE, styles, }) {
17
- // Style fields are merged as arrays (default, then override) so a partial
18
- // override (e.g. just backgroundColor) doesn't drop the default's
19
- // borderRadius, or the placeholder's alignItems/justifyContent that center
20
- // the icon.
21
18
  const merged = {
22
- thumbnail: [defaultStyles.thumbnail, styles?.thumbnail],
23
- placeholder: [defaultStyles.placeholder, styles?.placeholder],
19
+ ...mergeSlotStyles(defaultStyles, styles),
24
20
  iconColor: styles?.iconColor ?? defaultStyles.iconColor,
25
21
  };
26
22
  const dimensions = { width: size, height: size };
@@ -1,4 +1,5 @@
1
1
  import type { StyleProp, TextStyle, ViewStyle } from "react-native";
2
+ import { type KitLocale } from "../../i18n/locale.js";
2
3
  /**
3
4
  * Per-slot style overrides for {@link UndoToast}. Every field is optional and
4
5
  * is **merged after** the matching default (as a style array), so overriding
@@ -10,7 +11,7 @@ export interface UndoToastStyles {
10
11
  toast?: StyleProp<ViewStyle>;
11
12
  /** The message text on the left. Truncated to a single line. */
12
13
  message?: StyleProp<TextStyle>;
13
- /** The action label on the right (the tappable "Undo"). */
14
+ /** The action label on the right (the tappable "Annuler" / "Undo"). */
14
15
  action?: StyleProp<TextStyle>;
15
16
  }
16
17
  export interface UndoToastProps {
@@ -23,9 +24,14 @@ export interface UndoToastProps {
23
24
  /**
24
25
  * Label of the action button.
25
26
  *
26
- * @defaultValue "Undo"
27
+ * @defaultValue "Annuler" (`"Undo"` with `locale="en"`)
27
28
  */
28
29
  actionLabel?: string;
30
+ /**
31
+ * Language of the default `actionLabel` — French by default, or the
32
+ * nearest `KitLocaleProvider`'s.
33
+ */
34
+ locale?: KitLocale;
29
35
  /**
30
36
  * Called when the action button is tapped. Wire this to your reverse-the-
31
37
  * change logic (restore the row, re-insert the item…). The host is
@@ -38,7 +44,7 @@ export interface UndoToastProps {
38
44
  /**
39
45
  * A bottom-of-screen snackbar for **undoing an action that already
40
46
  * happened** — the counterpart to a delete that runs immediately with no
41
- * confirmation dialog (for instance a {@link SwipeToDeleteRow} swipe).
47
+ * confirmation dialog (for instance a {@link SwipeableRow} swipe).
42
48
  *
43
49
  * `UndoToast` is presentational only: it does not time itself out, animate
44
50
  * in/out, or stack. The host owns that — typically a piece of state holding
@@ -96,5 +102,5 @@ export interface UndoToastProps {
96
102
  * )}
97
103
  * ```
98
104
  */
99
- export declare function UndoToast({ message, actionLabel, onAction, styles, }: UndoToastProps): import("react").JSX.Element;
105
+ export declare function UndoToast({ message, actionLabel, locale, onAction, styles, }: UndoToastProps): import("react").JSX.Element;
100
106
  //# sourceMappingURL=UndoToast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UndoToast.d.ts","sourceRoot":"","sources":["../../../src/components/list/UndoToast.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGpE;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAkCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,wBAAgB,SAAS,CAAC,EACxB,OAAO,EACP,WAAoB,EACpB,QAAQ,EACR,MAAM,GACP,EAAE,cAAc,+BAmBhB"}
1
+ {"version":3,"file":"UndoToast.d.ts","sourceRoot":"","sources":["../../../src/components/list/UndoToast.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGpE,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AAGpE;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,gEAAgE;IAChE,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,uEAAuE;IACvE,MAAM,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAuCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,wBAAgB,SAAS,CAAC,EACxB,OAAO,EACP,WAAW,EACX,MAAM,EACN,QAAQ,EACR,MAAM,GACP,EAAE,cAAc,+BAkBhB"}
@@ -1,5 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Pressable, Text, View } from "react-native";
3
+ import { useKitLocale } from "../../i18n/locale.js";
4
+ import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
5
+ const defaultActionLabels = {
6
+ fr: "Annuler",
7
+ en: "Undo",
8
+ };
3
9
  const defaultStyles = {
4
10
  toast: {
5
11
  position: "absolute",
@@ -34,7 +40,7 @@ const defaultStyles = {
34
40
  /**
35
41
  * A bottom-of-screen snackbar for **undoing an action that already
36
42
  * happened** — the counterpart to a delete that runs immediately with no
37
- * confirmation dialog (for instance a {@link SwipeToDeleteRow} swipe).
43
+ * confirmation dialog (for instance a {@link SwipeableRow} swipe).
38
44
  *
39
45
  * `UndoToast` is presentational only: it does not time itself out, animate
40
46
  * in/out, or stack. The host owns that — typically a piece of state holding
@@ -92,13 +98,10 @@ const defaultStyles = {
92
98
  * )}
93
99
  * ```
94
100
  */
95
- export function UndoToast({ message, actionLabel = "Undo", onAction, styles, }) {
101
+ export function UndoToast({ message, actionLabel, locale, onAction, styles, }) {
102
+ const resolvedLocale = useKitLocale(locale);
96
103
  // Merge each slot as [default, override] so a partial override doesn't drop
97
104
  // the rest of that slot's default (positioning, shadow, flex…).
98
- const merged = {
99
- toast: [defaultStyles.toast, styles?.toast],
100
- message: [defaultStyles.message, styles?.message],
101
- action: [defaultStyles.action, styles?.action],
102
- };
103
- return (_jsxs(View, { style: merged.toast, children: [_jsx(Text, { style: merged.message, numberOfLines: 1, children: message }), _jsx(Pressable, { onPress: onAction, hitSlop: 8, accessibilityRole: "button", children: _jsx(Text, { style: merged.action, children: actionLabel }) })] }));
105
+ const merged = mergeSlotStyles(defaultStyles, styles);
106
+ return (_jsxs(View, { style: merged.toast, children: [_jsx(Text, { style: merged.message, numberOfLines: 1, children: message }), _jsx(Pressable, { onPress: onAction, hitSlop: 8, accessibilityRole: "button", children: _jsx(Text, { style: merged.action, children: actionLabel ?? defaultActionLabels[resolvedLocale] }) })] }));
104
107
  }
@@ -1,5 +1,5 @@
1
- export * from "./ColorDot";
2
- export * from "./SwipeableRow";
3
- export * from "./Thumbnail";
4
- export * from "./UndoToast";
1
+ export * from "./ColorDot.js";
2
+ export * from "./SwipeableRow.js";
3
+ export * from "./Thumbnail.js";
4
+ export * from "./UndoToast.js";
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/list/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/list/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
@@ -1,4 +1,4 @@
1
- export * from "./ColorDot";
2
- export * from "./SwipeableRow";
3
- export * from "./Thumbnail";
4
- export * from "./UndoToast";
1
+ export * from "./ColorDot.js";
2
+ export * from "./SwipeableRow.js";
3
+ export * from "./Thumbnail.js";
4
+ export * from "./UndoToast.js";
@@ -1,4 +1,5 @@
1
1
  import type { ImageStyle, StyleProp, TextStyle, ViewStyle } from "react-native";
2
+ import { type KitLocale } from "../../i18n/locale.js";
2
3
  export interface PhotoPickerStyles {
3
4
  photoPicker?: StyleProp<ViewStyle>;
4
5
  photoPreview?: StyleProp<ImageStyle>;
@@ -14,7 +15,12 @@ export interface PhotoPickerLabels {
14
15
  addPlaceholderText?: string;
15
16
  cameraPermissionTitle?: string;
16
17
  cameraPermissionMessage?: string;
18
+ /**
19
+ * @deprecated Unused: choosing from the library needs no permission (the
20
+ * system photo picker), so no "access denied" alert is ever shown.
21
+ */
17
22
  libraryPermissionTitle?: string;
23
+ /** @deprecated Unused — see `libraryPermissionTitle`. */
18
24
  libraryPermissionMessage?: string;
19
25
  takePhoto?: string;
20
26
  chooseFromLibrary?: string;
@@ -28,7 +34,12 @@ export interface PhotoPickerProps {
28
34
  /** Used as-is in titles/accessibility labels, e.g. "of the container". */
29
35
  photoLabel: string;
30
36
  labels?: PhotoPickerLabels;
37
+ /**
38
+ * Language of the built-in labels — French by default, or the nearest
39
+ * `KitLocaleProvider`'s. `labels` still overrides individual strings.
40
+ */
41
+ locale?: KitLocale;
31
42
  styles?: PhotoPickerStyles;
32
43
  }
33
- export declare function PhotoPicker({ photoUri, onChange, savePhoto, photoLabel, labels, styles, }: PhotoPickerProps): import("react").JSX.Element;
44
+ export declare function PhotoPicker({ photoUri, onChange, savePhoto, photoLabel, labels, locale, styles, }: PhotoPickerProps): import("react").JSX.Element;
34
45
  //# sourceMappingURL=PhotoPicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PhotoPicker.d.ts","sourceRoot":"","sources":["../../../src/components/picker/PhotoPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKhF,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnC,YAAY,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IACrC,gBAAgB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,oBAAoB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,sBAAsB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACxD,qBAAqB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAkDD,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,UAAU,EACV,MAAM,EACN,MAAM,GACP,EAAE,gBAAgB,+BAoHlB"}
1
+ {"version":3,"file":"PhotoPicker.d.ts","sourceRoot":"","sources":["../../../src/components/picker/PhotoPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKhF,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AAGpE,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnC,YAAY,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IACrC,gBAAgB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,oBAAoB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,sBAAsB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACxD,qBAAqB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,yDAAyD;IACzD,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAyED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,UAAU,EACV,MAAM,EACN,MAAM,EACN,MAAM,GACP,EAAE,gBAAgB,+BAqGlB"}
@@ -2,6 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { Alert, Image, Pressable, Text, View } from "react-native";
3
3
  import { Ionicons } from "@expo/vector-icons";
4
4
  import * as ImagePicker from "expo-image-picker";
5
+ import { useKitLocale } from "../../i18n/locale.js";
6
+ import { mergeSlotStyles } from "../../utils/helpers/mergeSlotStyles.js";
5
7
  const defaultStyles = {
6
8
  photoPicker: { alignSelf: "center", marginTop: 8 },
7
9
  photoPreview: {
@@ -32,39 +34,38 @@ const defaultStyles = {
32
34
  iconColor: "#6b7280",
33
35
  };
34
36
  const defaultLabels = {
35
- photoTitle: (photoLabel) => `Photo ${photoLabel}`,
36
- editAccessibilityLabel: (photoLabel) => `Photo ${photoLabel}. Modifier.`,
37
- addAccessibilityLabel: (photoLabel) => `Ajouter une photo ${photoLabel}`,
38
- addPlaceholderText: "Ajouter une photo",
39
- cameraPermissionTitle: "Accès à l'appareil photo refusé",
40
- cameraPermissionMessage: "Autorise l'accès dans les réglages du téléphone pour prendre une photo.",
41
- libraryPermissionTitle: "Accès aux photos refusé",
42
- libraryPermissionMessage: "Autorise l'accès dans les réglages du téléphone pour choisir une photo.",
43
- takePhoto: "Prendre une photo",
44
- chooseFromLibrary: "Choisir dans la galerie",
45
- cancel: "Annuler",
46
- removePhoto: "Retirer la photo",
37
+ fr: {
38
+ photoTitle: (photoLabel) => `Photo ${photoLabel}`,
39
+ editAccessibilityLabel: (photoLabel) => `Photo ${photoLabel}. Modifier.`,
40
+ addAccessibilityLabel: (photoLabel) => `Ajouter une photo ${photoLabel}`,
41
+ addPlaceholderText: "Ajouter une photo",
42
+ cameraPermissionTitle: "Accès à l'appareil photo refusé",
43
+ cameraPermissionMessage: "Autorise l'accès dans les réglages du téléphone pour prendre une photo.",
44
+ takePhoto: "Prendre une photo",
45
+ chooseFromLibrary: "Choisir dans la galerie",
46
+ cancel: "Annuler",
47
+ removePhoto: "Retirer la photo",
48
+ },
49
+ en: {
50
+ photoTitle: (photoLabel) => `Photo ${photoLabel}`,
51
+ editAccessibilityLabel: (photoLabel) => `Photo ${photoLabel}. Edit.`,
52
+ addAccessibilityLabel: (photoLabel) => `Add a photo ${photoLabel}`,
53
+ addPlaceholderText: "Add a photo",
54
+ cameraPermissionTitle: "Camera access denied",
55
+ cameraPermissionMessage: "Allow access in the phone's settings to take a photo.",
56
+ takePhoto: "Take a photo",
57
+ chooseFromLibrary: "Choose from library",
58
+ cancel: "Cancel",
59
+ removePhoto: "Remove photo",
60
+ },
47
61
  };
48
62
  // Photo picker (camera or library) with a preview.
49
- export function PhotoPicker({ photoUri, onChange, savePhoto, photoLabel, labels, styles, }) {
50
- // Style fields are merged as arrays (default, then override) so a partial
51
- // override only changes the properties it specifies instead of replacing
52
- // the whole default style object.
63
+ export function PhotoPicker({ photoUri, onChange, savePhoto, photoLabel, labels, locale, styles, }) {
53
64
  const mergedStyles = {
54
- photoPicker: [defaultStyles.photoPicker, styles?.photoPicker],
55
- photoPreview: [defaultStyles.photoPreview, styles?.photoPreview],
56
- photoPlaceholder: [
57
- defaultStyles.photoPlaceholder,
58
- styles?.photoPlaceholder,
59
- ],
60
- photoPlaceholderText: [
61
- defaultStyles.photoPlaceholderText,
62
- styles?.photoPlaceholderText,
63
- ],
64
- clearLink: [defaultStyles.clearLink, styles?.clearLink],
65
+ ...mergeSlotStyles(defaultStyles, styles),
65
66
  iconColor: styles?.iconColor ?? defaultStyles.iconColor,
66
67
  };
67
- const t = { ...defaultLabels, ...labels };
68
+ const t = { ...defaultLabels[useKitLocale(locale)], ...labels };
68
69
  async function pickFromCamera() {
69
70
  const permission = await ImagePicker.requestCameraPermissionsAsync();
70
71
  if (!permission.granted) {
@@ -81,12 +82,10 @@ export function PhotoPicker({ photoUri, onChange, savePhoto, photoLabel, labels,
81
82
  onChange(await savePhoto(result.assets[0].uri));
82
83
  }
83
84
  }
85
+ // No permission request: the library is opened through the system photo
86
+ // picker, which needs none — so apps don't have to keep the storage
87
+ // permissions just for this.
84
88
  async function pickFromLibrary() {
85
- const permission = await ImagePicker.requestMediaLibraryPermissionsAsync();
86
- if (!permission.granted) {
87
- Alert.alert(t.libraryPermissionTitle, t.libraryPermissionMessage);
88
- return;
89
- }
90
89
  const result = await ImagePicker.launchImageLibraryAsync({
91
90
  mediaTypes: "images",
92
91
  quality: 0.5,
@@ -1,3 +1,4 @@
1
+ import { type KitLocale } from "../../i18n/locale.js";
1
2
  import type { PickerModalLabels, PickerModalStyles } from "./PickerModal.styles.js";
2
3
  export type { PickerModalLabels, PickerModalStyles, } from "./PickerModal.styles.js";
3
4
  export interface PickerItem {
@@ -35,7 +36,12 @@ export interface PickerModalProps {
35
36
  */
36
37
  groupOrder?: string[];
37
38
  labels?: PickerModalLabels;
39
+ /**
40
+ * Language of the built-in labels and of voice search — French by default, or the nearest
41
+ * `KitLocaleProvider`'s. `labels` still overrides individual strings.
42
+ */
43
+ locale?: KitLocale;
38
44
  styles?: PickerModalStyles;
39
45
  }
40
- export declare function PickerModal({ visible, title, items, onSelect, onClose, emptyMessage, initialQuery, filterItems, extraActions, groupOrder, labels, styles, }: PickerModalProps): import("react").JSX.Element;
46
+ export declare function PickerModal({ visible, title, items, onSelect, onClose, emptyMessage, initialQuery, filterItems, extraActions, groupOrder, labels, locale, styles, }: PickerModalProps): import("react").JSX.Element;
41
47
  //# sourceMappingURL=PickerModal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PickerModal.d.ts","sourceRoot":"","sources":["../../../src/components/picker/PickerModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AAMjC,YAAY,EACV,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;IACnE,qFAAqF;IACrF,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,EAAE,CAAC;IACxD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAID,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,MAAM,EACN,MAAM,GACP,EAAE,gBAAgB,+BAwJlB"}
1
+ {"version":3,"file":"PickerModal.d.ts","sourceRoot":"","sources":["../../../src/components/picker/PickerModal.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AAGpE,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AAMjC,YAAY,EACV,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;IACnE,qFAAqF;IACrF,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,EAAE,CAAC;IACxD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAID,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,MAAM,EACN,MAAM,EACN,MAAM,GACP,EAAE,gBAAgB,+BAsIlB"}