@lotics/ui 7.17.0 → 7.18.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/AGENTS.md CHANGED
@@ -21,9 +21,11 @@ typeahead, async search, virtualization, and a11y the primitive already ships.
21
21
  app stays English. Wired so far: `Pagination`, `SortHeader`/`Table.sortLabels`, `OptionList`
22
22
  (+ `Select`/`Combobox` built on it), `FilterChip`, `Drawer`, `Confidence`, `RemainderMeter`,
23
23
  `ChangeReview`/`ChangeReviewActions`, `DateRangeFilterField`/`DateFilter` (presets + footer +
24
- time-segment a11y, one `dateRange` slice), and `FormField` (the `optional` marker). Adding a string to a wired component's `*Labels` forces
24
+ time-segment a11y, one `dateRange` slice), `FormField` (the `optional` marker), and
25
+ `FileRows`/`FileGalleryModal`/`FilePreview` (one `gallery` slice: the ⋯ menu incl. remove+confirm,
26
+ the gallery chrome, and the preview captions). Adding a string to a wired component's `*Labels` forces
25
27
  both packs in `locale.tsx` to fill it (compile error) — that's how the kit avoids a silent English
26
- leak. Not yet on the provider (pass `labels` for now): calendar/gantt, the file/preview/comment labels.
28
+ leak. Not yet on the provider (pass `labels` for now): calendar/gantt, the comment labels.
27
29
 
28
30
  ---
29
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/ui",
3
- "version": "7.17.0",
3
+ "version": "7.18.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./tokens": "./src/tokens.ts",
@@ -18,7 +18,8 @@ import type { DisplayFile } from "./file_thumbnail";
18
18
  import { FilePreview } from "./file_preview";
19
19
  import { isImageMimeType } from "./mime";
20
20
  import { useImageRotation, type ImageRotation } from "./use_image_rotation";
21
- import { resolveGalleryLabels, type GalleryLabels } from "./file_preview_types";
21
+ import { type GalleryLabels } from "./file_preview_types";
22
+ import { useLoticsLocale } from "./locale";
22
23
  import { downloadFileFromUrl } from "./download";
23
24
  import { ActionMenu, type ActionMenuItem } from "./action_menu";
24
25
  import { useScreenSize } from "./use_screen_size";
@@ -153,7 +154,7 @@ export function FileGalleryModal(props: FileGalleryModalProps) {
153
154
  const file = files[activeIndex];
154
155
  if (!file) return null;
155
156
 
156
- const l = resolveGalleryLabels(labels);
157
+ const l = { ...useLoticsLocale().gallery, ...labels };
157
158
  const isImage = isImageMimeType(file.mimeType);
158
159
  const total = files.length;
159
160
  const rotated = rot.rotationFor(file.id) !== 0;
@@ -3,7 +3,8 @@ import { Text } from "./text";
3
3
  import { DocumentCard } from "./file_thumbnail";
4
4
  import { isImageMimeType } from "./mime";
5
5
  import { RotatableImage } from "./rotatable_image";
6
- import { type FilePreviewProps, resolveLabels } from "./file_preview_types";
6
+ import { type FilePreviewProps } from "./file_preview_types";
7
+ import { useLoticsLocale } from "./locale";
7
8
 
8
9
  /**
9
10
  * Native (mobile) fallback: images render full-bleed; everything else shows a
@@ -11,7 +12,7 @@ import { type FilePreviewProps, resolveLabels } from "./file_preview_types";
11
12
  * the `.web.tsx` variant carries it; native consumers download instead.
12
13
  */
13
14
  export function FilePreview({ file, labels, rotation }: FilePreviewProps) {
14
- const l = resolveLabels(labels);
15
+ const l = { ...useLoticsLocale().gallery, ...labels };
15
16
  if (isImageMimeType(file.mimeType)) {
16
17
  return <RotatableImage uri={file.url} alt={file.filename} rotation={rotation} />;
17
18
  }
@@ -13,7 +13,8 @@ import {
13
13
  isAudioMimeType,
14
14
  isPreviewableMimeType,
15
15
  } from "./mime";
16
- import { type FilePreviewProps, resolveLabels, type PreviewLabels } from "./file_preview_types";
16
+ import { type FilePreviewProps, type PreviewLabels } from "./file_preview_types";
17
+ import { useLoticsLocale } from "./locale";
17
18
  import { SpreadsheetView } from "./spreadsheet_view";
18
19
  import { RotatableImage } from "./rotatable_image";
19
20
  import { downloadFileFromUrl } from "./download";
@@ -36,7 +37,7 @@ import { colors } from "./colors";
36
37
  * (purity test). Lifted from the frontend gallery so both share one renderer.
37
38
  */
38
39
  export function FilePreview({ file, labels, onError, rotation, credentials }: FilePreviewProps) {
39
- const l = resolveLabels(labels);
40
+ const l = { ...useLoticsLocale().gallery, ...labels };
40
41
 
41
42
  if (isImageMimeType(file.mimeType)) {
42
43
  return (
@@ -2,8 +2,9 @@ import type { DisplayFile } from "./file_thumbnail";
2
2
 
3
3
  /**
4
4
  * Caption/error strings shown inside the preview. `@lotics/ui` is i18n-free
5
- * (purity test forbids lingui), so the host passes translated strings; English
6
- * is the fallback.
5
+ * (purity test forbids lingui): the strings resolve from the `LoticsLocale`
6
+ * `gallery` slice (`LoticsLocaleProvider`, default English) with a per-instance
7
+ * `labels` prop as the one-off override.
7
8
  */
8
9
  export interface PreviewLabels {
9
10
  notAvailable: string;
@@ -12,13 +13,6 @@ export interface PreviewLabels {
12
13
  passwordProtected: string;
13
14
  }
14
15
 
15
- export const defaultPreviewLabels: PreviewLabels = {
16
- notAvailable: "Preview not available",
17
- loadFailed: "Failed to load preview",
18
- download: "Download file",
19
- passwordProtected: "This file is password-protected and cannot be previewed",
20
- };
21
-
22
16
  export interface FilePreviewProps {
23
17
  file: DisplayFile;
24
18
  /** Override any subset of the English default labels. */
@@ -40,14 +34,10 @@ export interface FilePreviewProps {
40
34
  credentials?: RequestCredentials;
41
35
  }
42
36
 
43
- export function resolveLabels(labels: Partial<PreviewLabels> | undefined): PreviewLabels {
44
- return labels ? { ...defaultPreviewLabels, ...labels } : defaultPreviewLabels;
45
- }
46
-
47
37
  /**
48
38
  * Strings for the full-screen `FileGalleryModal` chrome (toolbar + nav), on top
49
- * of the inner `PreviewLabels`. Same i18n-free contract: host passes translated
50
- * strings, English is the fallback.
39
+ * of the inner `PreviewLabels`. Same contract: the `LoticsLocale` `gallery`
40
+ * slice supplies them; a per-instance `labels` prop overrides.
51
41
  */
52
42
  export interface GalleryLabels extends PreviewLabels {
53
43
  close: string;
@@ -65,22 +55,3 @@ export interface GalleryLabels extends PreviewLabels {
65
55
  saveRotation: string;
66
56
  }
67
57
 
68
- export const defaultGalleryLabels: GalleryLabels = {
69
- ...defaultPreviewLabels,
70
- close: "Close",
71
- previous: "Previous",
72
- next: "Next",
73
- actions: "Actions",
74
- openExternal: "Open in new tab",
75
- remove: "Remove",
76
- removeConfirmTitle: "Remove file",
77
- removeConfirmMessage: (filename) => `Remove "${filename}"?`,
78
- cancel: "Cancel",
79
- rotateLeft: "Rotate left",
80
- rotateRight: "Rotate right",
81
- saveRotation: "Save rotation",
82
- };
83
-
84
- export function resolveGalleryLabels(labels: Partial<GalleryLabels> | undefined): GalleryLabels {
85
- return labels ? { ...defaultGalleryLabels, ...labels } : defaultGalleryLabels;
86
- }
package/src/file_rows.tsx CHANGED
@@ -12,7 +12,8 @@ import { ActionMenu, type ActionMenuItem } from "./action_menu";
12
12
  import { FileGalleryModal } from "./file_gallery_modal";
13
13
  import { resolveMime } from "./file_badge";
14
14
  import { downloadFileFromUrl } from "./download";
15
- import { resolveGalleryLabels, type GalleryLabels } from "./file_preview_types";
15
+ import { type GalleryLabels } from "./file_preview_types";
16
+ import { useLoticsLocale } from "./locale";
16
17
  import type { DisplayFile } from "./file_thumbnail";
17
18
 
18
19
  export interface FileRowsProps {
@@ -47,7 +48,7 @@ export interface FileRowsProps {
47
48
  */
48
49
  export function FileRows({ files, meta, onRemove, onOpenExternal, onDownload, onError, labels, gap = 8, credentials }: FileRowsProps) {
49
50
  const [activeIndex, setActiveIndex] = useState<number | null>(null);
50
- const l = resolveGalleryLabels(labels);
51
+ const l = { ...useLoticsLocale().gallery, ...labels };
51
52
 
52
53
  if (files.length === 0) return null;
53
54
 
package/src/locale.tsx CHANGED
@@ -5,6 +5,7 @@ import { type ConfidenceLabels } from "./confidence";
5
5
  import { type FindingLabels } from "./finding";
6
6
  import { type RemainderMeterLabels } from "./remainder_meter";
7
7
  import { type DateRangeFilterFieldLabels } from "./date_range_filter_field";
8
+ import { type GalleryLabels } from "./file_preview_types";
8
9
 
9
10
  /**
10
11
  * The kit's localizable strings, one slice per string-bearing component. A
@@ -61,6 +62,10 @@ export interface LoticsLocale {
61
62
  * from/to, the footer Clear/Done, the trigger placeholder, and the time-field
62
63
  * segment a11y names. */
63
64
  dateRange: DateRangeFilterFieldLabels;
65
+ /** `FileRows` / `FileGalleryModal` / `FilePreview`: the per-row ⋯ menu
66
+ * (open/download/remove + the confirm), the gallery chrome (close, prev/next,
67
+ * rotate), and the preview captions (not-available / load-failed / password). */
68
+ gallery: GalleryLabels;
64
69
  }
65
70
 
66
71
  /** The platform default — English. Every component's hardcoded default lives
@@ -112,6 +117,24 @@ export const en: LoticsLocale = {
112
117
  selectDateRange: "Select date range", selectDate: "Select date",
113
118
  clear: "Clear", done: "Done", placeholder: "All time",
114
119
  },
120
+ gallery: {
121
+ close: "Close",
122
+ previous: "Previous",
123
+ next: "Next",
124
+ actions: "Actions",
125
+ openExternal: "Open in new tab",
126
+ remove: "Remove",
127
+ removeConfirmTitle: "Remove file",
128
+ removeConfirmMessage: (filename) => `Remove "${filename}"?`,
129
+ cancel: "Cancel",
130
+ rotateLeft: "Rotate left",
131
+ rotateRight: "Rotate right",
132
+ saveRotation: "Save rotation",
133
+ notAvailable: "Preview not available",
134
+ loadFailed: "Failed to load preview",
135
+ download: "Download file",
136
+ passwordProtected: "This file is password-protected and cannot be previewed",
137
+ },
115
138
  };
116
139
 
117
140
  /** Vietnamese. Maintained once here so every app (and the frontend) shares one
@@ -163,6 +186,24 @@ export const vi: LoticsLocale = {
163
186
  selectDateRange: "Chọn khoảng ngày", selectDate: "Chọn ngày",
164
187
  clear: "Xóa", done: "Xong", placeholder: "Tất cả thời gian",
165
188
  },
189
+ gallery: {
190
+ close: "Đóng",
191
+ previous: "Trước",
192
+ next: "Sau",
193
+ actions: "Thao tác",
194
+ openExternal: "Mở trong thẻ mới",
195
+ remove: "Gỡ tệp",
196
+ removeConfirmTitle: "Gỡ tệp",
197
+ removeConfirmMessage: (filename) => `Gỡ "${filename}"?`,
198
+ cancel: "Hủy",
199
+ rotateLeft: "Xoay trái",
200
+ rotateRight: "Xoay phải",
201
+ saveRotation: "Lưu ảnh đã xoay",
202
+ notAvailable: "Không xem trước được định dạng này",
203
+ loadFailed: "Không tải được bản xem trước",
204
+ download: "Tải xuống",
205
+ passwordProtected: "Tệp có mật khẩu — không xem trước được",
206
+ },
166
207
  };
167
208
 
168
209
  const LoticsLocaleContext = createContext<LoticsLocale>(en);