inertia-bootstrap-forms 1.0.79 → 1.0.81

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
@@ -166,9 +166,12 @@ export const UppyInput: DefineComponent<{
166
166
  type: Boolean,
167
167
  default: true,
168
168
  },
169
+ errorHandler: {type: Function, default: null},
170
+ config: {type: Object, default: () => ({})},
169
171
  modelValue: String,
172
+ XHRConfig: {type: Object, default: {}},
173
+ useXHR: {type: Boolean, default: true},
170
174
  url: { type: String, default: "/upload" },
171
- options: { type: Object, default: () => ({}) },
172
175
  }, {},
173
176
  any,
174
177
  {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inertia-bootstrap-forms",
3
- "version": "1.0.79",
3
+ "version": "1.0.81",
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
@@ -11,7 +11,7 @@
11
11
  </template>
12
12
 
13
13
  <script setup>
14
- import {computed, inject, onBeforeUnmount, onMounted, shallowRef, ref} from 'vue'
14
+ import {computed, inject, onBeforeUnmount, onMounted, shallowRef, ref, watch} from 'vue'
15
15
  import {
16
16
  Dropzone,
17
17
  FilesList,
@@ -43,6 +43,8 @@ const emits = defineEmits([
43
43
  const restrictionCaption = ref(null);
44
44
  const inputEl = ref(null);
45
45
  const uppy = shallowRef(null);
46
+ const isResetting = ref(false);
47
+ const isUnmounting = ref(false);
46
48
 
47
49
  // Inject form and group contexts
48
50
  const form = inject("form", {value: {}, errors: {}, getID: n => n});
@@ -64,9 +66,8 @@ const modelValue = computed({
64
66
  }
65
67
  });
66
68
 
67
- // ایجاد اینستنس اختصاصی برای هر کامپوننت
68
69
  uppy.value = new Uppy({
69
- id: props.name, // جلوگیری از تداخل با استفاده از نام پروپ
70
+ id: props.name,
70
71
  autoProceed: true,
71
72
  ...props.config,
72
73
  restrictions: {
@@ -91,21 +92,19 @@ uppy.value.on('upload-success', (file, response) => {
91
92
  });
92
93
 
93
94
  uppy.value.on('file-added', (file) => emits('file-added', file));
95
+
94
96
  uppy.value.on('file-removed', (file) => {
95
97
  const serverResponse = file.response?.body ?? file.response;
96
98
 
97
99
  if (props.multiple && Array.isArray(modelValue.value)) {
98
100
  modelValue.value = modelValue.value.filter(item => {
99
- // مقایسه بر اساس شناسه یا کل آبجکت (بسته به ساختار ارسالی سرور شما)
100
- // اگر سرور ID برمی‌گرداند: return item.id !== serverResponse.id;
101
- // اگر مستقیماً خود آبجکت است:
102
101
  return JSON.stringify(item) !== JSON.stringify(serverResponse);
103
102
  });
104
103
  } else {
105
104
  modelValue.value = null;
106
105
  }
107
106
 
108
- if (serverResponse) {
107
+ if (serverResponse && !isResetting.value && !isUnmounting.value) {
109
108
  fetch(props.url, {
110
109
  method: 'DELETE',
111
110
  headers: {
@@ -120,16 +119,15 @@ uppy.value.on('file-removed', (file) => {
120
119
  });
121
120
 
122
121
  uppy.value.on('progress', (progress) => {
123
- form.value['uploading'] = (progress >= 100 || progress <=0) ? null : progress;
122
+ form.value['uploading'] = (progress >= 100 || progress <= 0) ? null : progress;
124
123
  emits('progress', progress)
125
124
  });
126
125
  uppy.value.on('upload-progress', (file, progress) => emits('upload-progress', file, progress));
127
126
  uppy.value.on('upload-pause', (file, progress) => emits('upload-pause', file, progress));
128
127
  uppy.value.on('cancel-all', () => emits('cancel-all'));
129
- uppy.value.on('retry-all', () => emits('retry-all', ));
128
+ uppy.value.on('retry-all', () => emits('retry-all'));
130
129
  uppy.value.on('upload-stalled', (error, files) => emits('upload-stalled', error, files));
131
130
  uppy.value.on('upload-retry', (file) => emits('upload-retry', file));
132
-
133
131
  uppy.value.on('complete', (result) => emits('complete', result));
134
132
 
135
133
  uppy.value.on('error', (error) => {
@@ -147,11 +145,16 @@ uppy.value.on('restriction-failed', (file, error) => {
147
145
  emits('restriction-failed', file, error);
148
146
  });
149
147
 
148
+ watch(() => form.value?.wasSuccessful, (newVal, oldVal) => {
149
+ if (newVal === true && oldVal === false) {
150
+ resetUppy();
151
+ }
152
+ });
153
+
150
154
  onMounted(() => {
151
- let XHR;
152
155
  if (props.useXHR) {
153
156
  import('@uppy/xhr-upload').then(module => {
154
- XHR = module.default; // چون اکثر پکیج‌ها default export دارند
157
+ const XHR = module.default;
155
158
  uppy.value.use(XHR, {
156
159
  method: 'POST',
157
160
  endpoint: props.url,
@@ -163,17 +166,27 @@ onMounted(() => {
163
166
  });
164
167
  }
165
168
 
166
- if(uppy.value?.opts?.restrictions){
169
+ if (uppy.value?.opts?.restrictions) {
167
170
  restrictionCaption.value = buildRestrictionsCaption(uppy.value.opts.restrictions)
168
171
  }
169
172
  });
170
173
 
171
174
  onBeforeUnmount(() => {
175
+ isUnmounting.value = true;
172
176
  if (uppy.value) {
173
177
  uppy.value.destroy();
174
178
  }
175
179
  });
176
180
 
181
+ function resetUppy() {
182
+ if (uppy.value) {
183
+ isResetting.value = true;
184
+ uppy.value.cancelAll();
185
+ isResetting.value = false;
186
+ modelValue.value = props.multiple ? [] : null;
187
+ }
188
+ }
189
+
177
190
  function handleError(error) {
178
191
  if (props.errorHandler) {
179
192
  props.errorHandler(error);
@@ -193,9 +206,13 @@ function showError(message) {
193
206
  }
194
207
  }
195
208
 
196
- function formatBytesToKB(size) {
197
- if (!size) return null;
198
- return Math.round(size / 1024);
209
+ const niceBytesUnits = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
210
+ function niceBytes(x) {
211
+ let l = 0, n = parseInt(x, 10) || 0;
212
+ while (n >= 1024 && ++l) {
213
+ n = n / 1024;
214
+ }
215
+ return (n.toFixed(n < 10 && l > 0 ? 1 : 0) + niceBytesUnits[l]);
199
216
  }
200
217
 
201
218
  function buildRestrictionsCaption(restrictions) {
@@ -212,7 +229,6 @@ function buildRestrictionsCaption(restrictions) {
212
229
 
213
230
  const parts = [];
214
231
 
215
- // پسوندها
216
232
  if (allowedFileTypes && allowedFileTypes.length) {
217
233
  const types = allowedFileTypes
218
234
  .map(type => type.replace('.', ''))
@@ -220,7 +236,6 @@ function buildRestrictionsCaption(restrictions) {
220
236
  parts.push(`فقط فایل‌های ${types}`);
221
237
  }
222
238
 
223
- // تعداد فایل
224
239
  if (maxNumberOfFiles) {
225
240
  parts.push(`امکان انتخاب حداکثر ${maxNumberOfFiles} فایل`);
226
241
  }
@@ -229,25 +244,22 @@ function buildRestrictionsCaption(restrictions) {
229
244
  parts.push(`حداقل ${minNumberOfFiles} فایل نیاز است`);
230
245
  }
231
246
 
232
- // حجم هر فایل
233
247
  if (maxFileSize) {
234
- parts.push(`با حداکثر حجم ${formatBytesToKB(maxFileSize)} کیلوبایت برای هر فایل`);
248
+ parts.push(`با حداکثر حجم ${niceBytes(maxFileSize)} برای هر فایل`);
235
249
  }
236
250
 
237
251
  if (minFileSize) {
238
- parts.push(`با حداقل حجم ${formatBytesToKB(minFileSize)} کیلوبایت برای هر فایل`);
252
+ parts.push(`با حداقل حجم ${niceBytes(minFileSize)} برای هر فایل`);
239
253
  }
240
254
 
241
- // مجموع حجم
242
255
  if (maxTotalFileSize) {
243
- parts.push(`و مجموع حجم کل حداکثر ${formatBytesToKB(maxTotalFileSize)} کیلوبایت`);
256
+ parts.push(`و مجموع حجم کل حداکثر ${niceBytes(maxTotalFileSize)}`);
244
257
  }
245
258
 
246
259
  if (!parts.length) return '';
247
260
 
248
261
  return parts.join('، ') + ' مجاز است.';
249
262
  }
250
-
251
263
  </script>
252
264
 
253
265
  <style>
@@ -272,9 +284,8 @@ function buildRestrictionsCaption(restrictions) {
272
284
  margin-bottom: 5px;
273
285
  }
274
286
 
275
- .uppy-input-area .uppy-input-area--caption{
287
+ .uppy-input-area .uppy-input-area--caption {
276
288
  text-align: center;
277
289
  margin: 5px 0;
278
290
  }
279
-
280
291
  </style>