@lotics/ui 18.1.0 → 18.2.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/package.json +1 -1
- package/src/file_grid.tsx +5 -0
- package/src/file_thumbnail.tsx +27 -10
- package/src/file_thumbnail_grid.tsx +4 -0
package/package.json
CHANGED
package/src/file_grid.tsx
CHANGED
|
@@ -59,6 +59,10 @@ export interface FileGridProps {
|
|
|
59
59
|
* e.g. open the gallery at the first hidden file. */
|
|
60
60
|
onOverflowPress?: (hiddenCount: number) => void;
|
|
61
61
|
style?: ViewStyle;
|
|
62
|
+
/** Render every tile INERT — no press, no `button` role, no tab stop. Use it
|
|
63
|
+
* when something ABOVE the grid owns the press (a table cell, a popover
|
|
64
|
+
* trigger, a pressable row): a tile that keeps its button nests one button
|
|
65
|
+
* inside another. */
|
|
62
66
|
disablePress?: boolean;
|
|
63
67
|
partialRowAlign?: "start" | "end";
|
|
64
68
|
selectedIds?: ReadonlySet<string>;
|
|
@@ -162,6 +166,7 @@ export function FileGrid(props: FileGridProps) {
|
|
|
162
166
|
file={item.file}
|
|
163
167
|
size={size}
|
|
164
168
|
onPress={disablePress ? undefined : () => handleFilePress(item.file)}
|
|
169
|
+
disablePress={disablePress}
|
|
165
170
|
onRemove={onDisplayRemove ? () => onDisplayRemove(item.removeId) : undefined}
|
|
166
171
|
selected={selectedIds?.has(item.file.id)}
|
|
167
172
|
/>
|
package/src/file_thumbnail.tsx
CHANGED
|
@@ -66,6 +66,12 @@ interface FileThumbnailProps {
|
|
|
66
66
|
size?: number;
|
|
67
67
|
/** Called when thumbnail is pressed */
|
|
68
68
|
onPress?: () => void;
|
|
69
|
+
/** Render the tile INERT — no press handler, no `button` role, no tab stop.
|
|
70
|
+
* Without this an `onPress`-less tile still falls back to opening the file,
|
|
71
|
+
* so it stays a `<button>`: dropping a strip into a pressable row (a table
|
|
72
|
+
* cell, a `PressableRow`) then nests a button in a button. Set it whenever
|
|
73
|
+
* something ABOVE the tile owns the press. */
|
|
74
|
+
disablePress?: boolean;
|
|
69
75
|
/** Called when thumbnail is long-pressed */
|
|
70
76
|
onLongPress?: () => void;
|
|
71
77
|
/** Called when the completed file is removed */
|
|
@@ -87,8 +93,15 @@ interface FileThumbnailProps {
|
|
|
87
93
|
* Works with any file source via DisplayFile interface.
|
|
88
94
|
*/
|
|
89
95
|
export function FileThumbnail(props: FileThumbnailProps) {
|
|
90
|
-
const { file, size, onPress, onLongPress, onRemove, selected, uploading, isTemplate } = props;
|
|
96
|
+
const { file, size, onPress, onLongPress, onRemove, selected, uploading, isTemplate, disablePress } = props;
|
|
91
97
|
const accessibilityLabel = props.accessibilityLabel ?? file.filename;
|
|
98
|
+
// A tile with no `onPress` still OPENS the file — a useful default for a bare
|
|
99
|
+
// thumbnail in a list or a gallery. But a caller that said `disablePress`
|
|
100
|
+
// means it: inventing a handler there renders a <button>, and the one place a
|
|
101
|
+
// compact strip belongs is a table cell, which is itself pressable. Nesting a
|
|
102
|
+
// button in a button is invalid HTML and two tab stops for one action.
|
|
103
|
+
const press = disablePress ? undefined : onPress;
|
|
104
|
+
const pressOrOpen = disablePress ? undefined : (onPress ?? (() => Linking.openURL(file.url)));
|
|
92
105
|
|
|
93
106
|
const rootStyle =
|
|
94
107
|
size !== undefined ? { width: size, height: size } : { width: "100%" as const, aspectRatio: 1 };
|
|
@@ -96,7 +109,7 @@ export function FileThumbnail(props: FileThumbnailProps) {
|
|
|
96
109
|
if (isImageMimeType(file.mimeType)) {
|
|
97
110
|
return (
|
|
98
111
|
<View style={rootStyle}>
|
|
99
|
-
<ImageThumbnail file={file} size={size} accessibilityLabel={accessibilityLabel} onPress={
|
|
112
|
+
<ImageThumbnail file={file} size={size} accessibilityLabel={accessibilityLabel} onPress={press} onLongPress={onLongPress} />
|
|
100
113
|
{uploading && <UploadingOverlay size={size} />}
|
|
101
114
|
{onRemove && <RemoveButton onPress={onRemove} />}
|
|
102
115
|
{selected !== undefined && <SelectionOverlay selected={selected} />}
|
|
@@ -114,7 +127,7 @@ export function FileThumbnail(props: FileThumbnailProps) {
|
|
|
114
127
|
size={size}
|
|
115
128
|
isTemplate={isTemplate}
|
|
116
129
|
accessibilityLabel={accessibilityLabel}
|
|
117
|
-
onPress={
|
|
130
|
+
onPress={pressOrOpen}
|
|
118
131
|
onLongPress={onLongPress}
|
|
119
132
|
/>
|
|
120
133
|
{uploading && <UploadingOverlay size={size} />}
|
|
@@ -132,7 +145,7 @@ export function FileThumbnail(props: FileThumbnailProps) {
|
|
|
132
145
|
icon={mediaIcon}
|
|
133
146
|
size={size}
|
|
134
147
|
accessibilityLabel={accessibilityLabel}
|
|
135
|
-
onPress={
|
|
148
|
+
onPress={pressOrOpen}
|
|
136
149
|
onLongPress={onLongPress}
|
|
137
150
|
/>
|
|
138
151
|
) : (
|
|
@@ -142,7 +155,7 @@ export function FileThumbnail(props: FileThumbnailProps) {
|
|
|
142
155
|
size={size}
|
|
143
156
|
isTemplate={isTemplate}
|
|
144
157
|
accessibilityLabel={accessibilityLabel}
|
|
145
|
-
onPress={
|
|
158
|
+
onPress={pressOrOpen}
|
|
146
159
|
onLongPress={onLongPress}
|
|
147
160
|
/>
|
|
148
161
|
)}
|
|
@@ -206,7 +219,8 @@ export function DocumentBadge(props: DocumentBadgeProps) {
|
|
|
206
219
|
<Pressable
|
|
207
220
|
onPress={onPress}
|
|
208
221
|
onLongPress={onLongPress}
|
|
209
|
-
accessibilityRole="button"
|
|
222
|
+
accessibilityRole={onPress ? "button" : undefined}
|
|
223
|
+
tabIndex={onPress ? undefined : -1}
|
|
210
224
|
accessibilityLabel={accessibilityLabel ?? resolveMime(mimeType).label}
|
|
211
225
|
{...focusProps}
|
|
212
226
|
style={focusVisible ? { boxShadow: FOCUS_RING, borderRadius: 6 } : undefined}
|
|
@@ -262,7 +276,8 @@ export function DocumentCard(props: DocumentCardProps) {
|
|
|
262
276
|
]}
|
|
263
277
|
onPress={onPress}
|
|
264
278
|
onLongPress={onLongPress}
|
|
265
|
-
accessibilityRole="button"
|
|
279
|
+
accessibilityRole={onPress ? "button" : undefined}
|
|
280
|
+
tabIndex={onPress ? undefined : -1}
|
|
266
281
|
accessibilityLabel={a11yLabel}
|
|
267
282
|
{...focusProps}
|
|
268
283
|
>
|
|
@@ -313,7 +328,8 @@ export function MediaCard(props: MediaCardProps) {
|
|
|
313
328
|
style={({ pressed }) => [styles.mediaCardCompact, sizeStyle, { backgroundColor: color }, pressed && styles.pressedDim, focusVisible && { boxShadow: FOCUS_RING }]}
|
|
314
329
|
onPress={onPress}
|
|
315
330
|
onLongPress={onLongPress}
|
|
316
|
-
accessibilityRole="button"
|
|
331
|
+
accessibilityRole={onPress ? "button" : undefined}
|
|
332
|
+
tabIndex={onPress ? undefined : -1}
|
|
317
333
|
accessibilityLabel={a11yLabel}
|
|
318
334
|
{...focusProps}
|
|
319
335
|
>
|
|
@@ -327,7 +343,8 @@ export function MediaCard(props: MediaCardProps) {
|
|
|
327
343
|
const backdrop = iconSize + 20;
|
|
328
344
|
|
|
329
345
|
return (
|
|
330
|
-
<Pressable style={[styles.documentCard, sizeStyle, focusVisible && { boxShadow: FOCUS_RING }]} onPress={onPress} onLongPress={onLongPress} accessibilityRole="button"
|
|
346
|
+
<Pressable style={[styles.documentCard, sizeStyle, focusVisible && { boxShadow: FOCUS_RING }]} onPress={onPress} onLongPress={onLongPress} accessibilityRole={onPress ? "button" : undefined}
|
|
347
|
+
tabIndex={onPress ? undefined : -1} accessibilityLabel={a11yLabel} {...focusProps}>
|
|
331
348
|
{(state) => (
|
|
332
349
|
<>
|
|
333
350
|
<View style={[styles.mediaCardBody, { backgroundColor: color }]}>
|
|
@@ -381,7 +398,7 @@ function ImageThumbnail(props: ImageThumbnailProps) {
|
|
|
381
398
|
: { width: "100%" as const, height: "100%" as const };
|
|
382
399
|
|
|
383
400
|
return (
|
|
384
|
-
<Pressable onPress={onPress} onLongPress={onLongPress} accessibilityRole={onPress ? "button" : "image"} accessibilityLabel={a11yLabel} {...focusProps} style={[styles.imageThumbnail, sizeStyle, focusVisible && { boxShadow: FOCUS_RING }]}>
|
|
401
|
+
<Pressable onPress={onPress} onLongPress={onLongPress} accessibilityRole={onPress ? "button" : "image"} tabIndex={onPress ? undefined : -1} accessibilityLabel={a11yLabel} {...focusProps} style={[styles.imageThumbnail, sizeStyle, focusVisible && { boxShadow: FOCUS_RING }]}>
|
|
385
402
|
{(state) => (
|
|
386
403
|
<>
|
|
387
404
|
<Image
|
|
@@ -188,6 +188,10 @@ export function FileThumbnailGrid(props: FileThumbnailGridProps) {
|
|
|
188
188
|
file={file}
|
|
189
189
|
size={size}
|
|
190
190
|
onPress={disablePress || !onFilePress ? undefined : () => onFilePress(file)}
|
|
191
|
+
// Withholding `onPress` is NOT enough: a tile with none falls back to
|
|
192
|
+
// opening the file, so it stays a button and a tab stop. The prop has
|
|
193
|
+
// to reach the tile that honors it.
|
|
194
|
+
disablePress={disablePress}
|
|
191
195
|
onRemove={onRemove ? () => onRemove(file.id) : undefined}
|
|
192
196
|
selected={selectedIds?.has(file.id)}
|
|
193
197
|
/>
|