@mixd-id/web-scaffold 0.1.240411014 → 0.1.240411016

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.
Files changed (40) hide show
  1. package/package.json +1 -1
  2. package/src/components/Article.vue +9 -16
  3. package/src/components/Carousel.vue +0 -2
  4. package/src/components/CodeEditor.vue +5 -16
  5. package/src/components/CollapsiblePanel.vue +70 -0
  6. package/src/components/ColorPicker2.vue +34 -17
  7. package/src/components/ColorPicker3.vue +14 -6
  8. package/src/components/Image.vue +43 -103
  9. package/src/components/ImageUploader.vue +114 -0
  10. package/src/components/Link.vue +23 -23
  11. package/src/components/MenuItem1.vue +36 -0
  12. package/src/components/Modal.vue +2 -2
  13. package/src/components/Paragraph.vue +1 -2
  14. package/src/components/SvgEditor.vue +173 -0
  15. package/src/components/Testimonial.vue +1 -1
  16. package/src/components/TreeView.vue +8 -7
  17. package/src/components/TreeViewItem.vue +13 -4
  18. package/src/configs/web-page-builder.js +17 -2
  19. package/src/index.js +8 -0
  20. package/src/mixin/component.js +32 -39
  21. package/src/themes/default/index.js +13 -0
  22. package/src/utils/wss.mjs +12 -10
  23. package/src/widgets/BackgroundColorSetting.vue +2 -1
  24. package/src/widgets/BorderColorSetting.vue +57 -0
  25. package/src/widgets/CollapsiblePanelSetting.vue +46 -0
  26. package/src/widgets/ComponentSetting2.vue +30 -30
  27. package/src/widgets/Header2.vue +34 -71
  28. package/src/widgets/Header2Setting.vue +88 -176
  29. package/src/widgets/ImageSetting.vue +12 -23
  30. package/src/widgets/LinkSetting.vue +60 -37
  31. package/src/widgets/LinkSettingModal.vue +173 -0
  32. package/src/widgets/MenuItem1Setting.vue +78 -0
  33. package/src/widgets/ModalSetting.vue +42 -44
  34. package/src/widgets/MultiValueSetting2.vue +19 -7
  35. package/src/widgets/OGSettingModal.vue +105 -0
  36. package/src/widgets/ShareSetting.vue +67 -60
  37. package/src/widgets/TextBlockSetting.vue +16 -13
  38. package/src/widgets/WebComponentSelector.vue +12 -8
  39. package/src/widgets/WebPageBuilder.vue +346 -437
  40. package/tailwind.config.js +2 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.240411014",
4
+ "version": "0.1.240411016",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -1,19 +1,17 @@
1
1
  <template>
2
- <div :class="$style.comp" :style="computedStyle">
3
- <article ref="article" :class="$style.article"
4
- v-html="computedHtml"
5
- :contenteditable="editMode === 1"
6
- @input="onInput"
7
- @click="onClick"
8
- @paste="onPaste"></article>
9
- </div>
2
+ <article ref="article" :class="$style.article"
3
+ v-html="computedHtml"
4
+ :style="computedStyle"
5
+ :contenteditable="editMode === 1"
6
+ @input="onInput"
7
+ @click="onClick"
8
+ @paste="onPaste"></article>
10
9
  </template>
11
10
 
12
11
  <script>
13
12
 
14
13
  import { componentMixin } from '../mixin/component';
15
14
  import {getSelection, restoreSelection, saveSelection} from "../utils/selection";
16
- import {applyDatasourceReplacer} from "../utils/helpers.mjs";
17
15
 
18
16
  export default{
19
17
 
@@ -331,9 +329,7 @@ export default{
331
329
  computed: {
332
330
 
333
331
  computedHtml(){
334
- if(this.editMode && this.editMode === 1)
335
- return this.htmlText
336
- return applyDatasourceReplacer(this.htmlText, this.pageData)
332
+ return this.htmlText
337
333
  },
338
334
 
339
335
  },
@@ -350,11 +346,8 @@ export default{
350
346
 
351
347
  <style module>
352
348
 
353
- .comp{
354
- @apply relative;
355
- }
356
-
357
349
  .article{
350
+ @apply relative;
358
351
  }
359
352
  .article *{
360
353
  }
@@ -299,7 +299,6 @@ export default{
299
299
  <style module>
300
300
 
301
301
  .comp{
302
- white-space: nowrap;
303
302
  overflow: hidden;
304
303
  position: relative;
305
304
  }
@@ -317,7 +316,6 @@ export default{
317
316
  }
318
317
 
319
318
  .inner{
320
- white-space: nowrap;
321
319
  will-change: transform;
322
320
  @apply flex flex-row items-stretch;
323
321
  }
@@ -1,10 +1,9 @@
1
1
  <template>
2
2
  <div :class="$style.comp">
3
- <div class="flex flex-row bg-text-50 p-2">
4
- <div class="flex-1">&nbsp;</div>
5
- </div>
6
- <code v-html="modelValue" contenteditable="true" spellcheck="false"
7
- @paste="onPaste"></code>
3
+ <code contenteditable="true" spellcheck="false"
4
+ @paste="onPaste">
5
+ {{ modelValue }}
6
+ </code>
8
7
  </div>
9
8
  </template>
10
9
 
@@ -20,19 +19,9 @@ export default{
20
19
 
21
20
  methods: {
22
21
 
23
- beautify(){
24
- const html = JSON.parse(JSON.stringify(this.modelValue, null, 2))
25
- this.$emit('update:modelValue', html)
26
- },
27
-
28
22
  onPaste(e) {
29
23
  e.preventDefault()
30
-
31
24
  let text = (e.clipboardData || window.clipboardData).getData("text");
32
- const el = document.createElement('div')
33
- el.innerHTML = text
34
- text = el.innerText
35
-
36
25
  this.$emit('update:modelValue', text)
37
26
  }
38
27
 
@@ -45,7 +34,7 @@ export default{
45
34
  <style module>
46
35
 
47
36
  .comp{
48
- @apply border-text-50 border-[1px] rounded-lg overflow-hidden flex flex-col;
37
+ @apply border-[1px] border-text-200 bg-base-300 rounded-lg flex flex-col overflow-hidden;
49
38
  }
50
39
 
51
40
  .comp code{
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <div :class="$style.comp">
3
+
4
+ <div class="p-3 cursor-pointer flex flex-row" @click="expanded = !expanded">
5
+ <div class="flex-1">{{ text ?? 'Untitled' }}</div>
6
+ <button type="button">
7
+ <svg :class="expanded ? 'rotate-180' : ''" width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M224 416c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L224 338.8l169.4-169.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-192 192C240.4 412.9 232.2 416 224 416z"/></svg>
8
+ </button>
9
+ </div>
10
+
11
+ <div v-if="expanded || editMode === 1" class="px-3">
12
+ <component v-for="comp in items"
13
+ :is="`${comp.type}`"
14
+ :key="comp.uid"
15
+ :="comp" />
16
+ </div>
17
+
18
+ </div>
19
+ </template>
20
+
21
+ <script>
22
+
23
+ import {componentMixin} from "../mixin/component";
24
+
25
+ export default{
26
+
27
+ mixins: [ componentMixin ],
28
+
29
+ props:{
30
+ items: Array,
31
+ text: String,
32
+ },
33
+
34
+ data(){
35
+ return {
36
+ expanded: false
37
+ }
38
+ },
39
+
40
+ provide(){
41
+ return {
42
+ parentData: this.data
43
+ }
44
+ }
45
+
46
+ }
47
+
48
+ </script>
49
+
50
+ <style>
51
+
52
+ .menuitem2-enter-active,
53
+ .menuitem2-leave-active {
54
+ max-height: 100vh;
55
+ transition: all 300ms cubic-bezier(0.25, 1, 0.5, 1);
56
+ }
57
+
58
+ .menuitem2-enter-from,
59
+ .menuitem2-leave-to{
60
+ max-height: 0;
61
+ }
62
+
63
+ </style>
64
+
65
+ <style module>
66
+
67
+ .comp {
68
+ }
69
+
70
+ </style>
@@ -1,13 +1,16 @@
1
1
  <template>
2
2
  <div :class="$style.comp">
3
3
 
4
- <small class="text-text-400" v-if="title">{{ title }}</small>
4
+ <small class="text-text-400" v-if="title">
5
+ {{ title }}
6
+ </small>
5
7
 
6
8
  <div :class="circleClass" :style="circleStyle"
7
9
  @click="mode === 'hex' ? $refs.inputColor.click() : $refs.contextMenu.open($refs.btn)"
8
10
  ref="btn"></div>
11
+
9
12
  <input type="color" :class="$style.inputColor" ref="inputColor"
10
- @change="select($refs.inputColor.value)"/>
13
+ @change="select($refs.inputColor.value)" />
11
14
 
12
15
  <ContextMenu ref="contextMenu" :dismiss="false">
13
16
  <div class="p-4 flex flex-col gap-4">
@@ -28,6 +31,7 @@
28
31
  </div>
29
32
  </div>
30
33
  </ContextMenu>
34
+
31
35
  </div>
32
36
  </template>
33
37
 
@@ -37,8 +41,6 @@ import {hexToRgb, rgbToHex} from "../utils/helpers.mjs";
37
41
 
38
42
  export default{
39
43
 
40
- emits: [ 'change', 'update:modelValue' ],
41
-
42
44
  props: {
43
45
 
44
46
  mode: {
@@ -76,30 +78,41 @@ export default{
76
78
 
77
79
  customColor: undefined,
78
80
 
79
- modelValue: String,
80
-
81
81
  prefix: String,
82
82
 
83
83
  valueType: String,
84
84
 
85
+
86
+ name: String,
87
+
88
+ item: {
89
+ type: Object,
90
+ required: true
91
+ },
92
+
93
+ viewType: String,
94
+
95
+ viewIndex: Number,
96
+
97
+ viewTypes: Array,
98
+
85
99
  },
86
100
 
87
101
  methods: {
88
102
 
89
103
  select(color){
90
104
  if(this.mode === 'class'){
91
- this.$emit('update:modelValue', color ? `${this.prefix}${this.keys[0][0]}` + color : '')
105
+ this.value[this.viewIndex] = `${this.viewType}${this.keys[0][0]}${color}`
92
106
  }
93
107
  else{
94
108
  if(this.valueType === 'rgb'){
95
109
  const hex = hexToRgb(color)
96
- this.$emit('update:modelValue', `${hex.r},${hex.g},${hex.b}`)
110
+ this.value[this.viewIndex] = `${hex.r},${hex.g},${hex.b}`
97
111
  }
98
112
  else{
99
- this.$emit('update:modelValue', color)
113
+ this.value[this.viewIndex] = color
100
114
  }
101
115
  }
102
- this.$emit('change')
103
116
  this.$refs.contextMenu.close()
104
117
  }
105
118
 
@@ -107,16 +120,20 @@ export default{
107
120
 
108
121
  computed:{
109
122
 
110
- customColorCount(){
111
- const count = parseInt(this.customColor)
112
- return isNaN(count) ? 0 : count
113
- },
123
+ value(){
124
+ if(!Array.isArray(this.item.props[this.name]))
125
+ this.item.props[this.name] = []
126
+
127
+ return this.item.props[this.name]
128
+ },
114
129
 
115
130
  circleClass(){
131
+ const value = this.value[this.viewIndex]
132
+
116
133
  return [
117
134
  this.$style.circle,
118
135
  this.mode === 'class' ?
119
- (this.modelValue ?? '').replace('text-', 'bg-').replace('border-', 'bg-') :
136
+ (value ?? '').replace('text-', 'bg-').replace('border-', 'bg-') :
120
137
  ''
121
138
  ]
122
139
  .filter(_=>_)
@@ -126,9 +143,9 @@ export default{
126
143
  circleStyle(){
127
144
  if(this.mode !== 'class'){
128
145
 
129
- let value = this.modelValue
146
+ let value = this.value[this.viewIndex]
130
147
  if(this.valueType === 'rgb'){
131
- value = rgbToHex(...(this.modelValue ?? '').split(','))
148
+ value = rgbToHex(...(value ?? '').split(','))
132
149
  }
133
150
 
134
151
  return {
@@ -2,18 +2,21 @@
2
2
  <div :class="$style.comp">
3
3
 
4
4
  <Dropdown v-model="mode" @change="calculate">
5
+ <option value="none">None</option>
5
6
  <option value="solid">Solid</option>
6
7
  <option value="linear">Linear Gradient</option>
7
8
  <option value="radial">Radial Gradient</option>
8
9
  </Dropdown>
9
10
 
10
- <div class="h-[8px]" :style="{ background:computedBackground }"></div>
11
+ <div v-if="computedBackground"
12
+ class="h-[8px] border-[1px] border-text-200 rounded-lg"
13
+ :style="{ background:computedBackground }"></div>
11
14
 
12
15
  <div v-if="mode === 'solid'">
13
16
  <input type="color" v-model="color1" @change="calculate" />
14
17
  </div>
15
18
 
16
- <div v-else class="flex flex-row gap-3">
19
+ <div v-else-if="[ 'linear', 'radial' ].includes(mode)" class="flex flex-row gap-3">
17
20
  <input type="color" v-model="color1" @change="calculate" />
18
21
  <div class="flex-1"></div>
19
22
  <input type="color" v-model="color2" @change="calculate" />
@@ -64,8 +67,8 @@ export default {
64
67
  data() {
65
68
  return {
66
69
  mode: "solid", // solid, linear, radial
67
- color1: "#ff0000",
68
- color2: "#0000ff",
70
+ color1: "",
71
+ color2: "",
69
72
  };
70
73
  },
71
74
 
@@ -73,11 +76,16 @@ export default {
73
76
  computedBackground() {
74
77
  if (this.mode === "solid") {
75
78
  return this.color1;
76
- } else if (this.mode === "linear") {
79
+ }
80
+ else if (this.mode === "linear") {
77
81
  return `linear-gradient(to right, ${this.color1}, ${this.color2})`;
78
- } else {
82
+ }
83
+ else if (this.mode === "radial") {
79
84
  return `radial-gradient(circle, ${this.color1}, ${this.color2})`;
80
85
  }
86
+ else{
87
+ return null
88
+ }
81
89
  },
82
90
  },
83
91
  };
@@ -18,7 +18,7 @@
18
18
  </slot>
19
19
 
20
20
  <div v-else-if="status === 2 && actualSrc.indexOf('<svg') >= 0" v-html="actualSrc"></div>
21
- <img v-else-if="status === 2" :class="computedItemClass" :src="actualSrc" ref="img" :alt="alt" />
21
+ <img v-else-if="status === 2" :class="computedItemClass" :src="actualSrc" ref="img" :alt="alt" @error="status = 3" />
22
22
 
23
23
  <slot v-else-if="status === 3" name="error" :instance="this">
24
24
  <div :class="$style.loading">
@@ -158,107 +158,48 @@ export default{
158
158
  },
159
159
 
160
160
  async loadSrc(){
161
+ if(!this.isVisible) return
161
162
 
162
- if(!this.isVisible){
163
- return
164
- }
163
+ const setSrc = (src) => {
164
+ let reader
165
165
 
166
- if(typeof this.src === 'string') {
166
+ if(typeof src === 'string') {
167
+ if(src.startsWith('data:image/') || src.indexOf('<svg') >= 0);
168
+ else{
169
+ if(src.indexOf('://') < 0 && src.substring(0, 1) !== '/'){
170
+ src = ((import.meta.env.VITE_IMAGE_HOST ?? '') + '/' + src)
171
+ }
172
+ }
167
173
 
168
- if (this.src.startsWith('data:image')) {
169
- this.actualSrc = this.src
170
- this.status = 2
171
- }
172
- else if(this.src.indexOf('<svg') >= 0){
173
- this.actualSrc = this.src
174
+ this.actualSrc = src
174
175
  this.status = 2
175
176
  }
176
- else{
177
- const src = {}
178
-
179
- if(typeof this.src === 'string'){
180
- this.src.split(',').forEach((text) => {
181
- let [ prefix, ...args ] = text.split(':')
182
-
183
- if(args.length > 0 && args[0].substring(0, 2) !== '//'){
184
- src[prefix.trim()] = args.join(':').trim()
185
- }
186
- else{
187
- src['all'] = text
188
- }
189
- })
190
- }
191
-
192
- let imgSrc
193
- for(const b in screens){
194
- if(document.documentElement.clientWidth > b && screens[b] in src){
195
- imgSrc = src[screens[b]]
196
- }
197
- }
198
-
199
- if(imgSrc !== this.actualSrc){
200
- var img = new Image()
201
- img.addEventListener('load', () => {
202
- if(img.getAttribute('data-src') !== this.src) return
203
- this.status = 2
204
- this.actualSrc = img.src
205
- })
206
- img.addEventListener('error', (err) => {
207
- if(img.getAttribute('data-src') !== this.src) return
208
- this.status = 3
209
- this.actualSrc = this.defaultSrc
210
- })
211
- img.src = imgSrc
212
- img.setAttribute('data-src', this.src)
213
- this.status = 1
214
- }
215
- }
216
- }
217
- else if(Array.isArray(this.src)){
218
-
219
- const src = {}
220
- src['all'] = ((this.src[0] ?? '').indexOf('://') < 0 ? import.meta.env.VITE_IMAGE_HOST + '/' : '') + this.src[0]
221
- if(this.src[1]){
222
- src['md'] = ((this.src[1] ?? '').indexOf('://') < 0 ? import.meta.env.VITE_IMAGE_HOST + '/' : '') + this.src[1]
223
- }
224
-
225
- let imgSrc
226
- for(const b in screens){
227
- if(document.documentElement.clientWidth > b && screens[b] in src){
228
- imgSrc = src[screens[b]]
229
- }
230
- }
231
-
232
- if(imgSrc !== this.actualSrc){
233
- var img = new Image()
234
- img.addEventListener('load', () => {
235
- this.status = 2
236
- this.actualSrc = img.src
237
- })
238
- img.addEventListener('error', (err) => {
239
- this.status = 3
240
- this.actualSrc = this.defaultSrc
241
- })
242
- img.src = imgSrc
243
- this.status = 1
244
- }
245
- }
246
- else if(this.src instanceof File){
247
- var reader = new FileReader();
248
177
 
249
- reader.addEventListener('load', () => {
250
- this.status = 2
251
- this.actualSrc = reader.result
252
- }, false)
178
+ else if(src instanceof File){
179
+ reader = new FileReader();
253
180
 
254
- reader.addEventListener('error', () => {
255
- this.status = 3
256
- this.actualSrc = this.defaultSrc
257
- })
181
+ reader.addEventListener('load', () => {
182
+ this.status = 2
183
+ this.actualSrc = reader.result
184
+ }, false)
258
185
 
259
- reader.readAsDataURL(this.src)
260
- this.status = 1
261
- }
186
+ reader.addEventListener('error', () => {
187
+ this.status = 3
188
+ this.actualSrc = this.defaultSrc
189
+ })
190
+
191
+ reader.readAsDataURL(src)
192
+ this.status = 1
193
+ }
194
+ }
195
+
196
+ if(Array.isArray(this.src)){
197
+ const imgSrc = this.src[this.$device.mediaIndex]
198
+ setSrc(imgSrc)
199
+ }
200
+ else if(this.src){
201
+ setSrc(this.src)
202
+ }
262
203
  else{
263
204
  this.status = 0
264
205
  }
@@ -284,9 +225,12 @@ export default{
284
225
 
285
226
  watch:{
286
227
 
287
- src(to, from){
288
- this.loadSrc()
289
- },
228
+ src: {
229
+ handler(){
230
+ this.loadSrc()
231
+ },
232
+ deep: true
233
+ },
290
234
 
291
235
  }
292
236
  }
@@ -296,15 +240,11 @@ export default{
296
240
  <style module>
297
241
 
298
242
  .comp{
299
- @apply relative overflow-hidden;
243
+ @apply relative flex items-center justify-center overflow-hidden aspect-square;
300
244
  }
301
245
 
302
246
  .img{
303
- @apply w-full h-full object-contain;
304
- }
305
-
306
- .editArea{
307
- @apply absolute top-0 left-0 right-0 bottom-0;
247
+ @apply w-full h-full object-cover;
308
248
  }
309
249
 
310
250
  .loading{
@@ -0,0 +1,114 @@
1
+ <template>
2
+ <button ref="btn"
3
+ type="button"
4
+ class="text-primary text-sm"
5
+ @click="$refs.contextMenu.open($refs.btn)">
6
+ <slot>Upload</slot>
7
+ </button>
8
+
9
+ <input type="file" class="hidden" ref="file" accept="image/*" @change="onFileUpload" />
10
+
11
+ <ContextMenu ref="contextMenu" position="bottom-right">
12
+ <div class="flex flex-col min-w-[200px]">
13
+
14
+ <button class="menu-item w-full p-3 text-left flex flex-row"
15
+ @click="$refs.file.click()">
16
+ Upload Image File...
17
+ </button>
18
+
19
+ <button class="menu-item w-full p-3 text-left flex flex-row"
20
+ @click="$refs.modal.open()">
21
+ SVG Text
22
+ </button>
23
+ </div>
24
+ </ContextMenu>
25
+
26
+ <Modal ref="modal" width="480" height="480">
27
+ <template v-slot:head>
28
+ <div class="relative p-5">
29
+ <h3>Add SVG Text</h3>
30
+ <div class="absolute top-0 right-0 p-2">
31
+ <button type="button" class="p-2" @click="$refs.modal.close()">
32
+ <svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
33
+ <path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
34
+ </svg>
35
+ </button>
36
+ </div>
37
+ </div>
38
+ </template>
39
+ <template v-slot:foot="{ context }">
40
+ <div class="p-5">
41
+ <Button class="w-[90px]"
42
+ :state="`${context.value}`.length > 0 ? 1 : -1"
43
+ @click="addSvg(context)">
44
+ Add
45
+ </Button>
46
+ </div>
47
+ </template>
48
+
49
+ <template #default="{ context }">
50
+ <div class="flex-1 p-5 flex flex-col gap-3">
51
+
52
+ <div>
53
+ <SvgEditor v-model="context.value" class="" />
54
+ </div>
55
+
56
+ </div>
57
+ </template>
58
+ </Modal>
59
+ </template>
60
+
61
+ <script setup>
62
+
63
+ import {useTemplateRef} from "vue";
64
+ import ContextMenu from "./ContextMenu.vue";
65
+ import SvgEditor from "./SvgEditor.vue";
66
+
67
+ const { uploadFn } = defineProps({
68
+ uploadFn: Function
69
+ })
70
+
71
+ const file = useTemplateRef('file')
72
+ const modal = useTemplateRef('modal')
73
+ const emits = defineEmits([ 'change' ])
74
+
75
+ function onFileUpload(e){
76
+ if(typeof uploadFn === 'function'){
77
+ uploadFn(e.target.files[0])
78
+ .then(res => {
79
+ emits('change', res.name)
80
+ file.value.value = null
81
+ })
82
+ .catch(e => {
83
+ console.error(e)
84
+ })
85
+ }
86
+ else{
87
+ emits('change', e.target.files[0])
88
+ file.value.value = null
89
+ }
90
+ }
91
+
92
+ function addSvg(obj){
93
+ emits('change', obj.value)
94
+ modal.value.close()
95
+ }
96
+
97
+ function edit(value){
98
+ if(`${value}`.indexOf('<svg') >= 0){
99
+ modal.value.open({ value })
100
+ }
101
+ }
102
+
103
+ defineExpose({
104
+ edit
105
+ })
106
+
107
+ </script>
108
+
109
+ <style module>
110
+
111
+ .comp {
112
+ }
113
+
114
+ </style>