@bagelink/vue 1.6.47 → 1.6.51

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 (170) 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/Zoomer.vue.d.ts +0 -1
  19. package/dist/components/Zoomer.vue.d.ts.map +1 -1
  20. package/dist/components/analytics/LineChart.vue.d.ts.map +1 -1
  21. package/dist/components/analytics/PieChart.vue.d.ts +2 -1
  22. package/dist/components/analytics/PieChart.vue.d.ts.map +1 -1
  23. package/dist/components/analytics/index.d.ts +1 -1
  24. package/dist/components/analytics/index.d.ts.map +1 -1
  25. package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
  26. package/dist/components/form/BglMultiStepForm.vue.d.ts.map +1 -1
  27. package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
  28. package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
  29. package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
  30. package/dist/components/form/inputs/RadioGroup.vue.d.ts.map +1 -1
  31. package/dist/components/form/inputs/RangeInput.vue.d.ts +11 -11
  32. package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
  33. package/dist/components/form/inputs/RichText/components/TableGridSelector.vue.d.ts.map +1 -1
  34. package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
  35. package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
  36. package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
  37. package/dist/components/layout/AppSidebar.vue.d.ts +1 -0
  38. package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
  39. package/dist/components/layout/Layout.vue.d.ts.map +1 -1
  40. package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
  41. package/dist/components/layout/index.d.ts +3 -3
  42. package/dist/components/layout/index.d.ts.map +1 -1
  43. package/dist/index.cjs +34 -25
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.mjs +6668 -5883
  47. package/dist/plugins/useToast.d.ts.map +1 -1
  48. package/dist/style.css +1 -1
  49. package/package.json +5 -10
  50. package/src/components/AccordionItem.vue +11 -11
  51. package/src/components/AddToCalendar.vue +1 -1
  52. package/src/components/AddressSearch.vue +9 -8
  53. package/src/components/Alert.vue +2 -1
  54. package/src/components/Badge.vue +5 -5
  55. package/src/components/BglVideo.vue +44 -45
  56. package/src/components/Btn.vue +15 -15
  57. package/src/components/Card.vue +10 -8
  58. package/src/components/Carousel.vue +159 -162
  59. package/src/components/DataPreview.vue +1 -1
  60. package/src/components/DragOver.vue +6 -6
  61. package/src/components/Dropdown.vue +39 -38
  62. package/src/components/Flag.vue +7 -6
  63. package/src/components/Icon/Icon.vue +22 -22
  64. package/src/components/IframeVue.vue +5 -5
  65. package/src/components/Image.vue +17 -17
  66. package/src/components/ImportData.vue +79 -79
  67. package/src/components/ListItem.vue +20 -13
  68. package/src/components/Loading.vue +10 -9
  69. package/src/components/MapEmbed/Index.vue +24 -24
  70. package/src/components/Modal.vue +11 -9
  71. package/src/components/ModalForm.vue +9 -8
  72. package/src/components/NavBar.vue +6 -6
  73. package/src/components/Pagination.vue +27 -27
  74. package/src/components/Pill.vue +11 -12
  75. package/src/components/Rating.vue +2 -2
  76. package/src/components/Slider.vue +75 -75
  77. package/src/components/Spreadsheet/Index.vue +34 -34
  78. package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
  79. package/src/components/Zoomer.vue +165 -170
  80. package/src/components/analytics/BarChart.vue +6 -6
  81. package/src/components/analytics/KpiCard.vue +2 -2
  82. package/src/components/analytics/LineChart.vue +63 -61
  83. package/src/components/analytics/PieChart.vue +104 -90
  84. package/src/components/analytics/index.ts +2 -2
  85. package/src/components/calendar/CalendarPopover.vue +1 -1
  86. package/src/components/calendar/Index.vue +1 -1
  87. package/src/components/calendar/views/AgendaView.vue +3 -3
  88. package/src/components/calendar/views/DayView.vue +6 -6
  89. package/src/components/calendar/views/MonthView.vue +2 -2
  90. package/src/components/calendar/views/WeekView.vue +18 -18
  91. package/src/components/dataTable/DataTable.vue +4 -4
  92. package/src/components/dataTable/useSorting.ts +1 -1
  93. package/src/components/dataTable/useTableData.ts +15 -15
  94. package/src/components/dataTable/useTableSelection.ts +15 -15
  95. package/src/components/dataTable/useTableVirtualization.ts +1 -1
  96. package/src/components/draggable/useDraggable.ts +42 -42
  97. package/src/components/form/BagelForm.vue +15 -15
  98. package/src/components/form/BglFieldSet.vue +5 -3
  99. package/src/components/form/BglMultiStepForm.vue +20 -21
  100. package/src/components/form/inputs/CheckInput.vue +2 -2
  101. package/src/components/form/inputs/CodeEditor/format.ts +7 -7
  102. package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
  103. package/src/components/form/inputs/ColorInput.vue +5 -4
  104. package/src/components/form/inputs/DateInput.vue +8 -9
  105. package/src/components/form/inputs/DatePicker.vue +24 -24
  106. package/src/components/form/inputs/EmailInput.vue +24 -24
  107. package/src/components/form/inputs/NumberInput.vue +26 -26
  108. package/src/components/form/inputs/OTP.vue +7 -7
  109. package/src/components/form/inputs/PasswordInput.vue +3 -2
  110. package/src/components/form/inputs/RadioGroup.vue +28 -25
  111. package/src/components/form/inputs/RadioPillsInput.vue +12 -12
  112. package/src/components/form/inputs/RangeInput.vue +21 -21
  113. package/src/components/form/inputs/RichText/components/EditorToolbar.vue +107 -92
  114. package/src/components/form/inputs/RichText/components/TableGridSelector.vue +64 -64
  115. package/src/components/form/inputs/RichText/components/gridBox.vue +10 -8
  116. package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
  117. package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
  118. package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
  119. package/src/components/form/inputs/RichText/index.vue +138 -138
  120. package/src/components/form/inputs/RichText/utils/commands.ts +84 -85
  121. package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
  122. package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
  123. package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
  124. package/src/components/form/inputs/RichText/utils/table.ts +19 -19
  125. package/src/components/form/inputs/SelectBtn.vue +1 -1
  126. package/src/components/form/inputs/SelectInput.vue +54 -54
  127. package/src/components/form/inputs/SignaturePad.vue +40 -40
  128. package/src/components/form/inputs/TableField.vue +1 -1
  129. package/src/components/form/inputs/TelInput.vue +54 -53
  130. package/src/components/form/inputs/TextInput.vue +19 -19
  131. package/src/components/form/inputs/ToggleInput.vue +2 -2
  132. package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
  133. package/src/components/form/useBagelFormState.ts +5 -5
  134. package/src/components/layout/AppLayout.vue +2 -2
  135. package/src/components/layout/AppSidebar.vue +77 -16
  136. package/src/components/layout/Layout.vue +12 -10
  137. package/src/components/layout/SidebarMenu.vue +4 -4
  138. package/src/components/layout/TabbedLayout.vue +17 -17
  139. package/src/components/layout/Tabs.vue +4 -5
  140. package/src/components/layout/TabsNav.vue +14 -14
  141. package/src/components/layout/index.ts +3 -5
  142. package/src/components/lightbox/Lightbox.vue +22 -22
  143. package/src/components/lightbox/index.ts +8 -8
  144. package/src/composables/index.ts +8 -8
  145. package/src/composables/useAddToCalendar.ts +13 -13
  146. package/src/composables/useDevice.ts +2 -2
  147. package/src/composables/useFormField.ts +4 -4
  148. package/src/composables/usePolling.ts +8 -8
  149. package/src/composables/useSchemaField.ts +38 -38
  150. package/src/composables/useTheme.ts +9 -9
  151. package/src/composables/useValidateFieldValue.ts +2 -2
  152. package/src/directives/pattern.ts +25 -25
  153. package/src/directives/ripple.ts +4 -4
  154. package/src/directives/vResize.ts +6 -6
  155. package/src/index.ts +1 -0
  156. package/src/plugins/bagel.ts +4 -4
  157. package/src/plugins/useToast.ts +56 -51
  158. package/src/styles/layout.css +1 -1
  159. package/src/types/index.ts +1 -1
  160. package/src/utils/BagelFormUtils.ts +7 -7
  161. package/src/utils/calendar/Helpers.ts +8 -8
  162. package/src/utils/calendar/dateUtils.ts +22 -22
  163. package/src/utils/calendar/time.ts +25 -25
  164. package/src/utils/calendar/week.ts +25 -25
  165. package/src/utils/elementUtils.ts +27 -27
  166. package/src/utils/sizeParsing.ts +2 -2
  167. package/src/utils/strings.ts +5 -5
  168. package/src/utils/tapDetector.ts +11 -11
  169. package/src/utils/useSearch.ts +29 -29
  170. package/vite.config.ts +0 -2
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { Option } from '@bagelink/vue'
3
3
 
4
- import { onMounted, watch } from 'vue'
4
+ import { onMounted, ref, watch } from 'vue'
5
5
 
6
6
  const props = withDefaults(
7
7
  defineProps<{
@@ -20,38 +20,38 @@ const props = withDefaults(
20
20
  const emits = defineEmits(['update:modelValue'])
21
21
 
22
22
  function getLabel(option: Option) {
23
- if ('string' === typeof option) {return option}
24
- if ('number' === typeof option) {return `${option}`}
25
- if ('boolean' === typeof option) {return option ? 'Yes' : 'No'}
23
+ if (typeof option === 'string') { return option }
24
+ if (typeof option === 'number') { return `${option}` }
25
+ if (typeof option === 'boolean') { return option ? 'Yes' : 'No' }
26
26
  return option.label
27
27
  }
28
28
 
29
29
  function getValue(option: Option) {
30
- if ('string' === typeof option) {return option}
31
- if ('number' === typeof option) {return option}
32
- if ('boolean' === typeof option) {return option ? 'Yes' : 'No'}
30
+ if (typeof option === 'string') { return option }
31
+ if (typeof option === 'number') { return option }
32
+ if (typeof option === 'boolean') { return option ? 'Yes' : 'No' }
33
33
  return option.value
34
34
  }
35
35
 
36
- let selectedValue = $ref(props.modelValue)
36
+ const selectedValue = ref(props.modelValue)
37
37
 
38
38
  function handleSelect(e: Event) {
39
39
  const newVal = (e.target as any)?.value
40
40
  emits('update:modelValue', newVal)
41
- selectedValue = newVal
41
+ selectedValue.value = newVal
42
42
  }
43
43
 
44
44
  watch(
45
45
  () => props.modelValue,
46
46
  (newVal, oldVal) => {
47
- if (newVal === oldVal || oldVal === undefined) {return}
48
- if (selectedValue !== newVal) {selectedValue = newVal}
47
+ if (newVal === oldVal || oldVal === undefined) { return }
48
+ if (selectedValue.value !== newVal) { selectedValue.value = newVal }
49
49
  },
50
50
  { immediate: true },
51
51
  )
52
52
 
53
53
  onMounted(() => {
54
- selectedValue = props.modelValue
54
+ selectedValue.value = props.modelValue
55
55
  })
56
56
  </script>
57
57
 
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { watch } from 'vue'
2
+ import { computed, ref, watch } from 'vue'
3
3
 
4
4
  export interface RangeInputProps {
5
5
  modelValue: number | [number, number]
@@ -26,48 +26,48 @@ const {
26
26
  formatValue = (value: number) => value.toString()
27
27
  } = props
28
28
 
29
- let from = $ref<number>(Array.isArray(props.modelValue) ? props.modelValue[0] : (props.modelValue ?? min))
30
- let to = $ref<number>(Array.isArray(props.modelValue) ? props.modelValue[1] : max)
29
+ const from = ref<number>(Array.isArray(props.modelValue) ? props.modelValue[0] : (props.modelValue ?? min))
30
+ const to = ref<number>(Array.isArray(props.modelValue) ? props.modelValue[1] : max)
31
31
 
32
- const validFrom = $computed(() => Math.min(Math.max(from, min), multiRange ? to : max))
33
- const validTo = $computed(() => Math.max(Math.min(to, max), from))
32
+ const validFrom = computed(() => Math.min(Math.max(from.value, min), multiRange ? to.value : max))
33
+ const validTo = computed(() => Math.max(Math.min(to.value, max), from.value))
34
34
 
35
- const fromPercentage = $computed(() => ((validFrom - min) / (max - min)) * 100)
36
- const toPercentage = $computed(() => ((validTo - min) / (max - min)) * 100)
35
+ const fromPercentage = computed(() => ((validFrom.value - min) / (max - min)) * 100)
36
+ const toPercentage = computed(() => ((validTo.value - min) / (max - min)) * 100)
37
37
 
38
38
  watch(() => props.modelValue, (newVal) => {
39
39
  if (Array.isArray(newVal) && multiRange) {
40
- from = newVal[0] ?? min
41
- to = newVal[1] ?? max
40
+ from.value = newVal[0] ?? min
41
+ to.value = newVal[1] ?? max
42
42
  } else if (!Array.isArray(newVal)) {
43
- from = newVal ?? min
44
- to = max
43
+ from.value = newVal ?? min
44
+ to.value = max
45
45
  }
46
46
  }, { immediate: true })
47
47
 
48
48
  function handleInput(value: number, isFromInput: boolean) {
49
49
  if (isFromInput) {
50
- from = value
50
+ from.value = value
51
51
  } else {
52
- to = value
52
+ to.value = value
53
53
  }
54
- emit('update:modelValue', multiRange ? [validFrom, validTo] : validFrom)
54
+ emit('update:modelValue', multiRange ? [validFrom.value, validTo.value] : validFrom.value)
55
55
  }
56
56
 
57
- const rangeStyle = $computed(() => {
57
+ const rangeStyle = computed(() => {
58
58
  if (multiRange) {
59
59
  return {
60
- left: `${fromPercentage}%`,
61
- width: `${toPercentage - fromPercentage}%`
60
+ left: `${fromPercentage.value}%`,
61
+ width: `${toPercentage.value - fromPercentage.value}%`
62
62
  }
63
63
  }
64
64
  return props.rtl
65
- ? { left: `${100 - fromPercentage}%`, width: `${fromPercentage}%` }
66
- : { left: '0', width: `${fromPercentage}%` }
65
+ ? { left: `${100 - fromPercentage.value}%`, width: `${fromPercentage.value}%` }
66
+ : { left: '0', width: `${fromPercentage.value}%` }
67
67
  })
68
68
 
69
- const displayFrom = $computed(() => formatValue(validFrom))
70
- const displayTo = $computed(() => formatValue(validTo))
69
+ const displayFrom = computed(() => formatValue(validFrom.value))
70
+ const displayTo = computed(() => formatValue(validTo.value))
71
71
  </script>
72
72
 
73
73
  <template>
@@ -31,42 +31,42 @@ const emit = defineEmits(['action'])
31
31
 
32
32
  // Function to get the current alignment icon based on active styles
33
33
  function getCurrentAlignmentIcon(): string {
34
- if (selectedStyles.has('alignLeft')) {return 'format_align_left'}
35
- if (selectedStyles.has('alignCenter')) {return 'format_align_center'}
36
- if (selectedStyles.has('alignRight')) {return 'format_align_right'}
37
- if (selectedStyles.has('alignJustify')) {return 'format_align_justify'}
34
+ if (selectedStyles.has('alignLeft')) { return 'format_align_left' }
35
+ if (selectedStyles.has('alignCenter')) { return 'format_align_center' }
36
+ if (selectedStyles.has('alignRight')) { return 'format_align_right' }
37
+ if (selectedStyles.has('alignJustify')) { return 'format_align_justify' }
38
38
  return 'format_align_left' // default
39
39
  }
40
40
 
41
41
  // Function to check if any alignment is active
42
42
  function isAlignmentActive(): boolean {
43
- return selectedStyles.has('alignLeft') ||
44
- selectedStyles.has('alignCenter') ||
45
- selectedStyles.has('alignRight') ||
46
- selectedStyles.has('alignJustify')
43
+ return selectedStyles.has('alignLeft')
44
+ || selectedStyles.has('alignCenter')
45
+ || selectedStyles.has('alignRight')
46
+ || selectedStyles.has('alignJustify')
47
47
  }
48
48
 
49
49
  // Helper function to check if an action should be hidden
50
50
  function shouldHideAction(actionName: string): boolean {
51
51
  // Check if it's in the hide array - this covers ALL items including:
52
- // bold, italic, underline, h1, h2, h3, h4, h5, h6, link, image, video, embed,
52
+ // bold, italic, underline, h1, h2, h3, h4, h5, h6, link, image, video, embed,
53
53
  // ul, ol, blockquote, code, clear, direction, table, fullScreen
54
- if (hide.includes(actionName)) {return true}
54
+ if (hide.includes(actionName)) { return true }
55
55
 
56
56
  // Alternative name mappings for some actions
57
57
  const alternativeNames: Record<string, string[]> = {
58
- 'image': ['insertImage', 'image'],
59
- 'video': ['insertVideo', 'video'],
60
- 'embed': ['insertEmbed', 'embed'],
61
- 'table': ['insertTable'],
62
- 'direction': ['textDirection'],
63
- 'fullScreen': ['fullScreen'],
64
- 'ul': ['unorderedList'],
65
- 'ol': ['orderedList'],
66
- 'splitView': ['splitView'],
67
- 'p': ['p'],
68
- 'align': ['alignMenu'],
69
- 'alignment': ['alignMenu']
58
+ image: ['insertImage', 'image'],
59
+ video: ['insertVideo', 'video'],
60
+ embed: ['insertEmbed', 'embed'],
61
+ table: ['insertTable'],
62
+ direction: ['textDirection'],
63
+ fullScreen: ['fullScreen'],
64
+ ul: ['unorderedList'],
65
+ ol: ['orderedList'],
66
+ splitView: ['splitView'],
67
+ p: ['p'],
68
+ align: ['alignMenu'],
69
+ alignment: ['alignMenu']
70
70
  }
71
71
 
72
72
  // Check alternative names
@@ -78,28 +78,30 @@ function shouldHideAction(actionName: string): boolean {
78
78
 
79
79
  // Map action names to check against specific hide props (for backward compatibility)
80
80
  const actionMap: Record<string, boolean> = {
81
- 'insertImage': hideImages,
82
- 'insertVideo': hideVideos,
83
- 'insertEmbed': hideEmbeds,
84
- 'insertTable': hideTables,
85
- 'alignMenu': hideAlignment,
86
- 'textDirection': hideDirections,
87
- 'h5': hideH5H6,
88
- 'h6': hideH5H6
81
+ insertImage: hideImages,
82
+ insertVideo: hideVideos,
83
+ insertEmbed: hideEmbeds,
84
+ insertTable: hideTables,
85
+ alignMenu: hideAlignment,
86
+ textDirection: hideDirections,
87
+ h5: hideH5H6,
88
+ h6: hideH5H6
89
89
  }
90
90
 
91
91
  return actionMap[actionName] || false
92
92
  }
93
93
 
94
+ const configToOption = (action: ToolbarConfigOption) => toolbarOptions.find(option => option.name === action) as ToolbarOption
95
+
94
96
  // Helper function to check if a separator should be shown
95
97
  function shouldShowSeparator(currentIndex: number): boolean {
96
98
  const allActions = config.map(configToOption).filter(Boolean)
97
99
 
98
100
  // Simple approach: find the last visible item before this separator
99
101
  let lastVisibleBeforeIndex = -1
100
- for (let i = currentIndex - 1; 0 <= i; i--) {
102
+ for (let i = currentIndex - 1; i >= 0; i--) {
101
103
  const action = allActions[i]
102
- if (action && 'separator' !== action.name && !shouldHideAction(action.name)) {
104
+ if (action && action.name !== 'separator' && !shouldHideAction(action.name)) {
103
105
  lastVisibleBeforeIndex = i
104
106
  break
105
107
  }
@@ -109,28 +111,28 @@ function shouldShowSeparator(currentIndex: number): boolean {
109
111
  let firstVisibleAfterIndex = -1
110
112
  for (let i = currentIndex + 1; i < allActions.length; i++) {
111
113
  const action = allActions[i]
112
- if (action && 'separator' !== action.name && !shouldHideAction(action.name)) {
114
+ if (action && action.name !== 'separator' && !shouldHideAction(action.name)) {
113
115
  firstVisibleAfterIndex = i
114
116
  break
115
117
  }
116
118
  }
117
119
 
118
120
  // Don't show if we don't have visible items on both sides
119
- if (-1 === lastVisibleBeforeIndex || -1 === firstVisibleAfterIndex) {
121
+ if (lastVisibleBeforeIndex === -1 || firstVisibleAfterIndex === -1) {
120
122
  return false
121
123
  }
122
124
 
123
125
  // Check if there's already a visible separator between these items
124
126
  for (let i = lastVisibleBeforeIndex + 1; i < currentIndex; i++) {
125
127
  const action = allActions[i]
126
- if (action && 'separator' === action.name) {
128
+ if (action && action.name === 'separator') {
127
129
  // There's already a separator closer to the visible items
128
130
  return false
129
131
  }
130
132
  }
131
133
 
132
134
  return true
133
- } const configToOption = (action: ToolbarConfigOption) => toolbarOptions.find(option => option.name === action) as ToolbarOption
135
+ }
134
136
 
135
137
  function runAction(name: ToolbarConfigOption, value?: string) {
136
138
  console.log('EditorToolbar: runAction called', { name, value })
@@ -181,61 +183,75 @@ function handleOpenAdvanced() {
181
183
  </script>
182
184
 
183
185
  <template>
184
- <div class="toolbar flex gap-025 pb-05 flex-wrap" role="toolbar" style="position: relative;">
185
- <template v-for="(action, index) in config.map(configToOption).filter(Boolean)" :key="index">
186
- <!-- Tables -->
187
- <TableGridSelector v-if="action.name === 'insertTable' && !shouldHideAction('insertTable')" @insert="handleQuickTableInsert" @open-advanced="handleOpenAdvanced" />
188
- <!-- Images -->
189
- <Btn v-else-if="action.name === 'insertImage' && !shouldHideAction('insertImage')" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
190
- :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)" />
191
-
192
- <!-- Videos -->
193
- <Btn v-else-if="action.name === 'insertVideo' && !shouldHideAction('insertVideo')" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
194
- :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)" />
195
-
196
- <!-- Embeds -->
197
- <Btn v-else-if="action.name === 'insertEmbed' && !shouldHideAction('insertEmbed')" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
198
- :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)" />
199
-
200
- <!-- Alignment Menu -->
201
- <Dropdown v-else-if="action.name === 'alignMenu' && !shouldHideAction('alignMenu')" placement="bottom-start" thin flat :icon="getCurrentAlignmentIcon()"
202
- :class="{ 'alignment-active': isAlignmentActive() }">
203
- <template #default="{ hide }">
204
- <div class="flex flex-column p-025">
205
- <Btn thin flat icon="format_align_left" :class="{ active: selectedStyles.has('alignLeft') }" @click="runAction('alignLeft'); hide()" />
206
- <Btn thin flat icon="format_align_center" :class="{ active: selectedStyles.has('alignCenter') }" @click="runAction('alignCenter'); hide()" />
207
- <Btn thin flat icon="format_align_right" :class="{ active: selectedStyles.has('alignRight') }" @click="runAction('alignRight'); hide()" />
208
- <Btn thin flat icon="format_align_justify" :class="{ active: selectedStyles.has('alignJustify') }" @click="runAction('alignJustify'); hide()" />
209
- </div>
210
- </template>
211
- </Dropdown>
212
-
213
- <!-- Text Direction -->
214
- <Btn v-else-if="action.name === 'textDirection' && !shouldHideAction('textDirection')" v-tooltip="action.label"
215
- :icon="selectedStyles.has('textDirection') ? 'format_textdirection_l_to_r' : 'format_textdirection_r_to_l'" thin flat :aria-label="action.name"
216
- :class="[action.class, { active: selectedStyles.has('textDirection') }]" class="" tabindex="-1" @click="runAction(action.name)" />
217
-
218
- <!-- H5 and H6 -->
219
- <Btn v-else-if="(action.name === 'h5' || action.name === 'h6') && !shouldHideAction(action.name)" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
220
- :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)" />
221
-
222
- <!-- All other buttons - check if they should be hidden by the hide array -->
223
- <Btn v-else-if="action.name !== 'separator' &&
224
- action.name !== 'insertTable' &&
225
- action.name !== 'insertImage' &&
226
- action.name !== 'insertVideo' &&
227
- action.name !== 'insertEmbed' &&
228
- action.name !== 'alignMenu' &&
229
- action.name !== 'textDirection' &&
230
- action.name !== 'h5' &&
231
- action.name !== 'h6' &&
232
- !shouldHideAction(action.name)" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name" :class="[action.class, { active: selectedStyles.has(action.name) }]" class=""
233
- tabindex="-1" @click="runAction(action.name)" />
234
-
235
- <!-- Separator -->
236
- <span v-else-if="action.name === 'separator' && shouldShowSeparator(index)" :key="`separator-${index}`" class="opacity-2 mb-025">|</span>
237
- </template>
238
- </div>
186
+ <div class="toolbar flex gap-025 pb-05 flex-wrap" role="toolbar" style="position: relative;">
187
+ <template v-for="(action, index) in config.map(configToOption).filter(Boolean)" :key="index">
188
+ <!-- Tables -->
189
+ <TableGridSelector v-if="action.name === 'insertTable' && !shouldHideAction('insertTable')" @insert="handleQuickTableInsert" @open-advanced="handleOpenAdvanced" />
190
+ <!-- Images -->
191
+ <Btn
192
+ v-else-if="action.name === 'insertImage' && !shouldHideAction('insertImage')" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
193
+ :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)"
194
+ />
195
+
196
+ <!-- Videos -->
197
+ <Btn
198
+ v-else-if="action.name === 'insertVideo' && !shouldHideAction('insertVideo')" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
199
+ :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)"
200
+ />
201
+
202
+ <!-- Embeds -->
203
+ <Btn
204
+ v-else-if="action.name === 'insertEmbed' && !shouldHideAction('insertEmbed')" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
205
+ :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)"
206
+ />
207
+
208
+ <!-- Alignment Menu -->
209
+ <Dropdown
210
+ v-else-if="action.name === 'alignMenu' && !shouldHideAction('alignMenu')" placement="bottom-start" thin flat :icon="getCurrentAlignmentIcon()"
211
+ :class="{ 'alignment-active': isAlignmentActive() }"
212
+ >
213
+ <template #default="{ hide }">
214
+ <div class="flex flex-column p-025">
215
+ <Btn thin flat icon="format_align_left" :class="{ active: selectedStyles.has('alignLeft') }" @click="runAction('alignLeft'); hide()" />
216
+ <Btn thin flat icon="format_align_center" :class="{ active: selectedStyles.has('alignCenter') }" @click="runAction('alignCenter'); hide()" />
217
+ <Btn thin flat icon="format_align_right" :class="{ active: selectedStyles.has('alignRight') }" @click="runAction('alignRight'); hide()" />
218
+ <Btn thin flat icon="format_align_justify" :class="{ active: selectedStyles.has('alignJustify') }" @click="runAction('alignJustify'); hide()" />
219
+ </div>
220
+ </template>
221
+ </Dropdown>
222
+
223
+ <!-- Text Direction -->
224
+ <Btn
225
+ v-else-if="action.name === 'textDirection' && !shouldHideAction('textDirection')" v-tooltip="action.label"
226
+ :icon="selectedStyles.has('textDirection') ? 'format_textdirection_l_to_r' : 'format_textdirection_r_to_l'" thin flat :aria-label="action.name"
227
+ :class="[action.class, { active: selectedStyles.has('textDirection') }]" class="" tabindex="-1" @click="runAction(action.name)"
228
+ />
229
+
230
+ <!-- H5 and H6 -->
231
+ <Btn
232
+ v-else-if="(action.name === 'h5' || action.name === 'h6') && !shouldHideAction(action.name)" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name"
233
+ :class="[action.class, { active: selectedStyles.has(action.name) }]" class="" tabindex="-1" @click="runAction(action.name)"
234
+ />
235
+
236
+ <!-- All other buttons - check if they should be hidden by the hide array -->
237
+ <Btn
238
+ v-else-if="action.name !== 'separator'
239
+ && action.name !== 'insertTable'
240
+ && action.name !== 'insertImage'
241
+ && action.name !== 'insertVideo'
242
+ && action.name !== 'insertEmbed'
243
+ && action.name !== 'alignMenu'
244
+ && action.name !== 'textDirection'
245
+ && action.name !== 'h5'
246
+ && action.name !== 'h6'
247
+ && !shouldHideAction(action.name)" v-tooltip="action.label" :icon="action.icon" thin flat :aria-label="action.name" :class="[action.class, { active: selectedStyles.has(action.name) }]" class=""
248
+ tabindex="-1" @click="runAction(action.name)"
249
+ />
250
+
251
+ <!-- Separator -->
252
+ <span v-else-if="action.name === 'separator' && shouldShowSeparator(index)" :key="`separator-${index}`" class="opacity-2 mb-025">|</span>
253
+ </template>
254
+ </div>
239
255
  </template>
240
256
 
241
257
  <style scoped>
@@ -268,4 +284,3 @@ function handleOpenAdvanced() {
268
284
  color: white !important;
269
285
  }
270
286
  </style>
271
-
@@ -1,11 +1,10 @@
1
1
  <script setup lang="ts">
2
- import { ref, computed } from 'vue'
3
2
  import { Btn, Dropdown } from '@bagelink/vue'
4
-
3
+ import { ref, computed } from 'vue'
5
4
 
6
5
  const emit = defineEmits<{
7
- insert: [rows: number, cols: number]
8
- openAdvanced: []
6
+ insert: [rows: number, cols: number]
7
+ openAdvanced: []
9
8
  }>()
10
9
 
11
10
  const hoveredRow = ref(0)
@@ -15,80 +14,81 @@ const maxRows = 10
15
14
  const maxCols = 10
16
15
 
17
16
  const gridCells = computed(() => {
18
- const cells = []
19
- for (let row = 1; row <= maxRows; row++) {
20
- for (let col = 1; col <= maxCols; col++) {
21
- cells.push({
22
- row,
23
- col,
24
- isActive: row <= hoveredRow.value && col <= hoveredCol.value
25
- })
26
- }
27
- }
28
- return cells
17
+ const cells = []
18
+ for (let row = 1; row <= maxRows; row++) {
19
+ for (let col = 1; col <= maxCols; col++) {
20
+ cells.push({
21
+ row,
22
+ col,
23
+ isActive: row <= hoveredRow.value && col <= hoveredCol.value
24
+ })
25
+ }
26
+ }
27
+ return cells
29
28
  })
30
29
 
31
30
  const selectionText = computed(() => {
32
- if (0 === hoveredRow.value || 0 === hoveredCol.value) {
33
- return 'Select table size'
34
- }
35
- return `${hoveredRow.value} × ${hoveredCol.value}`
31
+ if (hoveredRow.value === 0 || hoveredCol.value === 0) {
32
+ return 'Select table size'
33
+ }
34
+ return `${hoveredRow.value} × ${hoveredCol.value}`
36
35
  })
37
36
 
38
- const handleCellHover = (row: number, col: number) => {
39
- hoveredRow.value = row
40
- hoveredCol.value = col
37
+ function handleCellHover(row: number, col: number) {
38
+ hoveredRow.value = row
39
+ hoveredCol.value = col
41
40
  }
42
41
 
43
- const handleCellClick = (row: number, col: number, hide: () => void) => {
44
- emit('insert', row, col)
45
- hide()
42
+ function handleCellClick(row: number, col: number, hide: () => void) {
43
+ emit('insert', row, col)
44
+ hide()
46
45
  }
47
46
 
48
- const handleAdvanced = (hide: () => void) => {
49
- emit('openAdvanced')
50
- hide()
47
+ function handleAdvanced(hide: () => void) {
48
+ emit('openAdvanced')
49
+ hide()
51
50
  }
52
51
 
53
- const handleMouseLeave = () => {
54
- hoveredRow.value = 0
55
- hoveredCol.value = 0
52
+ function handleMouseLeave() {
53
+ hoveredRow.value = 0
54
+ hoveredCol.value = 0
56
55
  }
57
56
  </script>
58
57
 
59
58
  <template>
60
- <Dropdown placement="bottom-start" thin flat icon="table">
61
- <template #default="{ hide }">
62
- <div class="table-grid-selector p-075">
63
- <!-- Header -->
64
- <div class="txt-center mb-075">
65
- <div style="font-size: 14px; font-weight: 500; color: #333; margin-bottom: 4px;">
66
- {{ selectionText }}
67
- </div>
68
- <div style="font-size: 12px; color: #666;">
69
- Hover to select size
70
- </div>
71
- </div>
59
+ <Dropdown placement="bottom-start" thin flat icon="table">
60
+ <template #default="{ hide }">
61
+ <div class="table-grid-selector p-075">
62
+ <!-- Header -->
63
+ <div class="txt-center mb-075">
64
+ <div style="font-size: 14px; font-weight: 500; color: #333; margin-bottom: 4px;">
65
+ {{ selectionText }}
66
+ </div>
67
+ <div style="font-size: 12px; color: #666;">
68
+ Hover to select size
69
+ </div>
70
+ </div>
71
+
72
+ <!-- Grid -->
73
+ <div style="display: grid; grid-template-columns: repeat(10, 20px); grid-template-rows: repeat(10, 20px); gap: 2px; margin-bottom: 12px; direction: ltr;" @mouseleave="handleMouseLeave" @blur="handleMouseLeave">
74
+ <div
75
+ v-for="cell in gridCells" :key="`${cell.row}-${cell.col}`" tabindex="0" :style="{
76
+ width: '20px',
77
+ height: '20px',
78
+ border: '1px solid #ddd',
79
+ backgroundColor: cell.isActive ? 'var(--bgl-primary)' : '#fff',
80
+ cursor: 'pointer',
81
+ borderRadius: '2px',
82
+ transition: 'background-color 0.1s ease',
83
+ }" @focus="handleCellHover(cell)" @mouseenter="handleCellHover(cell.row, cell.col)" @click="handleCellClick(cell.row, cell.col, hide)"
84
+ />
85
+ </div>
72
86
 
73
- <!-- Grid -->
74
- <div style="display: grid; grid-template-columns: repeat(10, 20px); grid-template-rows: repeat(10, 20px); gap: 2px; margin-bottom: 12px; direction: ltr;" @mouseleave="handleMouseLeave">
75
- <div v-for="cell in gridCells" :key="`${cell.row}-${cell.col}`" @mouseenter="handleCellHover(cell.row, cell.col)" @click="handleCellClick(cell.row, cell.col, hide)" :style="{
76
- width: '20px',
77
- height: '20px',
78
- border: '1px solid #ddd',
79
- backgroundColor: cell.isActive ? 'var(--bgl-primary)' : '#fff',
80
- cursor: 'pointer',
81
- borderRadius: '2px',
82
- transition: 'background-color 0.1s ease'
83
- }">
84
- </div>
85
- </div>
86
-
87
- <!-- Advanced button -->
88
- <div class="border-top pt-075">
89
- <Btn @click="handleAdvanced(hide)" value="Advanced Settings" icon="settings" class="bg-gray-30 color-black" />
90
- </div>
91
- </div>
92
- </template>
93
- </Dropdown>
87
+ <!-- Advanced button -->
88
+ <div class="border-top pt-075">
89
+ <Btn value="Advanced Settings" icon="settings" class="bg-gray-30 color-black" @click="handleAdvanced(hide)" />
90
+ </div>
91
+ </div>
92
+ </template>
93
+ </Dropdown>
94
94
  </template>
@@ -1,20 +1,22 @@
1
1
  <script setup lang="ts">
2
+ import { computed, ref } from 'vue'
3
+
2
4
  const props = defineProps<{
3
5
  gridSize?: number
4
6
  }>()
5
7
  const emit = defineEmits(['select'])
6
8
  const fb = 1
7
9
  const base = props.gridSize || 5
8
- const hoveredRow = $ref(fb)
9
- const hoveredCol = $ref(fb)
10
+ const hoveredRow = ref(fb)
11
+ const hoveredCol = ref(fb)
10
12
 
11
- const rowSize = $computed(() => {
12
- const enlarge = Math.min(hoveredRow + 1, 20)
13
- return hoveredRow > (base - 1) ? enlarge : base
13
+ const rowSize = computed(() => {
14
+ const enlarge = Math.min(hoveredRow.value + 1, 20)
15
+ return hoveredRow.value > (base - 1) ? enlarge : base
14
16
  })
15
- const colSize = $computed(() => {
16
- const enlarge = Math.min(hoveredCol + 1, 20)
17
- return hoveredCol > (base - 1) ? enlarge : base
17
+ const colSize = computed(() => {
18
+ const enlarge = Math.min(hoveredCol.value + 1, 20)
19
+ return hoveredCol.value > (base - 1) ? enlarge : base
18
20
  })
19
21
  </script>
20
22
 
@@ -8,7 +8,7 @@ export function useCommands(state: EditorState, debug?: { logCommand: (command:
8
8
 
9
9
  // Function to immediately update styles
10
10
  const updateStylesImmediately = () => {
11
- if (!state.doc) {return}
11
+ if (!state.doc) { return }
12
12
 
13
13
  const styles = new Set<string>()
14
14
  const styleTypes = [