inertia-bootstrap-forms 1.0.64 → 1.0.66

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/index.d.ts CHANGED
@@ -165,6 +165,10 @@ export const UppyInput: DefineComponent<{
165
165
  type: Boolean,
166
166
  default: false,
167
167
  },
168
+ showRestrictionCaption: {
169
+ type: Boolean,
170
+ default: true,
171
+ },
168
172
  modelValue: String,
169
173
  url: { type: String, default: "/upload" },
170
174
  options: { type: Object, default: () => ({}) },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inertia-bootstrap-forms",
3
- "version": "1.0.64",
3
+ "version": "1.0.66",
4
4
  "description": "Create bootstrap forms with inertia and twitter bootstrap",
5
5
  "main": "dist/inertia-bootstrap-forms.cjs.js",
6
6
  "module": "dist/inertia-bootstrap-forms.es.js",
package/src/UppyInput.vue CHANGED
@@ -6,6 +6,7 @@
6
6
  <Dropzone/>
7
7
  </slot>
8
8
  </UppyContextProvider>
9
+ <div class="uppy-input-area--caption small text-body-secondary fst-italic" v-if="restrictionCaption">{{restrictionCaption}}</div>
9
10
  </div>
10
11
  </template>
11
12
 
@@ -28,6 +29,7 @@ const props = defineProps({
28
29
  url: {type: String, default: '/upload'},
29
30
  config: {type: Object, default: () => ({})},
30
31
  errorHandler: {type: Function, default: null},
32
+ showRestrictionCaption: {type: Boolean, default: true},
31
33
  })
32
34
 
33
35
  const emits = defineEmits([
@@ -38,6 +40,7 @@ const emits = defineEmits([
38
40
  'restriction-failed',
39
41
  ])
40
42
 
43
+ const restrictionCaption = ref(null);
41
44
  const inputEl = ref(null);
42
45
  const uppy = shallowRef(null);
43
46
 
@@ -67,7 +70,7 @@ uppy.value = new Uppy({
67
70
  autoProceed: true,
68
71
  ...props.config,
69
72
  restrictions: {
70
- maxNumberOfFiles: props.multiple ? 10 : 1,
73
+ maxNumberOfFiles: props.multiple ? null : 1,
71
74
  ...(props.config?.restrictions || {})
72
75
  },
73
76
  });
@@ -89,8 +92,9 @@ uppy.value.on('upload-success', (file, response) => {
89
92
 
90
93
  uppy.value.on('file-added', (file) => emits('file-added', file));
91
94
  uppy.value.on('file-removed', (file) => {
95
+ const serverResponse = file.response?.body ?? file.response;
96
+
92
97
  if (props.multiple && Array.isArray(modelValue.value)) {
93
- const serverResponse = file.response?.body ?? file.response;
94
98
  modelValue.value = modelValue.value.filter(item => {
95
99
  // مقایسه بر اساس شناسه یا کل آبجکت (بسته به ساختار ارسالی سرور شما)
96
100
  // اگر سرور ID برمی‌گرداند: return item.id !== serverResponse.id;
@@ -101,30 +105,42 @@ uppy.value.on('file-removed', (file) => {
101
105
  modelValue.value = null;
102
106
  }
103
107
 
104
- // بخش حذف از سرور
105
- if (file.response) {
108
+ if (serverResponse) {
106
109
  fetch(props.url, {
107
110
  method: 'DELETE',
108
111
  headers: {
109
112
  'X-Requested-With': 'XMLHttpRequest',
110
113
  'Content-Type': 'application/json',
111
114
  },
112
- body: JSON.stringify(file.response.body ?? file.response),
115
+ body: JSON.stringify(serverResponse),
113
116
  });
114
117
  }
115
118
 
116
119
  emits('file-removed', file);
117
120
  });
118
121
 
122
+ uppy.value.on('progress', (progress) => emits('progress', progress));
123
+ uppy.value.on('upload-progress', (file, progress) => emits('upload-progress', file, progress));
124
+ uppy.value.on('upload-pause', (file, progress) => emits('upload-pause', file, progress));
125
+ uppy.value.on('cancel-all', () => emits('cancel-all'));
126
+ uppy.value.on('retry-all', () => emits('retry-all', ));
127
+ uppy.value.on('upload-stalled', (error, files) => emits('upload-stalled', error, files));
128
+ uppy.value.on('upload-retry', (file) => emits('upload-retry', file));
129
+
119
130
  uppy.value.on('complete', (result) => emits('complete', result));
120
- uppy.value.on('error', (error) => emits('error', error));
131
+
132
+ uppy.value.on('error', (error) => {
133
+ emits('error', error)
134
+ });
135
+
136
+ uppy.value.on('upload-error', (file, error, response) => {
137
+ const errorMessage = JSON.parse(response.response)?.message ?? error;
138
+ handleError(errorMessage);
139
+ emits('upload-error', file, error, response, errorMessage)
140
+ });
121
141
 
122
142
  uppy.value.on('restriction-failed', (file, error) => {
123
- if (props.errorHandler) {
124
- props.errorHandler(error);
125
- } else {
126
- showError(error.message);
127
- }
143
+ handleError(error.message);
128
144
  emits('restriction-failed', file, error);
129
145
  });
130
146
 
@@ -136,7 +152,6 @@ onMounted(() => {
136
152
  uppy.value.use(XHR, {
137
153
  method: 'POST',
138
154
  endpoint: props.url,
139
- withCredentials: false,
140
155
  headers: {
141
156
  'accept': 'application/json',
142
157
  },
@@ -144,6 +159,12 @@ onMounted(() => {
144
159
  });
145
160
  });
146
161
  }
162
+
163
+ if(uppy.value?.opts?.restrictions){
164
+ console.log(uppy.value?.opts?.restrictions);
165
+ restrictionCaption.value = buildRestrictionsCaption(uppy.value.opts.restrictions)
166
+ console.log('restrictionCaption', restrictionCaption.value);
167
+ }
147
168
  });
148
169
 
149
170
  onBeforeUnmount(() => {
@@ -152,6 +173,14 @@ onBeforeUnmount(() => {
152
173
  }
153
174
  });
154
175
 
176
+ function handleError(error) {
177
+ if (props.errorHandler) {
178
+ props.errorHandler(error);
179
+ } else if (error) {
180
+ showError(error);
181
+ }
182
+ }
183
+
155
184
  function showError(message) {
156
185
  const errorEl = document.createElement('div');
157
186
  errorEl.textContent = message;
@@ -162,6 +191,62 @@ function showError(message) {
162
191
  setTimeout(() => errorEl.remove(), 3000);
163
192
  }
164
193
  }
194
+
195
+ function formatBytesToKB(size) {
196
+ if (!size) return null;
197
+ return Math.round(size / 1024);
198
+ }
199
+
200
+ function buildRestrictionsCaption(restrictions) {
201
+ if (!restrictions) return '';
202
+
203
+ const {
204
+ allowedFileTypes,
205
+ maxFileSize,
206
+ minFileSize,
207
+ maxNumberOfFiles,
208
+ minNumberOfFiles,
209
+ maxTotalFileSize,
210
+ } = restrictions;
211
+
212
+ const parts = [];
213
+
214
+ // پسوندها
215
+ if (allowedFileTypes && allowedFileTypes.length) {
216
+ const types = allowedFileTypes
217
+ .map(type => type.replace('.', ''))
218
+ .join('، ');
219
+ parts.push(`فقط فایل با پسوندهای ${types}`);
220
+ }
221
+
222
+ // تعداد فایل
223
+ if (maxNumberOfFiles) {
224
+ parts.push(`امکان انتخاب حداکثر ${maxNumberOfFiles} فایل`);
225
+ }
226
+
227
+ if (minNumberOfFiles) {
228
+ parts.push(`حداقل ${minNumberOfFiles} فایل نیاز است`);
229
+ }
230
+
231
+ // حجم هر فایل
232
+ if (maxFileSize) {
233
+ parts.push(`با حداکثر حجم ${formatBytesToKB(maxFileSize)} کیلوبایت برای هر فایل`);
234
+ }
235
+
236
+ if (minFileSize) {
237
+ parts.push(`با حداقل حجم ${formatBytesToKB(minFileSize)} کیلوبایت برای هر فایل`);
238
+ }
239
+
240
+ // مجموع حجم
241
+ if (maxTotalFileSize) {
242
+ parts.push(`و مجموع حجم کل حداکثر ${formatBytesToKB(maxTotalFileSize)} کیلوبایت`);
243
+ }
244
+
245
+ if (!parts.length) return '';
246
+
247
+ return parts.join('، ') + ' مجاز است.';
248
+ }
249
+
165
250
  </script>
166
251
 
167
252
  <style>