@salesforce/webapp-template-feature-react-file-upload-experimental 1.60.2 → 1.61.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 +126 -9
- package/dist/CHANGELOG.md +16 -0
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/package-lock.json +64 -47
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/assets/icon-image-close.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/assets/image.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/assets/success.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/components/FileUploadDropZone.tsx +2 -2
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/components/FileUploadFileItem.tsx +3 -3
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/components/FileUploadIcons.tsx +47 -15
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/pages/UploadTest.tsx +5 -5
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/vite.config.ts +2 -1
- package/dist/package.json +1 -1
- package/package.json +3 -3
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/assets/icon-image-close.svg +3 -0
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/assets/image.svg +3 -0
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/assets/success.svg +3 -0
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/components/FileUploadDropZone.tsx +2 -2
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/components/FileUploadFileItem.tsx +3 -3
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/components/FileUploadIcons.tsx +47 -15
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/components/ui/__inherit__button.tsx +1 -7
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/components/ui/__inherit__dialog.tsx +1 -1
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/pages/UploadTest.tsx +5 -5
- package/src/force-app/main/default/webapplications/feature-react-file-upload/vite.config.ts +2 -1
- package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/assets/utility.svg +0 -1
- package/src/force-app/main/default/webapplications/feature-react-file-upload/src/assets/utility.svg +0 -1
package/README.md
CHANGED
|
@@ -14,13 +14,82 @@ File upload feature: use the **FileUpload** component as-is with out-of-the-box
|
|
|
14
14
|
|
|
15
15
|
- **createContentVersion** – Manually create a ContentVersion record from a contentBodyId.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## Agent Configuration Guide
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
When implementing the FileUpload component, agents should prompt users for the following properties to configure the component appropriately:
|
|
20
|
+
|
|
21
|
+
### Required Information
|
|
22
|
+
|
|
23
|
+
1. **Multiple File Selection** (`multiple`):
|
|
24
|
+
- Prompt: "Should users be able to upload multiple files at once?"
|
|
25
|
+
- Type: Boolean (true/false)
|
|
26
|
+
- Default: false (single file only)
|
|
27
|
+
|
|
28
|
+
2. **Upload Context** (`recordId`):
|
|
29
|
+
- Prompt: "Do you want to link uploaded files to a specific Salesforce record?"
|
|
30
|
+
- Type: String (Salesforce record ID) or omit
|
|
31
|
+
- Note: If provided, creates ContentVersion and links to record immediately. If omitted, only returns `contentBodyId`.
|
|
32
|
+
- **Record Form Pattern**: If used in a record creation form where the record doesn't exist yet, omit `recordId` during upload, then use `createContentVersion` with the `contentBodyId` and the newly created record ID after form submission.
|
|
33
|
+
|
|
34
|
+
3. **Completion Handler** (`onUploadComplete`):
|
|
35
|
+
- Prompt: "What should happen after files are successfully uploaded?"
|
|
36
|
+
- Type: Function that receives array of uploaded files
|
|
37
|
+
- Required properties to handle: `name`, `size`, `contentBodyId`, `contentVersionId`
|
|
38
|
+
|
|
39
|
+
### Optional Configuration
|
|
40
|
+
|
|
41
|
+
4. **File Type Restrictions** (`accept`):
|
|
42
|
+
- Prompt: "What file types should be accepted? (e.g., 'image/_', '.pdf', 'image/_,.pdf')"
|
|
43
|
+
- Type: String (MIME types or file extensions)
|
|
44
|
+
- Default: All file types accepted
|
|
45
|
+
|
|
46
|
+
5. **File Size Limit** (`maxFileSize`):
|
|
47
|
+
- Prompt: "What is the maximum file size in MB?"
|
|
48
|
+
- Type: Number (in megabytes)
|
|
49
|
+
- Default: 2048 MB (2 GB)
|
|
50
|
+
|
|
51
|
+
6. **User Guidance** (`formatHint`):
|
|
52
|
+
- Prompt: "What hint text should be displayed to users? (e.g., 'JPEG, PNG, PDF, up to 50MB')"
|
|
53
|
+
- Type: String
|
|
54
|
+
- Default: None
|
|
55
|
+
|
|
56
|
+
7. **Styling** (`dropZoneClassName`):
|
|
57
|
+
- Prompt: "Do you need custom CSS classes for the drop zone?"
|
|
58
|
+
- Type: String (CSS class names)
|
|
59
|
+
- Default: Standard styling
|
|
60
|
+
|
|
61
|
+
8. **Error Handling** (`onUploadError`):
|
|
62
|
+
- Prompt: "How should upload errors be handled?"
|
|
63
|
+
- Type: Function that receives error information
|
|
64
|
+
- Default: Standard error display
|
|
65
|
+
|
|
66
|
+
9. **Container Styling** (`className`):
|
|
67
|
+
- Prompt: "Do you need custom CSS classes for the container?"
|
|
68
|
+
- Type: String (CSS class names)
|
|
69
|
+
- Default: Standard styling
|
|
70
|
+
|
|
71
|
+
### Example Agent Flow
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Agent: "I'll help you set up the FileUpload component. Let me ask you a few questions:"
|
|
75
|
+
|
|
76
|
+
1. "Should users be able to upload multiple files at once?" → User: "Yes"
|
|
77
|
+
2. "Do you want to link uploaded files to a specific Salesforce record?" → User: "Yes, to an Account record"
|
|
78
|
+
3. "What file types should be accepted?" → User: "Images and PDFs only"
|
|
79
|
+
4. "What is the maximum file size in MB?" → User: "50 MB"
|
|
80
|
+
5. "What hint text should be displayed to users?" → User: "JPEG, PNG, PDF, up to 50MB"
|
|
81
|
+
6. "How should files be handled after upload?" → User: "Log them to console"
|
|
82
|
+
|
|
83
|
+
Agent generates:
|
|
84
|
+
<FileUpload
|
|
85
|
+
multiple
|
|
86
|
+
accept="image/*,.pdf"
|
|
87
|
+
recordId={accountId}
|
|
88
|
+
maxFileSize={50}
|
|
89
|
+
formatHint="JPEG, PNG, PDF, up to 50MB"
|
|
90
|
+
onUploadComplete={(files) => console.log("Uploaded:", files)}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
24
93
|
|
|
25
94
|
## Usage
|
|
26
95
|
|
|
@@ -60,7 +129,55 @@ Omit `recordId` to only upload the file and get the `contentBodyId`:
|
|
|
60
129
|
/>
|
|
61
130
|
```
|
|
62
131
|
|
|
63
|
-
### Option 3:
|
|
132
|
+
### Option 3: Upload files before record exists (Record Form pattern)
|
|
133
|
+
|
|
134
|
+
When using FileUpload in a record creation form, omit `recordId` during upload, then create ContentVersion after the form is submitted and the record ID is available:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import {
|
|
138
|
+
FileUpload,
|
|
139
|
+
createContentVersion,
|
|
140
|
+
} from "@salesforce/webapp-template-feature-react-file-upload-experimental";
|
|
141
|
+
|
|
142
|
+
function CreateRecordForm() {
|
|
143
|
+
const [uploadedFiles, setUploadedFiles] = useState([]);
|
|
144
|
+
|
|
145
|
+
const handleFileUploadComplete = (files) => {
|
|
146
|
+
// Store contentBodyId for later use
|
|
147
|
+
setUploadedFiles(files);
|
|
148
|
+
console.log("Files uploaded, contentBodyIds stored:", files);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const handleFormSubmit = async (formData) => {
|
|
152
|
+
// 1. Create the record first
|
|
153
|
+
const newRecordId = await createRecord(formData);
|
|
154
|
+
|
|
155
|
+
// 2. Now link uploaded files to the newly created record
|
|
156
|
+
for (const file of uploadedFiles) {
|
|
157
|
+
const contentVersionId = await createContentVersion(
|
|
158
|
+
new File([""], file.name),
|
|
159
|
+
file.contentBodyId,
|
|
160
|
+
newRecordId, // Use the newly created record ID
|
|
161
|
+
);
|
|
162
|
+
console.log("ContentVersion created:", contentVersionId);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<form onSubmit={handleFormSubmit}>
|
|
168
|
+
{/* Form fields */}
|
|
169
|
+
<input name="name" placeholder="Record Name" />
|
|
170
|
+
|
|
171
|
+
{/* File upload without recordId */}
|
|
172
|
+
<FileUpload multiple onUploadComplete={handleFileUploadComplete} />
|
|
173
|
+
|
|
174
|
+
<button type="submit">Create Record</button>
|
|
175
|
+
</form>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Option 4: Manual ContentVersion creation
|
|
64
181
|
|
|
65
182
|
Upload file first, then manually create ContentVersion:
|
|
66
183
|
|
|
@@ -89,7 +206,7 @@ function MyComponent() {
|
|
|
89
206
|
}
|
|
90
207
|
```
|
|
91
208
|
|
|
92
|
-
### Option
|
|
209
|
+
### Option 5: Custom UI with your own trigger
|
|
93
210
|
|
|
94
211
|
Use the `useFileUpload` hook to control when the file picker opens. Render a hidden input and your own button or action.
|
|
95
212
|
|
|
@@ -117,7 +234,7 @@ function CustomUploadButton() {
|
|
|
117
234
|
}
|
|
118
235
|
```
|
|
119
236
|
|
|
120
|
-
### Option
|
|
237
|
+
### Option 6: Custom UI with drop zone and progress
|
|
121
238
|
|
|
122
239
|
Build a custom drop zone and inline progress list (no dialog) using `getDropZoneProps` and `fileItems`:
|
|
123
240
|
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.61.1](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.61.0...v1.61.1) (2026-03-02)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [1.61.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.60.2...v1.61.0) (2026-03-02)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [1.60.2](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.60.1...v1.60.2) (2026-02-27)
|
|
7
23
|
|
|
8
24
|
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
package/dist/force-app/main/default/webapplications/feature-react-file-upload/package-lock.json
CHANGED
|
@@ -6071,19 +6071,19 @@
|
|
|
6071
6071
|
}
|
|
6072
6072
|
},
|
|
6073
6073
|
"node_modules/@salesforce/sdk-core": {
|
|
6074
|
-
"version": "1.
|
|
6075
|
-
"resolved": "https://registry.npmjs.org/@salesforce/sdk-core/-/sdk-core-1.
|
|
6076
|
-
"integrity": "sha512-
|
|
6074
|
+
"version": "1.61.0",
|
|
6075
|
+
"resolved": "https://registry.npmjs.org/@salesforce/sdk-core/-/sdk-core-1.61.0.tgz",
|
|
6076
|
+
"integrity": "sha512-Hm5mIjHlqhcl6/bbF4YEYhM89DQG4gmnk0IRvBNu7lYo/p3rRRNwuR8SULebu6eIaoD18BL1YrWVkS+qXlftOw==",
|
|
6077
6077
|
"license": "SEE LICENSE IN LICENSE.txt"
|
|
6078
6078
|
},
|
|
6079
6079
|
"node_modules/@salesforce/sdk-data": {
|
|
6080
|
-
"version": "1.
|
|
6081
|
-
"resolved": "https://registry.npmjs.org/@salesforce/sdk-data/-/sdk-data-1.
|
|
6082
|
-
"integrity": "sha512-
|
|
6080
|
+
"version": "1.61.0",
|
|
6081
|
+
"resolved": "https://registry.npmjs.org/@salesforce/sdk-data/-/sdk-data-1.61.0.tgz",
|
|
6082
|
+
"integrity": "sha512-4o6H2YOnCakeH5tVb9zIdG2CMKiRZowRvJrD8v1wAARVsp21YLnei6KYdraE3Bx7t1SLh42EYVOhFiBcmTFzcQ==",
|
|
6083
6083
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6084
6084
|
"dependencies": {
|
|
6085
6085
|
"@conduit-client/salesforce-lightning-service-worker": "^3.7.0",
|
|
6086
|
-
"@salesforce/sdk-core": "^1.
|
|
6086
|
+
"@salesforce/sdk-core": "^1.61.0"
|
|
6087
6087
|
}
|
|
6088
6088
|
},
|
|
6089
6089
|
"node_modules/@salesforce/ts-types": {
|
|
@@ -6096,15 +6096,15 @@
|
|
|
6096
6096
|
}
|
|
6097
6097
|
},
|
|
6098
6098
|
"node_modules/@salesforce/vite-plugin-webapp-experimental": {
|
|
6099
|
-
"version": "1.
|
|
6100
|
-
"resolved": "https://registry.npmjs.org/@salesforce/vite-plugin-webapp-experimental/-/vite-plugin-webapp-experimental-1.
|
|
6101
|
-
"integrity": "sha512-
|
|
6099
|
+
"version": "1.61.0",
|
|
6100
|
+
"resolved": "https://registry.npmjs.org/@salesforce/vite-plugin-webapp-experimental/-/vite-plugin-webapp-experimental-1.61.0.tgz",
|
|
6101
|
+
"integrity": "sha512-51lKFmnGD5MkMPkTf6tmn5JieGGCSSyZ/xn/YoSBmAGMvIeGDwsVG0/AmNez/+zCgzNtPCZCyKpFj9Ky5PXT7w==",
|
|
6102
6102
|
"dev": true,
|
|
6103
6103
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6104
6104
|
"dependencies": {
|
|
6105
6105
|
"@babel/core": "^7.28.4",
|
|
6106
6106
|
"@babel/helper-plugin-utils": "^7.28.3",
|
|
6107
|
-
"@salesforce/webapp-experimental": "^1.
|
|
6107
|
+
"@salesforce/webapp-experimental": "^1.61.0"
|
|
6108
6108
|
},
|
|
6109
6109
|
"engines": {
|
|
6110
6110
|
"node": ">=20.0.0"
|
|
@@ -6114,13 +6114,13 @@
|
|
|
6114
6114
|
}
|
|
6115
6115
|
},
|
|
6116
6116
|
"node_modules/@salesforce/webapp-experimental": {
|
|
6117
|
-
"version": "1.
|
|
6118
|
-
"resolved": "https://registry.npmjs.org/@salesforce/webapp-experimental/-/webapp-experimental-1.
|
|
6119
|
-
"integrity": "sha512-
|
|
6117
|
+
"version": "1.61.0",
|
|
6118
|
+
"resolved": "https://registry.npmjs.org/@salesforce/webapp-experimental/-/webapp-experimental-1.61.0.tgz",
|
|
6119
|
+
"integrity": "sha512-m7SI2w/3UnSkPdmLYimPpbDI1d2wmYSrjsC2WCFG8Qo4SvEs+BGsPInh8Vxs32XKjiesaMV689RcWOA7dy/FWw==",
|
|
6120
6120
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6121
6121
|
"dependencies": {
|
|
6122
6122
|
"@salesforce/core": "^8.23.4",
|
|
6123
|
-
"@salesforce/sdk-data": "^1.
|
|
6123
|
+
"@salesforce/sdk-data": "^1.61.0",
|
|
6124
6124
|
"axios": "^1.7.7",
|
|
6125
6125
|
"micromatch": "^4.0.8",
|
|
6126
6126
|
"path-to-regexp": "^8.3.0"
|
|
@@ -6755,9 +6755,9 @@
|
|
|
6755
6755
|
"license": "MIT"
|
|
6756
6756
|
},
|
|
6757
6757
|
"node_modules/@types/node": {
|
|
6758
|
-
"version": "24.
|
|
6759
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.
|
|
6760
|
-
"integrity": "sha512-
|
|
6758
|
+
"version": "24.11.0",
|
|
6759
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz",
|
|
6760
|
+
"integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==",
|
|
6761
6761
|
"devOptional": true,
|
|
6762
6762
|
"license": "MIT",
|
|
6763
6763
|
"dependencies": {
|
|
@@ -8206,9 +8206,9 @@
|
|
|
8206
8206
|
}
|
|
8207
8207
|
},
|
|
8208
8208
|
"node_modules/caniuse-lite": {
|
|
8209
|
-
"version": "1.0.
|
|
8210
|
-
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.
|
|
8211
|
-
"integrity": "sha512-
|
|
8209
|
+
"version": "1.0.30001775",
|
|
8210
|
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz",
|
|
8211
|
+
"integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==",
|
|
8212
8212
|
"funding": [
|
|
8213
8213
|
{
|
|
8214
8214
|
"type": "opencollective",
|
|
@@ -8378,14 +8378,14 @@
|
|
|
8378
8378
|
}
|
|
8379
8379
|
},
|
|
8380
8380
|
"node_modules/cli-truncate": {
|
|
8381
|
-
"version": "5.
|
|
8382
|
-
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.
|
|
8383
|
-
"integrity": "sha512-
|
|
8381
|
+
"version": "5.2.0",
|
|
8382
|
+
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz",
|
|
8383
|
+
"integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==",
|
|
8384
8384
|
"dev": true,
|
|
8385
8385
|
"license": "MIT",
|
|
8386
8386
|
"dependencies": {
|
|
8387
|
-
"slice-ansi": "^
|
|
8388
|
-
"string-width": "^8.
|
|
8387
|
+
"slice-ansi": "^8.0.0",
|
|
8388
|
+
"string-width": "^8.2.0"
|
|
8389
8389
|
},
|
|
8390
8390
|
"engines": {
|
|
8391
8391
|
"node": ">=20"
|
|
@@ -8980,9 +8980,9 @@
|
|
|
8980
8980
|
"license": "MIT"
|
|
8981
8981
|
},
|
|
8982
8982
|
"node_modules/dedent": {
|
|
8983
|
-
"version": "1.7.
|
|
8984
|
-
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.
|
|
8985
|
-
"integrity": "sha512-
|
|
8983
|
+
"version": "1.7.2",
|
|
8984
|
+
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz",
|
|
8985
|
+
"integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==",
|
|
8986
8986
|
"license": "MIT",
|
|
8987
8987
|
"peerDependencies": {
|
|
8988
8988
|
"babel-plugin-macros": "^3.1.0"
|
|
@@ -9317,9 +9317,9 @@
|
|
|
9317
9317
|
}
|
|
9318
9318
|
},
|
|
9319
9319
|
"node_modules/enhanced-resolve": {
|
|
9320
|
-
"version": "5.
|
|
9321
|
-
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.
|
|
9322
|
-
"integrity": "sha512
|
|
9320
|
+
"version": "5.20.0",
|
|
9321
|
+
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz",
|
|
9322
|
+
"integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==",
|
|
9323
9323
|
"license": "MIT",
|
|
9324
9324
|
"dependencies": {
|
|
9325
9325
|
"graceful-fs": "^4.2.4",
|
|
@@ -10396,9 +10396,9 @@
|
|
|
10396
10396
|
}
|
|
10397
10397
|
},
|
|
10398
10398
|
"node_modules/flatted": {
|
|
10399
|
-
"version": "3.3.
|
|
10400
|
-
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.
|
|
10401
|
-
"integrity": "sha512-
|
|
10399
|
+
"version": "3.3.4",
|
|
10400
|
+
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz",
|
|
10401
|
+
"integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==",
|
|
10402
10402
|
"dev": true,
|
|
10403
10403
|
"license": "ISC"
|
|
10404
10404
|
},
|
|
@@ -13238,6 +13238,23 @@
|
|
|
13238
13238
|
"dev": true,
|
|
13239
13239
|
"license": "MIT"
|
|
13240
13240
|
},
|
|
13241
|
+
"node_modules/log-update/node_modules/slice-ansi": {
|
|
13242
|
+
"version": "7.1.2",
|
|
13243
|
+
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz",
|
|
13244
|
+
"integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
|
|
13245
|
+
"dev": true,
|
|
13246
|
+
"license": "MIT",
|
|
13247
|
+
"dependencies": {
|
|
13248
|
+
"ansi-styles": "^6.2.1",
|
|
13249
|
+
"is-fullwidth-code-point": "^5.0.0"
|
|
13250
|
+
},
|
|
13251
|
+
"engines": {
|
|
13252
|
+
"node": ">=18"
|
|
13253
|
+
},
|
|
13254
|
+
"funding": {
|
|
13255
|
+
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
|
13256
|
+
}
|
|
13257
|
+
},
|
|
13241
13258
|
"node_modules/log-update/node_modules/string-width": {
|
|
13242
13259
|
"version": "7.2.0",
|
|
13243
13260
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
|
@@ -14921,9 +14938,9 @@
|
|
|
14921
14938
|
"license": "MIT"
|
|
14922
14939
|
},
|
|
14923
14940
|
"node_modules/pump": {
|
|
14924
|
-
"version": "3.0.
|
|
14925
|
-
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.
|
|
14926
|
-
"integrity": "sha512-
|
|
14941
|
+
"version": "3.0.4",
|
|
14942
|
+
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
|
14943
|
+
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
|
14927
14944
|
"license": "MIT",
|
|
14928
14945
|
"dependencies": {
|
|
14929
14946
|
"end-of-stream": "^1.1.0",
|
|
@@ -15690,9 +15707,9 @@
|
|
|
15690
15707
|
"license": "MIT"
|
|
15691
15708
|
},
|
|
15692
15709
|
"node_modules/sax": {
|
|
15693
|
-
"version": "1.
|
|
15694
|
-
"resolved": "https://registry.npmjs.org/sax/-/sax-1.
|
|
15695
|
-
"integrity": "sha512-
|
|
15710
|
+
"version": "1.5.0",
|
|
15711
|
+
"resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz",
|
|
15712
|
+
"integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==",
|
|
15696
15713
|
"license": "BlueOak-1.0.0",
|
|
15697
15714
|
"engines": {
|
|
15698
15715
|
"node": ">=11.0.0"
|
|
@@ -16353,17 +16370,17 @@
|
|
|
16353
16370
|
}
|
|
16354
16371
|
},
|
|
16355
16372
|
"node_modules/slice-ansi": {
|
|
16356
|
-
"version": "
|
|
16357
|
-
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-
|
|
16358
|
-
"integrity": "sha512-
|
|
16373
|
+
"version": "8.0.0",
|
|
16374
|
+
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz",
|
|
16375
|
+
"integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==",
|
|
16359
16376
|
"dev": true,
|
|
16360
16377
|
"license": "MIT",
|
|
16361
16378
|
"dependencies": {
|
|
16362
|
-
"ansi-styles": "^6.2.
|
|
16363
|
-
"is-fullwidth-code-point": "^5.
|
|
16379
|
+
"ansi-styles": "^6.2.3",
|
|
16380
|
+
"is-fullwidth-code-point": "^5.1.0"
|
|
16364
16381
|
},
|
|
16365
16382
|
"engines": {
|
|
16366
|
-
"node": ">=
|
|
16383
|
+
"node": ">=20"
|
|
16367
16384
|
},
|
|
16368
16385
|
"funding": {
|
|
16369
16386
|
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52" width="100%" height="100%" fill="currentColor" aria-hidden="true">
|
|
2
|
+
<path d="M26 2C12.7 2 2 12.7 2 26s10.7 24 24 24 24-10.7 24-24S39.3 2 26 2zm4.9 24.8 7.8 7.8c.4.4.4 1 0 1.4l-2.8 2.8c-.4.4-1 .4-1.4 0L26.7 31c-.4-.4-1-.4-1.4 0l-7.8 7.8c-.4.4-1 .4-1.4 0L13.3 36c-.4-.4-.4-1 0-1.4l7.8-7.8c.4-.4.4-1 0-1.4l-7.9-7.9c-.4-.4-.4-1 0-1.4l2.8-2.8c.4-.4 1-.4 1.4 0l7.9 7.9c.4.4 1 .4 1.4 0l7.8-7.8c.4-.4 1-.4 1.4 0l2.8 2.8c.4.4.4 1 0 1.4l-7.8 7.8c-.3.4-.3 1 0 1.4z"/>
|
|
3
|
+
</svg>
|
package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/assets/image.svg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52" width="100%" height="100%" fill="currentColor" aria-hidden="true">
|
|
2
|
+
<path d="M50 10c0-2.2-1.8-4-4-4H6c-2.2 0-4 1.8-4 4v32c0 2.2 1.8 4 4 4h40c2.2 0 4-1.8 4-4V10zM39.6 38h-29c-1.2 0-1.9-1.3-1.3-2.3l8.8-15.3c.4-.7 1.3-.7 1.7 0l5.3 9.1c.4.6 1.3.7 1.7.1l4.3-6.2c.4-.6 1.3-.6 1.7 0L40.7 36c.6.9 0 2-1.1 2zM37 20c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
|
|
3
|
+
</svg>
|
package/dist/force-app/main/default/webapplications/feature-react-file-upload/src/assets/success.svg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52" width="100%" height="100%" fill="currentColor" aria-hidden="true">
|
|
2
|
+
<path d="M26 2C12.7 2 2 12.7 2 26s10.7 24 24 24 24-10.7 24-24S39.3 2 26 2zm13.4 18L24.1 35.5c-.6.6-1.6.6-2.2 0L13.5 27c-.6-.6-.6-1.6 0-2.2l2.2-2.2c.6-.6 1.6-.6 2.2 0l4.4 4.5c.4.4 1.1.4 1.5 0L35 15.5c.6-.6 1.6-.6 2.2 0l2.2 2.2c.7.6.7 1.6 0 2.3z"/>
|
|
3
|
+
</svg>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LABELS } from "../utils/labels";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ImageIcon } from "./FileUploadIcons";
|
|
4
4
|
|
|
5
5
|
export interface FileUploadDropZoneProps {
|
|
6
6
|
/** Props for the hidden file input (ref, type, accept, multiple, onChange) */
|
|
@@ -79,7 +79,7 @@ export function FileUploadDropZone({
|
|
|
79
79
|
className="inline-flex h-12 w-12 shrink-0 items-center justify-center text-gray-500"
|
|
80
80
|
aria-hidden
|
|
81
81
|
>
|
|
82
|
-
<
|
|
82
|
+
<ImageIcon size="lg" />
|
|
83
83
|
</span>
|
|
84
84
|
<p className="text-center text-sm font-medium text-gray-900">
|
|
85
85
|
{isDragging ? LABELS.dropFilesHere : LABELS.chooseFileOrDrop}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Button } from "./ui/button";
|
|
2
|
-
import { FileTypeIcon,
|
|
2
|
+
import { FileTypeIcon, IconImageClose, SuccessIcon } from "./FileUploadIcons";
|
|
3
3
|
import {
|
|
4
4
|
formatFileSize,
|
|
5
5
|
getFileExtension,
|
|
@@ -68,7 +68,7 @@ export function FileUploadFileItem({ item, onCancel }: FileUploadFileItemProps)
|
|
|
68
68
|
onClick={() => onCancel(item.file.name)}
|
|
69
69
|
aria-label={LABELS.cancelUpload(item.file.name)}
|
|
70
70
|
>
|
|
71
|
-
<
|
|
71
|
+
<IconImageClose fill="rgb(116, 116, 116)" />
|
|
72
72
|
</Button>
|
|
73
73
|
)}
|
|
74
74
|
{renderStatusIcon(item.state)}
|
|
@@ -80,7 +80,7 @@ export function FileUploadFileItem({ item, onCancel }: FileUploadFileItemProps)
|
|
|
80
80
|
|
|
81
81
|
function renderStatusIcon(state: FileUploadItem["state"]): React.ReactNode {
|
|
82
82
|
if (isUploading(state)) return null;
|
|
83
|
-
if (state === "success") return <
|
|
83
|
+
if (state === "success") return <SuccessIcon fill="rgb(46, 132, 74)" />;
|
|
84
84
|
if (state === "cancelled") {
|
|
85
85
|
return (
|
|
86
86
|
<span className="shrink-0 text-xs text-gray-500" aria-label={LABELS.cancelled}>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import symbolsUrl from "../assets/symbols.svg?url";
|
|
2
2
|
|
|
3
|
-
import utilitySvg from "../assets/utility.svg?url";
|
|
4
|
-
|
|
5
3
|
const IMAGE_EXTENSIONS = new Set([
|
|
6
4
|
"jpg",
|
|
7
5
|
"jpeg",
|
|
@@ -35,24 +33,58 @@ export function FileTypeIcon({ extension }: { extension: string }) {
|
|
|
35
33
|
</span>
|
|
36
34
|
);
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
|
|
37
|
+
import iconImageCloseSvg from "../assets/icon-image-close.svg?raw";
|
|
38
|
+
import successSvg from "../assets/success.svg?raw";
|
|
39
|
+
import imageSvg from "../assets/image.svg?raw";
|
|
40
|
+
|
|
41
|
+
/** Props for icon components (close, success, image) */
|
|
42
|
+
export interface IconProps {
|
|
43
|
+
size?: "sm" | "md" | "lg";
|
|
42
44
|
fill?: string;
|
|
43
45
|
}
|
|
44
46
|
|
|
47
|
+
const sizeClass = (size: IconProps["size"]) =>
|
|
48
|
+
size === "sm" ? "h-4 w-4" : size === "lg" ? "h-12 w-12" : "h-6 w-6";
|
|
49
|
+
|
|
45
50
|
/**
|
|
46
|
-
*
|
|
47
|
-
* and fill color. Used for clear, success, upload, etc.
|
|
51
|
+
* Close icon (circle with X). Renders from icon-image-close.svg.
|
|
48
52
|
*/
|
|
49
|
-
export function
|
|
50
|
-
const sizeClass = size === "sm" ? "h-4 w-4" : "h-6 w-6";
|
|
53
|
+
export function IconImageClose({ size = "md", fill = "currentColor" }: IconProps) {
|
|
51
54
|
return (
|
|
52
|
-
<span
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
<span
|
|
56
|
+
className={`inline-flex ${sizeClass(size)} shrink-0 items-center justify-center`}
|
|
57
|
+
style={{ color: fill }}
|
|
58
|
+
aria-hidden
|
|
59
|
+
dangerouslySetInnerHTML={{ __html: iconImageCloseSvg }}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Success icon (circle with checkmark). Renders from success.svg.
|
|
66
|
+
*/
|
|
67
|
+
export function SuccessIcon({ size = "md", fill = "currentColor" }: IconProps) {
|
|
68
|
+
return (
|
|
69
|
+
<span
|
|
70
|
+
className={`inline-flex ${sizeClass(size)} shrink-0 items-center justify-center`}
|
|
71
|
+
style={{ color: fill }}
|
|
72
|
+
aria-hidden
|
|
73
|
+
dangerouslySetInnerHTML={{ __html: successSvg }}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Image icon (picture frame). Renders from image.svg. Used for drop zone.
|
|
80
|
+
*/
|
|
81
|
+
export function ImageIcon({ size = "lg", fill = "currentColor" }: IconProps) {
|
|
82
|
+
return (
|
|
83
|
+
<span
|
|
84
|
+
className={`inline-flex ${sizeClass(size)} shrink-0 items-center justify-center`}
|
|
85
|
+
style={{ color: fill }}
|
|
86
|
+
aria-hidden
|
|
87
|
+
dangerouslySetInnerHTML={{ __html: imageSvg }}
|
|
88
|
+
/>
|
|
57
89
|
);
|
|
58
90
|
}
|
|
@@ -14,11 +14,11 @@ export default function UploadTest() {
|
|
|
14
14
|
console.log("Uploaded files:", JSON.stringify(files, null, 2));
|
|
15
15
|
|
|
16
16
|
try {
|
|
17
|
-
const userId = await getCurrentUserId();
|
|
18
|
-
// eslint-disable-next-line no-console
|
|
19
|
-
console.log("Current user ID:", userId);
|
|
20
|
-
|
|
21
17
|
for (const uploadedFile of files) {
|
|
18
|
+
if (uploadedFile.contentVersionId) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const userId = await getCurrentUserId();
|
|
22
22
|
// Create a File object from the uploaded file info (for API signature)
|
|
23
23
|
const file = new File([""], uploadedFile.name);
|
|
24
24
|
const contentVersionId = await createContentVersion(
|
|
@@ -45,9 +45,9 @@ export default function UploadTest() {
|
|
|
45
45
|
</p>
|
|
46
46
|
<FileUpload
|
|
47
47
|
multiple
|
|
48
|
+
recordId="500SG00001Bbi1dYAB"
|
|
48
49
|
accept="image/jpeg,.jpg,.jpeg,application/pdf,.pdf"
|
|
49
50
|
maxFileSize={50}
|
|
50
|
-
formatHint="JPEG and PDF formats, up to 50MB"
|
|
51
51
|
onUploadComplete={handleUploadComplete}
|
|
52
52
|
/>
|
|
53
53
|
</section>
|
package/dist/force-app/main/default/webapplications/feature-react-file-upload/vite.config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PluginOption } from "vite";
|
|
1
2
|
import { defineConfig } from "vite";
|
|
2
3
|
import react from "@vitejs/plugin-react";
|
|
3
4
|
import path from "path";
|
|
@@ -7,7 +8,7 @@ import salesforce from "@salesforce/vite-plugin-webapp-experimental";
|
|
|
7
8
|
|
|
8
9
|
export default defineConfig(({ mode }) => {
|
|
9
10
|
return {
|
|
10
|
-
plugins: [tailwindcss(), react(), salesforce({ debug: true })],
|
|
11
|
+
plugins: [tailwindcss(), react(), salesforce({ debug: true })] as PluginOption[],
|
|
11
12
|
|
|
12
13
|
build: {
|
|
13
14
|
outDir: resolve(__dirname, "dist"),
|
package/dist/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-feature-react-file-upload-experimental",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.61.1",
|
|
4
4
|
"description": "File upload feature with a component to upload files to core",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@salesforce/webapp-experimental": "^1.
|
|
44
|
+
"@salesforce/webapp-experimental": "^1.61.1",
|
|
45
45
|
"@types/react": "^19.2.7",
|
|
46
46
|
"@types/react-dom": "^19.2.3",
|
|
47
47
|
"nodemon": "^3.1.0",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"react-router": "^7.10.1",
|
|
50
50
|
"vite": "^7.3.1"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "74f2289f311e488569b6e9616a34604b2154802e"
|
|
53
53
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52" width="100%" height="100%" fill="currentColor" aria-hidden="true">
|
|
2
|
+
<path d="M26 2C12.7 2 2 12.7 2 26s10.7 24 24 24 24-10.7 24-24S39.3 2 26 2zm4.9 24.8 7.8 7.8c.4.4.4 1 0 1.4l-2.8 2.8c-.4.4-1 .4-1.4 0L26.7 31c-.4-.4-1-.4-1.4 0l-7.8 7.8c-.4.4-1 .4-1.4 0L13.3 36c-.4-.4-.4-1 0-1.4l7.8-7.8c.4-.4.4-1 0-1.4l-7.9-7.9c-.4-.4-.4-1 0-1.4l2.8-2.8c.4-.4 1-.4 1.4 0l7.9 7.9c.4.4 1 .4 1.4 0l7.8-7.8c.4-.4 1-.4 1.4 0l2.8 2.8c.4.4.4 1 0 1.4l-7.8 7.8c-.3.4-.3 1 0 1.4z"/>
|
|
3
|
+
</svg>
|
package/src/force-app/main/default/webapplications/feature-react-file-upload/src/assets/image.svg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52" width="100%" height="100%" fill="currentColor" aria-hidden="true">
|
|
2
|
+
<path d="M50 10c0-2.2-1.8-4-4-4H6c-2.2 0-4 1.8-4 4v32c0 2.2 1.8 4 4 4h40c2.2 0 4-1.8 4-4V10zM39.6 38h-29c-1.2 0-1.9-1.3-1.3-2.3l8.8-15.3c.4-.7 1.3-.7 1.7 0l5.3 9.1c.4.6 1.3.7 1.7.1l4.3-6.2c.4-.6 1.3-.6 1.7 0L40.7 36c.6.9 0 2-1.1 2zM37 20c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"/>
|
|
3
|
+
</svg>
|
package/src/force-app/main/default/webapplications/feature-react-file-upload/src/assets/success.svg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52" width="100%" height="100%" fill="currentColor" aria-hidden="true">
|
|
2
|
+
<path d="M26 2C12.7 2 2 12.7 2 26s10.7 24 24 24 24-10.7 24-24S39.3 2 26 2zm13.4 18L24.1 35.5c-.6.6-1.6.6-2.2 0L13.5 27c-.6-.6-.6-1.6 0-2.2l2.2-2.2c.6-.6 1.6-.6 2.2 0l4.4 4.5c.4.4 1.1.4 1.5 0L35 15.5c.6-.6 1.6-.6 2.2 0l2.2 2.2c.7.6.7 1.6 0 2.3z"/>
|
|
3
|
+
</svg>
|