inertia-bootstrap-forms 1.0.13 → 1.0.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inertia-bootstrap-forms",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
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",
@@ -0,0 +1,196 @@
1
+ <script>
2
+ import {inject} from "vue";
3
+
4
+ export default {
5
+ props: {
6
+ modelValue: '',
7
+ name: {
8
+ type: String,
9
+ required: true,
10
+ },
11
+ multiple: {
12
+ type: Boolean,
13
+ default: false,
14
+ },
15
+ endpoint: {
16
+ type: String,
17
+ default: '/upload',
18
+ },
19
+ },
20
+ setup(props) {
21
+ let form = inject('form');
22
+
23
+ if (form === undefined) {
24
+ form = {
25
+ errors: {},
26
+ getID(name) {
27
+ }
28
+ };
29
+ }
30
+
31
+ return {form};
32
+ },
33
+ computed: {
34
+ allFiles() {
35
+ return this.files
36
+ },
37
+ },
38
+ methods: {
39
+ addFile(file) {
40
+ let uploadedFile = {
41
+ id: crypto.randomUUID(),
42
+ percent: 0,
43
+ error: 0,
44
+ file: file,
45
+ };
46
+
47
+ if (this.multiple) {
48
+ this.files.push(uploadedFile);
49
+ } else {
50
+ this.files = [uploadedFile];
51
+ }
52
+
53
+ this.uploadFile(uploadedFile);
54
+ this.$refs.input.value = '';
55
+ },
56
+ calculatePercent(event, file) {
57
+ if (event.lengthComputable) {
58
+ this.files.find(item => item.id === file.id)['percent'] = Math.round((event.loaded / event.total) * 100);
59
+ }
60
+ },
61
+ addFileToInputValue(file, res) {
62
+ this.files.find(item => item.id === file.id).path = res.data.path;
63
+
64
+ this.form[this.name] = this.multiple ? this.files.map(item => item.path) : this.files[0].path;
65
+ this.$emit('update:modelValue', this.form[this.name]);
66
+ },
67
+ async uploadFile(file) {
68
+ let _this = this;
69
+ let formData = new FormData();
70
+ formData.append('file', file.file);
71
+
72
+ _this.files.find(item => item.id === file.id)['error'] = '';
73
+
74
+ await axios.post(this.endpoint,
75
+ formData, {
76
+ headers: {
77
+ 'Content-Type': 'multipart/form-data'
78
+ },
79
+ onUploadProgress: progressEvent => _this.calculatePercent(progressEvent, file)
80
+ }
81
+ ).then(function (res) {
82
+ _this.addFileToInputValue(file, res)
83
+ }).catch(function (err) {
84
+ _this.files.find(item => item.id === file.id)['error'] = (err.response?.data?.message || err.message);
85
+ });
86
+ },
87
+ async deleteFile(file) {
88
+ this.files = this.files.filter(item => item.id !== file.id);
89
+ await axios.delete(this.endpoint, {
90
+ data: file.path
91
+ });
92
+ },
93
+ fileSelected(e) {
94
+ Array.from(e.target.files).forEach(file => this.addFile(file));
95
+ }
96
+ },
97
+ data() {
98
+ return {
99
+ files: [],
100
+ }
101
+ }
102
+ }
103
+ </script>
104
+ <template>
105
+ <div class="file-input-uploader">
106
+ <input
107
+ ref="input"
108
+ :name="name"
109
+ :class="{'is-invalid': form?.errors[name] !== undefined}"
110
+ :disabled="form?.processing"
111
+ type="file"
112
+ :multiple="multiple"
113
+ @change="fileSelected"
114
+ class="form-control">
115
+ <div class="file-input-uploader--list">
116
+ <div :id="'file-'+file.id" class="file-input-uploader--list-item" v-for="file in allFiles">
117
+ <div class="file-input-uploader--progress" v-if="file.percent && file.percent< 100">
118
+ <div :style="{width: file.percent + '%'}"></div>
119
+ </div>
120
+ <div>{{ file.file.name }}</div>
121
+ <div class="file-input-uploader--list-error" v-if="file.error">{{ file.error }}</div>
122
+ <div class="file-input-uploader--list-item--size" dir="ltr">{{ Math.round(file.file.size / 1024) }}Kb</div>
123
+ <div class="file-input-uploader--list-item--actions">
124
+ <button @click="uploadFile(file)" type="button" class="file-input-uploader--list-item--btn" v-if="file.error">
125
+ <svg fill="#000000" width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
126
+ <path
127
+ d="M1,12A11,11,0,0,1,17.882,2.7l1.411-1.41A1,1,0,0,1,21,2V6a1,1,0,0,1-1,1H16a1,1,0,0,1-.707-1.707l1.128-1.128A8.994,8.994,0,0,0,3,12a1,1,0,0,1-2,0Zm21-1a1,1,0,0,0-1,1,9.01,9.01,0,0,1-9,9,8.9,8.9,0,0,1-4.42-1.166l1.127-1.127A1,1,0,0,0,8,17H4a1,1,0,0,0-1,1v4a1,1,0,0,0,.617.924A.987.987,0,0,0,4,23a1,1,0,0,0,.707-.293L6.118,21.3A10.891,10.891,0,0,0,12,23,11.013,11.013,0,0,0,23,12,1,1,0,0,0,22,11Z"/>
128
+ </svg>
129
+ </button>
130
+ <button @click="deleteFile(file)" type="button" class="file-input-uploader--list-item--btn" v-if="file.path || file.error">
131
+ <svg fill="#000000" width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
132
+ <path
133
+ d="M12,23A11,11,0,1,0,1,12,11.013,11.013,0,0,0,12,23ZM12,3a9,9,0,1,1-9,9A9.01,9.01,0,0,1,12,3ZM8.293,14.293,10.586,12,8.293,9.707A1,1,0,0,1,9.707,8.293L12,10.586l2.293-2.293a1,1,0,0,1,1.414,1.414L13.414,12l2.293,2.293a1,1,0,1,1-1.414,1.414L12,13.414,9.707,15.707a1,1,0,0,1-1.414-1.414Z"/>
134
+ </svg>
135
+ </button>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </template>
141
+ <style>
142
+ .file-input-uploader .file-input-uploader--list .file-input-uploader--list-item {
143
+ background-color: var(--bs-secondary-bg);
144
+ border-radius: var(--bs-border-radius);
145
+ position: relative;
146
+ display: flex;
147
+ align-items: center;
148
+ margin: 5px 0;
149
+ padding: 5px 10px;
150
+ }
151
+
152
+ .file-input-uploader .file-input-uploader--list .file-input-uploader--list-item--size {
153
+ margin-left: auto;
154
+ font-size: 90%;
155
+ padding: 0 5px;
156
+ color: var(--bs-secondary-color);
157
+ }
158
+
159
+ .file-input-uploader .file-input-uploader--list-item--btn {
160
+ display: inline-block;
161
+ outline: none;
162
+ border: 0;
163
+ padding: 7px 2px;
164
+ }
165
+
166
+ .file-input-uploader .file-input-uploader--list-item--btn:not(:last-child){
167
+ margin-right: 5px;
168
+ }
169
+
170
+ .file-input-uploader .file-input-uploader--list-item--btn > svg {
171
+ height: 20px;
172
+ width: 20px;
173
+ vertical-align: middle;
174
+ }
175
+
176
+ .file-input-uploader .file-input-uploader--progress {
177
+ position: absolute;
178
+ top: 2px;
179
+ left: 5px;
180
+ right: 5px;
181
+ }
182
+
183
+ .file-input-uploader .file-input-uploader--progress > div {
184
+ background-color: #de0021;
185
+ height: 7px;
186
+ width: 0;
187
+ min-width: 1%;
188
+ border-radius: var(--bs-border-radius)
189
+ }
190
+
191
+ .file-input-uploader .file-input-uploader--list-error {
192
+ font-size: 90%;
193
+ margin: 0 5px;
194
+ color: var(--bs-danger, #de0021);
195
+ }
196
+ </style>
@@ -4,7 +4,7 @@ import {LMap, LTileLayer, LMarker} from "@vue-leaflet/vue-leaflet";
4
4
  import {inject} from "vue";
5
5
 
6
6
  export default {
7
- name: 'locationInput',
7
+ name: 'LocationInput',
8
8
  components: {
9
9
  LMap, LTileLayer, LMarker
10
10
  },
@@ -223,7 +223,7 @@
223
223
 
224
224
  .choices__list--dropdown, .choices__list[aria-expanded] {
225
225
  display: none;
226
- z-index: 9;
226
+ z-index: 99999;
227
227
  position: absolute;
228
228
  width: 100%;
229
229
  background-color: #fff;
package/src/index.js CHANGED
@@ -10,7 +10,7 @@ import EmailInput from "./EmailInput.vue";
10
10
  import GroupControl from "./GroupControl.vue";
11
11
  import FormContainer from "./FormContainer.vue";
12
12
  import FormLabel from "./FormLabel.vue";
13
- import locationInput from "./locationInput.vue";
13
+ import LocationInput from "./LocationInput.vue";
14
14
  import MobileInput from "./MobileInput.vue";
15
15
  import PasswordInput from "./PasswordInput.vue";
16
16
  import QuantityInput from "./QuantityInput.vue";
@@ -35,7 +35,7 @@ export {
35
35
  EditorInput,
36
36
  GroupControl,
37
37
  FormContainer,
38
- locationInput,
38
+ LocationInput,
39
39
  MobileInput,
40
40
  PasswordInput,
41
41
  QuantityInput,