@bagelink/vue 1.15.558 → 1.15.565
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/components/Btn.vue.d.ts +2 -0
- package/dist/components/Btn.vue.d.ts.map +1 -1
- package/dist/components/dataTable/DataTable.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 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/richTextTypes.d.ts +2 -0
- package/dist/components/form/inputs/RichText/richTextTypes.d.ts.map +1 -1
- package/dist/components/form/inputs/ToggleInput.vue.d.ts.map +1 -1
- package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
- package/dist/core.css +1 -1
- package/dist/index.cjs +98 -98
- package/dist/index.css +1 -1
- package/dist/index.mjs +10046 -10014
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Btn.vue +29 -0
- package/src/components/dataTable/DataTable.vue +1 -1
- package/src/components/form/inputs/CheckInput.vue +1 -1
- package/src/components/form/inputs/RichText/index.vue +48 -18
- package/src/components/form/inputs/RichText/richTextTypes.ts +2 -0
- package/src/components/form/inputs/ToggleInput.vue +5 -1
- package/src/components/lightbox/Lightbox.vue +11 -3
package/package.json
CHANGED
package/src/components/Btn.vue
CHANGED
|
@@ -55,6 +55,8 @@ const props = withDefaults(
|
|
|
55
55
|
ripple?: boolean
|
|
56
56
|
fullWidth?: boolean
|
|
57
57
|
fullWidthMobile?: boolean
|
|
58
|
+
/** Allow the label to wrap onto multiple lines and grow the button vertically. */
|
|
59
|
+
multiline?: boolean
|
|
58
60
|
alignTxt?: 'center' | 'start' | 'end'
|
|
59
61
|
alignTxtMobile?: 'center' | 'start' | 'end'
|
|
60
62
|
onClick?: (e: MouseEvent) => void
|
|
@@ -224,6 +226,7 @@ const slots: SetupContext['slots'] = useSlots()
|
|
|
224
226
|
'bgl_btn_xlSize': computedSize === 'xl',
|
|
225
227
|
'bgl_btn_fullWidth': fullWidth,
|
|
226
228
|
'bgl_btn_fullWidthMobile': fullWidthMobile,
|
|
229
|
+
'bgl_btn_multiline': multiline,
|
|
227
230
|
'bgl_btn_alignStart': alignTxt === 'start',
|
|
228
231
|
'bgl_btn_alignEnd': alignTxt === 'end',
|
|
229
232
|
'bgl_btn_alignStartMobile': alignTxtMobile === 'start',
|
|
@@ -447,6 +450,32 @@ height: calc(var(--bgl-btn-height) * 1.5);
|
|
|
447
450
|
width: calc(var(--bgl-btn-height) * 1.5);
|
|
448
451
|
}
|
|
449
452
|
|
|
453
|
+
.bgl_btn.bgl_btn_multiline {
|
|
454
|
+
height: auto;
|
|
455
|
+
min-height: var(--bgl-btn-height);
|
|
456
|
+
line-height: 1.3;
|
|
457
|
+
padding-block: calc(var(--bgl-btn-padding) / 4);
|
|
458
|
+
white-space: normal;
|
|
459
|
+
overflow-wrap: anywhere;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.bgl_btn.bgl_btn_multiline.thin,
|
|
463
|
+
.bgl_btn.bgl_btn_multiline.bgl_btn_sSize {
|
|
464
|
+
min-height: calc(var(--bgl-btn-height) * 0.7);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.bgl_btn.bgl_btn_multiline.bgl_btn_xsSize {
|
|
468
|
+
min-height: calc(var(--bgl-btn-height) / 2);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.bgl_btn.bgl_btn_multiline.bgl_btn_lSize {
|
|
472
|
+
min-height: calc(var(--bgl-btn-height) * 1.2);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.bgl_btn.bgl_btn_multiline.bgl_btn_xlSize {
|
|
476
|
+
min-height: calc(var(--bgl-btn-height) * 1.5);
|
|
477
|
+
}
|
|
478
|
+
|
|
450
479
|
.bgl_btn_fullWidth {
|
|
451
480
|
width: 100%;
|
|
452
481
|
}
|
|
@@ -34,7 +34,7 @@ const loading = defineModel('loading', { default: false })
|
|
|
34
34
|
const itemHeight = defineModel('itemHeight', { default: 50 })
|
|
35
35
|
/** Cell font size. Number = px; string = any CSS size (e.g. '0.875rem'). */
|
|
36
36
|
const fontSize = defineModel<number | string | undefined>('fontSize', { default: undefined })
|
|
37
|
-
const selectedItems = defineModel<string[]>('selectedItems', { default:
|
|
37
|
+
const selectedItems = defineModel<string[]>('selectedItems', { default: () => [] })
|
|
38
38
|
|
|
39
39
|
const {
|
|
40
40
|
computedSchema,
|
|
@@ -20,7 +20,7 @@ const { shellClass, shellStyle } = useBagelInputShell(props)
|
|
|
20
20
|
const uid = Math.random().toString(36).slice(7)
|
|
21
21
|
const inputId = computed(() => props.id || uid)
|
|
22
22
|
|
|
23
|
-
const checked = defineModel<T>('modelValue'
|
|
23
|
+
const checked = defineModel<T>('modelValue')
|
|
24
24
|
|
|
25
25
|
const hasValue = computed(() => {
|
|
26
26
|
const v = checked.value
|
|
@@ -23,7 +23,7 @@ defineOptions({
|
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
const props = defineProps<{
|
|
26
|
-
modelValue
|
|
26
|
+
modelValue?: string | null
|
|
27
27
|
toolbarConfig?: ToolbarConfig
|
|
28
28
|
customToolbarButtons?: CustomToolbarButton[]
|
|
29
29
|
extensions?: Array<RichTextExtension | string>
|
|
@@ -61,16 +61,28 @@ const emit = defineEmits(['update:modelValue'])
|
|
|
61
61
|
|
|
62
62
|
const { shellClass, shellStyle } = useBagelInputShell(props)
|
|
63
63
|
const extensionRegistry = inject(RICH_TEXT_EXTENSION_REGISTRY_KEY, new Map())
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
const normalizedModelValue = computed(() => props.modelValue ?? '')
|
|
65
|
+
const hasEditorValue = computed(() => Boolean(normalizedModelValue.value.trim()))
|
|
66
|
+
const resolvedExtensions = computed(() => {
|
|
67
|
+
const active = new Map(
|
|
68
|
+
[...extensionRegistry.values()]
|
|
69
|
+
.filter(extension => extension.alwaysActive)
|
|
70
|
+
.map(extension => [extension.name, extension]),
|
|
71
|
+
)
|
|
72
|
+
for (const extension of props.extensions ?? []) {
|
|
73
|
+
if (typeof extension !== 'string') {
|
|
74
|
+
active.set(extension.name, extension)
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
const resolved = extensionRegistry.get(extension)
|
|
78
|
+
if (!resolved) {
|
|
79
|
+
console.warn(`[RichText] Unknown extension "${extension}".`)
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
active.set(resolved.name, resolved)
|
|
71
83
|
}
|
|
72
|
-
return [
|
|
73
|
-
})
|
|
84
|
+
return [...active.values()]
|
|
85
|
+
})
|
|
74
86
|
const extensionToolbarButtons = computed(() => resolvedExtensions.value.flatMap(extension => extension.toolbarButtons ?? []))
|
|
75
87
|
const effectiveCustomToolbarButtons = computed(() => [
|
|
76
88
|
...(props.customToolbarButtons ?? []),
|
|
@@ -309,6 +321,7 @@ const effectiveHideArray = computed(() => {
|
|
|
309
321
|
const showLinkModal = ref(false)
|
|
310
322
|
const linkForm = ref({
|
|
311
323
|
url: '',
|
|
324
|
+
title: '',
|
|
312
325
|
openInNewTab: true
|
|
313
326
|
})
|
|
314
327
|
|
|
@@ -497,7 +510,7 @@ const tablePreviewHtml = computed(() => {
|
|
|
497
510
|
})
|
|
498
511
|
|
|
499
512
|
// Initialize content from modelValue
|
|
500
|
-
editor.state.content =
|
|
513
|
+
editor.state.content = normalizedModelValue.value
|
|
501
514
|
|
|
502
515
|
// Matches Hebrew, Arabic, Syriac, Thaana, Arabic Supplement, Arabic Presentation Forms
|
|
503
516
|
const RTL_REGEX = /[\u0590-\u05FF\u0600-\u06FF\u0700-\u074F\u0750-\u077F\uFB1D-\uFDFD\uFE70-\uFEFC]/
|
|
@@ -725,6 +738,7 @@ function openLinkModal(selection: Selection, range: Range, existingLink: HTMLAnc
|
|
|
725
738
|
pendingLinkData = { selection, range, existingLink }
|
|
726
739
|
linkForm.value = {
|
|
727
740
|
url: existingLink?.href || '',
|
|
741
|
+
title: existingLink?.getAttribute('title') || '',
|
|
728
742
|
openInNewTab: existingLink?.target !== '_self'
|
|
729
743
|
}
|
|
730
744
|
showLinkModal.value = true
|
|
@@ -735,7 +749,7 @@ function submitLink() {
|
|
|
735
749
|
if (!pendingLinkData || !linkForm.value.url) { return }
|
|
736
750
|
|
|
737
751
|
const { selection, range, existingLink } = pendingLinkData
|
|
738
|
-
const { url, openInNewTab } = linkForm.value
|
|
752
|
+
const { url, title, openInNewTab } = linkForm.value
|
|
739
753
|
const { doc } = editor.state
|
|
740
754
|
|
|
741
755
|
if (!doc) { return }
|
|
@@ -743,6 +757,11 @@ function submitLink() {
|
|
|
743
757
|
if (existingLink) {
|
|
744
758
|
// Update existing link
|
|
745
759
|
existingLink.href = url
|
|
760
|
+
if (title.trim()) {
|
|
761
|
+
existingLink.title = title.trim()
|
|
762
|
+
} else {
|
|
763
|
+
existingLink.removeAttribute('title')
|
|
764
|
+
}
|
|
746
765
|
existingLink.target = openInNewTab ? '_blank' : '_self'
|
|
747
766
|
if (openInNewTab) {
|
|
748
767
|
existingLink.rel = 'noopener noreferrer'
|
|
@@ -754,6 +773,9 @@ function submitLink() {
|
|
|
754
773
|
try {
|
|
755
774
|
const anchor = doc.createElement('a')
|
|
756
775
|
anchor.href = url
|
|
776
|
+
if (title.trim()) {
|
|
777
|
+
anchor.title = title.trim()
|
|
778
|
+
}
|
|
757
779
|
anchor.target = openInNewTab ? '_blank' : '_self'
|
|
758
780
|
if (openInNewTab) {
|
|
759
781
|
anchor.rel = 'noopener noreferrer'
|
|
@@ -2357,7 +2379,7 @@ function handleTableContextMenu(event: MouseEvent) {
|
|
|
2357
2379
|
// Expose debug methods if debug mode is enabled
|
|
2358
2380
|
const debugMethods = computed(() => editor.state.debug)
|
|
2359
2381
|
const hasRTL = computed(() => getTextDirection(
|
|
2360
|
-
|
|
2382
|
+
normalizedModelValue.value.replace(/<[^>]*>/g, ''),
|
|
2361
2383
|
'ltr'
|
|
2362
2384
|
) === 'rtl')
|
|
2363
2385
|
|
|
@@ -2926,6 +2948,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2926
2948
|
|
|
2927
2949
|
// Populate the form with existing link data
|
|
2928
2950
|
linkForm.value.url = link.href
|
|
2951
|
+
linkForm.value.title = link.getAttribute('title') || ''
|
|
2929
2952
|
linkForm.value.openInNewTab = link.target === '_blank'
|
|
2930
2953
|
|
|
2931
2954
|
// Store the link data for editing
|
|
@@ -3235,7 +3258,7 @@ async function initEditor() {
|
|
|
3235
3258
|
background: #007bff !important;
|
|
3236
3259
|
}
|
|
3237
3260
|
` // Create a complete HTML document with proper doctype and meta tags
|
|
3238
|
-
const initialContent =
|
|
3261
|
+
const initialContent = normalizedModelValue.value || (props.placeholder ? `<p class="placeholder">${props.placeholder}</p>` : '')
|
|
3239
3262
|
const htmlContent = `
|
|
3240
3263
|
<!DOCTYPE html>
|
|
3241
3264
|
<html>
|
|
@@ -3324,7 +3347,7 @@ async function initEditor() {
|
|
|
3324
3347
|
useEditorKeyboard(doc, commands)
|
|
3325
3348
|
|
|
3326
3349
|
// Auto clear format for basic mode
|
|
3327
|
-
if (props.basic &&
|
|
3350
|
+
if (props.basic && normalizedModelValue.value) {
|
|
3328
3351
|
setTimeout(() => {
|
|
3329
3352
|
// Clear all formatting by removing styles and replacing with plain text
|
|
3330
3353
|
const elements = doc.body.querySelectorAll('*')
|
|
@@ -3535,7 +3558,7 @@ watch([currentInputColor, currentTextColor, currentFontFamily, effectiveContentS
|
|
|
3535
3558
|
// Reset initialization state when content changes significantly.
|
|
3536
3559
|
// Compare incoming value against the CLEAN output (not raw DOM innerHTML) to avoid
|
|
3537
3560
|
// false positives caused by editor chrome (table wrappers, edit buttons, etc.)
|
|
3538
|
-
watch(
|
|
3561
|
+
watch(normalizedModelValue, (newValue, oldValue) => {
|
|
3539
3562
|
const cleanCurrent = editor.state.doc ? getCleanHTML(editor.state.doc ?? null) : ''
|
|
3540
3563
|
if (newValue !== cleanCurrent) {
|
|
3541
3564
|
if (!oldValue || Math.abs(newValue.length - oldValue.length) > 50) {
|
|
@@ -3813,7 +3836,10 @@ const imgTransform = computed({
|
|
|
3813
3836
|
</div>
|
|
3814
3837
|
</div>
|
|
3815
3838
|
<!-- Link Modal -->
|
|
3816
|
-
<Dialog
|
|
3839
|
+
<Dialog
|
|
3840
|
+
:open="showLinkModal" :title="pendingLinkData?.existingLink ? 'Edit Link' : 'Add Link'"
|
|
3841
|
+
width="s" @update:open="showLinkModal = $event"
|
|
3842
|
+
>
|
|
3817
3843
|
<div class="flex gap-05 align-items-end">
|
|
3818
3844
|
<TextInput
|
|
3819
3845
|
v-model="linkForm.url" label="URL" type="url" placeholder="https://example.com"
|
|
@@ -3824,10 +3850,14 @@ const imgTransform = computed({
|
|
|
3824
3850
|
@click="visitLink"
|
|
3825
3851
|
/>
|
|
3826
3852
|
</div>
|
|
3853
|
+
<TextInput v-model="linkForm.title" label="Title" placeholder="Optional link title" />
|
|
3827
3854
|
<CheckInput v-model="linkForm.openInNewTab" label="Open in new tab" type="checkbox" class="mb-2 mt-05" />
|
|
3828
3855
|
<template #footer>
|
|
3829
3856
|
<Btn value="Cancel" flat thin @click="showLinkModal = false" />
|
|
3830
|
-
<Btn
|
|
3857
|
+
<Btn
|
|
3858
|
+
:value="pendingLinkData?.existingLink ? 'Update Link' : 'Add Link'"
|
|
3859
|
+
:disabled="!isValidUrl(linkForm.url)" @click="submitLink"
|
|
3860
|
+
/>
|
|
3831
3861
|
</template>
|
|
3832
3862
|
</Dialog>
|
|
3833
3863
|
|
|
@@ -89,6 +89,8 @@ export interface CustomToolbarButton {
|
|
|
89
89
|
export interface RichTextExtension {
|
|
90
90
|
name: string
|
|
91
91
|
label: string
|
|
92
|
+
/** Apply this extension to every RichText editor in the app without field-level opt-in. */
|
|
93
|
+
alwaysActive?: boolean
|
|
92
94
|
toolbarButtons?: CustomToolbarButton[]
|
|
93
95
|
contentStyles?: string
|
|
94
96
|
}
|
|
@@ -28,7 +28,7 @@ onMounted(() => {
|
|
|
28
28
|
|
|
29
29
|
<template>
|
|
30
30
|
<div
|
|
31
|
-
class="bagel-input bgl-toggle"
|
|
31
|
+
class="bagel-input bgl-toggle w-a"
|
|
32
32
|
:title
|
|
33
33
|
:class="[shellClass, { small, 'has-value': checked }]" :style="shellStyle"
|
|
34
34
|
>
|
|
@@ -99,6 +99,10 @@ outline: 1px solid var(--bgl-border-color) !important;
|
|
|
99
99
|
box-shadow:0 1px 5px 0 rgba(0,0,0,.1), 0 1px 2px -1px rgba(0,0,0,.1);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
:global(.bgl-dark-mode) .bgl-toggle input::before {
|
|
103
|
+
background: var(--bgl-dm-text-muted);
|
|
104
|
+
}
|
|
105
|
+
|
|
102
106
|
.bgl-toggle label {
|
|
103
107
|
padding-inline-start: 0.5rem;
|
|
104
108
|
transition: var(--bgl-transition);
|
|
@@ -108,7 +108,7 @@ defineExpose({ open, close })
|
|
|
108
108
|
<embed :src="normalizeURL(item?.src)" type="application/pdf" :title="item?.name">
|
|
109
109
|
</div>
|
|
110
110
|
|
|
111
|
-
<div v-else class="lightbox-file">
|
|
111
|
+
<div v-else class="lightbox-file flex-center">
|
|
112
112
|
<div class="file-info txt-white flex m_block align-items-start gap-025">
|
|
113
113
|
<Icon class="m-0 m_none" icon="draft" :size="10" weight="12" />
|
|
114
114
|
<Icon class="m-0 none m_block m_-mb-1" icon="draft" :size="4" weight="2" />
|
|
@@ -130,11 +130,14 @@ defineExpose({ open, close })
|
|
|
130
130
|
</template>
|
|
131
131
|
|
|
132
132
|
<template #prev-button="{ prev }">
|
|
133
|
-
<Btn
|
|
133
|
+
<Btn icon="arrow_back" color="black" :disabled="currentIndex === 0"
|
|
134
|
+
:class="{ 'color-black-70': currentIndex === 0 }" @click="prev"/>
|
|
134
135
|
</template>
|
|
135
136
|
|
|
136
137
|
<template #next-button="{ next }">
|
|
137
|
-
<Btn icon="arrow_forward" color="black"
|
|
138
|
+
<Btn icon="arrow_forward" color="black" :disabled="currentIndex === group.length - 1"
|
|
139
|
+
:class="{ 'color-black-70': currentIndex === group.length - 1 }"
|
|
140
|
+
@click="next" />
|
|
138
141
|
</template>
|
|
139
142
|
</Swiper>
|
|
140
143
|
|
|
@@ -151,6 +154,11 @@ defineExpose({ open, close })
|
|
|
151
154
|
</template>
|
|
152
155
|
|
|
153
156
|
<style>
|
|
157
|
+
.bgl-lightbox-swiper .swi-prev,
|
|
158
|
+
.bgl-lightbox-swiper .swi-next {
|
|
159
|
+
background: transparent;
|
|
160
|
+
padding: 0;
|
|
161
|
+
}
|
|
154
162
|
|
|
155
163
|
.bgl-lightbox:has(.bgl_vid) {
|
|
156
164
|
width: 90vw;
|