@bagelink/vue 1.5.15 → 1.5.20
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/bin/experimentalGenTypedRoutes.ts +15 -15
- package/bin/generateFormSchema.ts +12 -12
- package/bin/utils.ts +4 -4
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/RouterWrapper.vue.d.ts.map +1 -1
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
- package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts +5 -4
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/CheckInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -0
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ToggleInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/composables/useFormField.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +68 -55
- package/dist/index.mjs +34035 -143
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/AccordionItem.vue +2 -2
- package/src/components/AddToCalendar.vue +1 -1
- package/src/components/BglVideo.vue +8 -8
- package/src/components/Btn.vue +9 -9
- package/src/components/Card.vue +4 -4
- package/src/components/Carousel.vue +44 -44
- package/src/components/DataPreview.vue +1 -1
- package/src/components/DragOver.vue +6 -6
- package/src/components/Dropdown.vue +14 -14
- package/src/components/Flag.vue +3 -3
- package/src/components/Icon/Icon.vue +13 -13
- package/src/components/Image.vue +4 -4
- package/src/components/ImportData.vue +79 -79
- package/src/components/ListItem.vue +7 -7
- package/src/components/MapEmbed/Index.vue +6 -6
- package/src/components/Modal.vue +10 -10
- package/src/components/ModalForm.vue +4 -4
- package/src/components/NavBar.vue +2 -2
- package/src/components/Pagination.vue +9 -9
- package/src/components/Pill.vue +1 -1
- package/src/components/Rating.vue +2 -2
- package/src/components/RouterWrapper.vue +3 -3
- package/src/components/Slider.vue +77 -77
- package/src/components/Spreadsheet/Index.vue +34 -34
- package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
- package/src/components/Zoomer.vue +28 -28
- package/src/components/analytics/BarChart.vue +6 -6
- package/src/components/analytics/KpiCard.vue +2 -2
- package/src/components/analytics/LineChart.vue +14 -14
- package/src/components/analytics/PieChart.vue +11 -11
- package/src/components/calendar/CalendarPopover.vue +1 -1
- package/src/components/calendar/Index.vue +1 -1
- package/src/components/calendar/views/AgendaView.vue +2 -2
- package/src/components/calendar/views/DayView.vue +6 -6
- package/src/components/calendar/views/MonthView.vue +2 -2
- package/src/components/calendar/views/WeekView.vue +18 -18
- package/src/components/dataTable/DataTable.vue +3 -3
- package/src/components/dataTable/useSorting.ts +1 -1
- package/src/components/dataTable/useTableData.ts +15 -15
- package/src/components/dataTable/useTableSelection.ts +8 -8
- package/src/components/dataTable/useTableVirtualization.ts +1 -1
- package/src/components/draggable/useDraggable.ts +42 -42
- package/src/components/form/BagelForm.vue +66 -23
- package/src/components/form/BglMultiStepForm.vue +18 -18
- package/src/components/form/FieldArray.vue +177 -67
- package/src/components/form/inputs/CheckInput.vue +2 -1
- package/src/components/form/inputs/CodeEditor/Index.vue +1 -1
- package/src/components/form/inputs/CodeEditor/format.ts +7 -7
- package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
- package/src/components/form/inputs/DateInput.vue +6 -6
- package/src/components/form/inputs/DatePicker.vue +19 -19
- package/src/components/form/inputs/EmailInput.vue +14 -14
- package/src/components/form/inputs/NumberInput.vue +6 -6
- package/src/components/form/inputs/OTP.vue +3 -3
- package/src/components/form/inputs/RadioGroup.vue +1 -1
- package/src/components/form/inputs/RadioPillsInput.vue +8 -8
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +10 -10
- package/src/components/form/inputs/RichText/components/TableGridSelector.vue +1 -1
- package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
- package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
- package/src/components/form/inputs/RichText/index.vue +300 -132
- package/src/components/form/inputs/RichText/utils/commands.ts +69 -69
- package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
- package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
- package/src/components/form/inputs/RichText/utils/media.ts +6 -6
- package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
- package/src/components/form/inputs/RichText/utils/table.ts +19 -19
- package/src/components/form/inputs/SelectBtn.vue +1 -1
- package/src/components/form/inputs/SelectInput.vue +50 -26
- package/src/components/form/inputs/SignaturePad.vue +15 -15
- package/src/components/form/inputs/TableField.vue +1 -1
- package/src/components/form/inputs/TelInput.vue +6 -6
- package/src/components/form/inputs/TextInput.vue +5 -5
- package/src/components/form/inputs/ToggleInput.vue +2 -1
- package/src/components/form/inputs/Upload/UploadInput.vue +155 -102
- package/src/components/form/inputs/Upload/upload.ts +1 -1
- package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
- package/src/components/form/useBagelFormState.ts +5 -5
- package/src/components/layout/AppContent.vue +1 -1
- package/src/components/layout/AppLayout.vue +1 -1
- package/src/components/layout/Layout.vue +4 -4
- package/src/components/layout/TabbedLayout.vue +1 -1
- package/src/components/layout/Tabs.vue +2 -2
- package/src/components/layout/TabsNav.vue +7 -7
- package/src/components/lightbox/Lightbox.vue +8 -8
- package/src/components/lightbox/index.ts +8 -8
- package/src/composables/index.ts +2 -2
- package/src/composables/useAddToCalendar.ts +13 -13
- package/src/composables/useDevice.ts +2 -2
- package/src/composables/useExcel.ts +6 -6
- package/src/composables/useFormField.ts +5 -9
- package/src/composables/usePolling.ts +8 -8
- package/src/composables/useSchemaField.ts +53 -38
- package/src/composables/useTheme.ts +9 -9
- package/src/composables/useValidateFieldValue.ts +2 -2
- package/src/directives/pattern.ts +25 -25
- package/src/directives/ripple.ts +4 -4
- package/src/directives/vResize.ts +6 -6
- package/src/plugins/bagel.ts +4 -4
- package/src/plugins/useModal.ts +3 -3
- package/src/styles/layout.css +7 -1
- package/src/utils/BagelFormUtils.ts +7 -7
- package/src/utils/calendar/Helpers.ts +8 -8
- package/src/utils/calendar/dateUtils.ts +22 -22
- package/src/utils/calendar/time.ts +25 -25
- package/src/utils/calendar/week.ts +25 -25
- package/src/utils/elementUtils.ts +27 -27
- package/src/utils/index.ts +22 -22
- package/src/utils/sizeParsing.ts +2 -2
- package/src/utils/strings.ts +5 -5
- package/src/utils/tapDetector.ts +11 -11
- package/src/utils/useSearch.ts +29 -29
- package/vite.config.ts +1 -1
|
@@ -103,7 +103,7 @@ const input = $ref<HTMLInputElement>()
|
|
|
103
103
|
|
|
104
104
|
// Use custom validation function
|
|
105
105
|
function validateEmail(value: string) {
|
|
106
|
-
if (!value) return
|
|
106
|
+
if (!value) {return}
|
|
107
107
|
|
|
108
108
|
// Basic format validation
|
|
109
109
|
if (!EMAIL_REGEX.test(value)) {
|
|
@@ -133,19 +133,19 @@ const debouncedEmit = useDebounceFn(() => { emit('debounce', inputVal) }, 700)
|
|
|
133
133
|
|
|
134
134
|
// Validate input directly when value changes
|
|
135
135
|
function validateInput() {
|
|
136
|
-
if (!input) return
|
|
136
|
+
if (!input) {return}
|
|
137
137
|
|
|
138
138
|
input.setCustomValidity('')
|
|
139
|
-
if (!inputVal) return
|
|
139
|
+
if (!inputVal) {return}
|
|
140
140
|
const validationResult = validateEmail(inputVal)
|
|
141
|
-
if (typeof validationResult
|
|
141
|
+
if ('string' === typeof validationResult) {
|
|
142
142
|
input.setCustomValidity(validationResult)
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// Perform server validation of email
|
|
147
147
|
async function validateEmailWithServer(email: string) {
|
|
148
|
-
if (!props.serverValidate || !email || !EMAIL_REGEX.test(email)) return
|
|
148
|
+
if (!props.serverValidate || !email || !EMAIL_REGEX.test(email)) {return}
|
|
149
149
|
|
|
150
150
|
// If we've already validated this email, use cached result
|
|
151
151
|
if (validatedEmails.has(email)) {
|
|
@@ -163,10 +163,10 @@ async function validateEmailWithServer(email: string) {
|
|
|
163
163
|
headers: { 'Content-Type': 'application/json' }
|
|
164
164
|
})
|
|
165
165
|
|
|
166
|
-
if (!response.ok) throw new Error('Validation service unavailable')
|
|
166
|
+
if (!response.ok) {throw new Error('Validation service unavailable')}
|
|
167
167
|
|
|
168
168
|
const result = await response.json()
|
|
169
|
-
const isValid = result.status
|
|
169
|
+
const isValid = 'valid' === result.status || true === result.has_mx
|
|
170
170
|
|
|
171
171
|
isValidEmail.value = isValid
|
|
172
172
|
validatedEmails.set(email, isValid)
|
|
@@ -186,7 +186,7 @@ async function validateEmailWithServer(email: string) {
|
|
|
186
186
|
|
|
187
187
|
// Check for email typos and suggest corrections
|
|
188
188
|
function checkForTypos(email: string) {
|
|
189
|
-
if (!props.autocorrect || !email) return
|
|
189
|
+
if (!props.autocorrect || !email) {return}
|
|
190
190
|
|
|
191
191
|
// Handle case where domain is incomplete (missing TLD)
|
|
192
192
|
if (email.includes('@') && !email.includes('.')) {
|
|
@@ -203,7 +203,7 @@ function checkForTypos(email: string) {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
// Standard typo checking for complete emails
|
|
206
|
-
if (!email.includes('@')) return
|
|
206
|
+
if (!email.includes('@')) {return}
|
|
207
207
|
|
|
208
208
|
const [username, domain] = email.split('@')
|
|
209
209
|
const domainLower = domain.toLowerCase()
|
|
@@ -216,7 +216,7 @@ function checkForTypos(email: string) {
|
|
|
216
216
|
|
|
217
217
|
// Find close matches using Levenshtein distance
|
|
218
218
|
for (const commonDomain of COMMON_EMAIL_DOMAINS) {
|
|
219
|
-
if (calculateLevenshteinDistance(domainLower, commonDomain)
|
|
219
|
+
if (2 >= calculateLevenshteinDistance(domainLower, commonDomain)) {
|
|
220
220
|
suggestedCorrection.value = `${username}@${commonDomain}`.toLowerCase()
|
|
221
221
|
return
|
|
222
222
|
}
|
|
@@ -265,7 +265,7 @@ function calculateLevenshteinDistance(a: string, b: string): number {
|
|
|
265
265
|
const debouncedServerValidate = useDebounceFn(() => validateEmailWithServer(inputVal), 1000)
|
|
266
266
|
|
|
267
267
|
function updateInputVal() {
|
|
268
|
-
if (props.disabled) return
|
|
268
|
+
if (props.disabled) {return}
|
|
269
269
|
|
|
270
270
|
// Remove typo checking while typing - only do this on focusout now
|
|
271
271
|
// checkForTypos(inputVal)
|
|
@@ -293,7 +293,7 @@ function handleFocusout(e: FocusEvent) {
|
|
|
293
293
|
validateEmailWithServer(inputVal)
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
if (props.onFocusout) props.onFocusout(e)
|
|
296
|
+
if (props.onFocusout) {props.onFocusout(e)}
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
watch(
|
|
@@ -318,8 +318,8 @@ const focus = () => input?.focus()
|
|
|
318
318
|
defineExpose({ focus, hasFocus })
|
|
319
319
|
|
|
320
320
|
onMounted(() => {
|
|
321
|
-
if (props.autofocus) setTimeout(() => input?.focus(), 10)
|
|
322
|
-
|
|
321
|
+
if (props.autofocus) {setTimeout(() => input?.focus(), 10)}
|
|
322
|
+
// Don't auto-restore defaultValue - let user control their own content
|
|
323
323
|
})
|
|
324
324
|
</script>
|
|
325
325
|
|
|
@@ -76,19 +76,19 @@ const canDecrement = $computed(() => min === undefined || subtract(numberValue,
|
|
|
76
76
|
|
|
77
77
|
// Methods
|
|
78
78
|
function increment() {
|
|
79
|
-
if (!canAdd) return
|
|
79
|
+
if (!canAdd) {return}
|
|
80
80
|
numberValue = add(numberValue ?? 0, step)
|
|
81
81
|
emit('update:modelValue', numberValue)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function decrement() {
|
|
85
|
-
if (!canDecrement) return
|
|
85
|
+
if (!canDecrement) {return}
|
|
86
86
|
numberValue = subtract(numberValue || 0, step)
|
|
87
87
|
emit('update:modelValue', numberValue)
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
function formatNumber(num: number) {
|
|
91
|
-
if (Number.isNaN(num)) return ''
|
|
91
|
+
if (Number.isNaN(num)) {return ''}
|
|
92
92
|
const formatter = new Intl.NumberFormat('en-US', {
|
|
93
93
|
minimumFractionDigits: 0,
|
|
94
94
|
maximumFractionDigits: 20,
|
|
@@ -116,7 +116,7 @@ function inputHandler() {
|
|
|
116
116
|
const isTypingTrailingZeros = /\.\d*0$/.test(numeric) // Check if ending with decimal followed by digits ending in 0
|
|
117
117
|
|
|
118
118
|
if (emptyValue || isTypingDecimal || isTypingTrailingZeros) {
|
|
119
|
-
emit('update:modelValue',
|
|
119
|
+
emit('update:modelValue', '-' === numeric ? '-' : numeric)
|
|
120
120
|
return
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -128,14 +128,14 @@ function inputHandler() {
|
|
|
128
128
|
watch(() => numberValue, () => {
|
|
129
129
|
nextTick(() => {
|
|
130
130
|
// Don't reformat if user is currently typing a decimal or trailing zeros
|
|
131
|
-
if (formattedValue.endsWith('.') || /\.\d*0$/.test(formattedValue)) return
|
|
131
|
+
if (formattedValue.endsWith('.') || /\.\d*0$/.test(formattedValue)) {return}
|
|
132
132
|
formattedValue = numberValue !== undefined ? formatNumber(numberValue) : ''
|
|
133
133
|
})
|
|
134
134
|
})
|
|
135
135
|
|
|
136
136
|
watch(() => modelValue, (newVal) => {
|
|
137
137
|
if (newVal !== numberValue) {
|
|
138
|
-
if (
|
|
138
|
+
if ('string' === typeof newVal && ('-' === newVal || newVal.endsWith('.'))) {
|
|
139
139
|
formattedValue = newVal
|
|
140
140
|
return
|
|
141
141
|
}
|
|
@@ -12,7 +12,7 @@ function handlePaste(event: ClipboardEvent, index: number) {
|
|
|
12
12
|
const { clipboardData } = event
|
|
13
13
|
const pastedText = clipboardData?.getData('text').replaceAll(/\D/g, '') // Ensure only numeric digits are pasted
|
|
14
14
|
const pastedDigits = [...(pastedText ?? '')]
|
|
15
|
-
if (!pastedDigits) return
|
|
15
|
+
if (!pastedDigits) {return}
|
|
16
16
|
for (let i = 0; i < pastedDigits.length; i++) {
|
|
17
17
|
const digit = pastedDigits[i]
|
|
18
18
|
if (index + i < digits.length) {
|
|
@@ -41,10 +41,10 @@ function handleKeyDown(event: KeyboardEvent, index: number) {
|
|
|
41
41
|
return
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
if (event.key
|
|
44
|
+
if ('Backspace' === event.key) {
|
|
45
45
|
digits[index] = undefined
|
|
46
46
|
|
|
47
|
-
if (
|
|
47
|
+
if (0 !== index) {
|
|
48
48
|
const prevDigit = otpCont?.children[index - 1] as any
|
|
49
49
|
prevDigit.focus()
|
|
50
50
|
}
|
|
@@ -53,7 +53,7 @@ let loadedOptions = $ref<any[]>([])
|
|
|
53
53
|
const visibleOptions = $computed(() => Array.isArray(props.options) ? (props.options as any[]) : (loadedOptions as any[]))
|
|
54
54
|
|
|
55
55
|
async function loadOptionsIfNeeded() {
|
|
56
|
-
if (typeof props.options
|
|
56
|
+
if ('function' === typeof props.options) {
|
|
57
57
|
try {
|
|
58
58
|
loadedOptions = await props.options()
|
|
59
59
|
} catch {
|
|
@@ -20,16 +20,16 @@ const props = withDefaults(
|
|
|
20
20
|
const emits = defineEmits(['update:modelValue'])
|
|
21
21
|
|
|
22
22
|
function getLabel(option: Option) {
|
|
23
|
-
if (typeof option
|
|
24
|
-
if (typeof option
|
|
25
|
-
if (typeof option
|
|
23
|
+
if ('string' === typeof option) {return option}
|
|
24
|
+
if ('number' === typeof option) {return `${option}`}
|
|
25
|
+
if ('boolean' === typeof option) {return option ? 'Yes' : 'No'}
|
|
26
26
|
return option.label
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function getValue(option: Option) {
|
|
30
|
-
if (typeof option
|
|
31
|
-
if (typeof option
|
|
32
|
-
if (typeof option
|
|
30
|
+
if ('string' === typeof option) {return option}
|
|
31
|
+
if ('number' === typeof option) {return option}
|
|
32
|
+
if ('boolean' === typeof option) {return option ? 'Yes' : 'No'}
|
|
33
33
|
return option.value
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -44,8 +44,8 @@ function handleSelect(e: Event) {
|
|
|
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 !== newVal) {selectedValue = newVal}
|
|
49
49
|
},
|
|
50
50
|
{ immediate: true },
|
|
51
51
|
)
|
|
@@ -31,10 +31,10 @@ 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
|
|
|
@@ -51,7 +51,7 @@ function shouldHideAction(actionName: string): boolean {
|
|
|
51
51
|
// Check if it's in the hide array - this covers ALL items including:
|
|
52
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[]> = {
|
|
@@ -97,9 +97,9 @@ function shouldShowSeparator(currentIndex: number): boolean {
|
|
|
97
97
|
|
|
98
98
|
// Simple approach: find the last visible item before this separator
|
|
99
99
|
let lastVisibleBeforeIndex = -1
|
|
100
|
-
for (let i = currentIndex - 1;
|
|
100
|
+
for (let i = currentIndex - 1; 0 <= i; i--) {
|
|
101
101
|
const action = allActions[i]
|
|
102
|
-
if (action && action.name
|
|
102
|
+
if (action && 'separator' !== action.name && !shouldHideAction(action.name)) {
|
|
103
103
|
lastVisibleBeforeIndex = i
|
|
104
104
|
break
|
|
105
105
|
}
|
|
@@ -109,21 +109,21 @@ function shouldShowSeparator(currentIndex: number): boolean {
|
|
|
109
109
|
let firstVisibleAfterIndex = -1
|
|
110
110
|
for (let i = currentIndex + 1; i < allActions.length; i++) {
|
|
111
111
|
const action = allActions[i]
|
|
112
|
-
if (action && action.name
|
|
112
|
+
if (action && 'separator' !== action.name && !shouldHideAction(action.name)) {
|
|
113
113
|
firstVisibleAfterIndex = i
|
|
114
114
|
break
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
// Don't show if we don't have visible items on both sides
|
|
119
|
-
if (
|
|
119
|
+
if (-1 === lastVisibleBeforeIndex || -1 === firstVisibleAfterIndex) {
|
|
120
120
|
return false
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// Check if there's already a visible separator between these items
|
|
124
124
|
for (let i = lastVisibleBeforeIndex + 1; i < currentIndex; i++) {
|
|
125
125
|
const action = allActions[i]
|
|
126
|
-
if (action && action.name
|
|
126
|
+
if (action && 'separator' === action.name) {
|
|
127
127
|
// There's already a separator closer to the visible items
|
|
128
128
|
return false
|
|
129
129
|
}
|
|
@@ -29,7 +29,7 @@ const gridCells = computed(() => {
|
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
const selectionText = computed(() => {
|
|
32
|
-
if (hoveredRow.value
|
|
32
|
+
if (0 === hoveredRow.value || 0 === hoveredCol.value) {
|
|
33
33
|
return 'Select table size'
|
|
34
34
|
}
|
|
35
35
|
return `${hoveredRow.value} × ${hoveredCol.value}`
|
|
@@ -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 = [
|
|
@@ -54,7 +54,7 @@ export function useEditor() {
|
|
|
54
54
|
// Centralized state update functions
|
|
55
55
|
const updateState = {
|
|
56
56
|
styles: () => {
|
|
57
|
-
if (!state.doc) return
|
|
57
|
+
if (!state.doc) {return}
|
|
58
58
|
const styles = new Set<string>()
|
|
59
59
|
const styleTypes = [
|
|
60
60
|
'bold',
|
|
@@ -86,7 +86,7 @@ export function useEditor() {
|
|
|
86
86
|
state.selectedStyles = styles
|
|
87
87
|
},
|
|
88
88
|
content: (source: 'html' | 'text') => {
|
|
89
|
-
if (!state.doc) return
|
|
89
|
+
if (!state.doc) {return}
|
|
90
90
|
|
|
91
91
|
// Only push to undo stack if content has changed
|
|
92
92
|
const currentContent = state.doc.body.innerHTML
|
|
@@ -99,7 +99,7 @@ export function useEditor() {
|
|
|
99
99
|
const selection = state.doc.getSelection()
|
|
100
100
|
const range = selection?.rangeCount ? selection.getRangeAt(0).cloneRange() : null
|
|
101
101
|
|
|
102
|
-
if (
|
|
102
|
+
if ('html' === source) {
|
|
103
103
|
// Preserve iframes before setting content
|
|
104
104
|
const preserved = preserveIframes(state.content)
|
|
105
105
|
state.doc.body.innerHTML = preserved.html
|
|
@@ -125,7 +125,7 @@ export function useEditor() {
|
|
|
125
125
|
}
|
|
126
126
|
},
|
|
127
127
|
selection: () => {
|
|
128
|
-
if (!state.doc) return
|
|
128
|
+
if (!state.doc) {return}
|
|
129
129
|
const newSelection = state.doc.getSelection()
|
|
130
130
|
if (!newSelection) {
|
|
131
131
|
return
|
|
@@ -141,7 +141,7 @@ export function useEditor() {
|
|
|
141
141
|
const hasSelectionChanged = !state.selection
|
|
142
142
|
|| state.selection !== newSelection
|
|
143
143
|
|| state.rangeCount !== newSelection.rangeCount
|
|
144
|
-
|| (newSelection.rangeCount
|
|
144
|
+
|| (0 < newSelection.rangeCount && state.range && (
|
|
145
145
|
state.range.startContainer !== newSelection.getRangeAt(0).startContainer
|
|
146
146
|
|| state.range.startOffset !== newSelection.getRangeAt(0).startOffset
|
|
147
147
|
|| state.range.endContainer !== newSelection.getRangeAt(0).endContainer
|
|
@@ -152,7 +152,7 @@ export function useEditor() {
|
|
|
152
152
|
state.selection = newSelection
|
|
153
153
|
state.rangeCount = newSelection.rangeCount
|
|
154
154
|
|
|
155
|
-
if (newSelection.rangeCount
|
|
155
|
+
if (0 < newSelection.rangeCount) {
|
|
156
156
|
state.range = newSelection.getRangeAt(0).cloneRange()
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -171,7 +171,7 @@ export function useEditor() {
|
|
|
171
171
|
// History management
|
|
172
172
|
const history = {
|
|
173
173
|
undo: () => {
|
|
174
|
-
if (state.undoStack.length
|
|
174
|
+
if (0 === state.undoStack.length) {return}
|
|
175
175
|
state.redoStack.push(state.content)
|
|
176
176
|
const lastContent = state.undoStack.pop()
|
|
177
177
|
if (lastContent !== undefined) {
|
|
@@ -180,7 +180,7 @@ export function useEditor() {
|
|
|
180
180
|
}
|
|
181
181
|
},
|
|
182
182
|
redo: () => {
|
|
183
|
-
if (state.redoStack.length
|
|
183
|
+
if (0 === state.redoStack.length) {return}
|
|
184
184
|
state.undoStack.push(state.content)
|
|
185
185
|
const nextContent = state.redoStack.pop()
|
|
186
186
|
if (nextContent !== undefined) {
|
|
@@ -205,8 +205,8 @@ export function useEditor() {
|
|
|
205
205
|
|
|
206
206
|
const textContent = node.textContent?.trim() || ''
|
|
207
207
|
const innerHTML = node.innerHTML.trim()
|
|
208
|
-
const hasOnlyBr =
|
|
209
|
-
const hasOnlyNbsp =
|
|
208
|
+
const hasOnlyBr = '<br>' === innerHTML || '<br/>' === innerHTML
|
|
209
|
+
const hasOnlyNbsp = ' ' === innerHTML || '\u00A0' === textContent
|
|
210
210
|
const isEmpty = !textContent && !innerHTML
|
|
211
211
|
const isDirectChildOfBody = node.parentElement === doc.body
|
|
212
212
|
|
|
@@ -247,7 +247,7 @@ export function useEditor() {
|
|
|
247
247
|
|
|
248
248
|
const events = {
|
|
249
249
|
input: () => {
|
|
250
|
-
if (isUpdating) return
|
|
250
|
+
if (isUpdating) {return}
|
|
251
251
|
isUpdating = true
|
|
252
252
|
|
|
253
253
|
// Immediately update content
|
|
@@ -374,7 +374,7 @@ export function useEditor() {
|
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
// Add cleanup on component unmount
|
|
377
|
-
if (typeof window
|
|
377
|
+
if ('undefined' !== typeof window) {
|
|
378
378
|
window.addEventListener('beforeunload', () => {
|
|
379
379
|
if (cleanupListeners) {
|
|
380
380
|
cleanupListeners()
|
|
@@ -36,7 +36,7 @@ export function useEditorKeyboard(doc: Document, executor: CommandExecutor): voi
|
|
|
36
36
|
// This was causing conflicts with the main Enter key handler
|
|
37
37
|
|
|
38
38
|
// Handle other keyboard shortcuts
|
|
39
|
-
if (!e.ctrlKey && !e.metaKey) return
|
|
39
|
+
if (!e.ctrlKey && !e.metaKey) {return}
|
|
40
40
|
|
|
41
41
|
const matchingShortcut = shortcuts.find((shortcut) => {
|
|
42
42
|
const keyMatch = shortcut.key === e.key
|