@bagelink/vue 1.14.13 → 1.15.0

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 (238) hide show
  1. package/dist/components/AddressSearch.vue.d.ts +6 -7
  2. package/dist/components/Alert.vue.d.ts.map +1 -1
  3. package/dist/components/Avatar.vue.d.ts.map +1 -1
  4. package/dist/components/Badge.vue.d.ts.map +1 -1
  5. package/dist/components/Btn.vue.d.ts +1 -1
  6. package/dist/components/Btn.vue.d.ts.map +1 -1
  7. package/dist/components/Card.vue.d.ts.map +1 -1
  8. package/dist/components/Carousel.vue.d.ts +0 -11
  9. package/dist/components/Dropdown.vue.d.ts +0 -2
  10. package/dist/components/Dropdown.vue.d.ts.map +1 -1
  11. package/dist/components/Filter.vue.d.ts +30 -0
  12. package/dist/components/Filter.vue.d.ts.map +1 -0
  13. package/dist/components/FilterQuery.vue.d.ts +8 -3
  14. package/dist/components/Image.vue.d.ts.map +1 -1
  15. package/dist/components/ImportData.vue.d.ts.map +1 -1
  16. package/dist/components/ListItem.vue.d.ts.map +1 -1
  17. package/dist/components/MapEmbed/Index.vue.d.ts.map +1 -1
  18. package/dist/components/Modal.vue.d.ts +0 -1
  19. package/dist/components/Pagination.vue.d.ts.map +1 -1
  20. package/dist/components/Pill.vue.d.ts.map +1 -1
  21. package/dist/components/QueryFilter.vue.d.ts +30 -0
  22. package/dist/components/QueryFilter.vue.d.ts.map +1 -0
  23. package/dist/components/Swiper.vue.d.ts +6 -12
  24. package/dist/components/Swiper.vue.d.ts.map +1 -1
  25. package/dist/components/Toast.vue.d.ts.map +1 -1
  26. package/dist/components/analytics/PieChart.vue.d.ts +2 -2
  27. package/dist/components/calendar/CalendarPopover.vue.d.ts +8 -4
  28. package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
  29. package/dist/components/calendar/CalendarTypes.d.ts +0 -10
  30. package/dist/components/calendar/Index.vue.d.ts +4 -20
  31. package/dist/components/calendar/views/WeekView.vue.d.ts +1 -9
  32. package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
  33. package/dist/components/form/index.d.ts.map +1 -1
  34. package/dist/components/form/inputs/ArrayInput.vue.d.ts +2 -4
  35. package/dist/components/form/inputs/CheckInput.vue.d.ts +1 -2
  36. package/dist/components/form/inputs/Checkbox.vue.d.ts.map +1 -1
  37. package/dist/components/form/inputs/CodeEditor/Index.vue.d.ts +0 -54
  38. package/dist/components/form/inputs/ColorInput.vue.d.ts +1 -3
  39. package/dist/components/form/inputs/DateInput.vue.d.ts +1 -2
  40. package/dist/components/form/inputs/DatePicker.vue.d.ts +0 -1
  41. package/dist/components/form/inputs/EmailInput.vue.d.ts +2 -5
  42. package/dist/components/form/inputs/JSONInput.vue.d.ts +1 -2
  43. package/dist/components/form/inputs/MarkdownEditor.vue.d.ts +2 -7
  44. package/dist/components/form/inputs/NumberInput.vue.d.ts +1 -2
  45. package/dist/components/form/inputs/OTP.vue.d.ts +1 -2
  46. package/dist/components/form/inputs/PasswordInput.vue.d.ts +10 -16
  47. package/dist/components/form/inputs/RadioGroup.vue.d.ts +1 -3
  48. package/dist/components/form/inputs/RangeInput.vue.d.ts +1 -6
  49. package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -2
  50. package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
  51. package/dist/components/form/inputs/RichText/utils/media.d.ts.map +1 -1
  52. package/dist/components/form/inputs/SelectBtn.vue.d.ts +2 -2
  53. package/dist/components/form/inputs/SelectInput.vue.d.ts +13 -20
  54. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  55. package/dist/components/form/inputs/SignaturePad.vue.d.ts +1 -6
  56. package/dist/components/form/inputs/TableField.vue.d.ts +1 -2
  57. package/dist/components/form/inputs/TelInput.vue.d.ts +1 -2
  58. package/dist/components/form/inputs/TextInput.vue.d.ts +2 -3
  59. package/dist/components/form/inputs/ToggleInput.vue.d.ts +1 -2
  60. package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts +6 -27
  61. package/dist/components/form/inputs/Upload/upload.d.ts +1 -1
  62. package/dist/components/form/inputs/index.d.ts +0 -1
  63. package/dist/components/index.d.ts +1 -3
  64. package/dist/components/index.d.ts.map +1 -1
  65. package/dist/components/layout/AppContent.vue.d.ts +1 -1
  66. package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
  67. package/dist/components/layout/AppLayout.vue.d.ts +0 -2
  68. package/dist/components/layout/AppLayout.vue.d.ts.map +1 -1
  69. package/dist/components/layout/AppSidebar.vue.d.ts +1 -5
  70. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
  71. package/dist/components/layout/Panel.vue.d.ts.map +1 -1
  72. package/dist/components/layout/Resizable.vue.d.ts.map +1 -1
  73. package/dist/components/layout/Skeleton.vue.d.ts.map +1 -1
  74. package/dist/components/layout/TabsNav.vue.d.ts +1 -12
  75. package/dist/components/layout/TabsNav.vue.d.ts.map +1 -1
  76. package/dist/components/layout/appLayoutContext.d.ts +24 -0
  77. package/dist/components/layout/appLayoutContext.d.ts.map +1 -0
  78. package/dist/components/layout/index.d.ts.map +1 -1
  79. package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
  80. package/dist/composables/index.d.ts.map +1 -1
  81. package/dist/composables/useDevice.d.ts.map +1 -1
  82. package/dist/composables/useEscapeKey.d.ts +12 -0
  83. package/dist/composables/useEscapeKey.d.ts.map +1 -0
  84. package/dist/composables/useSchemaField.d.ts.map +1 -1
  85. package/dist/composables/useTheme.d.ts.map +1 -1
  86. package/dist/dialog/Dialog.vue.d.ts.map +1 -1
  87. package/dist/dialog/DialogConfirm.vue.d.ts.map +1 -1
  88. package/dist/form-flow/FormFlow.vue.d.ts.map +1 -1
  89. package/dist/form-flow/MultiStepForm.vue.d.ts +1 -6
  90. package/dist/form-flow/form-flow.d.ts +1 -24
  91. package/dist/form-flow/form-flow.d.ts.map +1 -1
  92. package/dist/i18n/index.d.ts +0 -838
  93. package/dist/index.cjs +245 -222
  94. package/dist/index.d.ts +0 -2
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.mjs +42201 -51162
  97. package/dist/plugins/bagel.d.ts.map +1 -1
  98. package/dist/style.css +1 -2
  99. package/dist/types/BagelForm.d.ts +1 -10
  100. package/dist/types/BagelForm.d.ts.map +1 -1
  101. package/dist/types/BtnOptions.d.ts.map +1 -1
  102. package/dist/types/NavLink.d.ts +1 -2
  103. package/dist/types/TableSchema.d.ts.map +1 -1
  104. package/dist/types/index.d.ts +1 -2
  105. package/dist/types/index.d.ts.map +1 -1
  106. package/dist/utils/BagelFormUtils.d.ts +0 -1
  107. package/dist/utils/calendar/dateUtils.d.ts +2 -2
  108. package/dist/utils/calendar/dateUtils.d.ts.map +1 -1
  109. package/dist/utils/constants.d.ts.map +1 -1
  110. package/dist/utils/date.d.ts +116 -0
  111. package/dist/utils/date.d.ts.map +1 -0
  112. package/dist/utils/fetch.d.ts +29 -0
  113. package/dist/utils/fetch.d.ts.map +1 -0
  114. package/dist/utils/index.d.ts +1 -1
  115. package/dist/utils/index.d.ts.map +1 -1
  116. package/dist/utils/string.d.ts +7 -0
  117. package/dist/utils/string.d.ts.map +1 -0
  118. package/dist/utils/useSearch.d.ts +1 -1
  119. package/package.json +3 -10
  120. package/src/components/AccordionItem.vue +5 -5
  121. package/src/components/Alert.vue +37 -16
  122. package/src/components/Avatar.vue +2 -1
  123. package/src/components/Badge.vue +145 -22
  124. package/src/components/BglVideo.vue +4 -4
  125. package/src/components/Btn.vue +81 -69
  126. package/src/components/Card.vue +7 -6
  127. package/src/components/Dropdown.vue +7 -14
  128. package/src/components/FieldSetVue.vue +2 -2
  129. package/src/components/FilterQuery.vue +3 -3
  130. package/src/components/Image.vue +5 -3
  131. package/src/components/JSONSchema.vue +4 -4
  132. package/src/components/JsonBuilder.vue +3 -3
  133. package/src/components/ListItem.vue +2 -4
  134. package/src/components/MapEmbed/Index.vue +18 -17
  135. package/src/components/NavBar.vue +2 -2
  136. package/src/components/Spreadsheet/Index.vue +4 -4
  137. package/src/components/Spreadsheet/SpreadsheetTable.vue +10 -10
  138. package/src/components/Swiper.vue +3 -1
  139. package/src/components/Toast.vue +57 -36
  140. package/src/components/calendar/CalendarPopover.vue +1 -1
  141. package/src/components/calendar/Index.vue +5 -5
  142. package/src/components/calendar/views/AgendaView.vue +2 -2
  143. package/src/components/calendar/views/DayView.vue +1 -1
  144. package/src/components/calendar/views/MonthView.vue +8 -8
  145. package/src/components/dataTable/DataTable.vue +68 -10
  146. package/src/components/form/index.ts +0 -4
  147. package/src/components/form/inputs/ArrayInput.vue +1 -1
  148. package/src/components/form/inputs/CheckInput.vue +6 -6
  149. package/src/components/form/inputs/Checkbox.vue +5 -4
  150. package/src/components/form/inputs/CodeEditor/Index.vue +1 -1
  151. package/src/components/form/inputs/ColorInput.vue +5 -5
  152. package/src/components/form/inputs/DatePicker.vue +3 -3
  153. package/src/components/form/inputs/EmailInput.vue +15 -15
  154. package/src/components/form/inputs/NumberInput.vue +11 -11
  155. package/src/components/form/inputs/OTP.vue +4 -4
  156. package/src/components/form/inputs/PasswordInput.vue +3 -3
  157. package/src/components/form/inputs/RadioGroup.vue +1 -1
  158. package/src/components/form/inputs/RichText/editor.css +4 -4
  159. package/src/components/form/inputs/RichText/index.vue +39 -39
  160. package/src/components/form/inputs/RichText/utils/media.ts +1 -92
  161. package/src/components/form/inputs/RichText/utils/table.ts +4 -4
  162. package/src/components/form/inputs/SelectBtn.vue +1 -1
  163. package/src/components/form/inputs/SelectInput.vue +16 -16
  164. package/src/components/form/inputs/SignaturePad.vue +6 -6
  165. package/src/components/form/inputs/TableField.vue +7 -7
  166. package/src/components/form/inputs/TelInput.vue +12 -12
  167. package/src/components/form/inputs/TextInput.vue +11 -11
  168. package/src/components/form/inputs/ToggleInput.vue +11 -11
  169. package/src/components/form/inputs/Upload/upload.css +16 -16
  170. package/src/components/index.ts +2 -9
  171. package/src/components/layout/AppContent.vue +5 -19
  172. package/src/components/layout/AppLayout.vue +47 -18
  173. package/src/components/layout/AppSidebar.vue +19 -36
  174. package/src/components/layout/BottomMenu.vue +1 -1
  175. package/src/components/layout/Resizable.vue +5 -2
  176. package/src/components/layout/Skeleton.vue +5 -4
  177. package/src/components/layout/TabsNav.vue +23 -23
  178. package/src/components/layout/appLayoutContext.ts +44 -0
  179. package/src/components/layout/index.ts +2 -0
  180. package/src/components/lightbox/Lightbox.vue +3 -9
  181. package/src/composables/index.ts +1 -0
  182. package/src/composables/useDevice.ts +2 -1
  183. package/src/composables/useEscapeKey.ts +56 -0
  184. package/src/composables/useSchemaField.ts +2 -17
  185. package/src/composables/useTheme.ts +23 -19
  186. package/src/form-flow/FormFlow.vue +2 -0
  187. package/src/form-flow/form-flow.ts +7 -0
  188. package/src/index.ts +0 -3
  189. package/src/plugins/bagel.ts +0 -15
  190. package/src/styles/app-layout.css +231 -0
  191. package/src/styles/appearance.css +179 -21
  192. package/src/styles/bagel.css +103 -97
  193. package/src/styles/buttons.css +8 -8
  194. package/src/styles/colors.css +0 -103
  195. package/src/styles/dark.css +25 -26
  196. package/src/styles/input-variants.css +11 -11
  197. package/src/styles/inputs.css +44 -61
  198. package/src/styles/layout.css +445 -1258
  199. package/src/styles/loginCard.css +1 -1
  200. package/src/styles/mobilLayout.css +153 -28
  201. package/src/styles/text.css +500 -1508
  202. package/src/styles/theme.css +199 -435
  203. package/src/styles/transitions.css +4 -4
  204. package/src/types/BagelForm.ts +46 -151
  205. package/src/types/BtnOptions.ts +5 -3
  206. package/src/types/TableSchema.ts +1 -0
  207. package/src/types/index.ts +0 -5
  208. package/src/utils/calendar/dateUtils.ts +2 -3
  209. package/src/utils/constants.ts +7 -0
  210. package/src/utils/date.ts +482 -0
  211. package/src/utils/fetch.ts +128 -0
  212. package/src/utils/index.ts +54 -3
  213. package/src/utils/sizeParsing.ts +5 -5
  214. package/src/utils/string.ts +56 -0
  215. package/vite.config.ts +5 -1
  216. package/bin/generateFormSchema.ts +0 -1035
  217. package/bin/utils.ts +0 -223
  218. package/src/components/Carousel.vue +0 -724
  219. package/src/components/ImportData.vue +0 -1749
  220. package/src/components/Modal.vue +0 -184
  221. package/src/components/ModalConfirm.vue +0 -42
  222. package/src/components/ModalForm.vue +0 -102
  223. package/src/components/Pill.vue +0 -149
  224. package/src/components/Slider.vue +0 -1446
  225. package/src/components/Title.vue +0 -23
  226. package/src/components/ToolBar.vue +0 -9
  227. package/src/components/form/BagelForm.vue +0 -219
  228. package/src/components/form/BglFieldSet.vue +0 -14
  229. package/src/components/form/BglMultiStepForm.vue +0 -469
  230. package/src/components/form/FieldArray.vue +0 -422
  231. package/src/components/form/useBagelFormState.ts +0 -76
  232. package/src/composables/useFormField.ts +0 -38
  233. package/src/dialog/DialogOLD.vue +0 -358
  234. package/src/plugins/modalTypes.ts +0 -61
  235. package/src/plugins/useModal.ts +0 -225
  236. package/src/styles/modal.css +0 -120
  237. package/src/styles/pillColors.css +0 -0
  238. package/src/utils/BagelFormUtils.ts +0 -684
@@ -17,7 +17,7 @@ const props = defineProps<{
17
17
  iconSize?: number | string
18
18
  iconMobileSize?: number | string
19
19
  thin?: boolean
20
- size?: 'xs' | 's' | 'm' | 'l' | 'xl' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'
20
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
21
21
  fullWidth?: boolean
22
22
  fullWidthMobile?: boolean
23
23
  alignTxt?: 'center' | 'start' | 'end'
@@ -146,10 +146,10 @@ onBeforeUnmount(() => {
146
146
  { active: isActive(tab) },
147
147
  {
148
148
  'bgl_tab-thin': thin,
149
- 'bgl_tab-xs': size === 'xs' || size === 'extra-small',
150
- 'bgl_tab-s': size === 's' || size === 'small',
151
- 'bgl_tab-l': size === 'l' || size === 'large',
152
- 'bgl_tab-xl': size === 'xl' || size === 'extra-large',
149
+ 'bgl_tab-xs': size === 'xs',
150
+ 'bgl_tab-s': size === 'sm',
151
+ 'bgl_tab-l': size === 'lg',
152
+ 'bgl_tab-xl': size === 'xl',
153
153
  'w-100p justify-center': fullWidth,
154
154
  'w-auto m_w-100p': fullWidthMobile,
155
155
  'bgl_tab-align-center': alignTxt === 'center',
@@ -171,17 +171,17 @@ onBeforeUnmount(() => {
171
171
 
172
172
  <style>
173
173
  :root {
174
- --bgl_tabs-background: var(--input-bg);
175
- --bgl_tabs-border-radius: var(--input-border-radius);
176
- --bgl_tabs-inline-padding: calc(var(--btn-padding) / 8);
177
- --bgl_tabs-block-padding: calc(var(--btn-padding) / 8);
174
+ --bgl_tabs-background: var(--bgl-input-bg);
175
+ --bgl_tabs-border-radius: var(--bgl-input-border-radius);
176
+ --bgl_tabs-inline-padding: calc(var(--bgl-btn-padding) / 8);
177
+ --bgl_tabs-block-padding: calc(var(--bgl-btn-padding) / 8);
178
178
  --bgl_tabs-shadow: inset 0 0 10px #00000012;
179
179
  --bgl_tabs-gap: 0.25rem;
180
- --bgl_tabs-font-size: var(--input-font-size);
181
- --bgl_tab-inline-padding: calc(var(--btn-padding) / 2);
182
- --bgl_tab-block-padding: calc(var(--btn-padding) / 8);
180
+ --bgl_tabs-font-size: var(--bgl-input-font-size);
181
+ --bgl_tab-inline-padding: calc(var(--bgl-btn-padding) / 2);
182
+ --bgl_tab-block-padding: calc(var(--bgl-btn-padding) / 8);
183
183
  --bgl_tab-gap: 0.5rem;
184
- --bgl_tabs-border-radius: var(--input-border-radius);
184
+ --bgl_tabs-border-radius: var(--bgl-input-border-radius);
185
185
  --bgl-tab-hover-bg: rgba(255, 255, 255, .4);
186
186
  --bgl_tabs-indicator-color: var(--bgl-popup-bg);
187
187
  --bgl-tabs-flat-indicator-color: var(--bgl-primary);
@@ -204,7 +204,7 @@ onBeforeUnmount(() => {
204
204
  cursor: pointer;
205
205
  font-size: inherit;
206
206
  font-family: inherit;
207
- height: calc(var(--btn-height) - var(--bgl_tabs-block-padding) * 2);
207
+ height: calc(var(--bgl-btn-height) - var(--bgl_tabs-block-padding) * 2);
208
208
  padding-inline: var(--bgl_tab-inline-padding);
209
209
  padding-block: 0;
210
210
  border-radius: var(--bgl_tab-border-radius);
@@ -242,7 +242,7 @@ onBeforeUnmount(() => {
242
242
  background: transparent;
243
243
  border-bottom: 1px solid var(--bgl-tabs-flat-indicator-color);
244
244
  border-radius: 0;
245
- top: calc(var(--btn-padding) * 1.25);
245
+ top: calc(var(--bgl-btn-padding) * 1.25);
246
246
  bottom: unset;
247
247
 
248
248
  }
@@ -255,30 +255,30 @@ onBeforeUnmount(() => {
255
255
  }
256
256
  .bgl_tab-thin {
257
257
  padding-inline: calc(var(--bgl_tab-inline-padding) / 2);
258
- height: calc(var(--btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
258
+ height: calc(var(--bgl-btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
259
259
  }
260
260
 
261
261
  .bgl_tab-xs {
262
262
  padding-inline: calc(var(--bgl_tab-inline-padding) / 3);
263
- font-size: calc(var(--input-font-size) * 0.6);
264
- height: calc(var(--btn-height) * 0.5 - var(--bgl_tabs-block-padding) * 2);
263
+ font-size: calc(var(--bgl-input-font-size) * 0.6);
264
+ height: calc(var(--bgl-btn-height) * 0.5 - var(--bgl_tabs-block-padding) * 2);
265
265
  }
266
266
 
267
267
  .bgl_tab-s {
268
268
  padding-inline: calc(var(--bgl_tab-inline-padding) / 1.5);
269
- height: calc(var(--btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
269
+ height: calc(var(--bgl-btn-height) * 0.7 - var(--bgl_tabs-block-padding) * 2);
270
270
  }
271
271
 
272
272
  .bgl_tab-l {
273
273
  padding-inline: calc(var(--bgl_tab-inline-padding) * 1.3);
274
- font-size: calc(var(--input-font-size) * 1.1);
275
- height: calc(var(--btn-height) * 1.2 - var(--bgl_tabs-block-padding) * 2);
274
+ font-size: calc(var(--bgl-input-font-size) * 1.1);
275
+ height: calc(var(--bgl-btn-height) * 1.2 - var(--bgl_tabs-block-padding) * 2);
276
276
  }
277
277
 
278
278
  .bgl_tab-xl {
279
279
  padding-inline: calc(var(--bgl_tab-inline-padding) * 1.6);
280
- font-size: calc(var(--input-font-size) * 1.3);
281
- height: calc(var(--btn-height) * 1.5 - var(--bgl_tabs-block-padding) * 2);
280
+ font-size: calc(var(--bgl-input-font-size) * 1.3);
281
+ height: calc(var(--bgl-btn-height) * 1.5 - var(--bgl_tabs-block-padding) * 2);
282
282
  }
283
283
 
284
284
  .bgl_tab-align-start {
@@ -0,0 +1,44 @@
1
+ import type { InjectionKey, Ref } from 'vue'
2
+ import { inject, ref } from 'vue'
3
+
4
+ export const SIDEBAR_COLLAPSED_WIDTH = '66px'
5
+ export const SIDEBAR_COLLAPSED_WIDTH_CARD = '82px'
6
+
7
+ export interface AppLayoutContext {
8
+ /** Sidebar open (expanded) state */
9
+ isOpen: Ref<boolean>
10
+ /** Viewport is below MOBILE_BREAKPOINT */
11
+ isMobile: Ref<boolean>
12
+ toggleMenu: () => void
13
+ /** Close the sidebar when on mobile (e.g. after navigating) */
14
+ closeOnMobile: () => void
15
+ sidebarWidth: string
16
+ sidebarCollapsedWidth: string
17
+ /** Sidebar rendered as a floating card */
18
+ sidebarCardStyle: boolean
19
+ }
20
+
21
+ export const AppLayoutKey: InjectionKey<AppLayoutContext> = Symbol('AppLayout')
22
+
23
+ /**
24
+ * Access the AppLayout context (sidebar open state, mobile flag, toggle).
25
+ * Works inside AppLayout's slots — including custom header buttons.
26
+ * Outside an AppLayout it warns (dev) and returns an inert fallback.
27
+ */
28
+ export function useAppLayout(): AppLayoutContext {
29
+ const ctx = inject(AppLayoutKey, null)
30
+ if (ctx) { return ctx }
31
+
32
+ if (import.meta.env?.DEV) {
33
+ console.warn('[bagelink] useAppLayout() called outside <AppLayout>. AppSidebar/AppContent are designed to be used inside it.')
34
+ }
35
+ return {
36
+ isOpen: ref(true),
37
+ isMobile: ref(false),
38
+ toggleMenu: () => {},
39
+ closeOnMobile: () => {},
40
+ sidebarWidth: '260px',
41
+ sidebarCollapsedWidth: SIDEBAR_COLLAPSED_WIDTH,
42
+ sidebarCardStyle: false,
43
+ }
44
+ }
@@ -1,6 +1,8 @@
1
1
  export { default as AppContent } from './AppContent.vue'
2
2
  export { default as AppLayout } from './AppLayout.vue'
3
3
  export { default as AppSidebar } from './AppSidebar.vue'
4
+ export { useAppLayout } from './appLayoutContext'
5
+ export type { AppLayoutContext } from './appLayoutContext'
4
6
  export { default as BottomMenu } from './BottomMenu.vue'
5
7
  export { default as Layout } from './Layout.vue'
6
8
  export { default as Panel } from './Panel.vue'
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { LightboxItem } from './lightbox.types'
3
3
 
4
- import { BglVideo, Btn, Icon, Zoomer, Image, normalizeURL, Swiper, downloadFile } from '@bagelink/vue'
4
+ import { BglVideo, Btn, Icon, Zoomer, Image, normalizeURL, Swiper, downloadFile, useEscapeKey } from '@bagelink/vue'
5
5
  import { computed, ref, watch } from 'vue'
6
6
 
7
7
  const isOpen = ref(false)
@@ -31,14 +31,14 @@ function open(item: LightboxItem, groupItems?: LightboxItem[]) {
31
31
  })
32
32
  if (currentIndex.value === -1) currentIndex.value = 0
33
33
  zoom.value = 1
34
- document.addEventListener('keydown', handleKeydown)
35
34
  }
36
35
 
37
36
  function close() {
38
37
  isOpen.value = false
39
- document.removeEventListener('keydown', handleKeydown)
40
38
  }
41
39
 
40
+ useEscapeKey(close, isOpen)
41
+
42
42
  function selectItem(index: number) {
43
43
  currentIndex.value = index
44
44
  zoom.value = 1
@@ -58,12 +58,6 @@ watch(() => currentIndex.value, () => {
58
58
  zoom.value = 1
59
59
  })
60
60
 
61
- function handleKeydown(event: KeyboardEvent) {
62
- if (event.key === 'Escape') {
63
- close()
64
- }
65
- }
66
-
67
61
  defineExpose({ open, close })
68
62
  </script>
69
63
 
@@ -6,6 +6,7 @@ import { computed, toValue } from 'vue'
6
6
 
7
7
  export { useAddToCalendar } from './useAddToCalendar'
8
8
  export { useDevice } from './useDevice'
9
+ export { useEscapeKey } from './useEscapeKey'
9
10
  export { useExcel } from './useExcel'
10
11
  export { useLocalStore } from './useLocalStore'
11
12
  export { usePolling } from './usePolling'
@@ -1,4 +1,5 @@
1
1
  import { onMounted, onUnmounted, ref } from 'vue'
2
+ import { MOBILE_BREAKPOINT } from '../utils/constants'
2
3
 
3
4
  export function useDevice() {
4
5
  const innerWidth = ref(0)
@@ -20,7 +21,7 @@ export function useDevice() {
20
21
 
21
22
  // Update current values
22
23
  innerWidth.value = window.innerWidth
23
- isMobile.value = window.innerWidth < 768
24
+ isMobile.value = window.innerWidth <= MOBILE_BREAKPOINT
24
25
  scrollY.value = window.scrollY
25
26
  scrollX.value = window.scrollX
26
27
  innerHeight.value = window.innerHeight
@@ -0,0 +1,56 @@
1
+ import type { MaybeRefOrGetter } from 'vue'
2
+ import { onBeforeUnmount, onMounted, toValue } from 'vue'
3
+
4
+ interface EscapeEntry {
5
+ handler: (e: KeyboardEvent) => void
6
+ enabled: () => boolean
7
+ }
8
+
9
+ const stack: EscapeEntry[] = []
10
+ let listening = false
11
+
12
+ function onDocumentKeydown(e: KeyboardEvent) {
13
+ if (e.key !== 'Escape') { return }
14
+ // LIFO: the most recently mounted (topmost) active layer handles Escape
15
+ for (let i = stack.length - 1; i >= 0; i--) {
16
+ if (stack[i].enabled()) {
17
+ stack[i].handler(e)
18
+ return
19
+ }
20
+ }
21
+ }
22
+
23
+ function syncListener() {
24
+ if (typeof document === 'undefined') { return }
25
+ if (stack.length > 0 && !listening) {
26
+ document.addEventListener('keydown', onDocumentKeydown)
27
+ listening = true
28
+ } else if (stack.length === 0 && listening) {
29
+ document.removeEventListener('keydown', onDocumentKeydown)
30
+ listening = false
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Run a handler when Escape is pressed, while `enabled` is truthy.
36
+ * - One shared document listener for the whole app
37
+ * - LIFO: the most recently mounted active layer wins (dropdown inside a lightbox closes first)
38
+ * - Automatically cleaned up on unmount
39
+ *
40
+ * @example
41
+ * useEscapeKey(() => close(), () => isOpen.value)
42
+ */
43
+ export function useEscapeKey(handler: (e: KeyboardEvent) => void, enabled: MaybeRefOrGetter<boolean> = true) {
44
+ const entry: EscapeEntry = { handler, enabled: () => !!toValue(enabled) }
45
+
46
+ onMounted(() => {
47
+ stack.push(entry)
48
+ syncListener()
49
+ })
50
+
51
+ onBeforeUnmount(() => {
52
+ const i = stack.indexOf(entry)
53
+ if (i !== -1) { stack.splice(i, 1) }
54
+ syncListener()
55
+ })
56
+ }
@@ -4,7 +4,6 @@ import type { Field, Attributes, Path, SchemaChild, BaseBagelField, VNodeFn } fr
4
4
  import {
5
5
  TextInput,
6
6
  NumberInput,
7
- FieldArray,
8
7
  SelectInput,
9
8
  ToggleInput,
10
9
  CheckInput,
@@ -12,7 +11,6 @@ import {
12
11
  UploadInput,
13
12
  DateInput,
14
13
  TabsNav,
15
- BglForm,
16
14
  bindAttrs,
17
15
  classify,
18
16
  keyToLabel,
@@ -74,7 +72,7 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
74
72
  text: TextInput,
75
73
  textarea: TextInput,
76
74
  number: NumberInput,
77
- array: FieldArray,
75
+ array: 'div',
78
76
  color: ColorInput,
79
77
  tel: TelInput,
80
78
  select: SelectInput,
@@ -85,7 +83,7 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
85
83
  file: UploadInput,
86
84
  date: DateInput,
87
85
  tabs: TabsNav,
88
- form: BglForm,
86
+ form: 'div',
89
87
  range: RangeInput,
90
88
  email: EmailInput
91
89
  }
@@ -195,19 +193,6 @@ export function useSchemaField<T extends { [key: string]: any }>(optns: UseSchem
195
193
  defaultValue,
196
194
  }
197
195
 
198
- // Special handling for FieldArray component to pass attrs.schema as schema prop
199
- if (Component === FieldArray && field.attrs?.schema) {
200
- props.schema = field.attrs.schema
201
- }
202
- // Special handling for FieldArray component to pass attrs.type as type prop
203
- if (Component === FieldArray && field.attrs?.type) {
204
- props.type = field.attrs.type
205
- }
206
- // Special handling for FieldArray component to pass collapsed prop
207
- if (Component === FieldArray && 'collapsed' in field) {
208
- props.collapsed = (field as any).collapsed
209
- }
210
-
211
196
  // Wire top-level onClick with conditional args
212
197
  if (typeof (field as any).onClick === 'function') {
213
198
  const original = (field as any).onClick as (val?: any, row?: T) => void
@@ -1,5 +1,5 @@
1
1
  // composables/useTheme.ts
2
- import { ref, computed, onMounted, watch } from 'vue'
2
+ import { ref, computed, watch } from 'vue'
3
3
 
4
4
  export interface ThemeOption {
5
5
  value: string
@@ -118,33 +118,37 @@ function addTheme(theme: ThemeOption) {
118
118
  * setTheme('ocean')
119
119
  */
120
120
 
121
- export function useTheme() {
122
- onMounted(() => {
123
- const saved = window.localStorage.getItem(STORAGE_KEY)
124
- const validTheme = themeOptions.value.find(t => t.value === saved)
121
+ // Module-level one-time init: a single matchMedia listener and a single
122
+ // colorMode watcher, no matter how many components call useTheme().
123
+ let initialized = false
125
124
 
126
- if (validTheme) {
127
- colorMode.value = saved!
128
- }
125
+ function initTheme() {
126
+ if (initialized || !isBrowser) { return }
127
+ initialized = true
128
+
129
+ const saved = window.localStorage.getItem(STORAGE_KEY)
130
+ if (themeOptions.value.some(t => t.value === saved)) {
131
+ colorMode.value = saved!
132
+ }
129
133
 
130
- // Apply initial theme
131
- applyTheme(colorMode.value)
134
+ applyTheme(colorMode.value)
132
135
 
133
- // React to system changes when in "system" mode
134
- const mq = window.matchMedia('(prefers-color-scheme: dark)')
135
- const handler = (e: MediaQueryListEvent) => {
136
- if (colorMode.value === 'system') {
137
- applyTheme('system')
138
- }
136
+ // React to system changes when in "system" mode
137
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
138
+ if (colorMode.value === 'system') {
139
+ applyTheme('system')
139
140
  }
140
- mq.addEventListener('change', handler)
141
141
  })
142
142
 
143
- // Watch for mode changes
143
+ // Persist + apply on mode changes
144
144
  watch(colorMode, (newMode) => {
145
- if (isBrowser) localStorage.setItem(STORAGE_KEY, newMode)
145
+ localStorage.setItem(STORAGE_KEY, newMode)
146
146
  applyTheme(newMode)
147
147
  })
148
+ }
149
+
150
+ export function useTheme() {
151
+ initTheme()
148
152
 
149
153
  const theme = computed(() => colorMode.value)
150
154
 
@@ -10,6 +10,7 @@ import EmailInput from '../components/form/inputs/EmailInput.vue'
10
10
  import NumberInput from '../components/form/inputs/NumberInput.vue'
11
11
  import PasswordInput from '../components/form/inputs/PasswordInput.vue'
12
12
  import RadioGroup from '../components/form/inputs/RadioGroup.vue'
13
+ import RangeInput from '../components/form/inputs/RangeInput.vue'
13
14
  import RichText from '../components/form/inputs/RichText/index.vue'
14
15
  import SelectBtn from '../components/form/inputs/SelectBtn.vue'
15
16
  import SelectInput from '../components/form/inputs/SelectInput.vue'
@@ -223,6 +224,7 @@ function getFieldComponent(fieldOrType: FieldBuilder | string) {
223
224
  array: ArrayInput,
224
225
  upload: UploadInput,
225
226
  color: ColorInput,
227
+ range: RangeInput,
226
228
  }
227
229
 
228
230
  return (componentMap[type] as typeof TextInput | undefined) ?? TextInput
@@ -358,6 +358,13 @@ export const $ = {
358
358
  return new Field('color', parseArgs(labelOrConfig, config))
359
359
  },
360
360
 
361
+ range(
362
+ labelOrConfig?: string | (BaseFieldConfig & { min?: number, max?: number, step?: number, multiRange?: boolean }),
363
+ config?: BaseFieldConfig & { min?: number, max?: number, step?: number, multiRange?: boolean }
364
+ ): FieldBuilder<number | [number, number]> {
365
+ return new Field('range', parseArgs(labelOrConfig, config))
366
+ },
367
+
361
368
  upload(
362
369
  labelOrConfig?: string | (BaseFieldConfig & {
363
370
  multiple?: boolean
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import './styles/bagel.css'
2
2
 
3
3
  export * from './components'
4
- export * from './components/form/useBagelFormState'
5
4
  export * from './composables'
6
5
  // Dialog (native <dialog> based)
7
6
  export * from './dialog'
@@ -23,14 +22,12 @@ export {
23
22
  useI18n,
24
23
  } from './i18n'
25
24
  export { type BagelOptions, BagelVue, getI18n } from './plugins/bagel'
26
- export { ModalPlugin, useModal } from './plugins/useModal'
27
25
 
28
26
  export { type BagelToastOptions, type ToastApi, ToastPlugin, useToast } from './plugins/useToast'
29
27
 
30
28
  export * from './types'
31
29
  export * from './utils'
32
30
  export * from './utils/allCountries'
33
- export * from './utils/BagelFormUtils'
34
31
  export * from './utils/calendar/dateUtils'
35
32
 
36
33
  export * from './utils/constants'
@@ -2,14 +2,12 @@ import type { Plugin } from 'vue'
2
2
  import type { CreateBagelI18nOptions } from '../i18n'
3
3
 
4
4
  import type { BagelToastOptions } from './useToast'
5
- import { configure } from '@bagelink/utils'
6
5
  import FloatingVue from 'floating-vue'
7
6
  import lightboxPlugin from '../components/lightbox/index'
8
7
  import { DialogPlugin } from '../dialog/useDialog'
9
8
  import { ripple, pattern } from '../directives'
10
9
  import { createI18n, getI18n } from '../i18n'
11
10
  import clickOutside from '../utils/clickOutside'
12
- import { ModalPlugin } from './useModal'
13
11
  import { ToastPlugin } from './useToast'
14
12
  import '@oddbird/popover-polyfill'
15
13
 
@@ -29,7 +27,6 @@ export const BagelVue: Plugin<BagelOptions> = {
29
27
  // Install UI plugins
30
28
  app.use(lightboxPlugin)
31
29
  app.use(DialogPlugin)
32
- app.use(ModalPlugin)
33
30
  app.use(ToastPlugin, options.toast || {})
34
31
 
35
32
  // Install FloatingVue for tooltips/popovers
@@ -46,18 +43,6 @@ export const BagelVue: Plugin<BagelOptions> = {
46
43
  // Setup i18n
47
44
  const i18n = createI18n(options.i18n || {})
48
45
  app.use(i18n as any)
49
-
50
- // Bridge locale into @bagelink/utils
51
- configure({
52
- locale: () => {
53
- try {
54
- const { locale } = getI18n().global
55
- return typeof locale === 'string' ? locale : locale.value
56
- } catch {
57
- return 'en'
58
- }
59
- },
60
- })
61
46
  },
62
47
  }
63
48