@bagelink/vue 1.17.2 → 1.18.3
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.
- package/dist/assetTransport.d.ts +9 -31
- package/dist/assetTransport.d.ts.map +1 -1
- package/dist/assets.d.ts +39 -20
- package/dist/assets.d.ts.map +1 -1
- package/dist/components/AddressSearch.vue.d.ts +40 -36
- package/dist/components/AddressSearch.vue.d.ts.map +1 -1
- package/dist/components/ContextMenu.vue.d.ts +518 -0
- package/dist/components/ContextMenu.vue.d.ts.map +1 -0
- package/dist/components/Dropdown.types.d.ts +25 -0
- package/dist/components/Dropdown.types.d.ts.map +1 -0
- package/dist/components/Dropdown.vue.d.ts +20 -15
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/FilterQuery.vue.d.ts +1 -1
- package/dist/components/FilterQuery.vue.d.ts.map +1 -1
- package/dist/components/Icon/Icon.vue.d.ts +0 -1
- package/dist/components/Icon/Icon.vue.d.ts.map +1 -1
- package/dist/components/Icon/constants.d.ts +0 -1
- package/dist/components/Icon/constants.d.ts.map +1 -1
- package/dist/components/Icon/types.d.ts +2 -3
- package/dist/components/Icon/types.d.ts.map +1 -1
- package/dist/components/Swiper.vue.d.ts +1 -1
- package/dist/components/draggable/useDraggable.d.ts.map +1 -1
- package/dist/components/form/inputs/IconPickerInput.vue.d.ts +48 -37
- package/dist/components/form/inputs/IconPickerInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useCommands.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts +3 -0
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/selection.d.ts +2 -0
- package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/table.d.ts +34 -8
- package/dist/components/form/inputs/RichText/utils/table.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts +74 -65
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts +2 -2
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/composables/index.d.ts +1 -1
- package/dist/composables/index.d.ts.map +1 -1
- package/dist/composables/useBoundedRectDrag.d.ts.map +1 -1
- package/dist/composables/usePointerSession.d.ts +14 -3
- package/dist/composables/usePointerSession.d.ts.map +1 -1
- package/dist/core.css +3 -3
- package/dist/directives/vResize.d.ts.map +1 -1
- package/dist/form-flow/FormFlow.vue.d.ts.map +1 -1
- package/dist/form-flow/form-flow.d.ts +4 -2
- package/dist/form-flow/form-flow.d.ts.map +1 -1
- package/dist/form-flow/schema-fields.d.ts +4 -1
- package/dist/form-flow/schema-fields.d.ts.map +1 -1
- package/dist/index.cjs +240 -153
- package/dist/index.css +1 -1
- package/dist/index.mjs +18461 -18283
- package/dist/style.css +3 -3
- package/dist/types/BagelForm.d.ts +2 -0
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/assetTransport.test.ts +33 -83
- package/src/assetTransport.ts +24 -90
- package/src/assets.test.ts +58 -99
- package/src/assets.ts +78 -161
- package/src/components/ContextMenu.vue +113 -0
- package/src/components/Dropdown.types.ts +27 -0
- package/src/components/Dropdown.vue +129 -64
- package/src/components/FilterQuery.vue +1 -1
- package/src/components/Icon/Icon.vue +8 -30
- package/src/components/Icon/constants.ts +0 -166
- package/src/components/Icon/types.ts +2 -3
- package/src/components/draggable/useDraggable.ts +67 -100
- package/src/components/form/inputs/IconPickerInput.vue +14 -9
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +43 -111
- package/src/components/form/inputs/RichText/composables/useCommands.ts +32 -54
- package/src/components/form/inputs/RichText/composables/useEditor.ts +45 -171
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +90 -14
- package/src/components/form/inputs/RichText/index.vue +1195 -1210
- package/src/components/form/inputs/RichText/utils/commands.ts +689 -1028
- package/src/components/form/inputs/RichText/utils/selection.ts +66 -41
- package/src/components/form/inputs/RichText/utils/table.ts +798 -136
- package/src/components/form/inputs/SelectInput.vue +6 -4
- package/src/components/form/inputs/Upload/AssetUploadInput.vue +2 -2
- package/src/components/index.ts +3 -1
- package/src/composables/index.ts +1 -1
- package/src/composables/useBoundedRectDrag.ts +9 -12
- package/src/composables/usePointerSession.ts +57 -12
- package/src/directives/vResize.ts +6 -7
- package/src/form-flow/FormFlow.vue +4 -0
- package/src/form-flow/form-flow.ts +8 -3
- package/src/form-flow/schema-fields.ts +9 -4
- package/src/styles/core.css +1 -18
- package/src/types/BagelForm.ts +2 -0
- package/dist/components/form/inputs/RichText/utils/formatting.d.ts +0 -10
- package/dist/components/form/inputs/RichText/utils/formatting.d.ts.map +0 -1
- package/src/components/form/inputs/RichText/components/gridBox.vue +0 -58
- package/src/components/form/inputs/RichText/utils/formatting.ts +0 -331
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { ToolbarConfig, ToolbarConfigOption, ToolbarOption } from '../richTextTypes'
|
|
3
|
-
import { Btn, Dropdown } from '../../../../../index'
|
|
3
|
+
import { Btn, Divider, Dropdown } from '../../../../../index'
|
|
4
4
|
import { basicToolbarConfig, toolbarOptions } from '../config'
|
|
5
5
|
import TableGridSelector from './TableGridSelector.vue'
|
|
6
6
|
|
|
@@ -29,16 +29,14 @@ const {
|
|
|
29
29
|
}>()
|
|
30
30
|
const emit = defineEmits(['action'])
|
|
31
31
|
|
|
32
|
-
// Function to get the current alignment icon based on active styles
|
|
33
32
|
function getCurrentAlignmentIcon(): string {
|
|
34
33
|
if (selectedStyles.has('alignLeft')) { return 'format_align_left' }
|
|
35
34
|
if (selectedStyles.has('alignCenter')) { return 'format_align_center' }
|
|
36
35
|
if (selectedStyles.has('alignRight')) { return 'format_align_right' }
|
|
37
36
|
if (selectedStyles.has('alignJustify')) { return 'format_align_justify' }
|
|
38
|
-
return 'format_align_left'
|
|
37
|
+
return 'format_align_left'
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
// Function to check if any alignment is active
|
|
42
40
|
function isAlignmentActive(): boolean {
|
|
43
41
|
return selectedStyles.has('alignLeft')
|
|
44
42
|
|| selectedStyles.has('alignCenter')
|
|
@@ -46,44 +44,46 @@ function isAlignmentActive(): boolean {
|
|
|
46
44
|
|| selectedStyles.has('alignJustify')
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
// Helper function to check if an action should be hidden
|
|
50
47
|
function shouldHideAction(actionName: string): boolean {
|
|
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,
|
|
53
|
-
// ul, ol, blockquote, code, clear, direction, table, fullScreen
|
|
54
48
|
if (hide.includes(actionName)) { return true }
|
|
55
49
|
|
|
56
|
-
// Alternative name mappings for some actions
|
|
57
50
|
const alternativeNames: Record<string, string[]> = {
|
|
58
51
|
image: ['insertImage', 'image'],
|
|
59
52
|
video: ['insertVideo', 'video'],
|
|
60
53
|
embed: ['insertEmbed', 'embed'],
|
|
61
54
|
table: ['insertTable'],
|
|
62
|
-
direction: ['textDirection'],
|
|
55
|
+
direction: ['textDirection', 'ltrDirection', 'rtlDirection'],
|
|
63
56
|
fullScreen: ['fullScreen'],
|
|
64
57
|
ul: ['unorderedList'],
|
|
65
58
|
ol: ['orderedList'],
|
|
66
59
|
splitView: ['splitView'],
|
|
67
60
|
p: ['p'],
|
|
68
|
-
align: ['alignMenu'],
|
|
69
|
-
alignment: ['alignMenu']
|
|
61
|
+
align: ['alignMenu', 'alignLeft', 'alignCenter', 'alignRight', 'alignJustify'],
|
|
62
|
+
alignment: ['alignMenu', 'alignLeft', 'alignCenter', 'alignRight', 'alignJustify']
|
|
70
63
|
}
|
|
71
64
|
|
|
72
|
-
// Check alternative names
|
|
73
65
|
for (const [hideKey, actionNames] of Object.entries(alternativeNames)) {
|
|
74
66
|
if (hide.includes(hideKey) && actionNames.includes(actionName)) {
|
|
75
67
|
return true
|
|
76
68
|
}
|
|
77
69
|
}
|
|
78
70
|
|
|
79
|
-
// Map action names to check against specific hide props (for backward compatibility)
|
|
80
71
|
const actionMap: Record<string, boolean> = {
|
|
81
72
|
insertImage: hideImages,
|
|
73
|
+
image: hideImages,
|
|
82
74
|
insertVideo: hideVideos,
|
|
75
|
+
video: hideVideos,
|
|
83
76
|
insertEmbed: hideEmbeds,
|
|
77
|
+
embed: hideEmbeds,
|
|
84
78
|
insertTable: hideTables,
|
|
85
79
|
alignMenu: hideAlignment,
|
|
80
|
+
alignLeft: hideAlignment,
|
|
81
|
+
alignCenter: hideAlignment,
|
|
82
|
+
alignRight: hideAlignment,
|
|
83
|
+
alignJustify: hideAlignment,
|
|
86
84
|
textDirection: hideDirections,
|
|
85
|
+
ltrDirection: hideDirections,
|
|
86
|
+
rtlDirection: hideDirections,
|
|
87
87
|
h5: hideH5H6,
|
|
88
88
|
h6: hideH5H6
|
|
89
89
|
}
|
|
@@ -93,11 +93,9 @@ function shouldHideAction(actionName: string): boolean {
|
|
|
93
93
|
|
|
94
94
|
const configToOption = (action: ToolbarConfigOption) => toolbarOptions.find(option => option.name === action) as ToolbarOption
|
|
95
95
|
|
|
96
|
-
// Helper function to check if a separator should be shown
|
|
97
96
|
function shouldShowSeparator(currentIndex: number): boolean {
|
|
98
97
|
const allActions = config.map(configToOption).filter(Boolean)
|
|
99
98
|
|
|
100
|
-
// Simple approach: find the last visible item before this separator
|
|
101
99
|
let lastVisibleBeforeIndex = -1
|
|
102
100
|
for (let i = currentIndex - 1; i >= 0; i--) {
|
|
103
101
|
const action = allActions[i]
|
|
@@ -107,7 +105,6 @@ function shouldShowSeparator(currentIndex: number): boolean {
|
|
|
107
105
|
}
|
|
108
106
|
}
|
|
109
107
|
|
|
110
|
-
// Find the first visible item after this separator
|
|
111
108
|
let firstVisibleAfterIndex = -1
|
|
112
109
|
for (let i = currentIndex + 1; i < allActions.length; i++) {
|
|
113
110
|
const action = allActions[i]
|
|
@@ -117,16 +114,13 @@ function shouldShowSeparator(currentIndex: number): boolean {
|
|
|
117
114
|
}
|
|
118
115
|
}
|
|
119
116
|
|
|
120
|
-
// Don't show if we don't have visible items on both sides
|
|
121
117
|
if (lastVisibleBeforeIndex === -1 || firstVisibleAfterIndex === -1) {
|
|
122
118
|
return false
|
|
123
119
|
}
|
|
124
120
|
|
|
125
|
-
// Check if there's already a visible separator between these items
|
|
126
121
|
for (let i = lastVisibleBeforeIndex + 1; i < currentIndex; i++) {
|
|
127
122
|
const action = allActions[i]
|
|
128
123
|
if (action && action.name === 'separator') {
|
|
129
|
-
// There's already a separator closer to the visible items
|
|
130
124
|
return false
|
|
131
125
|
}
|
|
132
126
|
}
|
|
@@ -135,49 +129,14 @@ function shouldShowSeparator(currentIndex: number): boolean {
|
|
|
135
129
|
}
|
|
136
130
|
|
|
137
131
|
function runAction(name: ToolbarConfigOption, value?: string) {
|
|
138
|
-
console.log('EditorToolbar: runAction called', { name, value })
|
|
139
132
|
emit('action', name, value)
|
|
140
133
|
}
|
|
141
134
|
|
|
142
135
|
function handleQuickTableInsert(rows: number, cols: number) {
|
|
143
|
-
|
|
144
|
-
const table = document.createElement('table')
|
|
145
|
-
table.style.width = '100%'
|
|
146
|
-
table.style.borderCollapse = 'collapse'
|
|
147
|
-
table.style.marginBottom = '1rem'
|
|
148
|
-
|
|
149
|
-
// Add header
|
|
150
|
-
const thead = document.createElement('thead')
|
|
151
|
-
const headerRow = thead.insertRow()
|
|
152
|
-
for (let j = 0; j < cols; j++) {
|
|
153
|
-
const th = document.createElement('th')
|
|
154
|
-
th.innerHTML = `Header ${j + 1}`
|
|
155
|
-
th.style.padding = '8px'
|
|
156
|
-
th.style.border = '1px solid #ddd'
|
|
157
|
-
th.style.backgroundColor = '#f4f4f4'
|
|
158
|
-
headerRow.appendChild(th)
|
|
159
|
-
}
|
|
160
|
-
table.appendChild(thead)
|
|
161
|
-
|
|
162
|
-
// Add body
|
|
163
|
-
const tbody = document.createElement('tbody')
|
|
164
|
-
for (let i = 0; i < rows; i++) {
|
|
165
|
-
const row = tbody.insertRow()
|
|
166
|
-
for (let j = 0; j < cols; j++) {
|
|
167
|
-
const cell = row.insertCell()
|
|
168
|
-
cell.innerHTML = ' '
|
|
169
|
-
cell.style.padding = '8px'
|
|
170
|
-
cell.style.border = '1px solid #ddd'
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
table.appendChild(tbody)
|
|
174
|
-
|
|
175
|
-
emit('action', 'insertTable', table.outerHTML)
|
|
136
|
+
emit('action', 'insertTable', `${rows}x${cols}`)
|
|
176
137
|
}
|
|
177
138
|
|
|
178
139
|
function handleOpenAdvanced() {
|
|
179
|
-
// The advanced table editor is now handled by the main RichText component
|
|
180
|
-
// through the insertTable command which opens the main modal
|
|
181
140
|
emit('action', 'insertTable')
|
|
182
141
|
}
|
|
183
142
|
</script>
|
|
@@ -187,35 +146,18 @@ function handleOpenAdvanced() {
|
|
|
187
146
|
<template v-for="(action, index) in config.map(configToOption).filter(Boolean)" :key="index">
|
|
188
147
|
<!-- Tables -->
|
|
189
148
|
<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
149
|
|
|
208
150
|
<!-- Alignment Menu -->
|
|
209
151
|
<Dropdown
|
|
210
152
|
v-else-if="action.name === 'alignMenu' && !shouldHideAction('alignMenu')" placement="bottom-start" thin flat :icon="getCurrentAlignmentIcon()"
|
|
211
153
|
:class="{ 'alignment-active': isAlignmentActive() }"
|
|
212
154
|
>
|
|
213
|
-
<template #default="{ hide }">
|
|
155
|
+
<template #default="{ hide: closeMenu }">
|
|
214
156
|
<div class="flex flex-column p-025">
|
|
215
|
-
<Btn thin flat icon="format_align_left" :class="{ active: selectedStyles.has('alignLeft') }" @click="runAction('alignLeft');
|
|
216
|
-
<Btn thin flat icon="format_align_center" :class="{ active: selectedStyles.has('alignCenter') }" @click="runAction('alignCenter');
|
|
217
|
-
<Btn thin flat icon="format_align_right" :class="{ active: selectedStyles.has('alignRight') }" @click="runAction('alignRight');
|
|
218
|
-
<Btn thin flat icon="format_align_justify" :class="{ active: selectedStyles.has('alignJustify') }" @click="runAction('alignJustify');
|
|
157
|
+
<Btn thin flat icon="format_align_left" :class="{ active: selectedStyles.has('alignLeft') }" @click="runAction('alignLeft'); closeMenu()" />
|
|
158
|
+
<Btn thin flat icon="format_align_center" :class="{ active: selectedStyles.has('alignCenter') }" @click="runAction('alignCenter'); closeMenu()" />
|
|
159
|
+
<Btn thin flat icon="format_align_right" :class="{ active: selectedStyles.has('alignRight') }" @click="runAction('alignRight'); closeMenu()" />
|
|
160
|
+
<Btn thin flat icon="format_align_justify" :class="{ active: selectedStyles.has('alignJustify') }" @click="runAction('alignJustify'); closeMenu()" />
|
|
219
161
|
</div>
|
|
220
162
|
</template>
|
|
221
163
|
</Dropdown>
|
|
@@ -224,66 +166,56 @@ function handleOpenAdvanced() {
|
|
|
224
166
|
<Btn
|
|
225
167
|
v-else-if="action.name === 'textDirection' && !shouldHideAction('textDirection')" v-tooltip="action.label"
|
|
226
168
|
: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') }]"
|
|
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)"
|
|
169
|
+
:class="[action.class, { active: selectedStyles.has('textDirection') }]" tabindex="-1" @click="runAction(action.name)"
|
|
234
170
|
/>
|
|
235
171
|
|
|
236
|
-
<!-- All other buttons
|
|
172
|
+
<!-- All other buttons -->
|
|
237
173
|
<Btn
|
|
238
174
|
v-else-if="action.name !== 'separator'
|
|
239
175
|
&& action.name !== 'insertTable'
|
|
240
|
-
&& action.name !== 'insertImage'
|
|
241
|
-
&& action.name !== 'insertVideo'
|
|
242
|
-
&& action.name !== 'insertEmbed'
|
|
243
176
|
&& action.name !== 'alignMenu'
|
|
244
177
|
&& action.name !== 'textDirection'
|
|
245
|
-
&& action.name
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
178
|
+
&& !shouldHideAction(action.name)"
|
|
179
|
+
v-tooltip="action.label"
|
|
180
|
+
:icon="action.icon"
|
|
181
|
+
thin
|
|
182
|
+
flat
|
|
183
|
+
:aria-label="action.name"
|
|
184
|
+
:class="[action.class, { active: selectedStyles.has(action.name) }]"
|
|
185
|
+
tabindex="-1"
|
|
186
|
+
@click="runAction(action.name)"
|
|
249
187
|
/>
|
|
250
188
|
|
|
251
189
|
<!-- Separator -->
|
|
252
|
-
<
|
|
190
|
+
<Divider v-else-if="action.name === 'separator' && shouldShowSeparator(index)" :key="`separator-${index}`" vertical size="1.25rem" class="mx-0125 align-self-center" />
|
|
253
191
|
</template>
|
|
254
192
|
<slot name="end" />
|
|
255
193
|
</div>
|
|
256
194
|
</template>
|
|
257
195
|
|
|
258
196
|
<style scoped>
|
|
259
|
-
|
|
260
197
|
.toolbar :deep(.active) {
|
|
261
|
-
background: var(--bgl-primary);
|
|
262
|
-
color: white !important;
|
|
198
|
+
background: var(--bgl-primary);
|
|
199
|
+
color: white !important;
|
|
263
200
|
}
|
|
264
201
|
.toolbar :deep(.active):hover {
|
|
265
|
-
background: var(--bgl-primary) !important;
|
|
202
|
+
background: var(--bgl-primary) !important;
|
|
266
203
|
color: white;
|
|
267
204
|
}
|
|
268
|
-
/* Headings menu styling */
|
|
269
205
|
.toolbar :deep(.dropdown-content) {
|
|
270
|
-
min-width: 40px;
|
|
206
|
+
min-width: 40px;
|
|
271
207
|
}
|
|
272
|
-
|
|
273
208
|
.toolbar :deep(.dropdown-content .btn) {
|
|
274
|
-
min-width: 32px;
|
|
275
|
-
height: 32px;
|
|
276
|
-
padding: 0;
|
|
209
|
+
min-width: 32px;
|
|
210
|
+
height: 32px;
|
|
211
|
+
padding: 0;
|
|
277
212
|
}
|
|
278
|
-
/* Alignment active state */
|
|
279
213
|
.alignment-active :deep(button) {
|
|
280
|
-
background: var(--bgl-primary) !important;
|
|
281
|
-
color: white !important;
|
|
214
|
+
background: var(--bgl-primary) !important;
|
|
215
|
+
color: white !important;
|
|
282
216
|
}
|
|
283
|
-
|
|
284
217
|
.alignment-active :deep(button:hover) {
|
|
285
|
-
background: var(--bgl-primary) !important;
|
|
286
|
-
color: white !important;
|
|
218
|
+
background: var(--bgl-primary) !important;
|
|
219
|
+
color: white !important;
|
|
287
220
|
}
|
|
288
|
-
|
|
289
221
|
</style>
|
|
@@ -1,60 +1,24 @@
|
|
|
1
1
|
import type { EditorState } from '../richTextTypes'
|
|
2
2
|
import { createCommandExecutor, createCommandRegistry } from '../utils/commands'
|
|
3
|
-
import {
|
|
3
|
+
import { computeActiveStyles } from '../utils/selection'
|
|
4
4
|
|
|
5
5
|
export function useCommands(state: EditorState, debug?: { logCommand: (command: string, value?: string) => void }) {
|
|
6
6
|
const commands = createCommandRegistry(state)
|
|
7
7
|
const executor = createCommandExecutor(state, commands)
|
|
8
8
|
|
|
9
|
-
// Function to immediately update styles
|
|
10
9
|
const updateStylesImmediately = () => {
|
|
11
10
|
if (!state.doc) { return }
|
|
12
|
-
|
|
13
|
-
const styles = new Set<string>()
|
|
14
|
-
const styleTypes = [
|
|
15
|
-
'bold',
|
|
16
|
-
'italic',
|
|
17
|
-
'underline',
|
|
18
|
-
'link',
|
|
19
|
-
'h1',
|
|
20
|
-
'h2',
|
|
21
|
-
'h3',
|
|
22
|
-
'h4',
|
|
23
|
-
'h5',
|
|
24
|
-
'h6',
|
|
25
|
-
'blockquote',
|
|
26
|
-
'p',
|
|
27
|
-
'orderedList',
|
|
28
|
-
'unorderedList',
|
|
29
|
-
'alignLeft',
|
|
30
|
-
'alignCenter',
|
|
31
|
-
'alignRight',
|
|
32
|
-
'alignJustify',
|
|
33
|
-
'textDirection',
|
|
34
|
-
'ltrDirection',
|
|
35
|
-
'rtlDirection'
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
styleTypes.forEach((style) => {
|
|
39
|
-
if (isStyleActive(style, state.doc!)) {
|
|
40
|
-
styles.add(style)
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
state.selectedStyles = styles
|
|
11
|
+
state.selectedStyles = computeActiveStyles(state.doc)
|
|
45
12
|
}
|
|
46
13
|
|
|
47
14
|
return {
|
|
48
15
|
execute: (command: string, value?: string) => {
|
|
49
16
|
if (!state.doc) {
|
|
50
|
-
console.log('[useCommands] No document available, skipping command')
|
|
51
17
|
return
|
|
52
18
|
}
|
|
53
19
|
|
|
54
|
-
// Log command if debug is enabled
|
|
55
20
|
debug?.logCommand(command, value)
|
|
56
21
|
|
|
57
|
-
// Handle view state commands directly (these don't need DOM manipulation)
|
|
58
22
|
if (['splitView', 'codeView', 'fullScreen'].includes(command)) {
|
|
59
23
|
switch (command) {
|
|
60
24
|
case 'splitView':
|
|
@@ -69,30 +33,44 @@ export function useCommands(state: EditorState, debug?: { logCommand: (command:
|
|
|
69
33
|
}
|
|
70
34
|
}
|
|
71
35
|
|
|
72
|
-
// Focus the editor before executing command
|
|
73
36
|
try {
|
|
74
|
-
state.doc.body.focus()
|
|
75
|
-
} catch
|
|
76
|
-
|
|
37
|
+
state.doc.body.focus({ preventScroll: true })
|
|
38
|
+
} catch {
|
|
39
|
+
// Ignore focus errors
|
|
77
40
|
}
|
|
78
41
|
|
|
79
|
-
//
|
|
42
|
+
// Restore selection if focusing the body cleared or collapsed the user's active selection
|
|
80
43
|
const selection = state.doc.getSelection()
|
|
81
|
-
if (selection
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
44
|
+
if (selection) {
|
|
45
|
+
if (selection.rangeCount > 0) {
|
|
46
|
+
const currentRange = selection.getRangeAt(0)
|
|
47
|
+
if (currentRange.collapsed && state.range && !state.range.collapsed) {
|
|
48
|
+
try {
|
|
49
|
+
selection.removeAllRanges()
|
|
50
|
+
selection.addRange(state.range)
|
|
51
|
+
} catch {
|
|
52
|
+
// Ignore invalid range
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
state.selection = selection
|
|
56
|
+
state.range = currentRange.cloneRange()
|
|
57
|
+
state.rangeCount = selection.rangeCount
|
|
58
|
+
}
|
|
59
|
+
} else if (state.range) {
|
|
60
|
+
try {
|
|
61
|
+
selection.removeAllRanges()
|
|
62
|
+
selection.addRange(state.range)
|
|
63
|
+
state.selection = selection
|
|
64
|
+
state.rangeCount = selection.rangeCount
|
|
65
|
+
} catch {
|
|
66
|
+
// Ignore invalid range
|
|
67
|
+
}
|
|
68
|
+
}
|
|
85
69
|
}
|
|
86
70
|
|
|
87
|
-
// Execute the command
|
|
88
71
|
try {
|
|
89
72
|
executor.execute(command, value)
|
|
90
|
-
|
|
91
|
-
// Update styles immediately after command execution for all commands except view state
|
|
92
|
-
const viewCommands = ['splitView', 'codeView', 'fullScreen']
|
|
93
|
-
if (!viewCommands.includes(command)) {
|
|
94
|
-
updateStylesImmediately()
|
|
95
|
-
}
|
|
73
|
+
updateStylesImmediately()
|
|
96
74
|
} catch (e) {
|
|
97
75
|
console.error('[useCommands] Error during command execution:', e)
|
|
98
76
|
}
|