@bagelink/vue 1.12.57 → 1.12.67
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/IframeVue.vue.d.ts.map +1 -1
- package/dist/components/Menu.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SignaturePad.vue.d.ts.map +1 -1
- package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
- package/dist/components/layout/TabsNav.vue.d.ts.map +1 -1
- package/dist/dialog/Dialog.vue.d.ts.map +1 -1
- package/dist/form-flow/FormFlow.vue.d.ts.map +1 -1
- package/dist/form-flow/form-flow.d.ts.map +1 -1
- package/dist/index.cjs +80 -80
- package/dist/index.mjs +4860 -4819
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Btn.vue +2 -2
- package/src/components/IframeVue.vue +4 -3
- package/src/components/Menu.vue +6 -1
- package/src/components/calendar/views/WeekView.vue +1 -1
- package/src/components/form/inputs/SignaturePad.vue +17 -0
- package/src/components/layout/AppContent.vue +1 -1
- package/src/components/layout/TabsNav.vue +55 -16
- package/src/dialog/Dialog.vue +6 -0
- package/src/form-flow/FormFlow.vue +9 -2
- package/src/form-flow/form-flow.ts +4 -4
package/package.json
CHANGED
package/src/components/Btn.vue
CHANGED
|
@@ -4,7 +4,7 @@ import type { SetupContext } from 'vue'
|
|
|
4
4
|
import { Icon, Loading, useModal, useI18n, resolveI18n } from '@bagelink/vue'
|
|
5
5
|
import { useSlots, ref, onMounted, onUnmounted, computed } from 'vue'
|
|
6
6
|
import { RouterLink } from 'vue-router'
|
|
7
|
-
|
|
7
|
+
defineOptions({ name: 'BglBtn' })
|
|
8
8
|
const props = withDefaults(
|
|
9
9
|
defineProps<{
|
|
10
10
|
disabled?: boolean
|
|
@@ -23,7 +23,7 @@ const props = withDefaults(
|
|
|
23
23
|
loading?: boolean
|
|
24
24
|
role?: string
|
|
25
25
|
value?: TranslatableString
|
|
26
|
-
to?: string
|
|
26
|
+
to?: string | Record<string, any>
|
|
27
27
|
href?: string
|
|
28
28
|
round?: boolean
|
|
29
29
|
is?: string
|
|
@@ -58,15 +58,16 @@ defineExpose({ contentWindow })
|
|
|
58
58
|
ref="iframe"
|
|
59
59
|
:src
|
|
60
60
|
:title
|
|
61
|
-
frameborder="
|
|
62
|
-
:width
|
|
63
|
-
:height
|
|
61
|
+
frameborder="0"
|
|
62
|
+
:width="width ?? '100%'"
|
|
63
|
+
:height="height ?? '100%'"
|
|
64
64
|
allowpaymentrequest="true"
|
|
65
65
|
:marginwidth
|
|
66
66
|
:marginheight
|
|
67
67
|
:csp
|
|
68
68
|
:scrolling
|
|
69
69
|
:srcset
|
|
70
|
+
style="display:block; border:none;"
|
|
70
71
|
@load="$event => emit('load', $event)"
|
|
71
72
|
/>
|
|
72
73
|
</template>
|
package/src/components/Menu.vue
CHANGED
|
@@ -43,8 +43,13 @@ defineProps<{ items: NavLink[] }>()
|
|
|
43
43
|
</template>
|
|
44
44
|
|
|
45
45
|
<style scoped>
|
|
46
|
-
.bgl_btn.router-link-active {
|
|
46
|
+
/* .bgl_btn.router-link-active {
|
|
47
47
|
background-color: var(--bgl-gray-40);
|
|
48
|
+
} */
|
|
49
|
+
|
|
50
|
+
.bglTopMenu .router-link-active {
|
|
51
|
+
background: var(--bgl-primary) !important;
|
|
52
|
+
color: var(--bgl-white) !important;
|
|
48
53
|
}
|
|
49
54
|
</style>
|
|
50
55
|
|
|
@@ -714,7 +714,7 @@ onUnmounted(() => {
|
|
|
714
714
|
backgroundColor: event.color || 'var(--bgl-primary)',
|
|
715
715
|
}" @mousedown.stop @click.stop="handleEventSelection(event, $event)"
|
|
716
716
|
>
|
|
717
|
-
<div class="overflow-hidden color-white p-025 txt12 h-100p">
|
|
717
|
+
<div class="overflow-hidden color-white p-025 txt12 h-100p flex gap-1 flex-wrap">
|
|
718
718
|
<div class="white-space ellipsis-1">
|
|
719
719
|
{{ event.title }}
|
|
720
720
|
</div>
|
|
@@ -31,6 +31,8 @@ const props = withDefaults(defineProps<{
|
|
|
31
31
|
format?: FormatType
|
|
32
32
|
clearable?: boolean
|
|
33
33
|
required?: boolean
|
|
34
|
+
label?: string
|
|
35
|
+
helptext?: string
|
|
34
36
|
}>(), {
|
|
35
37
|
clearable: true,
|
|
36
38
|
})
|
|
@@ -218,6 +220,8 @@ defineExpose({
|
|
|
218
220
|
:class="{ 'bg-transparent': disabled }"
|
|
219
221
|
@touchmove.prevent
|
|
220
222
|
>
|
|
223
|
+
<label v-if="label" class="label">{{ label }}</label>
|
|
224
|
+
<p v-if="helptext" class="helptext">{{ helptext }}</p>
|
|
221
225
|
<Btn
|
|
222
226
|
v-if="clearable && !disabled"
|
|
223
227
|
flat
|
|
@@ -258,6 +262,19 @@ defineExpose({
|
|
|
258
262
|
border-radius: var(--input-border-radius);
|
|
259
263
|
}
|
|
260
264
|
|
|
265
|
+
.bgl_input.signature-pad > .label {
|
|
266
|
+
display: block;
|
|
267
|
+
font-size: 0.8rem;
|
|
268
|
+
padding: 0.25rem 0.5rem 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.bgl_input.signature-pad > .helptext {
|
|
272
|
+
font-size: 0.75rem;
|
|
273
|
+
padding: 0.15rem 0.5rem 0.25rem;
|
|
274
|
+
margin: 0;
|
|
275
|
+
line-height: 1.4;
|
|
276
|
+
}
|
|
277
|
+
|
|
261
278
|
.bgl_input.signature-pad .canvas[disabled] {
|
|
262
279
|
background: var(--input-disabled-bg);
|
|
263
280
|
border: 1px solid var(--bgl-gray);
|
|
@@ -22,6 +22,7 @@ const props = defineProps<{
|
|
|
22
22
|
fullWidthMobile?: boolean
|
|
23
23
|
alignTxt?: 'center' | 'start' | 'end'
|
|
24
24
|
alignTxtMobile?: 'center' | 'start' | 'end'
|
|
25
|
+
outline?: boolean
|
|
25
26
|
}>()
|
|
26
27
|
|
|
27
28
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -34,21 +35,40 @@ currentTab.value
|
|
|
34
35
|
const tabsWrap = ref<HTMLElement | undefined>(undefined)
|
|
35
36
|
const tabEls = ref<HTMLElement[]>([])
|
|
36
37
|
|
|
38
|
+
let resizeObserver: ResizeObserver | undefined
|
|
39
|
+
|
|
40
|
+
/** Position relative to tabs wrap content box (works after breakpoint / font / scroll changes). */
|
|
41
|
+
function measureActiveTabIndicator(wrap: HTMLElement, activeTab: HTMLElement) {
|
|
42
|
+
const wrapRect = wrap.getBoundingClientRect()
|
|
43
|
+
const tabRect = activeTab.getBoundingClientRect()
|
|
44
|
+
const left = tabRect.left - wrapRect.left + wrap.scrollLeft
|
|
45
|
+
const width = tabRect.width
|
|
46
|
+
if (width > 0) {
|
|
47
|
+
wrap.style.setProperty('--indicator-left', `${left}px`)
|
|
48
|
+
wrap.style.setProperty('--indicator-width', `${width}px`)
|
|
49
|
+
wrap.style.setProperty('--indicator-opacity', '1')
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
37
53
|
function updateIndicator() {
|
|
38
54
|
nextTick(() => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}, 10)
|
|
55
|
+
const wrap = tabsWrap.value
|
|
56
|
+
if (!wrap) { return }
|
|
57
|
+
|
|
58
|
+
const apply = () => {
|
|
59
|
+
tabEls.value = Array.from(wrap.querySelectorAll<HTMLElement>('.bgl_tab'))
|
|
60
|
+
const activeTab = tabEls.value.find(tab => tab.classList.contains('active'))
|
|
61
|
+
if (!activeTab) {
|
|
62
|
+
wrap.style.setProperty('--indicator-opacity', '0')
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
measureActiveTabIndicator(wrap, activeTab)
|
|
51
66
|
}
|
|
67
|
+
|
|
68
|
+
// Double rAF: layout + media-query / font metrics often settle after one frame (e.g. mobile ↔ desktop).
|
|
69
|
+
requestAnimationFrame(() => {
|
|
70
|
+
requestAnimationFrame(apply)
|
|
71
|
+
})
|
|
52
72
|
})
|
|
53
73
|
}
|
|
54
74
|
|
|
@@ -80,32 +100,51 @@ watch(
|
|
|
80
100
|
onMounted(() => {
|
|
81
101
|
tabEls.value = Array.from(tabsWrap.value?.querySelectorAll('.bgl_tab') || [])
|
|
82
102
|
|
|
83
|
-
// Wait for the next frame to ensure all CSS and layout calculations are done
|
|
84
103
|
requestAnimationFrame(() => {
|
|
85
104
|
updateIndicator()
|
|
86
105
|
})
|
|
87
106
|
|
|
88
107
|
window.addEventListener('resize', updateIndicator)
|
|
108
|
+
tabsWrap.value?.addEventListener('scroll', updateIndicator, { passive: true })
|
|
109
|
+
|
|
110
|
+
if (typeof ResizeObserver !== 'undefined' && tabsWrap.value) {
|
|
111
|
+
resizeObserver = new ResizeObserver(() => {
|
|
112
|
+
updateIndicator()
|
|
113
|
+
})
|
|
114
|
+
resizeObserver.observe(tabsWrap.value)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (typeof window !== 'undefined' && window.visualViewport) {
|
|
118
|
+
// Mobile browser chrome / zoom — window "resize" alone can miss this.
|
|
119
|
+
window.visualViewport.addEventListener('resize', updateIndicator)
|
|
120
|
+
}
|
|
89
121
|
})
|
|
90
122
|
|
|
91
123
|
watch(
|
|
92
|
-
() =>
|
|
124
|
+
() => props.tabs,
|
|
93
125
|
() => {
|
|
94
126
|
nextTick(() => { updateIndicator() })
|
|
95
127
|
},
|
|
96
128
|
{ deep: true }
|
|
97
129
|
)
|
|
130
|
+
|
|
98
131
|
onBeforeUnmount(() => {
|
|
99
132
|
window.removeEventListener('resize', updateIndicator)
|
|
133
|
+
tabsWrap.value?.removeEventListener('scroll', updateIndicator)
|
|
134
|
+
resizeObserver?.disconnect()
|
|
135
|
+
resizeObserver = undefined
|
|
136
|
+
if (typeof window !== 'undefined' && window.visualViewport) {
|
|
137
|
+
window.visualViewport.removeEventListener('resize', updateIndicator)
|
|
138
|
+
}
|
|
100
139
|
})
|
|
101
140
|
</script>
|
|
102
141
|
|
|
103
142
|
<template>
|
|
104
|
-
<div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical }">
|
|
143
|
+
<div ref="tabsWrap" class="grid auto-flow-columns relative fit-content bgl_tabs_wrap overflow-hidden" :class="{ 'bgl_flat-tabs': flat, 'bgl_vertical-tabs': vertical, 'outline': outline }">
|
|
105
144
|
<slot name="tabs" v-bind="{ selectTab, isActive, tabLabel, tabs: tabEls }">
|
|
106
145
|
<button v-for="(tab, i) in props.tabs" :key="i" type="button" :class="[
|
|
107
146
|
{ active: isActive(tab) },
|
|
108
|
-
{
|
|
147
|
+
{
|
|
109
148
|
'bgl_tab-thin': thin,
|
|
110
149
|
'bgl_tab-xs': size === 'xs' || size === 'extra-small',
|
|
111
150
|
'bgl_tab-s': size === 's' || size === 'small',
|
package/src/dialog/Dialog.vue
CHANGED
|
@@ -399,12 +399,18 @@ dialog.dialog-right[style*="--dialog-width: 100%"] {
|
|
|
399
399
|
width: calc(100vw - 2rem);
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
+
dialog.dialog-left .grid-dialog,
|
|
403
|
+
dialog.dialog-right .grid-dialog {
|
|
404
|
+
height: 100%
|
|
405
|
+
}
|
|
406
|
+
|
|
402
407
|
/* Mobile adjustments */
|
|
403
408
|
@media screen and (max-width: 910px) {
|
|
404
409
|
|
|
405
410
|
dialog.dialog-left .grid-dialog,
|
|
406
411
|
dialog.dialog-right .grid-dialog {
|
|
407
412
|
max-height: 100vh;
|
|
413
|
+
height: unset !important;
|
|
408
414
|
}
|
|
409
415
|
|
|
410
416
|
dialog.dialog-left,
|
|
@@ -11,6 +11,7 @@ import NumberInput from '../components/form/inputs/NumberInput.vue'
|
|
|
11
11
|
import PasswordInput from '../components/form/inputs/PasswordInput.vue'
|
|
12
12
|
import RadioGroup from '../components/form/inputs/RadioGroup.vue'
|
|
13
13
|
import RichText from '../components/form/inputs/RichText/index.vue'
|
|
14
|
+
import SelectBtn from '../components/form/inputs/SelectBtn.vue'
|
|
14
15
|
import SelectInput from '../components/form/inputs/SelectInput.vue'
|
|
15
16
|
import TelInput from '../components/form/inputs/TelInput.vue'
|
|
16
17
|
import TextInput from '../components/form/inputs/TextInput.vue'
|
|
@@ -194,7 +195,13 @@ function generateLabel(key: string, field: FieldBuilder): string {
|
|
|
194
195
|
.join(' ')
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
function getFieldComponent(
|
|
198
|
+
function getFieldComponent(fieldOrType: FieldBuilder | string) {
|
|
199
|
+
// display: 'btn' on select/multiselect renders as SelectBtn
|
|
200
|
+
if (typeof fieldOrType !== 'string' && (fieldOrType._type === 'select' || fieldOrType._type === 'multiselect') && fieldOrType._config.display === 'btn') {
|
|
201
|
+
return SelectBtn
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const type = typeof fieldOrType === 'string' ? fieldOrType : fieldOrType._type
|
|
198
205
|
const componentMap: Record<string, any> = {
|
|
199
206
|
text: TextInput,
|
|
200
207
|
email: EmailInput,
|
|
@@ -435,7 +442,7 @@ defineExpose({
|
|
|
435
442
|
</template>
|
|
436
443
|
|
|
437
444
|
<!-- Default field rendering -->
|
|
438
|
-
<component :is="getFieldComponent(field
|
|
445
|
+
<component :is="getFieldComponent(field)" v-else v-bind="getFieldProps(field, key)" />
|
|
439
446
|
</slot>
|
|
440
447
|
</div>
|
|
441
448
|
|
|
@@ -326,8 +326,8 @@ export const $ = {
|
|
|
326
326
|
|
|
327
327
|
select<T extends string = string>(
|
|
328
328
|
optionsOrLabel: SelectOptions<T> | string,
|
|
329
|
-
labelOrOptionsOrConfig?: string | SelectOptions<T> | (BaseFieldConfig & { searchable?: boolean }),
|
|
330
|
-
config?: BaseFieldConfig & { searchable?: boolean }
|
|
329
|
+
labelOrOptionsOrConfig?: string | SelectOptions<T> | (BaseFieldConfig & { searchable?: boolean, display?: 'btn', thin?: boolean, outline?: boolean }),
|
|
330
|
+
config?: BaseFieldConfig & { searchable?: boolean, display?: 'btn', thin?: boolean, outline?: boolean }
|
|
331
331
|
): FieldBuilder<T> {
|
|
332
332
|
// Label-first: $.select('Country', ['USA', 'Canada'])
|
|
333
333
|
if (typeof optionsOrLabel === 'string') {
|
|
@@ -341,8 +341,8 @@ export const $ = {
|
|
|
341
341
|
|
|
342
342
|
multiselect<T extends string = string>(
|
|
343
343
|
optionsOrLabel: SelectOptions<T> | string,
|
|
344
|
-
labelOrOptionsOrConfig?: string | SelectOptions<T> | (BaseFieldConfig & { searchable?: boolean }),
|
|
345
|
-
config?: BaseFieldConfig & { searchable?: boolean }
|
|
344
|
+
labelOrOptionsOrConfig?: string | SelectOptions<T> | (BaseFieldConfig & { searchable?: boolean, display?: 'btn', thin?: boolean, outline?: boolean }),
|
|
345
|
+
config?: BaseFieldConfig & { searchable?: boolean, display?: 'btn', thin?: boolean, outline?: boolean }
|
|
346
346
|
): FieldBuilder<T[]> {
|
|
347
347
|
// Label-first: $.multiselect('Tags', ['tech', 'news'])
|
|
348
348
|
if (typeof optionsOrLabel === 'string') {
|