@bagelink/vue 1.15.295 → 1.15.299
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.map +1 -1
- package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts +16 -1
- package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts +22 -2
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/richTextTypes.d.ts +12 -0
- package/dist/components/form/inputs/RichText/richTextTypes.d.ts.map +1 -1
- package/dist/components/form/inputs/index.d.ts +1 -0
- package/dist/components/form/inputs/index.d.ts.map +1 -1
- package/dist/components/layout/AppContent.vue.d.ts +2 -0
- package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
- package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
- package/dist/form-flow/form-flow.d.ts +3 -0
- package/dist/form-flow/form-flow.d.ts.map +1 -1
- package/dist/index.cjs +59 -59
- package/dist/index.mjs +9753 -9705
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Btn.vue +4 -7
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +1 -0
- package/src/components/form/inputs/RichText/index.vue +68 -2
- package/src/components/form/inputs/RichText/richTextTypes.ts +14 -0
- package/src/components/form/inputs/index.ts +1 -0
- package/src/components/layout/AppContent.vue +10 -1
- package/src/components/lightbox/Lightbox.vue +4 -0
- package/src/form-flow/form-flow.ts +3 -2
package/package.json
CHANGED
package/src/components/Btn.vue
CHANGED
|
@@ -310,13 +310,10 @@ opacity: 0;
|
|
|
310
310
|
z-index: 1;
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
/*
|
|
314
|
-
.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
left: 50%;
|
|
318
|
-
transform: translate(-50%, -50%);
|
|
319
|
-
}
|
|
313
|
+
/* The overlay is `absolute-fill flex-center`, so it already centers the <Loading>
|
|
314
|
+
container. Don't re-center the inner ring with top/left:50% — that would override
|
|
315
|
+
the ring's own `translate(-thickness, -thickness)` compensation (it offsets the
|
|
316
|
+
ring-segment margins) and push the spinner slightly off-center. */
|
|
320
317
|
|
|
321
318
|
.bgl_btn .bgl_btn-icon {
|
|
322
319
|
font-size: calc(var(--bgl-input-font-size) * 1.3);
|
|
@@ -251,6 +251,7 @@ function handleOpenAdvanced() {
|
|
|
251
251
|
<!-- Separator -->
|
|
252
252
|
<span v-else-if="action.name === 'separator' && shouldShowSeparator(index)" :key="`separator-${index}`" class="opacity-2 mb-025">|</span>
|
|
253
253
|
</template>
|
|
254
|
+
<slot name="end" />
|
|
254
255
|
</div>
|
|
255
256
|
</template>
|
|
256
257
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!-- eslint-disable vue/multi-word-component-names -->
|
|
2
2
|
<script setup lang="ts">
|
|
3
|
-
import type { ToolbarConfig } from './richTextTypes'
|
|
3
|
+
import type { CustomToolbarButton, RichTextToolbarApi, ToolbarConfig } from './richTextTypes'
|
|
4
4
|
import { CodeEditor, copyText, Btn, Dialog, BglVideo, Icon, Card, ColorInput, pathKeyToURL } from '@bagelink/vue'
|
|
5
5
|
import { watch, onUnmounted, onBeforeUnmount, onMounted, ref, computed, useAttrs } from 'vue'
|
|
6
6
|
import CheckInput from '../CheckInput.vue'
|
|
@@ -23,6 +23,7 @@ defineOptions({
|
|
|
23
23
|
const props = defineProps<{
|
|
24
24
|
modelValue: string
|
|
25
25
|
toolbarConfig?: ToolbarConfig
|
|
26
|
+
customToolbarButtons?: CustomToolbarButton[]
|
|
26
27
|
debug?: boolean
|
|
27
28
|
label?: string
|
|
28
29
|
height?: number | string
|
|
@@ -64,6 +65,52 @@ const isInitializing = ref(false)
|
|
|
64
65
|
const hasInitialized = ref(false)
|
|
65
66
|
const commands = useCommands(editor.state, editor.state.debug)
|
|
66
67
|
|
|
68
|
+
function setBlock(tagName: string, className?: string, removeClasses: string[] = []) {
|
|
69
|
+
const { doc } = editor.state
|
|
70
|
+
if (!doc) return
|
|
71
|
+
|
|
72
|
+
const selection = doc.getSelection()
|
|
73
|
+
const savedRange = selection?.rangeCount
|
|
74
|
+
? selection.getRangeAt(0).cloneRange()
|
|
75
|
+
: editor.state.range?.cloneRange()
|
|
76
|
+
if (!savedRange) return
|
|
77
|
+
|
|
78
|
+
const node = savedRange.commonAncestorContainer
|
|
79
|
+
const element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement
|
|
80
|
+
const currentBlock = element?.closest('p,h1,h2,h3,h4,h5,h6,blockquote,li,div')
|
|
81
|
+
if (!currentBlock || currentBlock === doc.body) return
|
|
82
|
+
|
|
83
|
+
editor.state.undoStack.push(editor.state.content)
|
|
84
|
+
editor.state.redoStack = []
|
|
85
|
+
if (editor.state.undoStack.length > 50) editor.state.undoStack.shift()
|
|
86
|
+
|
|
87
|
+
const target = currentBlock.tagName.toLowerCase() === tagName.toLowerCase()
|
|
88
|
+
? currentBlock
|
|
89
|
+
: doc.createElement(tagName)
|
|
90
|
+
|
|
91
|
+
if (target !== currentBlock) {
|
|
92
|
+
while (currentBlock.firstChild) target.appendChild(currentBlock.firstChild)
|
|
93
|
+
currentBlock.parentNode?.replaceChild(target, currentBlock)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
removeClasses.forEach(name => target.classList.remove(name))
|
|
97
|
+
if (className) target.classList.add(className)
|
|
98
|
+
if (!target.classList.length) target.removeAttribute('class')
|
|
99
|
+
|
|
100
|
+
const nextRange = doc.createRange()
|
|
101
|
+
nextRange.selectNodeContents(target)
|
|
102
|
+
nextRange.collapse(false)
|
|
103
|
+
selection?.removeAllRanges()
|
|
104
|
+
selection?.addRange(nextRange)
|
|
105
|
+
editor.state.range = nextRange.cloneRange()
|
|
106
|
+
updateContentWithHistory(doc, true)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const toolbarApi: RichTextToolbarApi = {
|
|
110
|
+
execute: commands.execute,
|
|
111
|
+
setBlock
|
|
112
|
+
}
|
|
113
|
+
|
|
67
114
|
// Reactive theme colors with forced reactivity
|
|
68
115
|
const forceUpdate = ref(0)
|
|
69
116
|
const currentInputColor = computed(() => {
|
|
@@ -3372,7 +3419,26 @@ const imgTransform = computed({
|
|
|
3372
3419
|
:hide-embeds="hideEmbed" :hide-tables="hideTables" :hide-alignment="hideAlignment"
|
|
3373
3420
|
:hide-directions="hideDirections" :hide-h5-h6="hideH5H6" :hide="effectiveHideArray"
|
|
3374
3421
|
@action="commands.execute"
|
|
3375
|
-
|
|
3422
|
+
>
|
|
3423
|
+
<template #end>
|
|
3424
|
+
<slot name="toolbar-end" :api="toolbarApi">
|
|
3425
|
+
<Btn
|
|
3426
|
+
v-for="button in customToolbarButtons"
|
|
3427
|
+
:key="button.name"
|
|
3428
|
+
v-tooltip="button.label"
|
|
3429
|
+
:icon="button.icon"
|
|
3430
|
+
:value="button.value"
|
|
3431
|
+
:aria-label="button.label"
|
|
3432
|
+
:class="button.class"
|
|
3433
|
+
thin
|
|
3434
|
+
flat
|
|
3435
|
+
tabindex="-1"
|
|
3436
|
+
@mousedown.prevent
|
|
3437
|
+
@click="button.action(toolbarApi)"
|
|
3438
|
+
/>
|
|
3439
|
+
</slot>
|
|
3440
|
+
</template>
|
|
3441
|
+
</EditorToolbar>
|
|
3376
3442
|
<div class="editor-container" :class="{ 'split-view': editor.state.isSplitView }">
|
|
3377
3443
|
<div
|
|
3378
3444
|
class="content-area radius-05"
|
|
@@ -63,6 +63,20 @@ export type ToolbarConfigOption = string
|
|
|
63
63
|
|
|
64
64
|
export type ToolbarConfig = ToolbarConfigOption[]
|
|
65
65
|
|
|
66
|
+
export interface RichTextToolbarApi {
|
|
67
|
+
execute: (command: string, value?: string) => void
|
|
68
|
+
setBlock: (tagName: string, className?: string, removeClasses?: string[]) => void
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface CustomToolbarButton {
|
|
72
|
+
name: string
|
|
73
|
+
label: string
|
|
74
|
+
icon?: string
|
|
75
|
+
value?: string
|
|
76
|
+
class?: string
|
|
77
|
+
action: (api: RichTextToolbarApi) => void
|
|
78
|
+
}
|
|
79
|
+
|
|
66
80
|
export interface ToolbarOption {
|
|
67
81
|
name: string
|
|
68
82
|
label?: string
|
|
@@ -14,6 +14,7 @@ export { default as PasswordInput } from './PasswordInput.vue'
|
|
|
14
14
|
export { default as RadioGroup } from './RadioGroup.vue'
|
|
15
15
|
export { default as RangeInput } from './RangeInput.vue'
|
|
16
16
|
export { default as RichText } from './RichText/index.vue'
|
|
17
|
+
export type { CustomToolbarButton, RichTextToolbarApi } from './RichText/richTextTypes'
|
|
17
18
|
export { default as SelectBtn } from './SelectBtn.vue'
|
|
18
19
|
export { default as SelectInput } from './SelectInput.vue'
|
|
19
20
|
export { default as SignaturePad } from './SignaturePad.vue'
|
|
@@ -12,6 +12,8 @@ interface Props {
|
|
|
12
12
|
subtitle?: string
|
|
13
13
|
showMenuButton?: boolean
|
|
14
14
|
backTo?: string | Record<string, any>
|
|
15
|
+
/** Optional custom back action. When set, the back button calls this instead of navigating to backTo. */
|
|
16
|
+
onBack?: () => void
|
|
15
17
|
/**
|
|
16
18
|
* Header framing:
|
|
17
19
|
* 'border' → bottom hairline under the header (default — legacy behaviour).
|
|
@@ -146,7 +148,14 @@ const hasCenter = computed(() => !!slots['header-center'])
|
|
|
146
148
|
/>
|
|
147
149
|
|
|
148
150
|
<!-- Back Button -->
|
|
149
|
-
<Btn
|
|
151
|
+
<Btn
|
|
152
|
+
v-if="backTo || onBack"
|
|
153
|
+
icon="arrow_back"
|
|
154
|
+
thin
|
|
155
|
+
:to="onBack ? undefined : backTo"
|
|
156
|
+
class="back-btn bg-bg m_-ms-05 m_-me-05 color-black"
|
|
157
|
+
@click="onBack?.()"
|
|
158
|
+
/>
|
|
150
159
|
|
|
151
160
|
<!-- Page Title -->
|
|
152
161
|
<PageTitle v-if="title || subtitle" :subtitle="subtitle">
|
|
@@ -273,6 +273,7 @@ max-height: calc(100vh - 140px);
|
|
|
273
273
|
object-fit: contain;
|
|
274
274
|
border-radius: 3px;
|
|
275
275
|
margin: auto;
|
|
276
|
+
width: 100%;
|
|
276
277
|
}
|
|
277
278
|
|
|
278
279
|
.lightbox-pdf {
|
|
@@ -289,6 +290,9 @@ border-radius: 3px;
|
|
|
289
290
|
|
|
290
291
|
.lightbox-video iframe {
|
|
291
292
|
width: 90vw;
|
|
293
|
+
height: auto;
|
|
294
|
+
aspect-ratio: 16 / 9;
|
|
295
|
+
max-height: calc(100vh - 140px);
|
|
292
296
|
}
|
|
293
297
|
|
|
294
298
|
.lightbox-video video {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { Component } from 'vue'
|
|
12
12
|
import type { IconType } from '../types'
|
|
13
|
+
import type { CustomToolbarButton } from '../components/form/inputs/RichText/richTextTypes'
|
|
13
14
|
import { getOptionValue } from '../utils/options'
|
|
14
15
|
|
|
15
16
|
// ============================================================================
|
|
@@ -297,8 +298,8 @@ export const $ = {
|
|
|
297
298
|
},
|
|
298
299
|
|
|
299
300
|
richtext(
|
|
300
|
-
labelOrConfig?: string | (BaseFieldConfig & { autoheight?: boolean, basic?: boolean, simple?: boolean, fontSize?: number | string }),
|
|
301
|
-
config?: BaseFieldConfig & { autoheight?: boolean, basic?: boolean, simple?: boolean, fontSize?: number | string }
|
|
301
|
+
labelOrConfig?: string | (BaseFieldConfig & { autoheight?: boolean, basic?: boolean, simple?: boolean, fontSize?: number | string, customToolbarButtons?: CustomToolbarButton[] }),
|
|
302
|
+
config?: BaseFieldConfig & { autoheight?: boolean, basic?: boolean, simple?: boolean, fontSize?: number | string, customToolbarButtons?: CustomToolbarButton[] }
|
|
302
303
|
): FieldBuilder<string> {
|
|
303
304
|
return new Field('richtext', parseArgs(labelOrConfig, config))
|
|
304
305
|
},
|