@bagelink/vue 1.6.43 → 1.6.49

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/bin/experimentalGenTypedRoutes.ts +18 -19
  2. package/bin/utils.ts +4 -4
  3. package/dist/components/AddressSearch.vue.d.ts.map +1 -1
  4. package/dist/components/Alert.vue.d.ts.map +1 -1
  5. package/dist/components/BglVideo.vue.d.ts.map +1 -1
  6. package/dist/components/Card.vue.d.ts.map +1 -1
  7. package/dist/components/Carousel.vue.d.ts +2 -2
  8. package/dist/components/Carousel.vue.d.ts.map +1 -1
  9. package/dist/components/Dropdown.vue.d.ts.map +1 -1
  10. package/dist/components/Flag.vue.d.ts.map +1 -1
  11. package/dist/components/IframeVue.vue.d.ts.map +1 -1
  12. package/dist/components/ListItem.vue.d.ts.map +1 -1
  13. package/dist/components/Loading.vue.d.ts.map +1 -1
  14. package/dist/components/Modal.vue.d.ts.map +1 -1
  15. package/dist/components/ModalForm.vue.d.ts.map +1 -1
  16. package/dist/components/NavBar.vue.d.ts +1 -1
  17. package/dist/components/Pill.vue.d.ts.map +1 -1
  18. package/dist/components/Swiper.vue.d.ts +12 -4
  19. package/dist/components/Swiper.vue.d.ts.map +1 -1
  20. package/dist/components/Zoomer.vue.d.ts.map +1 -1
  21. package/dist/components/analytics/LineChart.vue.d.ts.map +1 -1
  22. package/dist/components/analytics/PieChart.vue.d.ts +2 -1
  23. package/dist/components/analytics/PieChart.vue.d.ts.map +1 -1
  24. package/dist/components/analytics/index.d.ts +1 -1
  25. package/dist/components/analytics/index.d.ts.map +1 -1
  26. package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
  27. package/dist/components/form/BglMultiStepForm.vue.d.ts.map +1 -1
  28. package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
  29. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  30. package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
  31. package/dist/components/form/inputs/RadioGroup.vue.d.ts.map +1 -1
  32. package/dist/components/form/inputs/RangeInput.vue.d.ts +11 -11
  33. package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
  34. package/dist/components/form/inputs/RichText/components/TableGridSelector.vue.d.ts.map +1 -1
  35. package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
  36. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  37. package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
  38. package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
  39. package/dist/components/layout/AppSidebar.vue.d.ts +1 -0
  40. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
  41. package/dist/components/layout/Layout.vue.d.ts.map +1 -1
  42. package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
  43. package/dist/components/layout/index.d.ts +3 -3
  44. package/dist/components/layout/index.d.ts.map +1 -1
  45. package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
  46. package/dist/index.cjs +24 -15
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.mjs +1530 -1404
  50. package/dist/plugins/modalTypes.d.ts +1 -8
  51. package/dist/plugins/modalTypes.d.ts.map +1 -1
  52. package/dist/plugins/useModal.d.ts.map +1 -1
  53. package/dist/style.css +1 -1
  54. package/package.json +1 -2
  55. package/src/components/AccordionItem.vue +13 -13
  56. package/src/components/AddToCalendar.vue +1 -1
  57. package/src/components/AddressSearch.vue +9 -8
  58. package/src/components/Alert.vue +2 -1
  59. package/src/components/Badge.vue +5 -5
  60. package/src/components/BglVideo.vue +44 -45
  61. package/src/components/Btn.vue +15 -15
  62. package/src/components/Card.vue +10 -8
  63. package/src/components/Carousel.vue +159 -162
  64. package/src/components/DataPreview.vue +1 -1
  65. package/src/components/DragOver.vue +6 -6
  66. package/src/components/Dropdown.vue +39 -38
  67. package/src/components/Flag.vue +7 -6
  68. package/src/components/Icon/Icon.vue +22 -22
  69. package/src/components/IframeVue.vue +5 -5
  70. package/src/components/Image.vue +17 -17
  71. package/src/components/ImportData.vue +79 -79
  72. package/src/components/ListItem.vue +12 -11
  73. package/src/components/Loading.vue +10 -9
  74. package/src/components/MapEmbed/Index.vue +24 -24
  75. package/src/components/Modal.vue +11 -9
  76. package/src/components/ModalForm.vue +15 -11
  77. package/src/components/NavBar.vue +6 -6
  78. package/src/components/Pagination.vue +27 -27
  79. package/src/components/Pill.vue +11 -12
  80. package/src/components/Rating.vue +2 -2
  81. package/src/components/Slider.vue +75 -75
  82. package/src/components/Spreadsheet/Index.vue +34 -34
  83. package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
  84. package/src/components/Swiper.vue +4 -4
  85. package/src/components/Zoomer.vue +282 -182
  86. package/src/components/analytics/BarChart.vue +6 -6
  87. package/src/components/analytics/KpiCard.vue +2 -2
  88. package/src/components/analytics/LineChart.vue +63 -61
  89. package/src/components/analytics/PieChart.vue +104 -90
  90. package/src/components/analytics/index.ts +2 -2
  91. package/src/components/calendar/CalendarPopover.vue +1 -1
  92. package/src/components/calendar/Index.vue +1 -1
  93. package/src/components/calendar/views/AgendaView.vue +3 -3
  94. package/src/components/calendar/views/DayView.vue +6 -6
  95. package/src/components/calendar/views/MonthView.vue +2 -2
  96. package/src/components/calendar/views/WeekView.vue +18 -18
  97. package/src/components/dataTable/DataTable.vue +4 -4
  98. package/src/components/dataTable/useSorting.ts +1 -1
  99. package/src/components/dataTable/useTableData.ts +15 -15
  100. package/src/components/dataTable/useTableSelection.ts +15 -15
  101. package/src/components/dataTable/useTableVirtualization.ts +1 -1
  102. package/src/components/draggable/useDraggable.ts +42 -42
  103. package/src/components/form/BagelForm.vue +15 -15
  104. package/src/components/form/BglFieldSet.vue +5 -3
  105. package/src/components/form/BglMultiStepForm.vue +20 -21
  106. package/src/components/form/inputs/CheckInput.vue +2 -2
  107. package/src/components/form/inputs/CodeEditor/format.ts +7 -7
  108. package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
  109. package/src/components/form/inputs/ColorInput.vue +5 -4
  110. package/src/components/form/inputs/DateInput.vue +8 -9
  111. package/src/components/form/inputs/DatePicker.vue +24 -24
  112. package/src/components/form/inputs/EmailInput.vue +24 -24
  113. package/src/components/form/inputs/NumberInput.vue +26 -26
  114. package/src/components/form/inputs/OTP.vue +7 -7
  115. package/src/components/form/inputs/PasswordInput.vue +3 -2
  116. package/src/components/form/inputs/RadioGroup.vue +28 -25
  117. package/src/components/form/inputs/RadioPillsInput.vue +12 -12
  118. package/src/components/form/inputs/RangeInput.vue +21 -21
  119. package/src/components/form/inputs/RichText/components/EditorToolbar.vue +107 -92
  120. package/src/components/form/inputs/RichText/components/TableGridSelector.vue +64 -64
  121. package/src/components/form/inputs/RichText/components/gridBox.vue +10 -8
  122. package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
  123. package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
  124. package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
  125. package/src/components/form/inputs/RichText/index.vue +138 -138
  126. package/src/components/form/inputs/RichText/utils/commands.ts +84 -85
  127. package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
  128. package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
  129. package/src/components/form/inputs/RichText/utils/media.ts +7 -7
  130. package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
  131. package/src/components/form/inputs/RichText/utils/table.ts +19 -19
  132. package/src/components/form/inputs/SelectBtn.vue +1 -1
  133. package/src/components/form/inputs/SelectInput.vue +54 -54
  134. package/src/components/form/inputs/SignaturePad.vue +40 -40
  135. package/src/components/form/inputs/TableField.vue +1 -1
  136. package/src/components/form/inputs/TelInput.vue +54 -53
  137. package/src/components/form/inputs/TextInput.vue +19 -19
  138. package/src/components/form/inputs/ToggleInput.vue +2 -2
  139. package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
  140. package/src/components/form/useBagelFormState.ts +5 -5
  141. package/src/components/layout/AppContent.vue +6 -3
  142. package/src/components/layout/AppLayout.vue +2 -2
  143. package/src/components/layout/AppSidebar.vue +83 -16
  144. package/src/components/layout/Layout.vue +12 -10
  145. package/src/components/layout/SidebarMenu.vue +4 -4
  146. package/src/components/layout/TabbedLayout.vue +17 -17
  147. package/src/components/layout/Tabs.vue +4 -5
  148. package/src/components/layout/TabsNav.vue +14 -14
  149. package/src/components/layout/index.ts +3 -5
  150. package/src/components/lightbox/Lightbox.vue +276 -126
  151. package/src/components/lightbox/index.ts +8 -8
  152. package/src/composables/index.ts +8 -8
  153. package/src/composables/useAddToCalendar.ts +13 -13
  154. package/src/composables/useDevice.ts +2 -2
  155. package/src/composables/useFormField.ts +4 -4
  156. package/src/composables/usePolling.ts +8 -8
  157. package/src/composables/useSchemaField.ts +38 -38
  158. package/src/composables/useTheme.ts +9 -9
  159. package/src/composables/useValidateFieldValue.ts +2 -2
  160. package/src/directives/pattern.ts +25 -25
  161. package/src/directives/ripple.ts +4 -4
  162. package/src/directives/vResize.ts +6 -6
  163. package/src/index.ts +1 -0
  164. package/src/plugins/bagel.ts +4 -4
  165. package/src/plugins/modalTypes.ts +1 -8
  166. package/src/plugins/useModal.ts +43 -18
  167. package/src/styles/layout.css +1 -1
  168. package/src/types/index.ts +1 -1
  169. package/src/utils/BagelFormUtils.ts +7 -7
  170. package/src/utils/calendar/Helpers.ts +8 -8
  171. package/src/utils/calendar/dateUtils.ts +22 -22
  172. package/src/utils/calendar/time.ts +25 -25
  173. package/src/utils/calendar/week.ts +25 -25
  174. package/src/utils/elementUtils.ts +27 -27
  175. package/src/utils/sizeParsing.ts +2 -2
  176. package/src/utils/strings.ts +5 -5
  177. package/src/utils/tapDetector.ts +11 -11
  178. package/src/utils/useSearch.ts +29 -29
  179. package/vite.config.ts +0 -2
@@ -8,7 +8,7 @@ import {
8
8
  } from '@bagelink/vue'
9
9
  import { until } from '@vueuse/core'
10
10
 
11
- import { onMounted, watch, nextTick } from 'vue'
11
+ import { computed, onMounted, ref, watch, nextTick } from 'vue'
12
12
 
13
13
  export interface TextInputProps extends ValidateInputBaseT {
14
14
  id?: string
@@ -44,40 +44,40 @@ const props = withDefaults(defineProps<TextInputProps>(), {
44
44
  modelValue: '',
45
45
  })
46
46
  const emit = defineEmits(['update:modelValue', 'debounce'])
47
- let inputVal = $ref<string | number>()
47
+ const inputVal = ref<string | number>()
48
48
 
49
- const input = $ref<HTMLTextAreaElement | HTMLInputElement>()
49
+ const input = ref<HTMLTextAreaElement | HTMLInputElement>()
50
50
 
51
51
  useValidateFieldValue(
52
- () => inputVal,
53
- () => input,
52
+ () => inputVal.value,
53
+ () => input.value,
54
54
  props.validate,
55
55
  props.getFormData
56
56
  )
57
57
 
58
- const inputRows = $computed(() => {
58
+ const inputRows = computed(() => {
59
59
  let rows = Number(props.rows) || 1
60
60
  if (props.autoheight)
61
- {rows = Math.max(rows, String(inputVal).split('\n').length)}
62
- if (props.multiline || props.code) {rows = Math.max(rows, 4)}
61
+ { rows = Math.max(rows, String(inputVal.value).split('\n').length) }
62
+ if (props.multiline || props.code) { rows = Math.max(rows, 4) }
63
63
  return rows
64
64
  })
65
65
 
66
66
  const debouncedEmit = useDebounceFn(() => {
67
- emit('debounce', inputVal as string)
67
+ emit('debounce', inputVal.value as string)
68
68
  }, 700)
69
69
 
70
70
  function autoResizeTextarea() {
71
- if (!props.autoheight || !input || 'TEXTAREA' !== input.tagName) {return}
71
+ if (!props.autoheight || !input.value || input.value.tagName !== 'TEXTAREA') { return }
72
72
 
73
- const textarea = input as HTMLTextAreaElement
73
+ const textarea = input.value as HTMLTextAreaElement
74
74
  textarea.style.height = 'auto'
75
75
  textarea.style.height = `${textarea.scrollHeight + 1}px`
76
76
  }
77
77
 
78
78
  function updateInputVal() {
79
- if (props.disabled) {return}
80
- emit('update:modelValue', inputVal as string)
79
+ if (props.disabled) { return }
80
+ emit('update:modelValue', inputVal.value as string)
81
81
  debouncedEmit()
82
82
 
83
83
  if (props.autoheight) {
@@ -88,8 +88,8 @@ function updateInputVal() {
88
88
  watch(
89
89
  () => props.modelValue,
90
90
  (newVal) => {
91
- if (newVal !== inputVal) {
92
- inputVal = newVal
91
+ if (newVal !== inputVal.value) {
92
+ inputVal.value = newVal
93
93
  if (props.autoheight) {
94
94
  nextTick(() => { autoResizeTextarea() })
95
95
  }
@@ -98,15 +98,15 @@ watch(
98
98
  { immediate: true }
99
99
  )
100
100
 
101
- const hasFocus = () => document.activeElement === input
102
- const focus = () => input?.focus()
101
+ const hasFocus = () => document.activeElement === input.value
102
+ const focus = () => input.value?.focus()
103
103
  defineExpose({ focus, hasFocus })
104
104
 
105
105
  onMounted(async () => {
106
106
  if (props.autofocus) {
107
- await until(() => input).toBeTruthy()
107
+ await until(() => input.value).toBeTruthy()
108
108
  await sleep(400)
109
- input?.focus()
109
+ input.value?.focus()
110
110
  }
111
111
  // Don't auto-restore defaultValue - let user control their own content
112
112
 
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { onMounted } from 'vue'
2
+ import { computed, onMounted } from 'vue'
3
3
 
4
4
  const props = withDefaults(defineProps<{
5
5
  label?: string
@@ -10,7 +10,7 @@ const props = withDefaults(defineProps<{
10
10
  defaultValue?: boolean
11
11
  }>(), { defaultValue: false })
12
12
 
13
- const inputId = $ref(props.id || Math.random().toString(36).slice(7))
13
+ const inputId = computed(() => props.id || Math.random().toString(36).slice(7))
14
14
 
15
15
  const checked = defineModel<boolean | undefined>('modelValue', { default: undefined })
16
16
 
@@ -32,7 +32,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
32
32
  const fileToUrl = (file: File) => URL.createObjectURL(file)
33
33
 
34
34
  function addFile(file?: File | File[] | FileList | null) {
35
- if (!file) {return}
35
+ if (!file) { return }
36
36
 
37
37
  let filesToAdd: File[] = []
38
38
 
@@ -58,18 +58,18 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
58
58
  }
59
59
 
60
60
  // Call the onFilesQueued callback if provided
61
- if (props.onFileQueued && 0 < newQueueFiles.length) {
61
+ if (props.onFileQueued && newQueueFiles.length > 0) {
62
62
  props.onFileQueued(newQueueFiles)
63
63
  }
64
64
  }
65
65
 
66
66
  async function removeFile(pathKeyOrFile: string | File | QueueFile) {
67
- if ('string' === typeof pathKeyOrFile) {
67
+ if (typeof pathKeyOrFile === 'string') {
68
68
  // Remove from both lists
69
69
  storageFiles.value = storageFiles.value.filter(file => file.path_key !== pathKeyOrFile)
70
70
 
71
71
  const pathKeyIndex = pk.value.indexOf(pathKeyOrFile)
72
- if (-1 !== pathKeyIndex) {
72
+ if (pathKeyIndex !== -1) {
73
73
  pk.value.splice(pathKeyIndex, 1)
74
74
  }
75
75
 
@@ -88,7 +88,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
88
88
  && queueFile.namespace === namespace
89
89
  )
90
90
 
91
- if (-1 !== index) {
91
+ if (index !== -1) {
92
92
  fileQueue.value.splice(index, 1)
93
93
  }
94
94
  }
@@ -124,7 +124,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
124
124
 
125
125
  // UI interaction
126
126
  function browse(autoFlush = false) {
127
- if (props.disabled) {return}
127
+ if (props.disabled) { return }
128
128
 
129
129
  const input = document.createElement('input')
130
130
  input.type = 'file'
@@ -13,11 +13,11 @@ export interface BagelFormState<T> {
13
13
 
14
14
  // Helper function to safely clone objects without circular references
15
15
  function safeClone(obj: any): any {
16
- if (null === obj || 'object' !== typeof obj) {return obj}
16
+ if (obj === null || typeof obj !== 'object') { return obj }
17
17
 
18
18
  const seen = new WeakSet()
19
19
  return JSON.parse(JSON.stringify(obj, (key, value) => {
20
- if ('object' === typeof value && null !== value) {
20
+ if (typeof value === 'object' && value !== null) {
21
21
  if (seen.has(value)) {
22
22
  return undefined // Remove circular reference
23
23
  }
@@ -37,7 +37,7 @@ export function provideBagelFormState<T>(initialData: T) {
37
37
  const keys = path.split(/[.[]/)
38
38
 
39
39
  // Initialize the root if it's not an object
40
- if ('object' !== typeof data.value || null === data.value) {
40
+ if (typeof data.value !== 'object' || data.value === null) {
41
41
  data.value = {} as T
42
42
  }
43
43
 
@@ -46,7 +46,7 @@ export function provideBagelFormState<T>(initialData: T) {
46
46
  // Build the path, ensuring each level is an object
47
47
  for (let i = 0; i < keys.length - 1; i++) {
48
48
  const key = keys[i]
49
- if (!(key in current) || 'object' !== typeof current[key] || null === current[key]) {
49
+ if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
50
50
  current[key] = {}
51
51
  }
52
52
  current = current[key]
@@ -71,6 +71,6 @@ export function provideBagelFormState<T>(initialData: T) {
71
71
 
72
72
  export function useBagelFormState<T>(injectionKey: typeof FORM_STATE_KEY = FORM_STATE_KEY): BagelFormState<T> {
73
73
  const state = inject<BagelFormState<T>>(injectionKey)
74
- if (!state) {throw new Error('BagelFormState must be provided')}
74
+ if (!state) { throw new Error('BagelFormState must be provided') }
75
75
  return state
76
76
  }
@@ -18,7 +18,11 @@ withDefaults(defineProps<Props>(), {
18
18
  })
19
19
 
20
20
  // Inject menu state from parent
21
- const menuState = inject('menuState') as {
21
+ const menuState = inject('menuState', {
22
+ isOpen: { value: true },
23
+ isMobile: { value: false },
24
+ toggleMenu: () => { },
25
+ }) as {
22
26
  isOpen: { value: boolean }
23
27
  isMobile: { value: boolean }
24
28
  toggleMenu: () => void
@@ -83,8 +87,7 @@ const hasSidebarCard = computed(() => {
83
87
 
84
88
  <!-- Page Content -->
85
89
  <main
86
- class="pageContent flex-grow overflow pt-1 pb-05 w-100p m_p-05 m_scrollbar-gutter-auto m_vw100"
87
- :class="{
90
+ class="pageContent flex-grow overflow pt-1 pb-05 w-100p m_p-05 m_scrollbar-gutter-auto m_vw100" :class="{
88
91
  'px-1': !hasSidebarCard,
89
92
  }"
90
93
  >
@@ -17,7 +17,7 @@ const isMobile = ref(false)
17
17
 
18
18
  // Check if mobile
19
19
  function checkMobile() {
20
- isMobile.value = 910 > window.innerWidth
20
+ isMobile.value = window.innerWidth < 910
21
21
  if (isMobile.value) {
22
22
  isOpen.value = false
23
23
  }
@@ -128,7 +128,7 @@ onUnmounted(() => {
128
128
  transition: margin-inline-start 400ms ease;
129
129
  min-height: 100vh
130
130
  }
131
-
131
+
132
132
  .page-content {
133
133
  overflow: auto;
134
134
  }
@@ -7,6 +7,7 @@ import { useRoute } from 'vue-router'
7
7
  // Extended interface for links that can have actions
8
8
  interface LinkWithAction extends NavLink {
9
9
  action?: () => void
10
+ activeRoutes?: string[] // נתיבים שצריכים להיות מסומנים כאקטיביים עבור הלינק הזה
10
11
  }
11
12
 
12
13
  interface Props {
@@ -38,7 +39,13 @@ const route = useRoute()
38
39
  const isTransitioning = ref(false)
39
40
 
40
41
  // Inject menu state from parent
41
- const menuState = inject('menuState') as {
42
+ const menuState = inject('menuState', {
43
+ isOpen: { value: true },
44
+ isMobile: { value: false },
45
+ closeOnMobile: () => void 0,
46
+ sidebarWidth: '260px',
47
+ sidebarCollapsedWidth: '66px',
48
+ }) as {
42
49
  isOpen: { value: boolean }
43
50
  isMobile: { value: boolean }
44
51
  closeOnMobile: () => void
@@ -60,6 +67,58 @@ watch(
60
67
  }
61
68
  )
62
69
 
70
+ // Check if a route is active (exact match, parent route, or custom activeRoutes)
71
+ function isActiveRoute(link: LinkWithAction): boolean {
72
+ const linkPath = link.to
73
+
74
+ if (!linkPath) {
75
+ return false
76
+ }
77
+
78
+ // אם יש activeRoutes מותאמים אישית, השתמש בהם בלבד
79
+ if (link.activeRoutes && link.activeRoutes.length > 0) {
80
+ return link.activeRoutes.some((activePath) => {
81
+ if (activePath === '/') {
82
+ return route.path === activePath
83
+ }
84
+ return route.path === activePath || route.path.startsWith(`${activePath}/`)
85
+ })
86
+ }
87
+
88
+ // אחרת, השתמש בלוגיקה האוטומטית הרגילה
89
+ if (linkPath === '/') {
90
+ return route.path === linkPath
91
+ }
92
+
93
+ // Exact match
94
+ if (route.path === linkPath) {
95
+ return true
96
+ }
97
+
98
+ // Check if current path starts with link path followed by a slash
99
+ // This handles nested routes like /organizations/id/settings
100
+ if (route.path.startsWith(`${linkPath}/`)) {
101
+ return true
102
+ }
103
+
104
+ // Handle dynamic routes - if linkPath has multiple segments and current path matches the pattern
105
+ const linkSegments = linkPath.split('/').filter(Boolean)
106
+ const routeSegments = route.path.split('/').filter(Boolean)
107
+
108
+ // If link has fewer segments than current route, check if the beginning matches
109
+ if (linkSegments.length <= routeSegments.length) {
110
+ return linkSegments.every((segment, index) => {
111
+ // Allow UUID-like patterns to match
112
+ if (segment.match(/^[a-f0-9-]{36}$/i) && routeSegments[index]?.match(/^[a-f0-9-]{36}$/i)) {
113
+ return true
114
+ }
115
+ return segment === routeSegments[index]
116
+ })
117
+ }
118
+
119
+ return false
120
+ }
121
+
63
122
  // Computed styles
64
123
  const sidebarStyles = computed(() => {
65
124
  let width = '280px'
@@ -117,15 +176,19 @@ const sidebarStyles = computed(() => {
117
176
  <!-- Navigation Links -->
118
177
  <nav class="sidebar-nav flex column flex-stretch gap-025 align-items-start scrollbar-gutter-stable">
119
178
  <Btn
120
- v-for="link in props.navLinks" :key="link.to" :title="!menuState.isOpen.value && !menuState.isMobile.value
121
- ? link.label
122
- : ''
123
- " fullWidth alignTxt="start" class="flex-shrink-0 px-1" :class="{ 'nav-btn-active': route.path === link.to }"
179
+ v-for="link in props.navLinks"
180
+ :key="link.to"
181
+ :title="!menuState.isOpen.value && !menuState.isMobile.value ? link.label : ''"
182
+ fullWidth
183
+ alignTxt="start"
184
+ class="flex-shrink-0 px-1"
185
+ :class="{ 'nav-btn-active': isActiveRoute(link) }"
124
186
  :style="{
125
- backgroundColor:
126
- route.path === link.to ? props.activeColor : props.bgColor,
127
- color: route.path === link.to ? 'white' : props.textColor,
128
- }" :to="link.to || '/'" @click="link.action"
187
+ backgroundColor: isActiveRoute(link) ? props.activeColor : props.bgColor,
188
+ color: isActiveRoute(link) ? 'white' : props.textColor,
189
+ }"
190
+ :to="link.to || '/'"
191
+ @click="link.action"
129
192
  >
130
193
  <Icon :name="link.icon" size="1.2" />
131
194
  <span class="nav-text">
@@ -134,15 +197,19 @@ const sidebarStyles = computed(() => {
134
197
  </Btn>
135
198
  </nav>
136
199
  <!-- Footer -->
137
- <div
138
- class="sidebar-footer flex column flex-stretch gap-025 align-items-start mt-auto scrollbar-gutter-stable"
139
- >
200
+ <div class="sidebar-footer flex column flex-stretch gap-025 align-items-start mt-auto">
140
201
  <!-- Footer Links -->
141
202
  <Btn
142
- v-for="link in props.footerLinks" :key="link.to || link.label" :title="!menuState.isOpen.value && !menuState.isMobile.value
143
- ? link.label
144
- : ''
145
- " alignTxt="start" fullWidth flat :icon="link.icon" class="flex-shrink-0 px-1" :to="link.to" @click="link.action"
203
+ v-for="link in props.footerLinks"
204
+ :key="link.to || link.label"
205
+ :title="!menuState.isOpen.value && !menuState.isMobile.value ? link.label : ''"
206
+ alignTxt="start"
207
+ fullWidth
208
+ flat
209
+ :icon="link.icon"
210
+ class="flex-shrink-0 px-1"
211
+ :to="link.to"
212
+ @click="link.action"
146
213
  >
147
214
  <span class="nav-text">
148
215
  {{ link.label }}
@@ -1,4 +1,6 @@
1
1
  <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+
2
4
  interface LayoutProrps {
3
5
  gap?: number
4
6
  h100?: boolean
@@ -20,20 +22,20 @@ const props = withDefaults(defineProps<LayoutProrps>(), {
20
22
 
21
23
  })
22
24
 
23
- const gridTemplateRows = $computed(() => (0 < props.rows.length ? props.rows.join(' ') : 'auto'))
24
- const gapSize = $computed(() => `${props.gap}rem`)
25
- const mGapSize = $computed(() => props.mGap !== undefined ? `${props.mGap}rem` : gapSize)
25
+ const gridTemplateRows = computed(() => (props.rows.length > 0 ? props.rows.join(' ') : 'auto'))
26
+ const gapSize = computed(() => `${props.gap}rem`)
27
+ const mGapSize = computed(() => props.mGap !== undefined ? `${props.mGap}rem` : gapSize.value)
26
28
 
27
- const mGridTemplateRows = $computed(() => {
28
- if (props.mRows?.length) {return props.mRows.join(' ')}
29
- return gridTemplateRows
29
+ const mGridTemplateRows = computed(() => {
30
+ if (props.mRows?.length) { return props.mRows.join(' ') }
31
+ return gridTemplateRows.value
30
32
  })
31
33
 
32
- const gridTemplateColumns = $computed(() => (0 < props.columns.length ? props.columns.join(' ') : 'auto'))
34
+ const gridTemplateColumns = computed(() => (props.columns.length > 0 ? props.columns.join(' ') : 'auto'))
33
35
 
34
- const mGridTemplateColumns = $computed(() => {
35
- if (props.mColumns?.length) {return props.mColumns.join(' ')}
36
- return gridTemplateColumns
36
+ const mGridTemplateColumns = computed(() => {
37
+ if (props.mColumns?.length) { return props.mColumns.join(' ') }
38
+ return gridTemplateColumns.value
37
39
  })
38
40
  </script>
39
41
 
@@ -2,7 +2,7 @@
2
2
  import type { NavLink } from '@bagelink/vue'
3
3
  import type { SetupContext } from 'vue'
4
4
  import { Btn, Card, Icon, useDebounceFn } from '@bagelink/vue'
5
- import { useSlots } from 'vue'
5
+ import { ref, useSlots } from 'vue'
6
6
 
7
7
  const props = defineProps<{
8
8
  navLinks?: NavLink[]
@@ -14,10 +14,10 @@ const emit = defineEmits(['update:open'])
14
14
 
15
15
  const slots: SetupContext['slots'] = useSlots()
16
16
 
17
- let isOpen = $ref(props.open)
17
+ const isOpen = ref(props.open)
18
18
  const toggleMenu = useDebounceFn(() => {
19
- isOpen = !isOpen
20
- emit('update:open', isOpen)
19
+ isOpen.value = !isOpen.value
20
+ emit('update:open', isOpen.value)
21
21
  })
22
22
  </script>
23
23
 
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { Raw } from 'vue'
3
3
  import type { Router } from 'vue-router'
4
- import { onMounted } from 'vue'
4
+ import { onMounted, ref } from 'vue'
5
5
 
6
6
  const props = defineProps<{
7
7
  title?: string
@@ -13,11 +13,11 @@ const props = defineProps<{
13
13
 
14
14
  const emit = defineEmits(['update:modelValue'])
15
15
 
16
- let activeTab = $ref<string>()
16
+ const activeTab = ref<string>()
17
17
  function changeTab(tab: string) {
18
- activeTab = tab
19
- emit('update:modelValue', activeTab)
20
- if (!props.router) {return}
18
+ activeTab.value = tab
19
+ emit('update:modelValue', activeTab.value)
20
+ if (!props.router) { return }
21
21
  void props.router.push({
22
22
  path: props.router.currentRoute.value.path,
23
23
  query: { ...props.router.currentRoute.value.query, t: tab },
@@ -27,10 +27,10 @@ function changeTab(tab: string) {
27
27
 
28
28
  onMounted(() => {
29
29
  const firstTab
30
- = props.modelValue
31
- || props.router?.currentRoute.value.query.t
32
- || props.tabs[0]
33
- activeTab = firstTab as string
30
+ = props.modelValue
31
+ || props.router?.currentRoute.value.query.t
32
+ || props.tabs[0]
33
+ activeTab.value = firstTab as string
34
34
  })
35
35
  </script>
36
36
 
@@ -58,25 +58,25 @@ onMounted(() => {
58
58
 
59
59
  <style scoped>
60
60
  .tab {
61
- text-transform: capitalize;
61
+ text-transform: capitalize;
62
62
  }
63
63
 
64
64
  .side-tabs {
65
- display: flex;
65
+ display: flex;
66
66
  }
67
67
 
68
68
  .side-tabs .tabs-top {
69
- margin-inline-end: 1rem;
69
+ margin-inline-end: 1rem;
70
70
  }
71
71
 
72
72
  .side-tabs .tabs {
73
- display: block;
74
- padding: 0;
75
- margin: 0;
76
- border: none;
73
+ display: block;
74
+ padding: 0;
75
+ margin: 0;
76
+ border: none;
77
77
  }
78
78
 
79
79
  .side-tabs .tab {
80
- border: none;
80
+ border: none;
81
81
  }
82
82
  </style>
@@ -2,7 +2,7 @@
2
2
  import type { Tab } from '@bagelink/vue'
3
3
  import type { SetupContext, VNode } from 'vue'
4
4
  import { TabsNav } from '@bagelink/vue'
5
- import { defineComponent, h, useSlots } from 'vue'
5
+ import { computed, defineComponent, h, useSlots } from 'vue'
6
6
 
7
7
  import { useTabs } from './tabsManager'
8
8
 
@@ -17,9 +17,9 @@ const slots: SetupContext['slots'] = useSlots()
17
17
  const group = Math.random().toString(36).slice(7)
18
18
  const { currentTab } = useTabs(group)
19
19
 
20
- const tabValue = (tab: Tab) => ('string' === typeof tab ? tab : tab.id)
20
+ const tabValue = (tab: Tab) => (typeof tab === 'string' ? tab : tab.id)
21
21
 
22
- const slctTab = $computed({
22
+ const slctTab = computed({
23
23
  get: () => props.modelValue || tabValue(props.tabs[0]),
24
24
  set: (value) => {
25
25
  emit('update:modelValue', value)
@@ -31,7 +31,7 @@ const tabComponent = defineComponent({
31
31
  const currentTabIndex = props.tabs.findIndex(
32
32
  tab => tabValue(tab) === currentTab.value
33
33
  )
34
- if (-1 === currentTabIndex) {return}
34
+ if (currentTabIndex === -1) { return }
35
35
  const slotChildren = slots.default?.()[1]?.children
36
36
 
37
37
  return h('div', (slotChildren as VNode[])[currentTabIndex])
@@ -39,7 +39,6 @@ const tabComponent = defineComponent({
39
39
  })
40
40
  </script>
41
41
 
42
- z
43
42
  <template>
44
43
  <TabsNav v-model="slctTab" :flat="flat" :tabs="tabs" :group class="mb-05" />
45
44
  <div v-if="currentTab">
@@ -23,7 +23,7 @@ const props = defineProps<{
23
23
  const emit = defineEmits(['update:modelValue'])
24
24
  const { currentTab } = useTabs(props.group)
25
25
  currentTab.value
26
- = props.modelValue || 'string' === typeof props.tabs[0]
26
+ = props.modelValue || typeof props.tabs[0] === 'string'
27
27
  ? props.tabs[0]
28
28
  : props.tabs[0].id
29
29
 
@@ -32,13 +32,13 @@ const tabs = ref<HTMLElement[]>([])
32
32
 
33
33
  function updateIndicator() {
34
34
  nextTick(() => {
35
- if (!tabsWrap.value) {return}
35
+ if (!tabsWrap.value) { return }
36
36
  const activeTab = tabs.value.find(tab => tab.classList.contains('active'))
37
37
  if (activeTab) {
38
38
  // Wait a bit more to ensure CSS is fully loaded and elements are properly sized
39
39
  setTimeout(() => {
40
40
  const { offsetLeft, offsetWidth } = activeTab
41
- if (0 <= offsetLeft && 0 < offsetWidth) { // Ensure valid measurements
41
+ if (offsetLeft >= 0 && offsetWidth > 0) { // Ensure valid measurements
42
42
  tabsWrap.value?.style.setProperty('--indicator-left', `${offsetLeft}px`)
43
43
  tabsWrap.value?.style.setProperty('--indicator-width', `${offsetWidth}px`)
44
44
  tabsWrap.value?.style.setProperty('--indicator-opacity', '1')
@@ -49,25 +49,25 @@ function updateIndicator() {
49
49
  }
50
50
 
51
51
  function selectTab(tab: TabType | string) {
52
- currentTab.value = 'string' === typeof tab ? tab : tab.id
52
+ currentTab.value = typeof tab === 'string' ? tab : tab.id
53
53
  emit('update:modelValue', currentTab.value)
54
54
  nextTick(() => { updateIndicator() })
55
55
  }
56
56
 
57
57
  function isActive(tab: TabType | string) {
58
- if ('string' === typeof tab) {return currentTab.value === tab}
58
+ if (typeof tab === 'string') { return currentTab.value === tab }
59
59
  return currentTab.value === tab.id
60
60
  }
61
61
 
62
62
  function tabLabel(tab: TabType | string) {
63
- if ('string' === typeof tab) {return tab}
63
+ if (typeof tab === 'string') { return tab }
64
64
  return tab.label
65
65
  }
66
66
 
67
67
  watch(
68
68
  () => props.modelValue,
69
69
  (value) => {
70
- if (value && !isActive(value)) {currentTab.value = value}
70
+ if (value && !isActive(value)) { currentTab.value = value }
71
71
  nextTick(() => { updateIndicator() })
72
72
  },
73
73
  { immediate: true }
@@ -97,14 +97,14 @@ onBeforeUnmount(() => {
97
97
  </script>
98
98
 
99
99
  <template>
100
- <div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical }">
101
- <slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs }">
102
- <button v-for="(tab, i) in props.tabs" :key="i" type="button" :class="{ active: isActive(tab) }" class="bgl_tab relative z-1" @click="selectTab(tab)">
103
- <Icon v-if="typeof tab !== 'string' && tab.icon" :icon="tab.icon" />
104
- {{ tabLabel(tab) }}
105
- </button>
100
+ <div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical }">
101
+ <slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs }">
102
+ <button v-for="(tab, i) in props.tabs" :key="i" type="button" :class="{ active: isActive(tab) }" class="bgl_tab relative z-1" @click="selectTab(tab)">
103
+ <Icon v-if="typeof tab !== 'string' && tab.icon" :icon="tab.icon" />
104
+ {{ tabLabel(tab) }}
105
+ </button>
106
106
  </slot>
107
- </div>
107
+ </div>
108
108
  </template>
109
109
 
110
110
  <style scoped>
@@ -1,3 +1,6 @@
1
+ export { default as AppContent } from './AppContent.vue'
2
+ export { default as AppLayout } from './AppLayout.vue'
3
+ export { default as AppSidebar } from './AppSidebar.vue'
1
4
  export { default as BottomMenu } from './BottomMenu.vue'
2
5
  export { default as Layout } from './Layout.vue'
3
6
  export { default as SidebarMenu } from './SidebarMenu.vue'
@@ -6,8 +9,3 @@ export { default as TabbedLayout } from './TabbedLayout.vue'
6
9
  export { default as Tabs } from './Tabs.vue'
7
10
  export { default as TabsBody } from './TabsBody.vue'
8
11
  export { default as TabsNav } from './TabsNav.vue'
9
- export { default as AppContent } from './AppContent.vue'
10
- export { default as AppLayout } from './AppLayout.vue'
11
- export { default as AppSidebar } from './AppSidebar.vue'
12
-
13
-