inertia-bootstrap-forms 1.0.56 → 1.0.57

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
@@ -10,6 +10,7 @@ import EditorInput from './src/EditorInput.vue';
10
10
  import EmailInput from './src/EmailInput.vue';
11
11
  import FileInput from './src/FileInput.vue';
12
12
  import SimpleUploader from './src/SimpleUploader.vue';
13
+ import UppyInput from './src/UppyInput.vue';
13
14
  import FormContainer from './src/FormContainer.vue';
14
15
  import FormLabel from './src/FormLabel.vue';
15
16
  import GroupControl from './src/GroupControl.vue';
@@ -40,6 +41,7 @@ export {
40
41
  EditorInput,
41
42
  EmailInput,
42
43
  DropzoneInput,
44
+ UppyInput,
43
45
  FileInput,
44
46
  SimpleUploader,
45
47
  FormContainer,
@@ -72,6 +74,7 @@ const Vue3FormComponents = {
72
74
  countryCodes,
73
75
  EditorInput,
74
76
  DropzoneInput,
77
+ UppyInput,
75
78
  EmailInput,
76
79
  FileInput,
77
80
  SimpleUploader,
@@ -153,6 +156,44 @@ export const EditorInput: DefineComponent<{
153
156
  }, {}, any>;
154
157
  export const EmailInput: DefineComponent<{}, {}, any>;
155
158
  export const DropzoneInput: DefineComponent<{}, {}, any>;
159
+ export const UppyInput: DefineComponent<{
160
+ name: {
161
+ type: String,
162
+ required: true,
163
+ },
164
+ multiple: {
165
+ type: Boolean,
166
+ default: false,
167
+ },
168
+ modelValue: String,
169
+ url: { type: String, default: "/upload" },
170
+ options: { type: Object, default: () => ({}) },
171
+ }, {},
172
+ any,
173
+ {},
174
+ {},
175
+ {},
176
+ {},
177
+ {
178
+ 'update:modelValue': (value: string) => void,
179
+ 'file-added': (file) => void,
180
+ 'file-removed': (file) => void,
181
+ 'beforeUpload': (files) => void,
182
+ 'progress': (progress) => void,
183
+ 'upload': (uploadID, file) => void,
184
+ 'upload-progress': (file, progress) => void,
185
+ 'upload-error': (file, error, response) => void,
186
+ 'upload-success': (file, response) => void,
187
+ 'upload-pause': (file, isPaused) => void,
188
+ 'complete': (result) => void,
189
+ 'error': (error) => void,
190
+ 'upload-retry': (file) => void,
191
+ 'upload-stalled': (error, files) => void,
192
+ 'retry-all': (files) => void,
193
+ 'cancel-all': () => void,
194
+ 'restriction-failed': (file, error) => void,
195
+ }
196
+ >;
156
197
  export const FileInput: DefineComponent<{}, {}, any>;
157
198
  export const SimpleUploader: DefineComponent<{}, {}, any>;
158
199
  export const FormContainer: DefineComponent<{}, {}, any>;
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "inertia-bootstrap-forms",
3
- "version": "1.0.56",
3
+ "version": "1.0.57",
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",
7
7
  "type": "module",
8
8
  "types": "./index.d.ts",
9
9
  "scripts": {
10
+ "dev": "vite build --watch",
10
11
  "build": "vite build"
11
12
  },
12
13
  "files": [
@@ -37,6 +38,13 @@
37
38
  ],
38
39
  "dependencies": {
39
40
  "@tinymce/tinymce-vue": "^6.1.0",
41
+ "@uppy/audio": "^3.1.0",
42
+ "@uppy/core": "^5.2.0",
43
+ "@uppy/dashboard": "^5.1.1",
44
+ "@uppy/drag-drop": "^5.1.0",
45
+ "@uppy/locales": "^5.1.1",
46
+ "@uppy/vue": "^3.2.0",
47
+ "@uppy/xhr-upload": "^5.1.1",
40
48
  "@vitejs/plugin-vue": "^5.2.4",
41
49
  "@vue-leaflet/vue-leaflet": "^0.10.1",
42
50
  "choices.js": "^11.1.0",
@@ -95,7 +95,6 @@ export default defineComponent({
95
95
  });
96
96
  },
97
97
  beforeUnmount() {
98
- this.rangeSliderEn?.destroy();
99
98
  },
100
99
  data() {
101
100
  return {
@@ -0,0 +1,184 @@
1
+ <template>
2
+ <div class="uppy-input-area" ref="inputEl" v-if="uppy">
3
+ <UppyContextProvider :name="'uu' + name" :uppy="uppy">
4
+ <slot :uppy="uppy">
5
+ <FilesList class="uppy-file-lists"/>
6
+ <Dropzone/>
7
+ </slot>
8
+ </UppyContextProvider>
9
+ </div>
10
+ </template>
11
+
12
+ <script setup>
13
+ import {computed, inject, onBeforeUnmount, onMounted, shallowRef, ref} from 'vue'
14
+ import {
15
+ Dropzone,
16
+ FilesList,
17
+ UppyContextProvider,
18
+ } from '@uppy/vue';
19
+ import Uppy from '@uppy/core';
20
+
21
+ import '@uppy/vue/css/style.css';
22
+ import '@uppy/audio/css/style.min.css';
23
+
24
+ const props = defineProps({
25
+ name: {type: String, required: true},
26
+ multiple: {type: Boolean, default: false},
27
+ useXHR: {type: Boolean, default: true},
28
+ XHRConfig: {type: Object, default: {}},
29
+ url: {type: String, default: '/upload'},
30
+ config: {type: Object, default: () => ({})},
31
+ errorHandler: {type: Function, default: null},
32
+ })
33
+
34
+ const emits = defineEmits([
35
+ 'update:modelValue', 'file-added', 'file-removed', 'beforeUpload',
36
+ 'progress', 'upload', 'upload-progress', 'upload-error',
37
+ 'upload-success', 'upload-pause', 'complete', 'error',
38
+ 'upload-retry', 'upload-stalled', 'retry-all', 'cancel-all',
39
+ 'restriction-failed',
40
+ ])
41
+
42
+ const inputEl = ref(null);
43
+ const uppy = shallowRef(null);
44
+
45
+ // Inject form and group contexts
46
+ const form = inject("form", {value: {}, errors: {}, getID: n => n});
47
+ const group = inject("group", null);
48
+
49
+ const modelValue = computed({
50
+ get() {
51
+ return group?.value?.name
52
+ ? group.value.getData(props.name)
53
+ : form.value[props.name];
54
+ },
55
+ set(val) {
56
+ if (group?.value?.name) {
57
+ group.value.setData(props.name, val);
58
+ } else {
59
+ form.value[props.name] = val;
60
+ }
61
+ emits("update:modelValue", val);
62
+ }
63
+ });
64
+
65
+ // ایجاد اینستنس اختصاصی برای هر کامپوننت
66
+ uppy.value = new Uppy({
67
+ id: props.name, // جلوگیری از تداخل با استفاده از نام پروپ
68
+ autoProceed: true,
69
+ ...props.config,
70
+ restrictions: {
71
+ maxNumberOfFiles: props.multiple ? 10 : 1,
72
+ ...(props.config?.restrictions || {})
73
+ },
74
+ });
75
+
76
+ uppy.value.on('before-upload', (files) => {
77
+ emits('beforeUpload', files);
78
+ });
79
+
80
+ uppy.value.on('upload-success', (file, response) => {
81
+ const result = response.body ?? response;
82
+ if (props.multiple) {
83
+ const currentValues = Array.isArray(modelValue.value) ? modelValue.value : [];
84
+ modelValue.value = [...currentValues, result];
85
+ } else {
86
+ modelValue.value = result;
87
+ }
88
+ emits('upload-success', file, response);
89
+ });
90
+
91
+ uppy.value.on('file-added', (file) => emits('file-added', file));
92
+ uppy.value.on('file-removed', (file) => {
93
+ if (props.multiple && Array.isArray(modelValue.value)) {
94
+ const serverResponse = file.response?.body ?? file.response;
95
+ modelValue.value = modelValue.value.filter(item => {
96
+ // مقایسه بر اساس شناسه یا کل آبجکت (بسته به ساختار ارسالی سرور شما)
97
+ // اگر سرور ID برمی‌گرداند: return item.id !== serverResponse.id;
98
+ // اگر مستقیماً خود آبجکت است:
99
+ return JSON.stringify(item) !== JSON.stringify(serverResponse);
100
+ });
101
+ } else {
102
+ modelValue.value = null;
103
+ }
104
+
105
+ // بخش حذف از سرور
106
+ if (file.response) {
107
+ fetch(props.url, {
108
+ method: 'DELETE',
109
+ headers: {
110
+ 'X-Requested-With': 'XMLHttpRequest',
111
+ 'Content-Type': 'application/json',
112
+ },
113
+ body: JSON.stringify(file.response.body ?? file.response),
114
+ });
115
+ }
116
+
117
+ emits('file-removed', file);
118
+ });
119
+
120
+ uppy.value.on('complete', (result) => emits('complete', result));
121
+ uppy.value.on('error', (error) => emits('error', error));
122
+
123
+ uppy.value.on('restriction-failed', (file, error) => {
124
+ if (props.errorHandler) {
125
+ props.errorHandler(error);
126
+ } else {
127
+ showError(error.message);
128
+ }
129
+ emits('restriction-failed', file, error);
130
+ });
131
+
132
+ onMounted(() => {
133
+ let XHR;
134
+ if (props.useXHR) {
135
+ import('@uppy/xhr-upload').then(module => {
136
+ XHR = module.default; // چون اکثر پکیج‌ها default export دارند
137
+ uppy.value.use(XHR, {
138
+ endpoint: props.url,
139
+ ...props.XHRConfig
140
+ });
141
+ });
142
+ }
143
+ });
144
+
145
+ onBeforeUnmount(() => {
146
+ if (uppy.value) {
147
+ uppy.value.destroy();
148
+ }
149
+ });
150
+
151
+ function showError(message) {
152
+ const errorEl = document.createElement('div');
153
+ errorEl.textContent = message;
154
+ errorEl.className = 'uppy-error';
155
+
156
+ if (inputEl.value) {
157
+ inputEl.value.prepend(errorEl);
158
+ setTimeout(() => errorEl.remove(), 3000);
159
+ }
160
+ }
161
+ </script>
162
+
163
+ <style>
164
+ .uppy-reset p {
165
+ margin-bottom: 0;
166
+ }
167
+
168
+ .uppy-file-lists > ul {
169
+ list-style: none;
170
+ padding: 0;
171
+ margin: 0;
172
+ }
173
+
174
+ .uppy-input-area .uppy-error {
175
+ display: block;
176
+ padding: 5px;
177
+ background-color: #f8d7da;
178
+ border: 1px solid #f5c2c7;
179
+ color: #842029;
180
+ text-align: center;
181
+ border-radius: 0.5rem;
182
+ margin-bottom: 5px;
183
+ }
184
+ </style>
package/src/index.js CHANGED
@@ -25,6 +25,7 @@ import TextInput from "./TextInput.vue";
25
25
  import DropzoneInput from "./DropzoneInput.vue";
26
26
  import SimpleUploader from "./SimpleUploader.vue";
27
27
  import RangeSliderInput from "./RangeSliderInput.vue";
28
+ import UppyInput from "./UppyInput.vue";
28
29
 
29
30
  export {
30
31
  AmountInput,
@@ -39,6 +40,7 @@ export {
39
40
  DropzoneInput,
40
41
  SimpleUploader,
41
42
  RangeSliderInput,
43
+ UppyInput,
42
44
  GroupControl,
43
45
  FormContainer,
44
46
  LocationInput,