@bagelink/vue 0.0.1035 → 0.0.1037

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 (247) hide show
  1. package/dist/components/Accordion.d.ts +12 -0
  2. package/dist/components/Accordion.d.ts.map +1 -0
  3. package/dist/components/AccordionItem.d.ts +34 -0
  4. package/dist/components/AccordionItem.d.ts.map +1 -0
  5. package/dist/components/Alert.d.ts +34 -0
  6. package/dist/components/Alert.d.ts.map +1 -0
  7. package/dist/components/Avatar.d.ts +36 -0
  8. package/dist/components/Avatar.d.ts.map +1 -0
  9. package/dist/components/Badge.d.ts +22 -0
  10. package/dist/components/Badge.d.ts.map +1 -0
  11. package/dist/components/BglComponent.vue.d.ts +24 -0
  12. package/dist/components/BglComponent.vue.d.ts.map +1 -0
  13. package/dist/components/BglVideo.d.ts +20 -0
  14. package/dist/components/BglVideo.d.ts.map +1 -0
  15. package/dist/components/Btn.d.ts +99 -0
  16. package/dist/components/Btn.d.ts.map +1 -0
  17. package/dist/components/Card.d.ts +39 -0
  18. package/dist/components/Card.d.ts.map +1 -0
  19. package/dist/components/Carousel.d.ts +74 -0
  20. package/dist/components/Carousel.d.ts.map +1 -0
  21. package/dist/components/ComboBox.vue.d.ts +3 -3
  22. package/dist/components/Comments.vue.d.ts +2 -2
  23. package/dist/components/ContactSubmissions.vue.d.ts +2 -2
  24. package/dist/components/DataPreview.d.ts +42 -0
  25. package/dist/components/DataPreview.d.ts.map +1 -0
  26. package/dist/components/Drop.vue.d.ts +34 -0
  27. package/dist/components/Drop.vue.d.ts.map +1 -0
  28. package/dist/components/FieldSetVue.vue.d.ts +22 -0
  29. package/dist/components/FieldSetVue.vue.d.ts.map +1 -0
  30. package/dist/components/FileUploader.vue.d.ts +60 -0
  31. package/dist/components/FileUploader.vue.d.ts.map +1 -0
  32. package/dist/components/Flag.d.ts +20 -0
  33. package/dist/components/Flag.d.ts.map +1 -0
  34. package/dist/components/FormSchema.vue.d.ts +5 -4
  35. package/dist/components/LangText.vue.d.ts +2 -2
  36. package/dist/components/ListItem.d.ts +34 -0
  37. package/dist/components/ListItem.d.ts.map +1 -0
  38. package/dist/components/ListView.d.ts +13 -0
  39. package/dist/components/ListView.d.ts.map +1 -0
  40. package/dist/components/MapEmbed.d.ts +3 -0
  41. package/dist/components/MapEmbed.d.ts.map +1 -0
  42. package/dist/components/MaterialIcon.d.ts +26 -0
  43. package/dist/components/MaterialIcon.d.ts.map +1 -0
  44. package/dist/components/Modal.d.ts +46 -0
  45. package/dist/components/Modal.d.ts.map +1 -0
  46. package/dist/components/ModalBglForm.vue.d.ts +21 -20
  47. package/dist/components/ModalConfirm.d.ts +24 -0
  48. package/dist/components/ModalConfirm.d.ts.map +1 -0
  49. package/dist/components/ModalForm.d.ts +78 -0
  50. package/dist/components/ModalForm.d.ts.map +1 -0
  51. package/dist/components/NavBar.d.ts +64 -0
  52. package/dist/components/NavBar.d.ts.map +1 -0
  53. package/dist/components/PageTitle.d.ts +24 -0
  54. package/dist/components/PageTitle.d.ts.map +1 -0
  55. package/dist/components/PersonPreview.vue.d.ts +5 -4
  56. package/dist/components/PersonPreviewFormkit.vue.d.ts +4 -3
  57. package/dist/components/Pill.vue.d.ts +1 -0
  58. package/dist/components/Pill.vue.d.ts.map +1 -1
  59. package/dist/components/RTXEditor.vue.d.ts +3 -3
  60. package/dist/components/RouterWrapper.d.ts +3 -0
  61. package/dist/components/RouterWrapper.d.ts.map +1 -0
  62. package/dist/components/TabbedLayout.vue.d.ts +5 -4
  63. package/dist/components/TableSchema.d.ts +35 -0
  64. package/dist/components/TableSchema.d.ts.map +1 -0
  65. package/dist/components/TableSchema.vue.d.ts.map +1 -1
  66. package/dist/components/Title.d.ts +42 -0
  67. package/dist/components/Title.d.ts.map +1 -0
  68. package/dist/components/TopBar.d.ts +12 -0
  69. package/dist/components/TopBar.d.ts.map +1 -0
  70. package/dist/components/charts/BarChart.vue.d.ts +2 -2
  71. package/dist/components/dashboard/Lineart.d.ts +20 -0
  72. package/dist/components/dashboard/Lineart.d.ts.map +1 -0
  73. package/dist/components/form/BglField.d.ts +25 -0
  74. package/dist/components/form/BglField.d.ts.map +1 -0
  75. package/dist/components/form/BglField.vue.d.ts +8 -6
  76. package/dist/components/form/BglField.vue.d.ts.map +1 -1
  77. package/dist/components/form/BglForm.d.ts +75 -0
  78. package/dist/components/form/BglForm.d.ts.map +1 -0
  79. package/dist/components/form/BglForm.vue.d.ts +5 -4
  80. package/dist/components/form/BglForm.vue.d.ts.map +1 -1
  81. package/dist/components/form/BglMultiStepForm.vue.d.ts +2 -2
  82. package/dist/components/form/FieldArray.vue.d.ts +1 -0
  83. package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
  84. package/dist/components/form/ItemRef.vue.d.ts +5 -3
  85. package/dist/components/form/ItemRef.vue.d.ts.map +1 -1
  86. package/dist/components/form/MaterialIcon.vue.d.ts +4 -3
  87. package/dist/components/form/PlainInputField.vue.d.ts +3 -3
  88. package/dist/components/form/inputs/CheckInput.d.ts +56 -0
  89. package/dist/components/form/inputs/CheckInput.d.ts.map +1 -0
  90. package/dist/components/form/inputs/Checkbox.d.ts +16 -0
  91. package/dist/components/form/inputs/Checkbox.d.ts.map +1 -0
  92. package/dist/components/form/inputs/ColorPicker.d.ts +48 -0
  93. package/dist/components/form/inputs/ColorPicker.d.ts.map +1 -0
  94. package/dist/components/form/inputs/CurrencyInput.vue.d.ts +3 -3
  95. package/dist/components/form/inputs/DateInput.d.ts +64 -0
  96. package/dist/components/form/inputs/DateInput.d.ts.map +1 -0
  97. package/dist/components/form/inputs/DatePicker.d.ts +33 -0
  98. package/dist/components/form/inputs/DatePicker.d.ts.map +1 -0
  99. package/dist/components/form/inputs/DatetimeInput.vue.d.ts +3 -3
  100. package/dist/components/form/inputs/DurationInput.vue.d.ts +3 -3
  101. package/dist/components/form/inputs/DynamicLinkField.vue.d.ts +3 -3
  102. package/dist/components/form/inputs/EmailInput.vue.d.ts +3 -3
  103. package/dist/components/form/inputs/FileUpload.d.ts +108 -0
  104. package/dist/components/form/inputs/FileUpload.d.ts.map +1 -0
  105. package/dist/components/form/inputs/FloatInput.vue.d.ts +3 -3
  106. package/dist/components/form/inputs/IntInput.vue.d.ts +3 -3
  107. package/dist/components/form/inputs/JSONInput.d.ts +53 -0
  108. package/dist/components/form/inputs/JSONInput.d.ts.map +1 -0
  109. package/dist/components/form/inputs/LinkField.vue.d.ts +3 -3
  110. package/dist/components/form/inputs/NumberInput.vue.d.ts.map +1 -1
  111. package/dist/components/form/inputs/Password.vue.d.ts +3 -3
  112. package/dist/components/form/inputs/PlainText.vue.d.ts +3 -3
  113. package/dist/components/form/inputs/RadioGroup.d.ts +42 -0
  114. package/dist/components/form/inputs/RadioGroup.d.ts.map +1 -0
  115. package/dist/components/form/inputs/RadioPillsInput.d.ts +48 -0
  116. package/dist/components/form/inputs/RadioPillsInput.d.ts.map +1 -0
  117. package/dist/components/form/inputs/RangeInput.vue.d.ts.map +1 -1
  118. package/dist/components/form/inputs/ReadOnlyInput.vue.d.ts +2 -2
  119. package/dist/components/form/inputs/RichText.d.ts +20 -0
  120. package/dist/components/form/inputs/RichText.d.ts.map +1 -0
  121. package/dist/components/form/inputs/RichText2/Toolbar.d.ts +22 -0
  122. package/dist/components/form/inputs/RichText2/Toolbar.d.ts.map +1 -0
  123. package/dist/components/form/inputs/RichText2/Toolbar.vue.d.ts.map +1 -1
  124. package/dist/components/form/inputs/RichText2/index.d.ts +24 -0
  125. package/dist/components/form/inputs/RichText2/index.d.ts.map +1 -0
  126. package/dist/components/form/inputs/RichText2/index.vue.d.ts +1 -0
  127. package/dist/components/form/inputs/RichText2/index.vue.d.ts.map +1 -1
  128. package/dist/components/form/inputs/RichTextEditor.vue.d.ts +3 -3
  129. package/dist/components/form/inputs/SelectField.vue.d.ts +6 -8
  130. package/dist/components/form/inputs/SelectField.vue.d.ts.map +1 -1
  131. package/dist/components/form/inputs/SelectInput.d.ts +55 -0
  132. package/dist/components/form/inputs/SelectInput.d.ts.map +1 -0
  133. package/dist/components/form/inputs/SignaturePad.d.ts +72 -0
  134. package/dist/components/form/inputs/SignaturePad.d.ts.map +1 -0
  135. package/dist/components/form/inputs/TableField.d.ts +45 -0
  136. package/dist/components/form/inputs/TableField.d.ts.map +1 -0
  137. package/dist/components/form/inputs/TelInput.d.ts +241 -0
  138. package/dist/components/form/inputs/TelInput.d.ts.map +1 -0
  139. package/dist/components/form/inputs/TextArea.vue.d.ts +3 -3
  140. package/dist/components/form/inputs/TextInput.d.ts +90 -0
  141. package/dist/components/form/inputs/TextInput.d.ts.map +1 -0
  142. package/dist/components/form/inputs/ToggleInput.d.ts +58 -0
  143. package/dist/components/form/inputs/ToggleInput.d.ts.map +1 -0
  144. package/dist/components/form/useBagelFormState.d.ts +11 -0
  145. package/dist/components/form/useBagelFormState.d.ts.map +1 -0
  146. package/dist/components/formkit/AddressArray.vue.d.ts +2 -2
  147. package/dist/components/formkit/BankDetailsArray.vue.d.ts +2 -2
  148. package/dist/components/formkit/ContactArrayFormKit.vue.d.ts +2 -2
  149. package/dist/components/formkit/FileUploader.vue.d.ts +2 -2
  150. package/dist/components/formkit/MiscFields.vue.d.ts +2 -2
  151. package/dist/components/formkit/Toggle.vue.d.ts +2 -2
  152. package/dist/components/index.d.ts +2 -0
  153. package/dist/components/index.d.ts.map +1 -1
  154. package/dist/components/layout/BottomMenu.d.ts +27 -0
  155. package/dist/components/layout/BottomMenu.d.ts.map +1 -0
  156. package/dist/components/layout/Layout.d.ts +58 -0
  157. package/dist/components/layout/Layout.d.ts.map +1 -0
  158. package/dist/components/layout/SidebarMenu.d.ts +38 -0
  159. package/dist/components/layout/SidebarMenu.d.ts.map +1 -0
  160. package/dist/components/layout/TabbedLayout.d.ts +42 -0
  161. package/dist/components/layout/TabbedLayout.d.ts.map +1 -0
  162. package/dist/components/layout/Tabs.d.ts +31 -0
  163. package/dist/components/layout/Tabs.d.ts.map +1 -0
  164. package/dist/components/layout/TabsBody.d.ts +23 -0
  165. package/dist/components/layout/TabsBody.d.ts.map +1 -0
  166. package/dist/components/layout/TabsNav.d.ts +35 -0
  167. package/dist/components/layout/TabsNav.d.ts.map +1 -0
  168. package/dist/components/whatsapp/form/MsgTemplate.vue.d.ts +4 -3
  169. package/dist/components/whatsapp/form/TextVariableExamples.vue.d.ts +2 -2
  170. package/dist/index.cjs +7045 -9110
  171. package/dist/index.d.ts +1 -0
  172. package/dist/index.d.ts.map +1 -1
  173. package/dist/index.mjs +7051 -9116
  174. package/dist/style.css +500 -494
  175. package/dist/styles.css +14073 -0
  176. package/dist/utils/BagelFormUtils.d.ts +31 -17
  177. package/dist/utils/BagelFormUtils.d.ts.map +1 -1
  178. package/dist/utils/objects.d.ts +1 -0
  179. package/dist/vue.css +14073 -0
  180. package/package.json +1 -1
  181. package/src/components/BglComponent.vue +174 -0
  182. package/src/components/FieldSetVue.vue +23 -0
  183. package/src/components/ModalForm.vue +1 -1
  184. package/src/components/Pill.vue +3 -2
  185. package/src/components/TableSchema.vue +3 -2
  186. package/src/components/form/BglField.vue +50 -77
  187. package/src/components/form/BglForm.vue +44 -31
  188. package/src/components/form/FieldArray.vue +25 -19
  189. package/src/components/form/inputs/NumberInput.vue +7 -8
  190. package/src/components/form/inputs/RangeInput.vue +9 -0
  191. package/src/components/form/useBagelFormState.ts +87 -0
  192. package/src/components/index.ts +5 -2
  193. package/src/index.ts +3 -1
  194. package/src/utils/BagelFormUtils.ts +12 -1
  195. package/dist/common-C_IH8b5S.cjs +0 -12580
  196. package/dist/common-DoeNgx31.js +0 -12579
  197. package/dist/components/AddressSaerch.vue.d.ts +0 -7
  198. package/dist/components/AddressSaerch.vue.d.ts.map +0 -1
  199. package/dist/components/Popover.vue.d.ts +0 -10
  200. package/dist/components/Popover.vue.d.ts.map +0 -1
  201. package/dist/components/form/inputs/RichText/Toolbar.vue.d.ts +0 -14
  202. package/dist/components/form/inputs/RichText/Toolbar.vue.d.ts.map +0 -1
  203. package/dist/components/form/inputs/RichText/formatting.d.ts +0 -11
  204. package/dist/components/form/inputs/RichText/formatting.d.ts.map +0 -1
  205. package/dist/components/form/inputs/RichText/richtext-types.d.ts +0 -3
  206. package/dist/components/form/inputs/RichText/richtext-types.d.ts.map +0 -1
  207. package/dist/components/form/inputs/Upload/UploadFile.vue.d.ts +0 -86
  208. package/dist/components/form/inputs/Upload/UploadFile.vue.d.ts.map +0 -1
  209. package/dist/components/sortable/Animation.d.ts +0 -43
  210. package/dist/components/sortable/Animation.d.ts.map +0 -1
  211. package/dist/components/sortable/BrowserInfo.d.ts +0 -7
  212. package/dist/components/sortable/BrowserInfo.d.ts.map +0 -1
  213. package/dist/components/sortable/EventDispatcher.d.ts +0 -13
  214. package/dist/components/sortable/EventDispatcher.d.ts.map +0 -1
  215. package/dist/components/sortable/PluginManager.d.ts +0 -27
  216. package/dist/components/sortable/PluginManager.d.ts.map +0 -1
  217. package/dist/components/sortable/Sortable.d.ts +0 -81
  218. package/dist/components/sortable/Sortable.d.ts.map +0 -1
  219. package/dist/components/sortable/index.d.ts +0 -5
  220. package/dist/components/sortable/index.d.ts.map +0 -1
  221. package/dist/components/sortable/utils.d.ts +0 -49
  222. package/dist/components/sortable/utils.d.ts.map +0 -1
  223. package/dist/composables/drag-n-drop/useDraggable.d.ts +0 -2
  224. package/dist/composables/drag-n-drop/useDraggable.d.ts.map +0 -1
  225. package/dist/editor-CUDRLdmS.js +0 -4
  226. package/dist/editor-Cu374vEW.cjs +0 -4
  227. package/dist/editor-a8DSbb6P.js +0 -4
  228. package/dist/editor-xBt_vIha.cjs +0 -4
  229. package/dist/heic2any-8wMqMfB_.js +0 -933
  230. package/dist/heic2any-BrqcNzfV.js +0 -935
  231. package/dist/heic2any-C8KwH72N.cjs +0 -934
  232. package/dist/heic2any-k9wDCKka.cjs +0 -932
  233. package/dist/index-DiG-xM9T.cjs +0 -35016
  234. package/dist/index-nGuSAiY2.js +0 -35017
  235. package/dist/plugins/drag-n-drop/draggable.d.ts +0 -4
  236. package/dist/plugins/drag-n-drop/draggable.d.ts.map +0 -1
  237. package/dist/plugins/drag-n-drop/droppable.d.ts +0 -4
  238. package/dist/plugins/drag-n-drop/droppable.d.ts.map +0 -1
  239. package/dist/plugins/drag-n-drop/index.d.ts +0 -5
  240. package/dist/plugins/drag-n-drop/index.d.ts.map +0 -1
  241. package/dist/plugins/drag-n-drop/useDraggable.d.ts +0 -8
  242. package/dist/plugins/drag-n-drop/useDraggable.d.ts.map +0 -1
  243. package/dist/plugins/drag-n-drop/useDroppable.d.ts +0 -7
  244. package/dist/plugins/drag-n-drop/useDroppable.d.ts.map +0 -1
  245. package/dist/types/materialIcon.d.ts +0 -2
  246. package/dist/types/materialIcon.d.ts.map +0 -1
  247. package/src/components/FieldSet.vue +0 -15
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "0.0.1035",
4
+ "version": "0.0.1037",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Neveh Allon",
@@ -0,0 +1,174 @@
1
+ <script setup lang="ts" generic="T extends Record<string, any>">
2
+ import {
3
+ CheckInput,
4
+ DateInput,
5
+ FieldArray,
6
+ type Field,
7
+ FileUpload,
8
+ RichText,
9
+ SelectInput,
10
+ TextInput,
11
+ ToggleInput,
12
+ bindAttrs,
13
+ classify,
14
+ NumberInput,
15
+ UploadInput,
16
+ BglForm,
17
+ TabsNav,
18
+ } from '@bagelink/vue'
19
+
20
+ const props = defineProps<{
21
+ field: Field<T>
22
+ id?: string
23
+ modelValue?: any
24
+ parentPath?: string
25
+ }>()
26
+
27
+ const emit = defineEmits<{
28
+ 'update:modelValue': [value: any]
29
+ }>()
30
+
31
+ const customAttrs = $ref<{ [key: string]: any }>({})
32
+
33
+ const is = $computed(() => {
34
+ if (props.field.$el === 'text') return TextInput
35
+ if (props.field.$el === 'textarea') {
36
+ customAttrs.multiline = true
37
+ return TextInput
38
+ }
39
+ if (props.field.$el === 'number') return NumberInput
40
+ if (props.field.$el === 'array') return FieldArray
41
+ if (props.field.$el === 'select') return SelectInput
42
+ if (props.field.$el === 'toggle') return ToggleInput
43
+ if (props.field.$el === 'check') return CheckInput
44
+ if (props.field.$el === 'richtext') return RichText
45
+ if (props.field.$el === 'upload') return UploadInput
46
+ if (props.field.$el === 'file') return FileUpload
47
+ if (props.field.$el === 'date') return DateInput
48
+ if (props.field.$el === 'tabs') return TabsNav
49
+ if (props.field.$el === 'form') return BglForm
50
+ return props.field.$el ?? 'div'
51
+ })
52
+
53
+ function getFieldData(path?: string) {
54
+ if (!path) return ''
55
+ const keys = path.split(/[.[]/)
56
+ let current = props.modelValue as any
57
+
58
+ for (let i = 0; i < keys.length; i++) {
59
+ const key = keys[i]
60
+ if (!current || typeof current !== 'object' || !(key in current)) {
61
+ return ''
62
+ }
63
+ current = current[key]
64
+ }
65
+ return current ?? ''
66
+ }
67
+ function safeClone(obj: any): any {
68
+ if (obj === null || typeof obj !== 'object') return obj
69
+
70
+ const seen = new WeakSet()
71
+ return JSON.parse(JSON.stringify(obj, (key, value) => {
72
+ if (typeof value === 'object' && value !== null) {
73
+ if (seen.has(value)) {
74
+ return undefined // Remove circular reference
75
+ }
76
+ seen.add(value)
77
+ }
78
+ return value
79
+ }))
80
+ }
81
+ function updateField(path: string, value: any) {
82
+ const keys = path.split(/[.[]/)
83
+
84
+ let current = props.modelValue ?? {} as any
85
+
86
+ // Build the path, ensuring each level is an object
87
+ for (let i = 0; i < keys.length - 1; i++) {
88
+ const key = keys[i]
89
+ if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
90
+ current[key] = {}
91
+ }
92
+ current = current[key]
93
+ }
94
+
95
+ // Safely clone the value to remove circular references
96
+ const safeValue = safeClone(value)
97
+ current[keys[keys.length - 1]] = safeValue
98
+ }
99
+
100
+ const fieldData = $computed({
101
+ get: () => {
102
+ if (!props.id) return props.modelValue ?? props.field.defaultValue ?? (props.field.$el === 'form' ? {} : '')
103
+ const value = getFieldData(props.id)
104
+ if (props.field.$el === 'form' && !value) return {}
105
+ return value ?? ''
106
+ },
107
+ set: (val: any) => {
108
+ if (!props.id) return
109
+ const currentValue = getFieldData(props.id)
110
+ if (JSON.stringify(val) === JSON.stringify(currentValue)) return
111
+
112
+ emit('update:modelValue', val)
113
+ if (props.field.onUpdate) {
114
+ props.field.onUpdate(val, currentValue)
115
+ }
116
+ updateField(props.id, val)
117
+ }
118
+ })
119
+
120
+ const vIf = $computed(() => {
121
+ if (props.field['v-if'] === undefined && props.field.vIf === undefined) return true
122
+ if (typeof props.field['v-if'] === 'boolean' || typeof props.field.vIf === 'boolean') return props.field['v-if']
123
+ if (typeof props.field['v-if'] === 'string' || typeof props.field.vIf === 'string') return true
124
+ if (typeof props.field['v-if'] === 'function') return props.field['v-if'](fieldData, props.modelValue as T)
125
+ if (typeof props.field.vIf === 'function') return props.field.vIf(fieldData, props.modelValue as T)
126
+ return true
127
+ })
128
+
129
+ const computedOptions = $computed(
130
+ () => bindAttrs({ options: props.field.options }, fieldData, props.modelValue).options
131
+ )
132
+
133
+ const computedAttrs = $computed(() => {
134
+ const attrs = { ...customAttrs, ...props.field.attrs }
135
+ return bindAttrs(attrs, fieldData, props.modelValue)
136
+ })
137
+
138
+ const computedClass = $computed(
139
+ () => classify(fieldData, props.modelValue, props.field.class, props.field.attrs?.class)
140
+ )
141
+ </script>
142
+
143
+ <template>
144
+ <component
145
+ v-bind="computedAttrs"
146
+ :is="is"
147
+ v-if="vIf"
148
+ :id="props.id"
149
+ v-model="fieldData"
150
+ :required="field.required"
151
+ :class="computedClass"
152
+ :label="field.label"
153
+ :placeholder="field.placeholder || field.label"
154
+ :defaultValue="field.defaultValue"
155
+ :disabled="field.disabled"
156
+ :options="computedOptions"
157
+ :helptext="field.helptext"
158
+ :schema="field.attrs?.schema ?? undefined"
159
+ >
160
+ <template v-if="field.$el === 'form'">
161
+ <slot />
162
+ </template>
163
+ <template v-else>
164
+ {{ fieldData }}
165
+ <BglComponent
166
+ v-for="(child, ii) in field.children"
167
+ :id="[props.id, child.id].filter(Boolean).join('.')"
168
+ :key="child.id || ii"
169
+ :field="child"
170
+ :parent-path="props.id"
171
+ />
172
+ </template>
173
+ </component>
174
+ </template>
@@ -0,0 +1,23 @@
1
+ <script lang="ts" setup>
2
+ defineProps<{
3
+ label?: string
4
+ legend?: string
5
+ }>()
6
+ </script>
7
+
8
+ <template>
9
+ <fieldset class="px-1 pt-025 pb-1">
10
+ <legend class="ms-1">
11
+ {{ legend || label }}
12
+ </legend>
13
+ <slot />
14
+ </fieldset>
15
+ </template>
16
+
17
+ <style scoped>
18
+ fieldset {
19
+ border: 1px solid var(--border-color);
20
+ border-radius: var(--card-border-radius);
21
+ padding: var(--space-md);
22
+ }
23
+ </style>
@@ -48,7 +48,7 @@ let submitting = $ref(false)
48
48
 
49
49
  async function runSubmit() {
50
50
  if (submitting) return
51
- if (form?.validateForm?.() === false) return
51
+ if (form?.validateForm() === false) return
52
52
  submitting = true
53
53
  try {
54
54
  await props.onSubmit?.(formData.value)
@@ -20,6 +20,7 @@ const props = defineProps<{
20
20
  outline?: boolean
21
21
  loading?: boolean
22
22
  value?: string
23
+ modelValue?: string
23
24
  round?: boolean
24
25
  btn?: BtnProp
25
26
  btnEnd?: BtnProp
@@ -91,8 +92,8 @@ const computedBackgroundColor = $computed(
91
92
  </div>
92
93
  <MaterialIcon v-if="icon" :icon="icon" />
93
94
  <slot />
94
- <template v-if="!slots.default && value">
95
- {{ value }}
95
+ <template v-if="!slots.default && (value)">
96
+ {{ value || modelValue }}
96
97
  </template>
97
98
  <MaterialIcon v-if="iconEnd" :icon="iconEnd" />
98
99
  <div v-if="loading" class="loading" />
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts" generic="T extends Record<string, any>">
2
2
  import {
3
- BglField,
3
+ BglComponent,
4
4
  type BglFormSchemaT,
5
5
  MaterialIcon,
6
6
  isDate,
@@ -272,7 +272,8 @@ watch(
272
272
  :field
273
273
  />
274
274
  <div v-else>
275
- <BglField
275
+ <BglComponent
276
+ :id="field.id"
276
277
  class="embedded-field"
277
278
  :field
278
279
  :modelValue="row"
@@ -11,23 +11,27 @@ import {
11
11
  ToggleInput,
12
12
  bindAttrs,
13
13
  classify,
14
- BagelForm,
15
14
  NumberInput,
16
15
  UploadInput,
16
+ type BagelFormState,
17
+ BglForm
17
18
  } from '@bagelink/vue'
19
+ import { inject } from 'vue'
18
20
  import TabsNav from '../layout/TabsNav.vue'
21
+ import { FORM_STATE_KEY } from './useBagelFormState'
19
22
 
20
- const props = withDefaults(
21
- defineProps<{
22
- field: Field<T>
23
- modelValue: { [key: string]: any }
24
- }>(),
25
- {
26
- modelValue: () => ({}),
27
- }
28
- )
23
+ const props = defineProps<{
24
+ field: Field<T>
25
+ id?: string
26
+ modelValue?: any
27
+ parentPath?: string
28
+ }>()
29
+
30
+ const emit = defineEmits<{
31
+ 'update:modelValue': [value: any]
32
+ }>()
29
33
 
30
- const emit = defineEmits(['update:modelValue'])
34
+ const formState = inject<BagelFormState<T>>(FORM_STATE_KEY)
31
35
 
32
36
  const customAttrs = $ref<{ [key: string]: any }>({})
33
37
 
@@ -47,90 +51,54 @@ const is = $computed(() => {
47
51
  if (props.field.$el === 'file') return FileUpload
48
52
  if (props.field.$el === 'date') return DateInput
49
53
  if (props.field.$el === 'tabs') return TabsNav
50
- if (props.field.$el === 'form') return BagelForm
54
+ if (props.field.$el === 'form') return BglForm
51
55
  return props.field.$el ?? 'div'
52
56
  })
53
57
 
54
- const formData = $computed({
55
- get: () => props.modelValue,
56
- set: (val: any) => {
57
- emit('update:modelValue', val)
58
+ const fieldData = $computed({
59
+ get: () => {
60
+ if (!props.id) return props.field.defaultValue ?? (props.field.$el === 'form' ? {} : '')
61
+ const value = formState?.getFieldData(props.id)
62
+ if (props.field.$el === 'form' && !value) return {}
63
+ return value ?? ''
58
64
  },
59
- })
60
-
61
- const objPathRegex = /[.\][]/
62
-
63
- function setFieldData(key: string, val: any) {
64
- const data = { ...props.modelValue }
65
- const keys = key.split(objPathRegex)
66
- let temp = data
67
- for (let i = 0; i < keys.length - 1; i++) {
68
- if (!temp[keys[i]]) {
69
- temp[keys[i]] = {}
70
- }
71
- temp = temp[keys[i]]
72
- }
73
- temp[keys[keys.length - 1]] = val
74
- return data
75
- }
76
-
77
- const isForm = $computed(() => props.field.$el === 'form' || props.field.$el === BagelForm)
65
+ set: (val: any) => {
66
+ if (!props.id) return
67
+ const currentValue = formState?.getFieldData(props.id)
68
+ if (JSON.stringify(val) === JSON.stringify(currentValue)) return
78
69
 
79
- function getFieldData(obj: any, key: string) {
80
- if (typeof obj !== 'object' || obj === null) return obj
81
- const keys = key.split(objPathRegex)
82
- let result = obj
83
- for (const k of keys) {
84
- if (result && k in result) {
85
- result = result[k]
86
- } else {
87
- return undefined
70
+ emit('update:modelValue', val)
71
+ if (props.field.onUpdate) {
72
+ props.field.onUpdate(val, currentValue)
88
73
  }
74
+ formState?.updateField(props.id, val)
89
75
  }
90
- return result
91
- }
92
-
93
- const fieldData = $computed({
94
- set: (val: any) => {
95
- if (isForm) {
96
- emit('update:modelValue', val)
97
- return
98
- }
99
- if (!props.field.id) return
100
- const data = setFieldData(props.field.id, val)
101
- emit('update:modelValue', data)
102
- },
103
- get: () => {
104
- if (props.field.id) return getFieldData(props.modelValue, props.field.id)
105
- if (isForm) return props.modelValue
106
- return props.field.defaultValue ?? ''
107
- },
108
76
  })
109
77
 
110
78
  const vIf = $computed(() => {
111
79
  if (props.field['v-if'] === undefined && props.field.vIf === undefined) return true
112
80
  if (typeof props.field['v-if'] === 'boolean' || typeof props.field.vIf === 'boolean') return props.field['v-if']
113
81
  if (typeof props.field['v-if'] === 'string' || typeof props.field.vIf === 'string') return true
114
- if (typeof props.field['v-if'] === 'function') return props.field['v-if'](fieldData, formData as T)
115
- if (typeof props.field.vIf === 'function') return props.field.vIf(fieldData, formData as T)
82
+ if (typeof props.field['v-if'] === 'function') return props.field['v-if'](fieldData, formState?.data.value as T)
83
+ if (typeof props.field.vIf === 'function') return props.field.vIf(fieldData, formState?.data.value as T)
116
84
  return true
117
85
  })
118
86
 
119
87
  const computedFieldData = $computed(
120
- () => props.field.transform?.(fieldData, props.modelValue as T) ?? fieldData
88
+ () => props.field.transform?.(fieldData, formState?.data.value as T) ?? fieldData
121
89
  )
122
90
 
123
91
  const computedOptions = $computed(
124
- () => bindAttrs({ options: props.field.options }, fieldData, props.modelValue).options
92
+ () => bindAttrs({ options: props.field.options }, fieldData, formState?.data.value).options
125
93
  )
126
94
 
127
95
  const computedAttrs = $computed(() => {
128
96
  const attrs = { ...customAttrs, ...props.field.attrs }
129
- return bindAttrs(attrs, fieldData, props.modelValue)
97
+ return bindAttrs(attrs, fieldData, formState?.data.value)
130
98
  })
131
99
 
132
100
  const computedClass = $computed(
133
- () => classify(fieldData, props.modelValue, props.field.class, props.field.attrs?.class)
101
+ () => classify(fieldData, formState?.data.value, props.field.class, props.field.attrs?.class)
134
102
  )
135
103
  </script>
136
104
 
@@ -139,7 +107,7 @@ const computedClass = $computed(
139
107
  v-bind="computedAttrs"
140
108
  :is="is"
141
109
  v-if="vIf"
142
- :id="field.id"
110
+ :id="props.id"
143
111
  v-model="fieldData"
144
112
  :required="field.required"
145
113
  :class="computedClass"
@@ -149,14 +117,19 @@ const computedClass = $computed(
149
117
  :disabled="field.disabled"
150
118
  :options="computedOptions"
151
119
  :helptext="field.helptext"
152
- @update:modelValue="($event: any) => field?.onUpdate?.($event, formData as T)"
120
+ :schema="field.attrs?.schema ?? undefined"
153
121
  >
154
- {{ computedFieldData }}
155
- <BglField
156
- v-for="(child, ii) in field.children"
157
- :key="child.id || ii"
158
- v-model="formData"
159
- :field="child"
160
- />
122
+ <template v-if="field.$el === 'form'">
123
+ <slot />
124
+ </template>
125
+ <template v-else>
126
+ <BglField
127
+ v-for="(child, ii) in field.children"
128
+ :id="[props.id, child.id].filter(Boolean).join('.')"
129
+ :key="child.id || ii"
130
+ :field="child"
131
+ :parent-path="props.id"
132
+ />
133
+ </template>
161
134
  </component>
162
135
  </template>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import { BglField, type BglFormSchemaFnT, Title, useBglSchema, useModal } from '@bagelink/vue'
3
- import { useSlots, watch } from 'vue'
3
+ import { inject, useSlots, watch } from 'vue'
4
+ import { FORM_STATE_KEY, provideBagelFormState, type BagelFormState } from './useBagelFormState'
4
5
 
5
6
  export type FormStatus = 'idle' | 'loading' | 'success' | 'error'
6
7
 
@@ -22,41 +23,55 @@ const props = withDefaults(
22
23
  const emit = defineEmits(['update:modelValue', 'submit', 'dirty'])
23
24
 
24
25
  const slots = useSlots()
25
-
26
26
  const { showModal } = useModal()
27
-
28
27
  const instAt = new Date()
29
28
  const timeSinceInst = () => Date.now() - instAt.getTime()
30
- let formData = $ref(props.modelValue || {})
31
- let isDirty = $ref(false)
32
- let data = $computed({
33
- set: (val: any) => {
34
- if (timeSinceInst() > 100) {
29
+
30
+ // Check if we're a nested form
31
+ const existingFormState = inject<BagelFormState | undefined>(FORM_STATE_KEY)
32
+ const isNested = Boolean(existingFormState && props.id)
33
+
34
+ // Only provide new form state if we're not nested
35
+ const { data, isDirty } = isNested
36
+ ? existingFormState!
37
+ : provideBagelFormState(props.modelValue)
38
+
39
+ // Only watch for external updates if we're not nested
40
+ if (!isNested) {
41
+ watch(() => props.modelValue, (newVal) => {
42
+ if (JSON.stringify(newVal) !== JSON.stringify(data.value)) {
43
+ data.value = newVal
44
+ }
45
+ }, { deep: true, immediate: true })
46
+
47
+ // Emit updates when internal state changes
48
+ watch(data, (newVal) => {
49
+ if (timeSinceInst() > 100 && JSON.stringify(newVal) !== JSON.stringify(props.modelValue)) {
35
50
  emit('dirty')
36
- isDirty = true
51
+ emit('update:modelValue', newVal)
37
52
  }
38
- formData = val
39
- emit('update:modelValue', val)
40
- },
41
- get: () => formData,
42
- })
53
+ }, { deep: true })
54
+ }
55
+
43
56
  const form = $ref<HTMLFormElement>()
44
57
 
45
58
  function validateForm() {
46
- // ? Ensures that scrolling does not dismiss validation-tooltip in safari
47
- setTimeout(() => form?.reportValidity(), 300) // TODO: check if browser is safari
48
-
59
+ setTimeout(() => form?.reportValidity(), 300)
49
60
  if (!form) return false
50
61
  return form.reportValidity()
51
62
  }
52
63
 
53
- const clearForm = () => (data = {})
64
+ function clearForm() {
65
+ if (!isNested) {
66
+ data.value = {}
67
+ }
68
+ }
54
69
 
55
70
  watch(
56
71
  () => props.status,
57
72
  (status) => {
58
- if (status === 'success') {
59
- isDirty = false
73
+ if (status === 'success' && !isNested) {
74
+ isDirty.value = false
60
75
  clearForm()
61
76
  }
62
77
  },
@@ -66,9 +81,10 @@ watch(
66
81
  function runSubmit() {
67
82
  const isValid = validateForm()
68
83
  if (!isValid) return
69
- // props.onSubmit?.(data);
70
- emit('submit', { ...formData })
71
- isDirty = false
84
+ emit('submit', { ...data.value })
85
+ if (!isNested) {
86
+ isDirty.value = false
87
+ }
72
88
  }
73
89
 
74
90
  const i18nT = (val: string) => val
@@ -91,9 +107,7 @@ function deleteItem() {
91
107
  )
92
108
  }
93
109
 
94
- const computedSchema = $computed(
95
- () => useBglSchema({ schema: props.schema })
96
- )
110
+ const computedSchema = $computed(() => useBglSchema({ schema: props.schema }))
97
111
 
98
112
  defineExpose({
99
113
  submit: runSubmit,
@@ -106,14 +120,13 @@ defineExpose({
106
120
 
107
121
  <template>
108
122
  <template v-if="id">
109
- <Title v-if="label" tag="h4" :label="label" />
110
123
  <BglField
111
124
  v-for="(field, i) in computedSchema"
125
+ :id="[id, field.id].filter(Boolean).join('.')"
112
126
  :key="field.id || `${i}p`"
113
- v-model="data"
114
127
  :field="field"
115
128
  />
116
- <slot name="submit" :submit="runSubmit" :isDirty :validateForm />
129
+ <slot name="submit" :submit="runSubmit" :isDirty="isDirty" :validateForm="validateForm" />
117
130
  </template>
118
131
  <form
119
132
  v-else-if="!slots.success || status !== 'success'"
@@ -123,11 +136,11 @@ defineExpose({
123
136
  <Title v-if="label" tag="h4" :label="label" />
124
137
  <BglField
125
138
  v-for="(field, i) in computedSchema"
139
+ :id="field.id"
126
140
  :key="field.id || `${i}p`"
127
- v-model="data"
128
141
  :field="field"
129
142
  />
130
- <slot name="submit" :submit="runSubmit" :isDirty :validateForm />
143
+ <slot name="submit" :submit="runSubmit" :isDirty="isDirty" :validateForm="validateForm" />
131
144
  </form>
132
145
  <slot v-if="status === 'success'" name="success" />
133
146
  <slot v-if="status === 'error'" name="error" />
@@ -7,7 +7,7 @@ import type {
7
7
  BglFormSchemaFnT,
8
8
  Field,
9
9
  } from '@bagelink/vue'
10
- import { BglForm, Btn } from '@bagelink/vue'
10
+ import { BglForm, BglField, Btn } from '@bagelink/vue'
11
11
 
12
12
  const props = withDefaults(
13
13
  defineProps<{
@@ -25,6 +25,7 @@ const props = withDefaults(
25
25
  defaultValue?: any
26
26
  add?: boolean
27
27
  delete?: boolean
28
+ transform?: (value: T) => T
28
29
  schema: BglFormSchemaFnT
29
30
  modelValue: T[]
30
31
  }>(),
@@ -53,31 +54,33 @@ function addItem() {
53
54
  emitValue()
54
55
  }
55
56
 
56
- // const computedField = $computed(
57
- // () => ({
58
- // label: props.label,
59
- // placeholder: props.placeholder,
60
- // children: props.children,
61
- // class: props.class,
62
- // attrs: props.attrs,
63
- // required: props.required,
64
- // disabled: props.disabled,
65
- // helptext: props.helptext,
66
- // options: props.options,
67
- // defaultValue: props.defaultValue,
68
- // $el: props.el,
69
- // }) as Field<T>
70
- // ) as Field<Record<string, any>>
57
+ const computedField = $computed(
58
+ () => ({
59
+ label: props.label,
60
+ placeholder: props.placeholder,
61
+ children: props.children,
62
+ // class: props.class,
63
+ attrs: props.attrs,
64
+ required: props.required,
65
+ disabled: props.disabled,
66
+ helptext: props.helptext,
67
+ options: props.options,
68
+ defaultValue: props.defaultValue,
69
+ transform: props.transform,
70
+ $el: props.el,
71
+ }) as Field<T>
72
+ ) as Field<Record<string, any>>
71
73
  </script>
72
74
 
73
75
  <template>
74
- <div>
76
+ <div :class="props.class">
75
77
  <p class="label mb-05">
76
78
  {{ label }}
77
79
  </p>
78
- <div class="-ms-05 ps-05 border-start">
80
+
81
+ <div v-if="schema" class="-ms-05 ps-05 border-start">
79
82
  <div v-for="(_, i) in data" :key="i" outline thin class="mb-05 itemBox transition p-05">
80
- <BglForm v-if="schema" v-model="data[i]" :schema="schema" @update:model-value="emitValue" />
83
+ <BglForm v-model="data[i]" :schema="schema" @update:model-value="emitValue" />
81
84
  <Btn
82
85
  v-if="props.delete"
83
86
  icon="delete"
@@ -92,6 +95,9 @@ function addItem() {
92
95
  <p>Add {{ label }}</p>
93
96
  </Btn>
94
97
  </div>
98
+ <template v-else>
99
+ <BglField v-for="(_, i) in data" :key="i" v-model="data[i]" :field="computedField" @update:model-value="emitValue" />
100
+ </template>
95
101
  </div>
96
102
  </template>
97
103
 
@@ -47,17 +47,16 @@ const btnLayouts: NumberLayout[] = ['horizontal', 'vertical']
47
47
 
48
48
  // Methods
49
49
  function increment() {
50
- if (!max || numberValue + step <= max) {
51
- numberValue = (numberValue || 0) + step
52
- emit('update:modelValue', numberValue)
53
- }
50
+ if (max !== undefined && (numberValue + step) > max) return
51
+ numberValue = (numberValue || 0) + step
52
+ emit('update:modelValue', numberValue)
54
53
  }
55
54
 
56
55
  function decrement() {
57
- if (!min || numberValue - step >= min) {
58
- numberValue = (numberValue || 0) - step
59
- emit('update:modelValue', numberValue)
60
- }
56
+ numberValue = numberValue || 0
57
+ if (min !== undefined && (numberValue - step) < min) return
58
+ numberValue = numberValue - step
59
+ emit('update:modelValue', numberValue)
61
60
  }
62
61
 
63
62
  function formatNumber(num: number) {