@xsolla/xui-image-uploader 0.174.3 → 0.176.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.
Files changed (2) hide show
  1. package/README.md +70 -0
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -2,6 +2,76 @@
2
2
 
3
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
+ <!-- BEGIN:xui-mcp-instructions:image-uploader -->
6
+ A specialised upload control for images. Renders as a square or landscape rectangle that acts as both the upload trigger and the image preview container. Once an image is uploaded, the zone fills with the image thumbnail; hovering over it reveals controls to replace or remove the image. Supports five sizes, two aspect ratios, and eight states covering the full upload lifecycle.
7
+
8
+ ### When to use
9
+
10
+ When the user must upload a single image — a profile photo, cover image, product thumbnail, brand logo, avatar, or banner
11
+ - When the uploaded image should be previewed in place immediately after selection
12
+ - When image replacement or removal must be available without navigating away
13
+ - In profile settings, onboarding flows, CMS editors, and product or entity configuration forms
14
+
15
+ ### When not to use
16
+
17
+ For uploading non-image files (PDFs, CSVs, documents) — use FileUploader or Drag & Drop Uploader
18
+
19
+ When multiple images must be uploaded simultaneously — use a Drag & Drop Uploader with multiple file support or a dedicated gallery uploader
20
+
21
+ When the image upload is part of a broader drag-and-drop area — use Drag & Drop Uploader
22
+
23
+ When cropping or editing the image after selection is required — pair ImageUploader with a dedicated image crop modal triggered after selection
24
+
25
+ ### Content guidelines
26
+
27
+ Upload hint — inside the zone in Default state, use a short hint below the icon: *"Upload photo"*, *"Add cover image"*, *"Choose image"*. Keep to one line.
28
+
29
+ Size and format hint — show accepted formats and max size as helper text below the zone (not inside it): *"PNG, JPG, WebP — max 5 MB"*, *"Recommended: 1200 × 630 px"*. At small sizes (S, XS) this may be omitted if space is too tight.
30
+ Error messages — be specific:
31
+ - *"File type not supported. Use JPG, PNG, or WebP."*
32
+ - *"Image exceeds the 5 MB limit."*
33
+ - *"Upload failed. Try again."*
34
+ - *"Please upload a profile photo to continue."* (required field)
35
+ - Replace / Remove labels — use exactly *"Replace"* and *"Remove"* in the overlay. Do not use *"Edit"* for replace or *"Delete"* for remove in this context — the terms are specific to the image slot, not the entity.
36
+ - Field label — always provide a visible label above the component: *"Profile photo"*, *"Cover image"*, *"Company logo"*. Do not rely on the hint inside the zone alone.
37
+
38
+ - Behaviour guidelines (from industry practice)
39
+ - Click to upload — clicking the zone in Default, Hover, or Focus state opens the native file dialog filtered to image types (e.g. accept=*"image/jpeg,image/png,image/webp,image/gif"*). After the user selects a file, begin validation immediately.
40
+ - File validation — validate client-side before uploading:
41
+ - File type: accept only image formats supported by the product
42
+ - File size: reject files above the maximum (e.g. 5 MB, 10 MB) If validation fails, switch to State=Error with a specific message. Do not start the upload for invalid files.
43
+ - Uploading — after successful validation, transition to State=Uploading and begin the upload. The zone becomes non-interactive.
44
+ - Upload success — on successful upload response, transition to State=Uploaded. The server-returned image URL (or the local object URL) fills the zone as a cropped preview.
45
+ - Upload failure — on network error or server rejection, transition to State=Error with a specific message. The zone becomes interactive again — the user can click to retry.
46
+ - Image fitting — the preview image fills the entire zone using object-fit: cover and object-position: center so the image is always fully visible and cropped to fit, regardless of the original aspect ratio. Do not letterbox or pillarbox.
47
+ - Replace — clicking Replace in State=Uploaded-hover opens the file dialog. The current image stays visible until the new image is successfully uploaded. If the new upload fails, revert to showing the previous image (not the error state) and surface the error as a Toast or inline message.
48
+ - Remove — clicking Remove deletes the image from the selection and returns to State=Default. If the image was already uploaded to a server, also trigger a server-side deletion request. Optionally confirm before removing if the action is irreversible.
49
+ - Touch devices — State=Uploaded-hover is not reachable on touch. Provide always-visible controls below the zone (small icon buttons for Replace and Remove) when the component is used on mobile.
50
+ - Disabled state — the zone cannot be clicked or focused. Provide a tooltip or nearby label explaining why upload is unavailable.
51
+
52
+ ### Accessibility
53
+
54
+ The upload zone must be implemented as a <button> or a <label> wrapping a hidden <input type=*"file"* accept=*"image/*"*>. It must be keyboard-focusable and activate on Enter / Space.
55
+
56
+ The zone must have aria-label describing its purpose — e.g. aria-label=*"Upload profile photo"*.
57
+
58
+ When State=Uploading, set aria-busy=*"true"* on the zone and update aria-label to *"Uploading profile photo…"*. The zone must not be focusable during upload.
59
+
60
+ When State=Uploaded, update aria-label to *"Profile photo uploaded. Hover or focus to replace or remove."* This tells keyboard users there are hidden actions available.
61
+
62
+ The Replace and Remove buttons in the overlay (State=Uploaded-hover) must always be keyboard-reachable via Tab, even when the overlay is visually hidden. Use CSS (opacity: 0; pointer-events: none) rather than display: none or visibility: hidden so they remain in the focus order.
63
+
64
+ The Replace button must have aria-label=*"Replace profile photo"* and the Remove button aria-label=*"Remove profile photo"* — not just *"Replace"* and *"Remove"* without context.
65
+
66
+ When State=Error, the error message must be associated via aria-describedby and placed in an aria-live=*"polite"* region.
67
+
68
+ When State=Disable, the zone must have aria-disabled=*"true"* and tabindex=*"-1"*.
69
+
70
+ The image preview is decorative — set aria-hidden=*"true"* on the <img> element inside the zone, since the zone's aria-label already communicates the current state.
71
+
72
+ For touch devices, the Replace and Remove controls that live outside the hover overlay must also have descriptive aria-label attributes.
73
+ <!-- END:xui-mcp-instructions:image-uploader -->
74
+
5
75
  ## Installation
6
76
 
7
77
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-image-uploader",
3
- "version": "0.174.3",
3
+ "version": "0.176.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -13,10 +13,10 @@
13
13
  "test:coverage": "vitest run --coverage"
14
14
  },
15
15
  "dependencies": {
16
- "@xsolla/xui-core": "0.174.3",
17
- "@xsolla/xui-icons-base": "0.174.3",
18
- "@xsolla/xui-primitives-core": "0.174.3",
19
- "@xsolla/xui-spinner": "0.174.3"
16
+ "@xsolla/xui-core": "0.176.0",
17
+ "@xsolla/xui-icons-base": "0.176.0",
18
+ "@xsolla/xui-primitives-core": "0.176.0",
19
+ "@xsolla/xui-spinner": "0.176.0"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "react": ">=16.8.0"