@bagelink/vue 0.0.466 → 0.0.471

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 (179) hide show
  1. package/dist/components/Accordion.vue.d.ts.map +1 -1
  2. package/dist/components/AccordionItem.vue.d.ts.map +1 -1
  3. package/dist/components/Alert.vue.d.ts +2 -2
  4. package/dist/components/Alert.vue.d.ts.map +1 -1
  5. package/dist/components/Avatar.vue.d.ts.map +1 -1
  6. package/dist/components/Badge.vue.d.ts +2 -2
  7. package/dist/components/Badge.vue.d.ts.map +1 -1
  8. package/dist/components/BglVideo.vue.d.ts +2 -2
  9. package/dist/components/BglVideo.vue.d.ts.map +1 -1
  10. package/dist/components/Btn.vue.d.ts.map +1 -1
  11. package/dist/components/Card.vue.d.ts.map +1 -1
  12. package/dist/components/Carousel.vue.d.ts +4 -2
  13. package/dist/components/Carousel.vue.d.ts.map +1 -1
  14. package/dist/components/DataPreview.vue.d.ts.map +1 -1
  15. package/dist/components/Drop.vue.d.ts +34 -0
  16. package/dist/components/Drop.vue.d.ts.map +1 -0
  17. package/dist/components/FileUploader.vue.d.ts +60 -0
  18. package/dist/components/FileUploader.vue.d.ts.map +1 -0
  19. package/dist/components/Flag.vue.d.ts +2 -2
  20. package/dist/components/Flag.vue.d.ts.map +1 -1
  21. package/dist/components/ListItem.vue.d.ts.map +1 -1
  22. package/dist/components/ListView.vue.d.ts.map +1 -1
  23. package/dist/components/MapEmbed.vue.d.ts +2 -2
  24. package/dist/components/MapEmbed.vue.d.ts.map +1 -1
  25. package/dist/components/MaterialIcon.vue.d.ts.map +1 -1
  26. package/dist/components/Modal.vue.d.ts +2 -1
  27. package/dist/components/Modal.vue.d.ts.map +1 -1
  28. package/dist/components/ModalConfirm.vue.d.ts.map +1 -1
  29. package/dist/components/ModalForm.vue.d.ts.map +1 -1
  30. package/dist/components/NavBar.vue.d.ts.map +1 -1
  31. package/dist/components/PageTitle.vue.d.ts.map +1 -1
  32. package/dist/components/TableSchema.vue.d.ts.map +1 -1
  33. package/dist/components/Title.vue.d.ts.map +1 -1
  34. package/dist/components/dashboard/Lineart.vue.d.ts.map +1 -1
  35. package/dist/components/dashboard/index.d.ts.map +1 -1
  36. package/dist/components/form/BglField.vue.d.ts.map +1 -1
  37. package/dist/components/form/BglForm.vue.d.ts +4 -2
  38. package/dist/components/form/BglForm.vue.d.ts.map +1 -1
  39. package/dist/components/form/ItemRef.vue.d.ts +1 -0
  40. package/dist/components/form/ItemRef.vue.d.ts.map +1 -1
  41. package/dist/components/form/index.d.ts.map +1 -1
  42. package/dist/components/form/inputs/CheckInput.vue.d.ts.map +1 -1
  43. package/dist/components/form/inputs/Checkbox.vue.d.ts.map +1 -1
  44. package/dist/components/form/inputs/ColorPicker.vue.d.ts.map +1 -1
  45. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  46. package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
  47. package/dist/components/form/inputs/FileUpload.vue.d.ts +2 -1
  48. package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -1
  49. package/dist/components/form/inputs/JSONInput.vue.d.ts.map +1 -1
  50. package/dist/components/form/inputs/RadioPillsInput.vue.d.ts.map +1 -1
  51. package/dist/components/form/inputs/RichText.vue.d.ts.map +1 -1
  52. package/dist/components/form/inputs/SelectField.vue.d.ts +1 -4
  53. package/dist/components/form/inputs/SelectField.vue.d.ts.map +1 -1
  54. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  55. package/dist/components/form/inputs/SignaturePad.vue.d.ts +56 -0
  56. package/dist/components/form/inputs/SignaturePad.vue.d.ts.map +1 -0
  57. package/dist/components/form/inputs/TableField.vue.d.ts.map +1 -1
  58. package/dist/components/form/inputs/TelInput.vue.d.ts +2 -2
  59. package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
  60. package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
  61. package/dist/components/form/inputs/ToggleInput.vue.d.ts.map +1 -1
  62. package/dist/components/form/inputs/index.d.ts +1 -0
  63. package/dist/components/form/inputs/index.d.ts.map +1 -1
  64. package/dist/components/index.d.ts.map +1 -1
  65. package/dist/components/layout/BottomMenu.vue.d.ts.map +1 -1
  66. package/dist/components/layout/Layout.vue.d.ts +2 -2
  67. package/dist/components/layout/Layout.vue.d.ts.map +1 -1
  68. package/dist/components/layout/SidebarMenu.vue.d.ts.map +1 -1
  69. package/dist/components/layout/TabbedLayout.vue.d.ts.map +1 -1
  70. package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
  71. package/dist/components/layout/TabsBody.vue.d.ts.map +1 -1
  72. package/dist/components/layout/TabsNav.vue.d.ts.map +1 -1
  73. package/dist/components/layout/index.d.ts.map +1 -1
  74. package/dist/index.cjs +17616 -20818
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.mjs +17616 -20818
  77. package/dist/plugins/bagel.d.ts +1 -1
  78. package/dist/plugins/bagel.d.ts.map +1 -1
  79. package/dist/plugins/modal.d.ts +14 -14
  80. package/dist/plugins/modal.d.ts.map +1 -1
  81. package/dist/style.css +330 -309
  82. package/dist/types/BagelForm.d.ts +16 -16
  83. package/dist/types/BagelForm.d.ts.map +1 -1
  84. package/dist/types/BtnOptions.d.ts +1 -1
  85. package/dist/types/BtnOptions.d.ts.map +1 -1
  86. package/dist/types/NavLink.d.ts +2 -2
  87. package/dist/types/NavLink.d.ts.map +1 -1
  88. package/dist/types/file.d.ts +2 -2
  89. package/dist/types/file.d.ts.map +1 -1
  90. package/dist/types/index.d.ts.map +1 -1
  91. package/dist/types/materialIcons.d.ts.map +1 -1
  92. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  93. package/dist/utils/allCountries.d.ts +2 -2
  94. package/dist/utils/allCountries.d.ts.map +1 -1
  95. package/dist/utils/clickOutside.d.ts.map +1 -1
  96. package/dist/utils/index.d.ts +5 -5
  97. package/dist/utils/index.d.ts.map +1 -1
  98. package/package.json +19 -17
  99. package/src/components/Accordion.vue +10 -10
  100. package/src/components/AccordionItem.vue +47 -47
  101. package/src/components/Alert.vue +21 -21
  102. package/src/components/Avatar.vue +15 -15
  103. package/src/components/Badge.vue +17 -16
  104. package/src/components/BglVideo.vue +43 -43
  105. package/src/components/Btn.vue +64 -65
  106. package/src/components/Card.vue +26 -26
  107. package/src/components/Carousel.vue +130 -134
  108. package/src/components/DataPreview.vue +30 -30
  109. package/src/components/Flag.vue +26 -26
  110. package/src/components/ListItem.vue +13 -13
  111. package/src/components/ListView.vue +2 -2
  112. package/src/components/MapEmbed.vue +33 -33
  113. package/src/components/MaterialIcon.vue +12 -12
  114. package/src/components/Modal.vue +73 -66
  115. package/src/components/ModalConfirm.vue +18 -18
  116. package/src/components/ModalForm.vue +79 -76
  117. package/src/components/NavBar.vue +33 -30
  118. package/src/components/PageTitle.vue +10 -8
  119. package/src/components/TableSchema.vue +123 -113
  120. package/src/components/Title.vue +8 -8
  121. package/src/components/dashboard/Lineart.vue +103 -96
  122. package/src/components/dashboard/index.ts +1 -1
  123. package/src/components/form/BglField.vue +61 -61
  124. package/src/components/form/BglFieldSet.vue +9 -8
  125. package/src/components/form/BglForm.vue +71 -70
  126. package/src/components/form/index.ts +4 -4
  127. package/src/components/form/inputs/CheckInput.vue +25 -23
  128. package/src/components/form/inputs/Checkbox.vue +10 -10
  129. package/src/components/form/inputs/ColorPicker.vue +26 -24
  130. package/src/components/form/inputs/DateInput.vue +39 -39
  131. package/src/components/form/inputs/DatePicker.vue +37 -36
  132. package/src/components/form/inputs/FileUpload.vue +165 -161
  133. package/src/components/form/inputs/FileUploadURL.vue +134 -132
  134. package/src/components/form/inputs/JSONInput.vue +29 -29
  135. package/src/components/form/inputs/RadioPillsInput.vue +49 -49
  136. package/src/components/form/inputs/RichText.vue +62 -63
  137. package/src/components/form/inputs/SelectInput.vue +173 -167
  138. package/src/components/form/inputs/SignaturePad.vue +150 -0
  139. package/src/components/form/inputs/TableField.vue +77 -76
  140. package/src/components/form/inputs/TelInput.vue +280 -285
  141. package/src/components/form/inputs/TextInput.vue +81 -76
  142. package/src/components/form/inputs/ToggleInput.vue +13 -13
  143. package/src/components/form/inputs/index.ts +17 -15
  144. package/src/components/formkit/FileUploader.vue +162 -158
  145. package/src/components/formkit/MiscFields.vue +20 -20
  146. package/src/components/formkit/Toggle.vue +13 -13
  147. package/src/components/index.ts +28 -28
  148. package/src/components/layout/BottomMenu.vue +25 -21
  149. package/src/components/layout/Layout.vue +29 -29
  150. package/src/components/layout/SidebarMenu.vue +31 -27
  151. package/src/components/layout/TabbedLayout.vue +47 -45
  152. package/src/components/layout/Tabs.vue +32 -32
  153. package/src/components/layout/TabsBody.vue +10 -10
  154. package/src/components/layout/TabsNav.vue +44 -44
  155. package/src/components/layout/index.ts +7 -7
  156. package/src/components/layout/tabsManager.ts +6 -6
  157. package/src/index.ts +13 -8
  158. package/src/plugins/bagel.ts +37 -37
  159. package/src/plugins/modal.ts +66 -67
  160. package/src/styles/layout.css +5 -3
  161. package/src/styles/mobilLayout.css +7 -0
  162. package/src/types/BagelForm.ts +27 -27
  163. package/src/types/BtnOptions.ts +13 -13
  164. package/src/types/NavLink.ts +8 -8
  165. package/src/types/file.ts +11 -11
  166. package/src/types/index.ts +16 -12
  167. package/src/types/materialIcons.ts +3249 -3249
  168. package/src/utils/BagelFormUtils.ts +23 -23
  169. package/src/utils/allCountries.ts +11 -12
  170. package/src/utils/clickOutside.ts +6 -6
  171. package/src/utils/index.ts +39 -41
  172. package/src/utils/lang.ts +13 -13
  173. package/src/utils/strings.ts +9 -9
  174. package/tsconfig.json +0 -1
  175. package/vite.config.ts +8 -8
  176. package/dist/components/Popover.vue.d.ts +0 -10
  177. package/dist/components/Popover.vue.d.ts.map +0 -1
  178. package/dist/types/materialIcon.d.ts +0 -2
  179. package/dist/types/materialIcon.d.ts.map +0 -1
@@ -1,8 +1,82 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, watch } from 'vue'
3
+ import {
4
+ MaterialIcon,
5
+ type MaterialIcons,
6
+ debounce,
7
+ } from '@bagelink/vue'
8
+
9
+ const props = withDefaults(
10
+ defineProps<{
11
+ id?: string
12
+ title?: string
13
+ helptext?: string
14
+ placeholder?: string
15
+ modelValue?: string | number
16
+ label?: string
17
+ small?: boolean
18
+ dense?: boolean
19
+ required?: boolean
20
+ pattern?: string
21
+ shrink?: boolean
22
+ disabled?: boolean
23
+ type?: string
24
+ nativeInputAttrs?: Record<string, any>
25
+ icon?: MaterialIcons
26
+ iconStart?: MaterialIcons
27
+ multiline?: boolean
28
+ autoheight?: boolean
29
+ code?: boolean
30
+ lines?: number
31
+ autocomplete?: AutoFillField
32
+ autofocus?: boolean
33
+ debounceDelay?: number
34
+ }>(),
35
+ {
36
+ type: 'text',
37
+ modelValue: '',
38
+ debounceDelay: 300,
39
+ },
40
+ )
41
+ const emit = defineEmits(['update:modelValue', 'debounce'])
42
+ let inputVal = $ref<string | number>()
43
+
44
+ const input = $ref<HTMLInputElement>()
45
+
46
+ const rows = $computed(() => {
47
+ if (props.lines) return props.lines
48
+ if (props.autoheight) return `${inputVal}`.split('\n').length || 1
49
+ if (props.multiline || props.code) return 4
50
+ return 1
51
+ })
52
+
53
+ function updateInputVal() {
54
+ if (props.disabled) return
55
+ emit('update:modelValue', inputVal as string)
56
+ debounce(() => { emit('debounce', inputVal) }, props.debounceDelay)
57
+ }
58
+
59
+ watch(
60
+ () => props.modelValue,
61
+ (newVal) => {
62
+ if (newVal !== inputVal) inputVal = newVal
63
+ },
64
+ { immediate: true },
65
+ )
66
+
67
+ onMounted(() => {
68
+ if (props.autofocus) setTimeout(() => input?.focus(), 10)
69
+ })
70
+ </script>
71
+
1
72
  <template>
2
73
  <div
3
74
  class="bagel-input text-input"
4
75
  :class="{
5
- dense, small, shrink, code,
76
+ dense,
77
+ small,
78
+ shrink,
79
+ code,
6
80
  textInputIconWrap: icon,
7
81
  txtInputIconStart: iconStart,
8
82
  }"
@@ -13,13 +87,13 @@
13
87
 
14
88
  <input
15
89
  v-if="!multiline && !autoheight && !code"
16
- :title="title"
17
- :autocomplete="autocomplete"
18
90
  :id="id"
91
+ ref="input"
19
92
  v-model="inputVal"
93
+ :title="title"
94
+ :autocomplete="autocomplete"
20
95
  :type="type"
21
96
  :rows="1"
22
- ref="input"
23
97
  :placeholder="placeholder || label"
24
98
  :disabled
25
99
  :required="required"
@@ -29,12 +103,12 @@
29
103
  >
30
104
  <textarea
31
105
  v-else
32
- :title="title"
33
106
  :id="id"
107
+ ref="input"
34
108
  v-model="inputVal"
109
+ :title="title"
35
110
  :type="type"
36
111
  :rows="rows"
37
- ref="input"
38
112
  :placeholder="placeholder || label"
39
113
  :disabled
40
114
  :required="required"
@@ -46,8 +120,8 @@
46
120
  </label>
47
121
 
48
122
  <MaterialIcon
49
- class="iconStart"
50
123
  v-if="iconStart"
124
+ class="iconStart"
51
125
  :icon="iconStart"
52
126
  />
53
127
  <MaterialIcon
@@ -57,75 +131,6 @@
57
131
  </div>
58
132
  </template>
59
133
 
60
- <script setup lang="ts">
61
- import { onMounted, watch } from 'vue';
62
- import {
63
- debounce, type MaterialIcons, MaterialIcon,
64
- } from '@bagelink/vue';
65
-
66
- const emit = defineEmits(['update:modelValue', 'debounce']);
67
- const props = withDefaults(
68
- defineProps<{
69
- id?: string;
70
- title?: string;
71
- helptext?: string;
72
- placeholder?: string;
73
- modelValue?: string | number;
74
- label?: string;
75
- small?: boolean;
76
- dense?: boolean;
77
- required?: boolean;
78
- pattern?: string;
79
- shrink?: boolean;
80
- disabled?: boolean;
81
- type?: string;
82
- nativeInputAttrs?: Record<string, any>;
83
- icon?: MaterialIcons;
84
- iconStart?: MaterialIcons;
85
- multiline?: boolean;
86
- autoheight?: boolean;
87
- code?: boolean;
88
- lines?: number;
89
- autocomplete?: AutoFillField;
90
- autofocus?: boolean;
91
- debounceDelay?: number;
92
- }>(),
93
- {
94
- type: 'text',
95
- modelValue: '',
96
- debounceDelay: 300,
97
- },
98
- );
99
- let inputVal = $ref<string | number>();
100
-
101
- const input = $ref<HTMLInputElement>();
102
-
103
- const rows = $computed(() => {
104
- if (props.lines) return props.lines;
105
- if (props.autoheight) return `${inputVal}`?.split('\n').length || 1;
106
- if (props.multiline || props.code) return 4;
107
- return 1;
108
- });
109
-
110
- function updateInputVal() {
111
- if (props.disabled) return;
112
- emit('update:modelValue', inputVal as string);
113
- debounce(() => emit('debounce', inputVal), props.debounceDelay);
114
- }
115
-
116
- watch(
117
- () => props.modelValue,
118
- (newVal) => {
119
- if (newVal !== inputVal) inputVal = newVal;
120
- },
121
- { immediate: true },
122
- );
123
-
124
- onMounted(() => {
125
- if (props.autofocus) setTimeout(() => input?.focus(), 10);
126
- });
127
- </script>
128
-
129
134
  <style>
130
135
  .bagel-input.shrink,
131
136
  .bagel-input.shrink input {
@@ -1,26 +1,26 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ label: string
4
+ id?: string
5
+ title?: string
6
+ small?: boolean
7
+ }>()
8
+
9
+ const checked = defineModel<boolean>('modelValue', { default: false })
10
+ </script>
11
+
1
12
  <template>
2
- <div class="bagel-input bgl-checkbox justify-content-center gap-1" :title="title" :class="{ small: small }">
13
+ <div class="bagel-input bgl-checkbox justify-content-center gap-1" :title="title" :class="{ small }">
3
14
  <div class="switch" :class="{ checked }">
4
15
  <span class="slider round" />
5
16
  </div>
6
17
  <label>
7
18
  {{ label }}
8
- <input :id="id" type="checkbox" v-model="checked">
19
+ <input :id="id" v-model="checked" type="checkbox">
9
20
  </label>
10
21
  </div>
11
22
  </template>
12
23
 
13
- <script setup lang="ts">
14
- defineProps<{
15
- label: string;
16
- id?: string;
17
- title?: string;
18
- small?: boolean;
19
- }>();
20
-
21
- const checked = defineModel<boolean>('modelValue', { default: false });
22
- </script>
23
-
24
24
  <style scoped>
25
25
  .bgl-checkbox {
26
26
  position: relative;
@@ -1,15 +1,17 @@
1
- export { default as CheckInput } from './CheckInput.vue';
2
- export { default as DateInput } from './DateInput.vue';
3
- export { default as JSONInput } from './JSONInput.vue';
4
- export { default as SelectInput } from './SelectInput.vue';
5
- export { default as TableField } from './TableField.vue';
6
- export { default as TextInput } from './TextInput.vue';
7
- export { default as Checkbox } from './Checkbox.vue';
8
- export { default as ColorPicker } from './ColorPicker.vue';
9
- export { default as DatePicker } from './DatePicker.vue';
10
- export { default as RadioPillsInput } from './RadioPillsInput.vue';
11
- export { default as FileUpload } from './FileUpload.vue';
12
- export { default as ToggleInput } from './ToggleInput.vue';
13
- export { default as RichText } from './RichText.vue';
14
- export { default as TelInput } from './TelInput.vue';
15
- export { Dropdown } from 'floating-vue';
1
+ export { default as CheckInput } from './CheckInput.vue'
2
+ export { default as DateInput } from './DateInput.vue'
3
+ export { default as JSONInput } from './JSONInput.vue'
4
+ export { default as SelectInput } from './SelectInput.vue'
5
+ export { default as TableField } from './TableField.vue'
6
+ export { default as TextInput } from './TextInput.vue'
7
+ export { default as Checkbox } from './Checkbox.vue'
8
+ export { default as ColorPicker } from './ColorPicker.vue'
9
+ export { default as DatePicker } from './DatePicker.vue'
10
+ export { default as RadioPillsInput } from './RadioPillsInput.vue'
11
+ export { default as FileUpload } from './FileUpload.vue'
12
+ export { default as ToggleInput } from './ToggleInput.vue'
13
+ export { default as RichText } from './RichText.vue'
14
+ export { default as TelInput } from './TelInput.vue'
15
+ export { default as SignaturePad } from './SignaturePad.vue'
16
+
17
+ export { Dropdown } from 'floating-vue'
@@ -1,3 +1,155 @@
1
+ <script setup lang="ts">
2
+ interface UploadFile {
3
+ dataUrl: string
4
+ progress: number
5
+ uploading: boolean
6
+ file?: File
7
+ name: string
8
+ serverFile?: any
9
+ uploaded: boolean
10
+ }
11
+
12
+ import { onMounted, onUnmounted } from 'vue'
13
+
14
+ import { Btn, MaterialIcon, useBagel } from '@bagelink/vue'
15
+
16
+ const props = withDefaults(
17
+ defineProps<{
18
+ context: Record<string, any>
19
+ dragDropLabel?: string
20
+ browseLabel?: string
21
+ multiple?: boolean
22
+ }>(),
23
+ {
24
+ dragDropLabel: 'Drag and drop your files here',
25
+ browseLabel: 'or browse',
26
+ multiple: false,
27
+ },
28
+ )
29
+
30
+ const bagel = useBagel()
31
+
32
+ let draggingOver = $ref(false)
33
+ const dropCircle = $ref<HTMLElement>()
34
+ const dropZoneEl = $ref<HTMLElement>()
35
+ const fileInputEl = $ref<HTMLInputElement>()
36
+
37
+ const files = $ref<UploadFile[]>([])
38
+
39
+ const computedDragDropLabel = $computed(() => props.context.attrs?.dragDropLabel || props.dragDropLabel)
40
+ const computedDrowseLabel = $computed(() => props.context.attrs?.browseLabel || props.browseLabel)
41
+ const computedMultiple = $computed(() => !!(props.context.attrs?.multiple || props.multiple))
42
+
43
+ const allowUpload = $computed(() => {
44
+ const tooManyFiles = !computedMultiple && files.length > 0
45
+ return !tooManyFiles
46
+ })
47
+
48
+ const openFileDialog = () => (allowUpload ? fileInputEl?.click() : '')
49
+
50
+ function animateCircle(e: DragEvent) {
51
+ e.preventDefault()
52
+ const zoneRect = dropZoneEl?.getBoundingClientRect()
53
+ if (!zoneRect) return
54
+ draggingOver = true
55
+ const left = e.clientX - zoneRect.left
56
+ const top = e.clientY - zoneRect.top
57
+ dropCircle?.style.setProperty('left', `${left}px`)
58
+ dropCircle?.style.setProperty('top', `${top}px`)
59
+ }
60
+
61
+ function emitValue() {
62
+ // const fileValues = files.map((f) => f.serverFile?.id);
63
+ const relationshipObjKey = props.context.attrs?.relationshipObjKey
64
+ if (!computedMultiple) return props.context.node.input(relationshipObjKey ? files[0].serverFile.id : files[0].serverFile)
65
+ // eslint-disable-next-line no-alert
66
+ alert('not implemented')
67
+ }
68
+
69
+ function isImg(file: UploadFile) {
70
+ return file.file?.type.includes('image')
71
+ || file.serverFile?.mimetype?.match(/image\/|jpg|png|gif|bmp|jpeg/i)
72
+ || file.serverFile.extension?.match(/jpg|png|gif|bmp|jpeg/i)
73
+ }
74
+
75
+ function uploadFiles() {
76
+ files.forEach(async (file) => {
77
+ if (file.uploaded || file.uploading || !file.file) return
78
+ file.uploading = true
79
+ file.serverFile = await bagel.uploadFile(file.file, {
80
+ onUploadProgress: (e: any) => (file.progress = e.progress * 100 - 1),
81
+ })
82
+ file.progress += 1
83
+ emitValue()
84
+ file.uploaded = true
85
+ file.uploading = false
86
+ })
87
+ }
88
+
89
+ async function deleteImg(file: UploadFile) {
90
+ await bagel.delete(`files/${file.serverFile.id}`)
91
+ const index = files.indexOf(file)
92
+ files.splice(index, 1)
93
+ emitValue()
94
+ }
95
+
96
+ function readAsDataURL(file: File): Promise<any> {
97
+ return new Promise((resolve, reject) => {
98
+ const reader = new FileReader()
99
+ reader.onload = () => { resolve(reader.result) }
100
+ reader.onerror = reject
101
+ reader.readAsDataURL(file)
102
+ })
103
+ }
104
+
105
+ async function addFiles(addedFiles: FileList) {
106
+ if (!allowUpload) return
107
+ for (let i = 0; i < addedFiles.length; i++) {
108
+ const f = addedFiles[i]
109
+ const file: UploadFile = {
110
+ // eslint-disable-next-line no-await-in-loop
111
+ dataUrl: await readAsDataURL(f),
112
+ file: f,
113
+ name: f.name,
114
+ progress: 0,
115
+ uploading: false,
116
+ uploaded: false,
117
+ }
118
+ files.push(file)
119
+ }
120
+ uploadFiles()
121
+ }
122
+
123
+ onMounted(() => {
124
+ dropZoneEl?.addEventListener('dragover', animateCircle)
125
+ const relationshipObjKey = props.context.attrs?.relationshipObjKey
126
+ const imageObj = relationshipObjKey ? props.context.node?.parent?.value[relationshipObjKey] : props.context.node?.value
127
+ if (!computedMultiple && imageObj) {
128
+ files.push({
129
+ serverFile: imageObj,
130
+ uploaded: true,
131
+ uploading: false,
132
+ progress: 100,
133
+ dataUrl: imageObj?.url,
134
+ name: imageObj?.name,
135
+ })
136
+ }
137
+ })
138
+ onUnmounted(() => dropZoneEl?.removeEventListener('dragover', animateCircle))
139
+
140
+ function handleFileInput(e: Event) {
141
+ const filesToAdd: FileList = (e.target as any).files
142
+ void addFiles(filesToAdd) // TODO: Nati: should be awaited?
143
+ }
144
+
145
+ function onDrop(e: DragEvent) {
146
+ draggingOver = false
147
+ e.preventDefault()
148
+ const filesToAdd = e.dataTransfer?.files
149
+ if (filesToAdd) void addFiles(filesToAdd) // TODO: Nati: should be awaited?
150
+ }
151
+ </script>
152
+
1
153
  <template>
2
154
  <div class="files-wrapper flex">
3
155
  <div
@@ -9,14 +161,14 @@
9
161
  >
10
162
  <Transition name="pop">
11
163
  <div
12
- ref="dropCircle"
13
164
  v-if="draggingOver"
165
+ ref="dropCircle"
14
166
  class="drop-circle"
15
167
  />
16
168
  </Transition>
17
169
  <div
18
- class="img-label"
19
170
  v-if="allowUpload"
171
+ class="img-label"
20
172
  >
21
173
  <p>
22
174
  {{ computedDragDropLabel }} <span>{{ computedDrowseLabel }}</span>
@@ -25,14 +177,14 @@
25
177
  <div class="uploading-wrap">
26
178
  <div
27
179
  v-for="(item, index) in files"
28
- :class="{ uploading: item.uploading }"
29
180
  :key="index"
181
+ :class="{ uploading: item.uploading }"
30
182
  >
31
183
  <div class="load-file-bar">
32
184
  <!-- Preview File if image -->
33
185
  <img
34
- width="40"
35
186
  v-if="isImg(item)"
187
+ width="40"
36
188
  :src="item.dataUrl"
37
189
  :alt="item.name"
38
190
  style="margin-inline-end: 10px"
@@ -48,8 +200,8 @@
48
200
  :class="{ complete: item.progress === 100 }"
49
201
  >
50
202
  <span
51
- class="progress"
52
203
  v-if="item.progress < 100"
204
+ class="progress"
53
205
  >{{
54
206
  `${item.progress.toFixed(0)}`
55
207
  }}</span>
@@ -59,11 +211,11 @@
59
211
  />
60
212
  </div>
61
213
  <Btn
214
+ v-if="item.progress === 100"
62
215
  thin
63
216
  class="delete-btn"
64
- @click.stop="deleteImg(item)"
65
217
  icon="delete"
66
- v-if="item.progress === 100"
218
+ @click.stop="deleteImg(item)"
67
219
  />
68
220
  </div>
69
221
  </div>
@@ -71,164 +223,15 @@
71
223
  </div>
72
224
  </div>
73
225
  <input
226
+ ref="fileInputEl"
74
227
  class="file-input"
75
228
  type="file"
76
- @change="handleFileInput"
77
- ref="fileInputEl"
78
229
  :multiple="computedMultiple"
230
+ @change="handleFileInput"
79
231
  >
80
232
  </div>
81
233
  </template>
82
234
 
83
- <script setup lang="ts">
84
- interface UploadFile {
85
- dataUrl: string;
86
- progress: number;
87
- uploading: boolean;
88
- file?: File;
89
- name: string;
90
- serverFile?: any;
91
- uploaded: boolean;
92
- }
93
-
94
- import { onMounted, onUnmounted } from 'vue';
95
-
96
- import { MaterialIcon, Btn, useBagel } from '@bagelink/vue';
97
-
98
- const bagel = useBagel();
99
-
100
- let draggingOver = $ref(false);
101
- const dropCircle = $ref<HTMLElement>();
102
- const dropZoneEl = $ref<HTMLElement>();
103
- const fileInputEl = $ref<HTMLInputElement>();
104
-
105
- const files = $ref<UploadFile[]>([]);
106
-
107
- const props = withDefaults(
108
- defineProps<{
109
- context: Record<string, any>;
110
- dragDropLabel?: string;
111
- browseLabel?: string;
112
- multiple?: boolean;
113
- }>(),
114
- {
115
- dragDropLabel: 'Drag and drop your files here',
116
- browseLabel: 'or browse',
117
- multiple: false,
118
- },
119
- );
120
-
121
- const computedDragDropLabel = $computed(() => props?.context?.attrs?.dragDropLabel || props?.dragDropLabel);
122
- const computedDrowseLabel = $computed(() => props?.context?.attrs?.browseLabel || props?.browseLabel);
123
- const computedMultiple = $computed(() => !!(props?.context?.attrs?.multiple || props?.multiple));
124
-
125
- const allowUpload = $computed(() => {
126
- const tooManyFiles = !computedMultiple && files.length > 0;
127
- return !tooManyFiles;
128
- });
129
-
130
- const openFileDialog = () => (allowUpload ? fileInputEl?.click() : '');
131
-
132
- function animateCircle(e: DragEvent) {
133
- e.preventDefault();
134
- const zoneRect = dropZoneEl?.getBoundingClientRect?.();
135
- if (!zoneRect) return;
136
- draggingOver = true;
137
- const left = e.clientX - zoneRect.left;
138
- const top = e.clientY - zoneRect.top;
139
- dropCircle?.style?.setProperty?.('left', `${left}px`);
140
- dropCircle?.style?.setProperty?.('top', `${top}px`);
141
- }
142
-
143
- function emitValue() {
144
- // const fileValues = files.map((f) => f.serverFile?.id);
145
- const relationshipObjKey = props.context?.attrs?.relationshipObjKey;
146
- if (!computedMultiple) return props.context?.node.input(relationshipObjKey ? files[0].serverFile.id : files[0].serverFile);
147
- // eslint-disable-next-line no-alert
148
- return alert('not implemented');
149
- }
150
-
151
- const isImg = (file: UploadFile) => file.file?.type.includes('image') ||
152
- file.serverFile?.mimetype?.match(/image\/|jpg|png|gif|bmp|jpeg/i) ||
153
- file.serverFile.extension?.match(/jpg|png|gif|bmp|jpeg/i);
154
-
155
- function uploadFiles() {
156
- files.forEach(async (file) => {
157
- if (file.uploaded || file.uploading || !file.file) return;
158
- file.uploading = true;
159
- file.serverFile = await bagel.uploadFile(file.file, {
160
- onUploadProgress: (e: any) => (file.progress = e.progress * 100 - 1),
161
- });
162
- file.progress += 1;
163
- emitValue();
164
- file.uploaded = true;
165
- file.uploading = false;
166
- });
167
- }
168
-
169
- const deleteImg = async (file: UploadFile) => {
170
- await bagel.delete(`files/${file.serverFile.id}`);
171
- const index = files.indexOf(file);
172
- files.splice(index, 1);
173
- emitValue();
174
- };
175
-
176
- function readAsDataURL(file: File): Promise<any> {
177
- return new Promise((resolve, reject) => {
178
- const reader = new FileReader();
179
- reader.onload = () => resolve(reader.result);
180
- reader.onerror = reject;
181
- reader.readAsDataURL(file);
182
- });
183
- }
184
-
185
- async function addFiles(addedFiles: FileList) {
186
- if (!allowUpload) return;
187
- for (let i = 0; i < addedFiles.length; i++) {
188
- const f = addedFiles[i];
189
- const file: UploadFile = {
190
- // eslint-disable-next-line no-await-in-loop
191
- dataUrl: await readAsDataURL(f),
192
- file: f,
193
- name: f.name,
194
- progress: 0,
195
- uploading: false,
196
- uploaded: false,
197
- };
198
- files.push(file);
199
- }
200
- uploadFiles();
201
- }
202
-
203
- onMounted(() => {
204
- dropZoneEl?.addEventListener('dragover', animateCircle);
205
- const relationshipObjKey = props.context?.attrs?.relationshipObjKey;
206
- const imageObj = relationshipObjKey ? props.context?.node?.parent?.value[relationshipObjKey] : props.context?.node?.value;
207
- if (!computedMultiple && imageObj) {
208
- files.push({
209
- serverFile: imageObj,
210
- uploaded: true,
211
- uploading: false,
212
- progress: 100,
213
- dataUrl: imageObj?.url,
214
- name: imageObj?.name,
215
- });
216
- }
217
- });
218
- onUnmounted(() => dropZoneEl?.removeEventListener('dragover', animateCircle));
219
-
220
- function handleFileInput(e: Event) {
221
- const filesToAdd: FileList = (e.target as any).files;
222
- void addFiles(filesToAdd); // TODO: Nati: should be awaited?
223
- }
224
-
225
- function onDrop(e: DragEvent) {
226
- draggingOver = false;
227
- e.preventDefault();
228
- const filesToAdd = e.dataTransfer?.files;
229
- if (filesToAdd) void addFiles(filesToAdd); // TODO: Nati: should be awaited?
230
- }
231
- </script>
232
235
  <style>
233
236
  .uploading-wrap {
234
237
  width: 100%;
@@ -375,6 +378,7 @@ function onDrop(e: DragEvent) {
375
378
  color: var(--bgl-green);
376
379
  }
377
380
  </style>
381
+
378
382
  <style>
379
383
  .pop-enter-active {
380
384
  transition: scale 0.2s cubic-bezier(0.55, 0, 0.1, 1);
@@ -1,37 +1,37 @@
1
+ <script lang="ts" setup>
2
+ import { Btn } from '@bagelink/vue'
3
+
4
+ const props = defineProps<{
5
+ context: Record<string, any>
6
+ addBtnLabel: string
7
+ }>()
8
+
9
+ const fields = $computed(() => props.context.node?.parent?.children || [])
10
+
11
+ function addToField(field: any) {
12
+ field.input([{}])
13
+ console.log(fields)
14
+ }
15
+ </script>
16
+
1
17
  <template>
2
18
  <div class="misc-wrap">
3
19
  <Btn
4
- class="add-btn"
5
- color="gray"
6
- flat
7
- @click="addToField(field)"
8
20
  v-for="(field, i) in fields.filter(
9
21
  (field: any) => field.value?.length === 0,
10
22
  )"
11
23
  :key="i"
24
+ class="add-btn"
25
+ color="gray"
26
+ flat
12
27
  thin
28
+ @click="addToField(field)"
13
29
  >
14
30
  {{ addBtnLabel }} {{ field.context?.label }}
15
31
  </Btn>
16
32
  </div>
17
33
  </template>
18
34
 
19
- <script lang="ts" setup>
20
- import { Btn } from '@bagelink/vue';
21
-
22
- const props = defineProps<{
23
- context: Record<string, any>;
24
- addBtnLabel: string;
25
- }>();
26
-
27
- const fields = $computed(() => props.context?.node?.parent?.children || []);
28
-
29
- const addToField = (field: any) => {
30
- field.input([{}]);
31
- console.log(fields);
32
- };
33
- </script>
34
-
35
35
  <style scoped>
36
36
  .misc-wrap {
37
37
  display: flex;