@xsolla/xui-image-uploader 0.149.0 → 0.149.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.
- package/README.md +41 -11
- package/native/index.d.mts +30 -10
- package/native/index.d.ts +30 -10
- package/native/index.js +40 -20
- package/native/index.js.map +1 -1
- package/native/index.mjs +40 -20
- package/native/index.mjs.map +1 -1
- package/package.json +5 -5
- package/web/index.d.mts +30 -10
- package/web/index.d.ts +30 -10
- package/web/index.js +40 -20
- package/web/index.js.map +1 -1
- package/web/index.mjs +40 -20
- package/web/index.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ImageUploader
|
|
2
2
|
|
|
3
|
-
A cross-platform React image uploader component supporting click-to-pick, drag-and-drop (web), controlled and uncontrolled usage, image preview with hover-to-remove, loading
|
|
3
|
+
A cross-platform React image uploader component supporting click-to-pick, drag-and-drop (web), controlled and uncontrolled usage, image preview with hover-to-remove, automatic loading state from async `onUpload`, error states, and a wide horizontal layout.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -66,7 +66,37 @@ export default function WideView() {
|
|
|
66
66
|
}
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
###
|
|
69
|
+
### Async Upload (Recommended)
|
|
70
|
+
|
|
71
|
+
If `onUpload` returns a `Promise`, the component automatically:
|
|
72
|
+
|
|
73
|
+
- Shows the uploading state (spinner + `uploadingPlaceholder`) until the
|
|
74
|
+
promise settles.
|
|
75
|
+
- On resolve with `{ url, filename? }` **or** a bare `string` URL, fires
|
|
76
|
+
`onChange(value)` with the canonical value — no manual wiring needed.
|
|
77
|
+
- On reject, fires `onChange(null, error)`.
|
|
78
|
+
|
|
79
|
+
You don't need `async`/`await` in the handler — just return the upload promise:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { ImageUploader } from '@xsolla/xui-image-uploader';
|
|
83
|
+
|
|
84
|
+
export default function AutoUpload() {
|
|
85
|
+
return (
|
|
86
|
+
<ImageUploader
|
|
87
|
+
uploadingPlaceholder="Uploading…"
|
|
88
|
+
// uploadFn can return Promise<string> or Promise<{ url, filename? }>
|
|
89
|
+
onUpload={file => uploadFn(file.file)}
|
|
90
|
+
onChange={value => form.setFieldValue('avatar', value?.url ?? null)}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Manual Loading Control
|
|
97
|
+
|
|
98
|
+
For finer-grained control (e.g. uploads triggered outside the component, or
|
|
99
|
+
to keep the spinner visible during post-upload work), pass `loading` explicitly:
|
|
70
100
|
|
|
71
101
|
```tsx
|
|
72
102
|
import * as React from 'react';
|
|
@@ -172,16 +202,16 @@ always discoverable.
|
|
|
172
202
|
| Prop | Type | Default | Description |
|
|
173
203
|
| :--- | :--- | :------ | :---------- |
|
|
174
204
|
| size | `"xl" \| "lg" \| "md" \| "sm" \| "xs"` | `"xl"` | Visual size of the uploader. |
|
|
175
|
-
| placeholder | `
|
|
176
|
-
| uploadingPlaceholder | `
|
|
205
|
+
| placeholder | `React.ReactNode` | `"Upload"` | Label shown under the icon (or filename in error state). Accepts a string or a custom React node. |
|
|
206
|
+
| uploadingPlaceholder | `React.ReactNode` | `"Uploading"` | Label shown while `loading` is true. Accepts a string or a custom React node. |
|
|
177
207
|
| description | `React.ReactNode` | - | Helper text below the placeholder. Only rendered when `wideView` is true. |
|
|
178
208
|
| errorMessage | `string` | - | Error message — when provided, the component renders in the error state. |
|
|
179
|
-
| wideView | `boolean` | `false` | Use the horizontal layout
|
|
209
|
+
| wideView | `boolean` | `false` | Use the horizontal layout. The box stretches to fill its parent's width. |
|
|
180
210
|
| disabled | `boolean` | `false` | Disabled state. |
|
|
181
211
|
| loading | `boolean` | `false` | Controlled loading state (shows spinner + uploading label). |
|
|
182
212
|
| value | `ImageUploaderValue \| null` | - | Controlled value. When provided, the component reflects this value. |
|
|
183
|
-
| onUpload | `(file: ImageUploaderFile) => void
|
|
184
|
-
| onChange | `(value: ImageUploaderValue \| null) => void` | - | Fires when the displayed value changes — on file pick (with a local data-URL preview)
|
|
213
|
+
| onUpload | `(file: ImageUploaderFile) => void \| Promise<ImageUploaderValue \| string \| void>` | - | Fires when the user picks (or drops) a file. If it returns a `Promise`, the component shows the uploading state until it settles, forwards a resolved value (object or bare URL string) to `onChange`, and forwards a rejection to `onChange(null, error)`. |
|
|
214
|
+
| onChange | `(value: ImageUploaderValue \| null, error?: Error) => void` | - | Fires when the displayed value changes — on file pick (with a local data-URL preview), after `onUpload` resolves (with the server value), or on remove (`null`). The optional `error` arg carries any rejection from `onUpload`. |
|
|
185
215
|
| onDelete | `() => void` | - | Fires when the user removes the image (trash click / clear). |
|
|
186
216
|
| accept | `string` | `"image/*"` | Accepted MIME types for the file input (web only). |
|
|
187
217
|
| openPicker | `() => Promise<ImageUploaderFile \| null>` | - | Native file picker hook. Required on native (no DOM `<input type="file">`). On web, omit this and the component falls back to a hidden file input. |
|
|
@@ -237,10 +267,10 @@ without a pointer.
|
|
|
237
267
|
|
|
238
268
|
### Layout
|
|
239
269
|
|
|
240
|
-
In `wideView`, the component stretches to fill its parent
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
270
|
+
In `wideView`, the component stretches to fill its parent's full width
|
|
271
|
+
(`width: 100%`), letting the consumer's layout (form column, grid cell, etc.)
|
|
272
|
+
control the maximum size. The square (non-wide) variants use fixed pixel
|
|
273
|
+
dimensions from the size tokens.
|
|
244
274
|
|
|
245
275
|
## Accessibility
|
|
246
276
|
|
package/native/index.d.mts
CHANGED
|
@@ -4,7 +4,7 @@ import { ThemeOverrideProps } from '@xsolla/xui-core';
|
|
|
4
4
|
type ImageUploaderSize = "xl" | "lg" | "md" | "sm" | "xs";
|
|
5
5
|
/** Controlled value shape. */
|
|
6
6
|
interface ImageUploaderValue {
|
|
7
|
-
filename
|
|
7
|
+
filename?: string;
|
|
8
8
|
url?: string;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
@@ -24,15 +24,15 @@ type ImageUploaderFile = {
|
|
|
24
24
|
interface ImageUploaderProps extends ThemeOverrideProps {
|
|
25
25
|
/** Size of the uploader. Figma default is `xl`. */
|
|
26
26
|
size?: ImageUploaderSize;
|
|
27
|
-
/** Placeholder
|
|
28
|
-
placeholder?:
|
|
29
|
-
/** Placeholder
|
|
30
|
-
uploadingPlaceholder?:
|
|
27
|
+
/** Placeholder shown under the icon. Accepts a string or a custom React node. */
|
|
28
|
+
placeholder?: React.ReactNode;
|
|
29
|
+
/** Placeholder shown while the file is uploading. Accepts a string or a custom React node. */
|
|
30
|
+
uploadingPlaceholder?: React.ReactNode;
|
|
31
31
|
/** Description below the placeholder. Only rendered when `wideView` is true. Accepts a string or a custom React node. */
|
|
32
32
|
description?: React.ReactNode;
|
|
33
33
|
/** Error message — when provided, component renders in the error state. */
|
|
34
34
|
errorMessage?: string;
|
|
35
|
-
/** Wide view (horizontal layout). When true, box
|
|
35
|
+
/** Wide view (horizontal layout). When true, the box stretches to its parent's full width. */
|
|
36
36
|
wideView?: boolean;
|
|
37
37
|
/** Disabled state. */
|
|
38
38
|
disabled?: boolean;
|
|
@@ -43,16 +43,36 @@ interface ImageUploaderProps extends ThemeOverrideProps {
|
|
|
43
43
|
/**
|
|
44
44
|
* Fires when the user picks (or drops) a file. Use this to perform the
|
|
45
45
|
* actual upload — the component itself does no I/O.
|
|
46
|
+
*
|
|
47
|
+
* If the handler returns a `Promise`:
|
|
48
|
+
* - The component automatically shows the uploading state (spinner +
|
|
49
|
+
* `uploadingPlaceholder`) until the promise settles.
|
|
50
|
+
* - If the promise resolves to an `ImageUploaderValue` (`{url, filename?}`)
|
|
51
|
+
* or a `string` URL, the component automatically calls `onChange(value)`
|
|
52
|
+
* with that value. The string form is sugar for `{url: <string>}`.
|
|
53
|
+
* - If the promise rejects, the component calls `onChange(null, error)`.
|
|
54
|
+
*
|
|
55
|
+
* For finer-grained control, pass `loading` explicitly instead.
|
|
46
56
|
*/
|
|
47
|
-
onUpload?: (file: ImageUploaderFile) => void
|
|
57
|
+
onUpload?: (file: ImageUploaderFile) => void | Promise<ImageUploaderValue | string | void>;
|
|
48
58
|
/**
|
|
49
59
|
* Fires when the displayed value changes — on file pick (with a local
|
|
50
|
-
* data-URL preview)
|
|
60
|
+
* data-URL preview), after upload resolves (with the server value), or on
|
|
61
|
+
* remove (`null`). The optional second argument carries any error thrown by
|
|
62
|
+
* the consumer's `onUpload`.
|
|
51
63
|
*/
|
|
52
|
-
onChange?: (value: ImageUploaderValue | null) => void;
|
|
64
|
+
onChange?: (value: ImageUploaderValue | null, error?: Error) => void;
|
|
53
65
|
/** Fires when the user removes the image (trash click / clear). */
|
|
54
66
|
onDelete?: () => void;
|
|
55
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Accepted file types — passed through to the hidden `<input accept>` as a
|
|
69
|
+
* picker hint (web only — ignored on native). Standard HTML syntax:
|
|
70
|
+
* comma-separated list of MIME types (`image/png`), MIME wildcards
|
|
71
|
+
* (`image/*`), or file extensions (`.png`). Defaults to `image/*`.
|
|
72
|
+
*
|
|
73
|
+
* No runtime validation is performed — the consumer's `onUpload` (or the
|
|
74
|
+
* backend it calls) is responsible for accepting/rejecting files.
|
|
75
|
+
*/
|
|
56
76
|
accept?: string;
|
|
57
77
|
/**
|
|
58
78
|
* Native file picker hook. Required on native (no DOM `<input type="file">`).
|
package/native/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ThemeOverrideProps } from '@xsolla/xui-core';
|
|
|
4
4
|
type ImageUploaderSize = "xl" | "lg" | "md" | "sm" | "xs";
|
|
5
5
|
/** Controlled value shape. */
|
|
6
6
|
interface ImageUploaderValue {
|
|
7
|
-
filename
|
|
7
|
+
filename?: string;
|
|
8
8
|
url?: string;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
@@ -24,15 +24,15 @@ type ImageUploaderFile = {
|
|
|
24
24
|
interface ImageUploaderProps extends ThemeOverrideProps {
|
|
25
25
|
/** Size of the uploader. Figma default is `xl`. */
|
|
26
26
|
size?: ImageUploaderSize;
|
|
27
|
-
/** Placeholder
|
|
28
|
-
placeholder?:
|
|
29
|
-
/** Placeholder
|
|
30
|
-
uploadingPlaceholder?:
|
|
27
|
+
/** Placeholder shown under the icon. Accepts a string or a custom React node. */
|
|
28
|
+
placeholder?: React.ReactNode;
|
|
29
|
+
/** Placeholder shown while the file is uploading. Accepts a string or a custom React node. */
|
|
30
|
+
uploadingPlaceholder?: React.ReactNode;
|
|
31
31
|
/** Description below the placeholder. Only rendered when `wideView` is true. Accepts a string or a custom React node. */
|
|
32
32
|
description?: React.ReactNode;
|
|
33
33
|
/** Error message — when provided, component renders in the error state. */
|
|
34
34
|
errorMessage?: string;
|
|
35
|
-
/** Wide view (horizontal layout). When true, box
|
|
35
|
+
/** Wide view (horizontal layout). When true, the box stretches to its parent's full width. */
|
|
36
36
|
wideView?: boolean;
|
|
37
37
|
/** Disabled state. */
|
|
38
38
|
disabled?: boolean;
|
|
@@ -43,16 +43,36 @@ interface ImageUploaderProps extends ThemeOverrideProps {
|
|
|
43
43
|
/**
|
|
44
44
|
* Fires when the user picks (or drops) a file. Use this to perform the
|
|
45
45
|
* actual upload — the component itself does no I/O.
|
|
46
|
+
*
|
|
47
|
+
* If the handler returns a `Promise`:
|
|
48
|
+
* - The component automatically shows the uploading state (spinner +
|
|
49
|
+
* `uploadingPlaceholder`) until the promise settles.
|
|
50
|
+
* - If the promise resolves to an `ImageUploaderValue` (`{url, filename?}`)
|
|
51
|
+
* or a `string` URL, the component automatically calls `onChange(value)`
|
|
52
|
+
* with that value. The string form is sugar for `{url: <string>}`.
|
|
53
|
+
* - If the promise rejects, the component calls `onChange(null, error)`.
|
|
54
|
+
*
|
|
55
|
+
* For finer-grained control, pass `loading` explicitly instead.
|
|
46
56
|
*/
|
|
47
|
-
onUpload?: (file: ImageUploaderFile) => void
|
|
57
|
+
onUpload?: (file: ImageUploaderFile) => void | Promise<ImageUploaderValue | string | void>;
|
|
48
58
|
/**
|
|
49
59
|
* Fires when the displayed value changes — on file pick (with a local
|
|
50
|
-
* data-URL preview)
|
|
60
|
+
* data-URL preview), after upload resolves (with the server value), or on
|
|
61
|
+
* remove (`null`). The optional second argument carries any error thrown by
|
|
62
|
+
* the consumer's `onUpload`.
|
|
51
63
|
*/
|
|
52
|
-
onChange?: (value: ImageUploaderValue | null) => void;
|
|
64
|
+
onChange?: (value: ImageUploaderValue | null, error?: Error) => void;
|
|
53
65
|
/** Fires when the user removes the image (trash click / clear). */
|
|
54
66
|
onDelete?: () => void;
|
|
55
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Accepted file types — passed through to the hidden `<input accept>` as a
|
|
69
|
+
* picker hint (web only — ignored on native). Standard HTML syntax:
|
|
70
|
+
* comma-separated list of MIME types (`image/png`), MIME wildcards
|
|
71
|
+
* (`image/*`), or file extensions (`.png`). Defaults to `image/*`.
|
|
72
|
+
*
|
|
73
|
+
* No runtime validation is performed — the consumer's `onUpload` (or the
|
|
74
|
+
* backend it calls) is responsible for accepting/rejecting files.
|
|
75
|
+
*/
|
|
56
76
|
accept?: string;
|
|
57
77
|
/**
|
|
58
78
|
* Native file picker hook. Required on native (no DOM `<input type="file">`).
|
package/native/index.js
CHANGED
|
@@ -305,6 +305,8 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
305
305
|
const fileInputRef = (0, import_react.useRef)(null);
|
|
306
306
|
const isControlled = value !== void 0;
|
|
307
307
|
const [internalPreview, setInternalPreview] = (0, import_react.useState)(null);
|
|
308
|
+
const [isAutoUploading, setIsAutoUploading] = (0, import_react.useState)(false);
|
|
309
|
+
const [autoError, setAutoError] = (0, import_react.useState)(null);
|
|
308
310
|
const [isHover, setIsHover] = (0, import_react.useState)(false);
|
|
309
311
|
const [isFocus, setIsFocus] = (0, import_react.useState)(false);
|
|
310
312
|
const [isPreviewHover, setIsPreviewHover] = (0, import_react.useState)(false);
|
|
@@ -330,10 +332,11 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
330
332
|
const alertBorder = theme.colors.control.alert.border;
|
|
331
333
|
const alertText = theme.colors.content.alert.primary;
|
|
332
334
|
const scrim = theme.colors.layer.scrim;
|
|
333
|
-
const
|
|
335
|
+
const resolvedError = errorMessage || autoError;
|
|
336
|
+
const hasError = !!resolvedError;
|
|
334
337
|
let state;
|
|
335
338
|
if (disabled) state = "disable";
|
|
336
|
-
else if (loading) state = "uploading";
|
|
339
|
+
else if (loading || isAutoUploading) state = "uploading";
|
|
337
340
|
else if (hasError) state = "error";
|
|
338
341
|
else if (preview)
|
|
339
342
|
state = isPreviewHover || isHoverless ? "uploadedHover" : "uploaded";
|
|
@@ -341,25 +344,42 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
341
344
|
else if (isHover) state = "hover";
|
|
342
345
|
else state = "default";
|
|
343
346
|
const emitFile = (img) => {
|
|
347
|
+
setAutoError(null);
|
|
344
348
|
if (!isControlled) setInternalPreview(img.uri);
|
|
345
|
-
onUpload?.(img);
|
|
346
349
|
onChange?.({
|
|
347
350
|
filename: img.name,
|
|
348
351
|
url: img.uri
|
|
349
352
|
});
|
|
353
|
+
const result = onUpload?.(img);
|
|
354
|
+
if (result && typeof result.then === "function") {
|
|
355
|
+
setIsAutoUploading(true);
|
|
356
|
+
Promise.resolve(result).then((uploaded) => {
|
|
357
|
+
let next = null;
|
|
358
|
+
if (typeof uploaded === "string") {
|
|
359
|
+
next = { url: uploaded };
|
|
360
|
+
} else if (uploaded && typeof uploaded === "object" && "url" in uploaded) {
|
|
361
|
+
next = uploaded;
|
|
362
|
+
}
|
|
363
|
+
if (next) {
|
|
364
|
+
if (!isControlled) setInternalPreview(next.url ?? null);
|
|
365
|
+
onChange?.(next);
|
|
366
|
+
}
|
|
367
|
+
}).catch((err) => {
|
|
368
|
+
setAutoError(err?.message || "Upload failed");
|
|
369
|
+
if (!isControlled) setInternalPreview(null);
|
|
370
|
+
onChange?.(null, err);
|
|
371
|
+
}).finally(() => setIsAutoUploading(false));
|
|
372
|
+
}
|
|
350
373
|
};
|
|
351
374
|
const handleWebFile = (file) => {
|
|
352
|
-
if (!file.type.startsWith("image/")) return;
|
|
353
375
|
const reader = new FileReader();
|
|
354
376
|
reader.onload = (e) => {
|
|
355
377
|
const uri = e.target?.result;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
file
|
|
362
|
-
});
|
|
378
|
+
const enriched = file;
|
|
379
|
+
enriched.uri = uri;
|
|
380
|
+
enriched.mimeType = file.type;
|
|
381
|
+
enriched.file = enriched;
|
|
382
|
+
emitFile(enriched);
|
|
363
383
|
};
|
|
364
384
|
reader.readAsDataURL(file);
|
|
365
385
|
};
|
|
@@ -403,6 +423,7 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
403
423
|
};
|
|
404
424
|
const removeImage = (e) => {
|
|
405
425
|
e?.stopPropagation?.();
|
|
426
|
+
setAutoError(null);
|
|
406
427
|
if (!isControlled) setInternalPreview(null);
|
|
407
428
|
setIsPreviewHover(false);
|
|
408
429
|
onDelete?.();
|
|
@@ -446,6 +467,7 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
446
467
|
break;
|
|
447
468
|
}
|
|
448
469
|
const rootGap = state === "error" ? sizeStyles.errorGap : 0;
|
|
470
|
+
const placeholderContent = state === "uploading" ? uploadingPlaceholder : placeholder;
|
|
449
471
|
const renderInner = () => {
|
|
450
472
|
if (state === "uploaded" || state === "uploadedHover") {
|
|
451
473
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
@@ -506,7 +528,7 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
506
528
|
...isWeb && { "aria-hidden": "true" }
|
|
507
529
|
}
|
|
508
530
|
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box, { ...isWeb && { "aria-hidden": "true" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_xui_icons_base.Image, { size: sizeStyles.iconSize, color: iconColor }) }),
|
|
509
|
-
|
|
531
|
+
placeholderContent && (typeof placeholderContent === "string" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
510
532
|
Text,
|
|
511
533
|
{
|
|
512
534
|
"data-testid": "image-uploader__placeholder",
|
|
@@ -522,9 +544,9 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
522
544
|
textOverflow: "ellipsis",
|
|
523
545
|
whiteSpace: "nowrap"
|
|
524
546
|
} : void 0,
|
|
525
|
-
children:
|
|
547
|
+
children: placeholderContent
|
|
526
548
|
}
|
|
527
|
-
),
|
|
549
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box, { "data-testid": "image-uploader__placeholder", children: placeholderContent })),
|
|
528
550
|
description && wideView && state !== "uploading" && state !== "error" && (typeof description === "string" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
529
551
|
Text,
|
|
530
552
|
{
|
|
@@ -582,9 +604,9 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
582
604
|
outline: "none",
|
|
583
605
|
transition: "background-color 0.15s ease, border-color 0.15s ease"
|
|
584
606
|
} : {};
|
|
585
|
-
const buttonAriaLabel = preview ? `Remove image${value?.filename ? `: ${value.filename}` : ""}` : state === "uploading" ? uploadingPlaceholder : placeholder;
|
|
607
|
+
const buttonAriaLabel = preview ? `Remove image${value?.filename ? `: ${value.filename}` : ""}` : state === "uploading" ? typeof uploadingPlaceholder === "string" ? uploadingPlaceholder : "Uploading" : typeof placeholder === "string" ? placeholder : "Upload";
|
|
586
608
|
const describedBy = [
|
|
587
|
-
state === "error" &&
|
|
609
|
+
state === "error" && resolvedError ? errorId : null,
|
|
588
610
|
description && wideView && state !== "uploading" && state !== "error" ? descriptionId : null
|
|
589
611
|
].filter(Boolean).join(" ") || void 0;
|
|
590
612
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -595,7 +617,6 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
595
617
|
gap: rootGap,
|
|
596
618
|
alignItems: "flex-start",
|
|
597
619
|
width: wideView ? "100%" : void 0,
|
|
598
|
-
maxWidth: wideView ? sizeStyles.wideWidth : void 0,
|
|
599
620
|
children: [
|
|
600
621
|
isWeb && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
601
622
|
"input",
|
|
@@ -627,7 +648,6 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
627
648
|
...webOnlyHandlers,
|
|
628
649
|
position: "relative",
|
|
629
650
|
width: wideView ? "100%" : sizeStyles.box,
|
|
630
|
-
maxWidth: wideView ? sizeStyles.wideWidth : void 0,
|
|
631
651
|
height: sizeStyles.box,
|
|
632
652
|
flexDirection: "column",
|
|
633
653
|
alignItems: "center",
|
|
@@ -644,7 +664,7 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
644
664
|
children: renderInner()
|
|
645
665
|
}
|
|
646
666
|
),
|
|
647
|
-
state === "error" &&
|
|
667
|
+
state === "error" && resolvedError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
648
668
|
Text,
|
|
649
669
|
{
|
|
650
670
|
"data-testid": "image-uploader__error",
|
|
@@ -652,7 +672,7 @@ var ImageUploader = (0, import_react.forwardRef)(
|
|
|
652
672
|
fontSize: sizeStyles.errorFontSize,
|
|
653
673
|
lineHeight: sizeStyles.errorLineHeight,
|
|
654
674
|
...isWeb && { id: errorId, role: "alert" },
|
|
655
|
-
children:
|
|
675
|
+
children: resolvedError
|
|
656
676
|
}
|
|
657
677
|
)
|
|
658
678
|
]
|
package/native/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.tsx","../../src/ImageUploader.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/index.tsx"],"sourcesContent":["export * from \"./ImageUploader\";\n","import React, { useRef, useState, useEffect, forwardRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text, isWeb } from \"@xsolla/xui-primitives\";\nimport {\n useId,\n useResolvedTheme,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\nimport { Image, TrashCan } from \"@xsolla/xui-icons-base\";\nimport { Spinner } from \"@xsolla/xui-spinner\";\n\nexport type ImageUploaderSize = \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n\n/** Controlled value shape. */\nexport interface ImageUploaderValue {\n filename: string;\n url?: string;\n}\n\n/**\n * Normalized file shape produced by the platform picker / drag-drop pipeline.\n * - `uri` is a data-URL on web and a file URI on native.\n * - On web, the original `File` is passed through for consumers that need it\n * (e.g. to upload via FormData / fetch).\n */\nexport type ImageUploaderFile = {\n name: string;\n size: number;\n uri: string;\n mimeType?: string;\n /** The original DOM File (web only) */\n file?: File;\n};\n\nexport interface ImageUploaderProps extends ThemeOverrideProps {\n /** Size of the uploader. Figma default is `xl`. */\n size?: ImageUploaderSize;\n /** Placeholder text shown under the icon (e.g. \"Upload\" or filename in error). */\n placeholder?: string;\n /** Placeholder text shown while the file is uploading. */\n uploadingPlaceholder?: string;\n /** Description below the placeholder. Only rendered when `wideView` is true. Accepts a string or a custom React node. */\n description?: React.ReactNode;\n /** Error message — when provided, component renders in the error state. */\n errorMessage?: string;\n /** Wide view (horizontal layout). When true, box uses `wideWidth` from sizing. */\n wideView?: boolean;\n /** Disabled state. */\n disabled?: boolean;\n /** Controlled loading state (shows spinner + \"Uploading\" label). */\n loading?: boolean;\n\n /** Controlled value. When provided, the component reflects this value. */\n value?: ImageUploaderValue | null;\n\n /**\n * Fires when the user picks (or drops) a file. Use this to perform the\n * actual upload — the component itself does no I/O.\n */\n onUpload?: (file: ImageUploaderFile) => void;\n /**\n * Fires when the displayed value changes — on file pick (with a local\n * data-URL preview) and on remove (`null`).\n */\n onChange?: (value: ImageUploaderValue | null) => void;\n /** Fires when the user removes the image (trash click / clear). */\n onDelete?: () => void;\n\n /** Accepted file types (web only — ignored on native). */\n accept?: string;\n /**\n * Native file picker hook. Required on native (no DOM `<input type=\"file\">`).\n * On web, omit this and the component falls back to a hidden file input.\n */\n openPicker?: () => Promise<ImageUploaderFile | null>;\n}\n\ntype InternalState =\n | \"default\"\n | \"hover\"\n | \"focus\"\n | \"uploading\"\n | \"uploaded\"\n | \"uploadedHover\"\n | \"error\"\n | \"disable\";\n\nexport const ImageUploader = forwardRef<HTMLInputElement, ImageUploaderProps>(\n (\n {\n size = \"xl\",\n placeholder = \"Upload\",\n uploadingPlaceholder = \"Uploading\",\n description,\n errorMessage,\n wideView = false,\n accept = \"image/*\",\n openPicker,\n value,\n onUpload,\n onChange,\n onDelete,\n disabled = false,\n loading = false,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const fileInputRef = useRef<HTMLInputElement>(null);\n const isControlled = value !== undefined;\n const [internalPreview, setInternalPreview] = useState<string | null>(null);\n const [isHover, setIsHover] = useState(false);\n const [isFocus, setIsFocus] = useState(false);\n const [isPreviewHover, setIsPreviewHover] = useState(false);\n // Touch / native devices have no hover, so the trash overlay would never\n // appear. Detect once on mount and force `uploadedHover` for those cases.\n const [isHoverless] = useState(\n () =>\n !isWeb ||\n (typeof window !== \"undefined\" &&\n !!window.matchMedia?.(\"(hover: none)\").matches)\n );\n\n const reactId = useId();\n const baseId = `image-uploader-${reactId.replace(/[^a-zA-Z0-9-]/g, \"\")}`;\n const descriptionId = `${baseId}-description`;\n const errorId = `${baseId}-error`;\n\n const preview = isControlled ? (value?.url ?? null) : internalPreview;\n\n useEffect(() => {\n if (!isControlled && value === null) setInternalPreview(null);\n }, [isControlled, value]);\n\n React.useImperativeHandle(\n ref,\n () => fileInputRef.current as HTMLInputElement,\n []\n );\n\n const sizeStyles = theme.sizing.imageUploader(size);\n const inputColors = theme.colors.control.input;\n const focusColors = theme.colors.control.focus;\n const alertBorder = theme.colors.control.alert.border;\n const alertText = theme.colors.content.alert.primary;\n const scrim = theme.colors.layer.scrim;\n\n const hasError = !!errorMessage;\n\n let state: InternalState;\n if (disabled) state = \"disable\";\n else if (loading) state = \"uploading\";\n else if (hasError) state = \"error\";\n else if (preview)\n state = isPreviewHover || isHoverless ? \"uploadedHover\" : \"uploaded\";\n else if (isFocus) state = \"focus\";\n else if (isHover) state = \"hover\";\n else state = \"default\";\n\n const emitFile = (img: ImageUploaderFile) => {\n if (!isControlled) setInternalPreview(img.uri);\n onUpload?.(img);\n onChange?.({\n filename: img.name,\n url: img.uri,\n });\n };\n\n const handleWebFile = (file: File) => {\n if (!file.type.startsWith(\"image/\")) return;\n const reader = new FileReader();\n reader.onload = (e) => {\n const uri = e.target?.result as string;\n emitFile({\n name: file.name,\n size: file.size,\n uri,\n mimeType: file.type,\n file,\n });\n };\n reader.readAsDataURL(file);\n };\n\n const handleClick = async () => {\n if (disabled || loading) return;\n if (preview) {\n removeImage();\n return;\n }\n if (openPicker) {\n const picked = await openPicker();\n if (picked) emitFile(picked);\n return;\n }\n if (isWeb) {\n fileInputRef.current?.click();\n }\n };\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = \"\";\n if (file) handleWebFile(file);\n };\n\n const handleDragOver = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!disabled && !loading && !preview) setIsHover(true);\n };\n\n const handleDragLeave = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsHover(false);\n };\n\n const handleDrop = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsHover(false);\n if (disabled || loading || preview) return;\n const file = e.dataTransfer.files?.[0];\n if (file) handleWebFile(file);\n };\n\n const removeImage = (e?: { stopPropagation?: () => void }) => {\n e?.stopPropagation?.();\n if (!isControlled) setInternalPreview(null);\n setIsPreviewHover(false);\n onDelete?.();\n onChange?.(null);\n if (isWeb && fileInputRef.current) fileInputRef.current.value = \"\";\n };\n\n let backgroundColor: string = inputColors.bg;\n let borderColor: string = inputColors.border;\n let borderStyle: \"dashed\" | \"solid\" = \"dashed\";\n let labelColor: string = inputColors.text;\n let descriptionColor: string = inputColors.placeholder;\n let iconColor: string = inputColors.text;\n\n switch (state) {\n case \"hover\":\n backgroundColor = inputColors.bgHover;\n borderColor = inputColors.borderHover;\n break;\n case \"focus\":\n case \"uploading\":\n backgroundColor = focusColors.bg;\n borderColor = focusColors.border;\n break;\n case \"uploaded\":\n case \"uploadedHover\":\n backgroundColor = \"transparent\";\n borderColor = \"transparent\";\n break;\n case \"error\":\n backgroundColor = inputColors.bg;\n borderColor = alertBorder;\n borderStyle = \"solid\";\n labelColor = alertText;\n iconColor = alertText;\n break;\n case \"disable\":\n backgroundColor = inputColors.bgDisable;\n borderColor = inputColors.borderDisable;\n labelColor = inputColors.textDisable;\n descriptionColor = inputColors.textDisable;\n iconColor = inputColors.textDisable;\n break;\n }\n\n const rootGap = state === \"error\" ? sizeStyles.errorGap : 0;\n\n const renderInner = () => {\n if (state === \"uploaded\" || state === \"uploadedHover\") {\n return (\n <>\n <Box\n as=\"img\"\n src={preview || undefined}\n alt={value?.filename ?? \"Uploaded image\"}\n position=\"absolute\"\n top={0}\n left={0}\n right={0}\n bottom={0}\n borderRadius={sizeStyles.radius}\n resizeMode=\"cover\"\n {...(isWeb && { width: \"100%\", height: \"100%\" })}\n style={isWeb ? { objectFit: \"cover\" } : undefined}\n />\n {state === \"uploadedHover\" && !disabled && (\n <>\n <Box\n position=\"absolute\"\n top={0}\n left={0}\n right={0}\n bottom={0}\n backgroundColor={scrim}\n borderRadius={sizeStyles.radius}\n {...(isWeb && { \"aria-hidden\": \"true\" })}\n />\n <Box\n position=\"relative\"\n width={sizeStyles.iconSize}\n height={sizeStyles.iconSize}\n alignItems=\"center\"\n justifyContent=\"center\"\n zIndex={1}\n pointerEvents=\"none\"\n {...(isWeb && { \"aria-hidden\": \"true\" })}\n >\n <TrashCan size={sizeStyles.iconSize} color=\"#ffffff\" />\n </Box>\n </>\n )}\n </>\n );\n }\n\n return (\n <>\n {state === \"uploading\" ? (\n <Spinner\n size={size}\n color={theme.colors.content.brand.primary}\n {...(isWeb && { \"aria-hidden\": \"true\" })}\n />\n ) : (\n <Box {...(isWeb && { \"aria-hidden\": \"true\" })}>\n <Image size={sizeStyles.iconSize} color={iconColor} />\n </Box>\n )}\n\n {placeholder && (\n <Text\n data-testid=\"image-uploader__placeholder\"\n color={labelColor}\n fontSize={sizeStyles.labelFontSize}\n lineHeight={sizeStyles.labelLineHeight}\n fontWeight=\"500\"\n textAlign=\"center\"\n numberOfLines={1}\n style={\n isWeb\n ? {\n maxWidth: \"100%\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : undefined\n }\n >\n {state === \"uploading\" ? uploadingPlaceholder : placeholder}\n </Text>\n )}\n\n {description &&\n wideView &&\n state !== \"uploading\" &&\n state !== \"error\" &&\n (typeof description === \"string\" ? (\n <Text\n data-testid=\"image-uploader__description\"\n color={descriptionColor}\n fontSize={sizeStyles.descriptionFontSize}\n lineHeight={sizeStyles.descriptionLineHeight}\n textAlign=\"center\"\n numberOfLines={1}\n style={\n isWeb\n ? {\n maxWidth: \"100%\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : undefined\n }\n {...(isWeb && { id: descriptionId })}\n >\n {description}\n </Text>\n ) : (\n <Box\n data-testid=\"image-uploader__description\"\n {...(isWeb && { id: descriptionId })}\n >\n {description}\n </Box>\n ))}\n </>\n );\n };\n\n // Web-only DOM event handlers — stripped on native.\n const webOnlyHandlers = isWeb\n ? {\n onMouseEnter: () => {\n if (disabled || loading) return;\n if (preview) setIsPreviewHover(true);\n else setIsHover(true);\n },\n onMouseLeave: () => {\n if (preview) setIsPreviewHover(false);\n else setIsHover(false);\n },\n onFocus: (e: React.FocusEvent<HTMLElement>) => {\n if (disabled || loading || preview) return;\n // Only show the focus visual state for keyboard focus, not for\n // pointer focus (e.g. after the native file picker is cancelled).\n if (\n typeof e.target?.matches === \"function\" &&\n !e.target.matches(\":focus-visible\")\n ) {\n return;\n }\n setIsFocus(true);\n },\n onBlur: () => setIsFocus(false),\n onDragOver: handleDragOver,\n onDragLeave: handleDragLeave,\n onDrop: handleDrop,\n }\n : {};\n\n // Web-only CSS props — dropped on native to avoid style warnings.\n const webOnlyStyle = isWeb\n ? {\n boxSizing: \"border-box\" as const,\n display: \"flex\" as const,\n cursor: (disabled || loading\n ? \"not-allowed\"\n : \"pointer\") as React.CSSProperties[\"cursor\"],\n outline: \"none\",\n transition: \"background-color 0.15s ease, border-color 0.15s ease\",\n }\n : {};\n\n const buttonAriaLabel = preview\n ? `Remove image${value?.filename ? `: ${value.filename}` : \"\"}`\n : state === \"uploading\"\n ? uploadingPlaceholder\n : placeholder;\n\n const describedBy =\n [\n state === \"error\" && errorMessage ? errorId : null,\n description && wideView && state !== \"uploading\" && state !== \"error\"\n ? descriptionId\n : null,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n return (\n <Box\n data-testid=\"image-uploader\"\n flexDirection=\"column\"\n gap={rootGap}\n alignItems=\"flex-start\"\n width={wideView ? \"100%\" : undefined}\n maxWidth={wideView ? sizeStyles.wideWidth : undefined}\n >\n {isWeb && (\n <input\n type=\"file\"\n ref={fileInputRef}\n accept={accept}\n onChange={handleFileChange}\n style={{ display: \"none\" }}\n disabled={disabled}\n tabIndex={-1}\n aria-hidden=\"true\"\n data-testid=\"image-uploader__input\"\n />\n )}\n\n <Box\n as={isWeb ? \"button\" : \"div\"}\n disabled={disabled || loading}\n data-testid=\"image-uploader__button\"\n onPress={handleClick}\n {...(isWeb && {\n \"aria-label\": buttonAriaLabel,\n \"aria-busy\": loading || undefined,\n \"aria-invalid\": state === \"error\" || undefined,\n \"aria-describedby\": describedBy,\n })}\n {...webOnlyHandlers}\n position=\"relative\"\n width={wideView ? \"100%\" : sizeStyles.box}\n maxWidth={wideView ? sizeStyles.wideWidth : undefined}\n height={sizeStyles.box}\n flexDirection=\"column\"\n alignItems=\"center\"\n justifyContent=\"center\"\n gap={sizeStyles.gap}\n padding={state === \"uploaded\" ? 0 : sizeStyles.padding}\n borderWidth={sizeStyles.borderWidth}\n borderStyle={borderStyle}\n borderColor={borderColor}\n borderRadius={sizeStyles.radius}\n backgroundColor={backgroundColor}\n overflow=\"hidden\"\n style={webOnlyStyle}\n >\n {renderInner()}\n </Box>\n\n {state === \"error\" && errorMessage && (\n <Text\n data-testid=\"image-uploader__error\"\n color={alertText}\n fontSize={sizeStyles.errorFontSize}\n lineHeight={sizeStyles.errorLineHeight}\n {...(isWeb && { id: errorId, role: \"alert\" })}\n >\n {errorMessage}\n </Text>\n )}\n </Box>\n );\n }\n);\n\nImageUploader.displayName = \"ImageUploader\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","export * from \"./Box\";\nexport * from \"./Text\";\nexport * from \"./Spinner\";\nexport * from \"./Icon\";\nexport * from \"./Divider\";\nexport * from \"./Input\";\nexport * from \"./TextArea\";\nexport * from \"./LinearGradient\";\n\nexport const isWeb = false;\nexport const isNative = true;\n"],"mappings":"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","names":["import_react_native","import_jsx_runtime","RNText","import_jsx_runtime","React"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.tsx","../../src/ImageUploader.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/index.tsx"],"sourcesContent":["export * from \"./ImageUploader\";\n","import React, { useRef, useState, useEffect, forwardRef } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text, isWeb } from \"@xsolla/xui-primitives\";\nimport {\n useId,\n useResolvedTheme,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\nimport { Image, TrashCan } from \"@xsolla/xui-icons-base\";\nimport { Spinner } from \"@xsolla/xui-spinner\";\n\nexport type ImageUploaderSize = \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n\n/** Controlled value shape. */\nexport interface ImageUploaderValue {\n filename?: string;\n url?: string;\n}\n\n/**\n * Normalized file shape produced by the platform picker / drag-drop pipeline.\n * - `uri` is a data-URL on web and a file URI on native.\n * - On web, the original `File` is passed through for consumers that need it\n * (e.g. to upload via FormData / fetch).\n */\nexport type ImageUploaderFile = {\n name: string;\n size: number;\n uri: string;\n mimeType?: string;\n /** The original DOM File (web only) */\n file?: File;\n};\n\nexport interface ImageUploaderProps extends ThemeOverrideProps {\n /** Size of the uploader. Figma default is `xl`. */\n size?: ImageUploaderSize;\n /** Placeholder shown under the icon. Accepts a string or a custom React node. */\n placeholder?: React.ReactNode;\n /** Placeholder shown while the file is uploading. Accepts a string or a custom React node. */\n uploadingPlaceholder?: React.ReactNode;\n /** Description below the placeholder. Only rendered when `wideView` is true. Accepts a string or a custom React node. */\n description?: React.ReactNode;\n /** Error message — when provided, component renders in the error state. */\n errorMessage?: string;\n /** Wide view (horizontal layout). When true, the box stretches to its parent's full width. */\n wideView?: boolean;\n /** Disabled state. */\n disabled?: boolean;\n /** Controlled loading state (shows spinner + \"Uploading\" label). */\n loading?: boolean;\n\n /** Controlled value. When provided, the component reflects this value. */\n value?: ImageUploaderValue | null;\n\n /**\n * Fires when the user picks (or drops) a file. Use this to perform the\n * actual upload — the component itself does no I/O.\n *\n * If the handler returns a `Promise`:\n * - The component automatically shows the uploading state (spinner +\n * `uploadingPlaceholder`) until the promise settles.\n * - If the promise resolves to an `ImageUploaderValue` (`{url, filename?}`)\n * or a `string` URL, the component automatically calls `onChange(value)`\n * with that value. The string form is sugar for `{url: <string>}`.\n * - If the promise rejects, the component calls `onChange(null, error)`.\n *\n * For finer-grained control, pass `loading` explicitly instead.\n */\n onUpload?: (\n file: ImageUploaderFile\n ) => void | Promise<ImageUploaderValue | string | void>;\n /**\n * Fires when the displayed value changes — on file pick (with a local\n * data-URL preview), after upload resolves (with the server value), or on\n * remove (`null`). The optional second argument carries any error thrown by\n * the consumer's `onUpload`.\n */\n onChange?: (value: ImageUploaderValue | null, error?: Error) => void;\n /** Fires when the user removes the image (trash click / clear). */\n onDelete?: () => void;\n\n /**\n * Accepted file types — passed through to the hidden `<input accept>` as a\n * picker hint (web only — ignored on native). Standard HTML syntax:\n * comma-separated list of MIME types (`image/png`), MIME wildcards\n * (`image/*`), or file extensions (`.png`). Defaults to `image/*`.\n *\n * No runtime validation is performed — the consumer's `onUpload` (or the\n * backend it calls) is responsible for accepting/rejecting files.\n */\n accept?: string;\n /**\n * Native file picker hook. Required on native (no DOM `<input type=\"file\">`).\n * On web, omit this and the component falls back to a hidden file input.\n */\n openPicker?: () => Promise<ImageUploaderFile | null>;\n}\n\ntype InternalState =\n | \"default\"\n | \"hover\"\n | \"focus\"\n | \"uploading\"\n | \"uploaded\"\n | \"uploadedHover\"\n | \"error\"\n | \"disable\";\n\nexport const ImageUploader = forwardRef<HTMLInputElement, ImageUploaderProps>(\n (\n {\n size = \"xl\",\n placeholder = \"Upload\",\n uploadingPlaceholder = \"Uploading\",\n description,\n errorMessage,\n wideView = false,\n accept = \"image/*\",\n openPicker,\n value,\n onUpload,\n onChange,\n onDelete,\n disabled = false,\n loading = false,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const fileInputRef = useRef<HTMLInputElement>(null);\n const isControlled = value !== undefined;\n const [internalPreview, setInternalPreview] = useState<string | null>(null);\n const [isAutoUploading, setIsAutoUploading] = useState(false);\n // Captures errors thrown by the consumer's `onUpload`. Surfaced via the\n // component's normal error UI when no explicit `errorMessage` prop is set.\n const [autoError, setAutoError] = useState<string | null>(null);\n const [isHover, setIsHover] = useState(false);\n const [isFocus, setIsFocus] = useState(false);\n const [isPreviewHover, setIsPreviewHover] = useState(false);\n // Touch / native devices have no hover, so the trash overlay would never\n // appear. Detect once on mount and force `uploadedHover` for those cases.\n const [isHoverless] = useState(\n () =>\n !isWeb ||\n (typeof window !== \"undefined\" &&\n !!window.matchMedia?.(\"(hover: none)\").matches)\n );\n\n const reactId = useId();\n const baseId = `image-uploader-${reactId.replace(/[^a-zA-Z0-9-]/g, \"\")}`;\n const descriptionId = `${baseId}-description`;\n const errorId = `${baseId}-error`;\n\n const preview = isControlled ? (value?.url ?? null) : internalPreview;\n\n useEffect(() => {\n if (!isControlled && value === null) setInternalPreview(null);\n }, [isControlled, value]);\n\n React.useImperativeHandle(\n ref,\n () => fileInputRef.current as HTMLInputElement,\n []\n );\n\n const sizeStyles = theme.sizing.imageUploader(size);\n const inputColors = theme.colors.control.input;\n const focusColors = theme.colors.control.focus;\n const alertBorder = theme.colors.control.alert.border;\n const alertText = theme.colors.content.alert.primary;\n const scrim = theme.colors.layer.scrim;\n\n // Resolved error message: explicit prop wins, fall back to caught upload error.\n const resolvedError = errorMessage || autoError;\n const hasError = !!resolvedError;\n\n let state: InternalState;\n if (disabled) state = \"disable\";\n else if (loading || isAutoUploading) state = \"uploading\";\n else if (hasError) state = \"error\";\n else if (preview)\n state = isPreviewHover || isHoverless ? \"uploadedHover\" : \"uploaded\";\n else if (isFocus) state = \"focus\";\n else if (isHover) state = \"hover\";\n else state = \"default\";\n\n const emitFile = (img: ImageUploaderFile) => {\n // Clear any prior error from a previous upload attempt.\n setAutoError(null);\n if (!isControlled) setInternalPreview(img.uri);\n onChange?.({\n filename: img.name,\n url: img.uri,\n });\n const result = onUpload?.(img);\n // If the consumer's onUpload returns a Promise:\n // - show the uploading state until it settles\n // - on resolve with a value, treat it as the canonical onChange payload\n // - on reject, surface the error internally AND via onChange(null, error)\n if (result && typeof (result as Promise<unknown>).then === \"function\") {\n setIsAutoUploading(true);\n Promise.resolve(result)\n .then((uploaded) => {\n // Accept either an ImageUploaderValue ({url, filename?}) or a\n // bare string URL as sugar for {url: <string>}.\n let next: ImageUploaderValue | null = null;\n if (typeof uploaded === \"string\") {\n next = { url: uploaded };\n } else if (\n uploaded &&\n typeof uploaded === \"object\" &&\n \"url\" in uploaded\n ) {\n next = uploaded as ImageUploaderValue;\n }\n if (next) {\n if (!isControlled) setInternalPreview(next.url ?? null);\n onChange?.(next);\n }\n })\n .catch((err: Error) => {\n // Surface internally so the error UI lights up without the\n // consumer having to wire up local state.\n setAutoError(err?.message || \"Upload failed\");\n // Reset preview so we don't keep showing the failed pick.\n if (!isControlled) setInternalPreview(null);\n onChange?.(null, err);\n })\n .finally(() => setIsAutoUploading(false));\n }\n };\n\n const handleWebFile = (file: File) => {\n const reader = new FileReader();\n reader.onload = (e) => {\n const uri = e.target?.result as string;\n // Mutate the DOM File so it satisfies BOTH the DOM File interface (for\n // direct use in FormData / fetch / .size checks) and ImageUploaderFile\n // (with .uri / .mimeType added). `.file` self-references for back-compat\n // with consumers that previously dereferenced `imageFile.file`.\n const enriched = file as File & ImageUploaderFile;\n (enriched as { uri?: string }).uri = uri;\n (enriched as { mimeType?: string }).mimeType = file.type;\n (enriched as { file?: File }).file = enriched;\n emitFile(enriched);\n };\n reader.readAsDataURL(file);\n };\n\n const handleClick = async () => {\n if (disabled || loading) return;\n if (preview) {\n removeImage();\n return;\n }\n if (openPicker) {\n const picked = await openPicker();\n if (picked) emitFile(picked);\n return;\n }\n if (isWeb) {\n fileInputRef.current?.click();\n }\n };\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = \"\";\n if (file) handleWebFile(file);\n };\n\n const handleDragOver = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!disabled && !loading && !preview) setIsHover(true);\n };\n\n const handleDragLeave = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsHover(false);\n };\n\n const handleDrop = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsHover(false);\n if (disabled || loading || preview) return;\n const file = e.dataTransfer.files?.[0];\n if (file) handleWebFile(file);\n };\n\n const removeImage = (e?: { stopPropagation?: () => void }) => {\n e?.stopPropagation?.();\n setAutoError(null);\n if (!isControlled) setInternalPreview(null);\n setIsPreviewHover(false);\n onDelete?.();\n onChange?.(null);\n if (isWeb && fileInputRef.current) fileInputRef.current.value = \"\";\n };\n\n let backgroundColor: string = inputColors.bg;\n let borderColor: string = inputColors.border;\n let borderStyle: \"dashed\" | \"solid\" = \"dashed\";\n let labelColor: string = inputColors.text;\n let descriptionColor: string = inputColors.placeholder;\n let iconColor: string = inputColors.text;\n\n switch (state) {\n case \"hover\":\n backgroundColor = inputColors.bgHover;\n borderColor = inputColors.borderHover;\n break;\n case \"focus\":\n case \"uploading\":\n backgroundColor = focusColors.bg;\n borderColor = focusColors.border;\n break;\n case \"uploaded\":\n case \"uploadedHover\":\n backgroundColor = \"transparent\";\n borderColor = \"transparent\";\n break;\n case \"error\":\n backgroundColor = inputColors.bg;\n borderColor = alertBorder;\n borderStyle = \"solid\";\n labelColor = alertText;\n iconColor = alertText;\n break;\n case \"disable\":\n backgroundColor = inputColors.bgDisable;\n borderColor = inputColors.borderDisable;\n labelColor = inputColors.textDisable;\n descriptionColor = inputColors.textDisable;\n iconColor = inputColors.textDisable;\n break;\n }\n\n const rootGap = state === \"error\" ? sizeStyles.errorGap : 0;\n const placeholderContent =\n state === \"uploading\" ? uploadingPlaceholder : placeholder;\n\n const renderInner = () => {\n if (state === \"uploaded\" || state === \"uploadedHover\") {\n return (\n <>\n <Box\n as=\"img\"\n src={preview || undefined}\n alt={value?.filename ?? \"Uploaded image\"}\n position=\"absolute\"\n top={0}\n left={0}\n right={0}\n bottom={0}\n borderRadius={sizeStyles.radius}\n resizeMode=\"cover\"\n {...(isWeb && { width: \"100%\", height: \"100%\" })}\n style={isWeb ? { objectFit: \"cover\" } : undefined}\n />\n {state === \"uploadedHover\" && !disabled && (\n <>\n <Box\n position=\"absolute\"\n top={0}\n left={0}\n right={0}\n bottom={0}\n backgroundColor={scrim}\n borderRadius={sizeStyles.radius}\n {...(isWeb && { \"aria-hidden\": \"true\" })}\n />\n <Box\n position=\"relative\"\n width={sizeStyles.iconSize}\n height={sizeStyles.iconSize}\n alignItems=\"center\"\n justifyContent=\"center\"\n zIndex={1}\n pointerEvents=\"none\"\n {...(isWeb && { \"aria-hidden\": \"true\" })}\n >\n <TrashCan size={sizeStyles.iconSize} color=\"#ffffff\" />\n </Box>\n </>\n )}\n </>\n );\n }\n\n return (\n <>\n {state === \"uploading\" ? (\n <Spinner\n size={size}\n color={theme.colors.content.brand.primary}\n {...(isWeb && { \"aria-hidden\": \"true\" })}\n />\n ) : (\n <Box {...(isWeb && { \"aria-hidden\": \"true\" })}>\n <Image size={sizeStyles.iconSize} color={iconColor} />\n </Box>\n )}\n\n {placeholderContent &&\n (typeof placeholderContent === \"string\" ? (\n <Text\n data-testid=\"image-uploader__placeholder\"\n color={labelColor}\n fontSize={sizeStyles.labelFontSize}\n lineHeight={sizeStyles.labelLineHeight}\n fontWeight=\"500\"\n textAlign=\"center\"\n numberOfLines={1}\n style={\n isWeb\n ? {\n maxWidth: \"100%\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : undefined\n }\n >\n {placeholderContent}\n </Text>\n ) : (\n <Box data-testid=\"image-uploader__placeholder\">\n {placeholderContent}\n </Box>\n ))}\n\n {description &&\n wideView &&\n state !== \"uploading\" &&\n state !== \"error\" &&\n (typeof description === \"string\" ? (\n <Text\n data-testid=\"image-uploader__description\"\n color={descriptionColor}\n fontSize={sizeStyles.descriptionFontSize}\n lineHeight={sizeStyles.descriptionLineHeight}\n textAlign=\"center\"\n numberOfLines={1}\n style={\n isWeb\n ? {\n maxWidth: \"100%\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : undefined\n }\n {...(isWeb && { id: descriptionId })}\n >\n {description}\n </Text>\n ) : (\n <Box\n data-testid=\"image-uploader__description\"\n {...(isWeb && { id: descriptionId })}\n >\n {description}\n </Box>\n ))}\n </>\n );\n };\n\n // Web-only DOM event handlers — stripped on native.\n const webOnlyHandlers = isWeb\n ? {\n onMouseEnter: () => {\n if (disabled || loading) return;\n if (preview) setIsPreviewHover(true);\n else setIsHover(true);\n },\n onMouseLeave: () => {\n if (preview) setIsPreviewHover(false);\n else setIsHover(false);\n },\n onFocus: (e: React.FocusEvent<HTMLElement>) => {\n if (disabled || loading || preview) return;\n // Only show the focus visual state for keyboard focus, not for\n // pointer focus (e.g. after the native file picker is cancelled).\n if (\n typeof e.target?.matches === \"function\" &&\n !e.target.matches(\":focus-visible\")\n ) {\n return;\n }\n setIsFocus(true);\n },\n onBlur: () => setIsFocus(false),\n onDragOver: handleDragOver,\n onDragLeave: handleDragLeave,\n onDrop: handleDrop,\n }\n : {};\n\n // Web-only CSS props — dropped on native to avoid style warnings.\n const webOnlyStyle = isWeb\n ? {\n boxSizing: \"border-box\" as const,\n display: \"flex\" as const,\n cursor: (disabled || loading\n ? \"not-allowed\"\n : \"pointer\") as React.CSSProperties[\"cursor\"],\n outline: \"none\",\n transition: \"background-color 0.15s ease, border-color 0.15s ease\",\n }\n : {};\n\n // aria-label needs a string; fall back to defaults when placeholder/uploadingPlaceholder\n // are passed as React nodes.\n const buttonAriaLabel = preview\n ? `Remove image${value?.filename ? `: ${value.filename}` : \"\"}`\n : state === \"uploading\"\n ? typeof uploadingPlaceholder === \"string\"\n ? uploadingPlaceholder\n : \"Uploading\"\n : typeof placeholder === \"string\"\n ? placeholder\n : \"Upload\";\n\n const describedBy =\n [\n state === \"error\" && resolvedError ? errorId : null,\n description && wideView && state !== \"uploading\" && state !== \"error\"\n ? descriptionId\n : null,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n return (\n <Box\n data-testid=\"image-uploader\"\n flexDirection=\"column\"\n gap={rootGap}\n alignItems=\"flex-start\"\n width={wideView ? \"100%\" : undefined}\n >\n {isWeb && (\n <input\n type=\"file\"\n ref={fileInputRef}\n accept={accept}\n onChange={handleFileChange}\n style={{ display: \"none\" }}\n disabled={disabled}\n tabIndex={-1}\n aria-hidden=\"true\"\n data-testid=\"image-uploader__input\"\n />\n )}\n\n <Box\n as={isWeb ? \"button\" : \"div\"}\n disabled={disabled || loading}\n data-testid=\"image-uploader__button\"\n onPress={handleClick}\n {...(isWeb && {\n \"aria-label\": buttonAriaLabel,\n \"aria-busy\": loading || undefined,\n \"aria-invalid\": state === \"error\" || undefined,\n \"aria-describedby\": describedBy,\n })}\n {...webOnlyHandlers}\n position=\"relative\"\n width={wideView ? \"100%\" : sizeStyles.box}\n height={sizeStyles.box}\n flexDirection=\"column\"\n alignItems=\"center\"\n justifyContent=\"center\"\n gap={sizeStyles.gap}\n padding={state === \"uploaded\" ? 0 : sizeStyles.padding}\n borderWidth={sizeStyles.borderWidth}\n borderStyle={borderStyle}\n borderColor={borderColor}\n borderRadius={sizeStyles.radius}\n backgroundColor={backgroundColor}\n overflow=\"hidden\"\n style={webOnlyStyle}\n >\n {renderInner()}\n </Box>\n\n {state === \"error\" && resolvedError && (\n <Text\n data-testid=\"image-uploader__error\"\n color={alertText}\n fontSize={sizeStyles.errorFontSize}\n lineHeight={sizeStyles.errorLineHeight}\n {...(isWeb && { id: errorId, role: \"alert\" })}\n >\n {resolvedError}\n </Text>\n )}\n </Box>\n );\n }\n);\n\nImageUploader.displayName = \"ImageUploader\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","export * from \"./Box\";\nexport * from \"./Text\";\nexport * from \"./Spinner\";\nexport * from \"./Icon\";\nexport * from \"./Divider\";\nexport * from \"./Input\";\nexport * from \"./TextArea\";\nexport * from \"./LinearGradient\";\n\nexport const isWeb = false;\nexport const isNative = true;\n"],"mappings":"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","names":["import_react_native","import_jsx_runtime","RNText","import_jsx_runtime","React"]}
|