@bagelink/vue 1.5.32 → 1.6.2
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/ListItem.vue.d.ts +1 -0
- package/dist/components/ListItem.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ArrayInput.vue.d.ts +33 -0
- package/dist/components/form/inputs/ArrayInput.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/SelectInput.vue.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/index.cjs +21 -21
- package/dist/index.mjs +3736 -3660
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/ListItem.vue +10 -8
- package/src/components/form/inputs/ArrayInput.vue +79 -0
- package/src/components/form/inputs/SelectInput.vue +28 -28
- package/src/components/form/inputs/index.ts +1 -0
- package/src/styles/text.css +36 -0
- package/src/styles/theme.css +1 -0
package/package.json
CHANGED
|
@@ -21,6 +21,7 @@ const props = withDefaults(
|
|
|
21
21
|
fullWidth?: boolean
|
|
22
22
|
ellipsis?: boolean
|
|
23
23
|
ripple?: boolean
|
|
24
|
+
tiny?: boolean
|
|
24
25
|
onClick?: () => void
|
|
25
26
|
}>(),
|
|
26
27
|
{
|
|
@@ -30,9 +31,9 @@ const props = withDefaults(
|
|
|
30
31
|
)
|
|
31
32
|
|
|
32
33
|
const isComponent = $computed(() => {
|
|
33
|
-
if (props.to) {return 'router-link'}
|
|
34
|
-
if (props.href) {return 'a'}
|
|
35
|
-
if (props.onClick) {return 'button'}
|
|
34
|
+
if (props.to) { return 'router-link' }
|
|
35
|
+
if (props.href) { return 'a' }
|
|
36
|
+
if (props.onClick) { return 'button' }
|
|
36
37
|
return 'div'
|
|
37
38
|
})
|
|
38
39
|
|
|
@@ -42,15 +43,15 @@ const isClickable = $computed(() => {
|
|
|
42
43
|
|
|
43
44
|
const bind = $computed(() => {
|
|
44
45
|
const obj: { [key: string]: any } = {}
|
|
45
|
-
if (props.to) {obj.to = props.to}
|
|
46
|
-
else if (props.href) {obj.href = props.href}
|
|
47
|
-
if (props.target && (props.to || props.href)) {obj.target = props.target}
|
|
46
|
+
if (props.to) { obj.to = props.to }
|
|
47
|
+
else if (props.href) { obj.href = props.href }
|
|
48
|
+
if (props.target && (props.to || props.href)) { obj.target = props.target }
|
|
48
49
|
|
|
49
50
|
obj.class = {
|
|
50
51
|
'notClickable': !(props.to || props.onClick),
|
|
51
52
|
'no-border-list': props.flat,
|
|
52
53
|
}
|
|
53
|
-
if (props.disabled) {obj.disabled = true}
|
|
54
|
+
if (props.disabled) { obj.disabled = true }
|
|
54
55
|
return obj
|
|
55
56
|
})
|
|
56
57
|
</script>
|
|
@@ -60,8 +61,9 @@ const bind = $computed(() => {
|
|
|
60
61
|
<component
|
|
61
62
|
:is="isComponent" v-bind="bind" v-ripple="ripple && isClickable"
|
|
62
63
|
class="flex flex-grow-1 gap-05 list-item" :class="{
|
|
63
|
-
'py-1': !props.thin,
|
|
64
|
+
'py-1': !props.thin && !props.tiny,
|
|
64
65
|
'py-05': props.thin,
|
|
66
|
+
'py-0': props.tiny,
|
|
65
67
|
'px-1': !props.fullWidth,
|
|
66
68
|
'px-0': props.fullWidth,
|
|
67
69
|
}" @click="onClick"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script setup lang="ts" generic="T = unknown">
|
|
2
|
+
import type { Ref, WritableComputedRef } from 'vue'
|
|
3
|
+
|
|
4
|
+
import { Btn } from '@bagelink/vue'
|
|
5
|
+
import { computed, ref, watch } from 'vue'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
label?: string
|
|
9
|
+
helpText?: string
|
|
10
|
+
modelValue: T[]
|
|
11
|
+
allowAdd?: boolean
|
|
12
|
+
allowDelete?: boolean
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const emit = defineEmits(['update:modelValue'])
|
|
16
|
+
|
|
17
|
+
defineSlots<{
|
|
18
|
+
default: (props: { item: WritableComputedRef<T>, index: number }) => unknown
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
const items = ref(Array.isArray(props.modelValue) ? [...props.modelValue] : []) as Ref<T[]>
|
|
22
|
+
|
|
23
|
+
watch(
|
|
24
|
+
() => props.modelValue,
|
|
25
|
+
(newVal) => {
|
|
26
|
+
if (Array.isArray(newVal)) {
|
|
27
|
+
items.value = [...newVal]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
function addItem() {
|
|
33
|
+
items.value.push(undefined as T)
|
|
34
|
+
updateModel()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function deleteItem(i: number) {
|
|
38
|
+
items.value.splice(i, 1)
|
|
39
|
+
updateModel()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function updateModel() {
|
|
43
|
+
emit('update:modelValue', [...items.value])
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function onUpdate(value: T, i: number) {
|
|
47
|
+
items.value[i] = value
|
|
48
|
+
updateModel()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Create a writable computed ref for each item
|
|
52
|
+
function getItemRef(i: number) {
|
|
53
|
+
return computed({
|
|
54
|
+
get: () => items.value[i],
|
|
55
|
+
set: (value) => {
|
|
56
|
+
onUpdate(value, i)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template>
|
|
63
|
+
<div>
|
|
64
|
+
<label v-if="label" class="txt12 txt-gray-90 mb-025">
|
|
65
|
+
{{ label }}
|
|
66
|
+
</label>
|
|
67
|
+
<p v-if="helpText" class="txt12 txt-gray-50 mb-05">
|
|
68
|
+
{{ helpText }}
|
|
69
|
+
</p>
|
|
70
|
+
<div
|
|
71
|
+
v-for="(_, i) in items" :key="i" class="array-input-row"
|
|
72
|
+
style="display: flex; align-items: center; gap: 0.5rem;"
|
|
73
|
+
>
|
|
74
|
+
<slot :item="getItemRef(i)" :index="i" />
|
|
75
|
+
<Btn v-if="allowDelete" v-tooltip="'Delete'" flat icon="delete" size="xs" @click="deleteItem(i)" />
|
|
76
|
+
</div>
|
|
77
|
+
<Btn v-if="allowAdd" icon="add" size="small" value="Add" @click="addItem" />
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
@@ -13,7 +13,7 @@ const props = withDefaults(defineProps<PropTypes>(), {
|
|
|
13
13
|
|
|
14
14
|
const emit = defineEmits(['update:modelValue'])
|
|
15
15
|
|
|
16
|
-
const isAsyncSource = (src: OptionsSource): src is (q: string) => Promise<Option[]> => 'function'
|
|
16
|
+
const isAsyncSource = (src: OptionsSource): src is (q: string) => Promise<Option[]> => typeof src === 'function'
|
|
17
17
|
|
|
18
18
|
type Primitive = string | number | boolean
|
|
19
19
|
|
|
@@ -48,8 +48,8 @@ let selected = $ref(false)
|
|
|
48
48
|
let open = $ref(false)
|
|
49
49
|
|
|
50
50
|
const selectedLabel = $computed((): string => {
|
|
51
|
-
if (
|
|
52
|
-
if (
|
|
51
|
+
if (selectedItemCount === 0) { return props.placeholder }
|
|
52
|
+
if (selectedItemCount > 4) {
|
|
53
53
|
const str = selectedItems
|
|
54
54
|
.slice(0, 4)
|
|
55
55
|
.map(item => getLabel(item))
|
|
@@ -77,30 +77,30 @@ function navigate(direction: 'up' | 'down') {
|
|
|
77
77
|
setTimeout(() => { navigate(direction) }, 210)
|
|
78
78
|
return
|
|
79
79
|
}
|
|
80
|
-
if ('up'
|
|
81
|
-
highlightedIndex =
|
|
82
|
-
} else if ('down'
|
|
80
|
+
if (direction === 'up') {
|
|
81
|
+
highlightedIndex = highlightedIndex > 0 ? highlightedIndex - 1 : results.value.length - 1
|
|
82
|
+
} else if (direction === 'down') {
|
|
83
83
|
highlightedIndex = highlightedIndex < results.value.length - 1 ? highlightedIndex + 1 : 0
|
|
84
84
|
}
|
|
85
85
|
setTimeout(() => {
|
|
86
86
|
const el = selectOptions?.children[highlightedIndex] as HTMLElement
|
|
87
|
-
if (el) {el.focus()}
|
|
88
|
-
else {highlightedIndex = -1}
|
|
87
|
+
if (el) { el.focus() }
|
|
88
|
+
else { highlightedIndex = -1 }
|
|
89
89
|
}, 10)
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
const isSelected = (option: Option) => selectedItems.find(item => getValue(option) === getValue(item)) !== undefined
|
|
93
93
|
|
|
94
94
|
function scrollToSelectedItem() {
|
|
95
|
-
if (!selectOptions ||
|
|
95
|
+
if (!selectOptions || selectedItemCount === 0) { return }
|
|
96
96
|
|
|
97
97
|
// Find the first selected item in the results
|
|
98
98
|
const selectedIndex = results.value.findIndex(option => isSelected(option))
|
|
99
|
-
if (
|
|
99
|
+
if (selectedIndex === -1) { return }
|
|
100
100
|
|
|
101
101
|
// Get the selected option element
|
|
102
102
|
const selectedElement = selectOptions.children[selectedIndex] as HTMLElement
|
|
103
|
-
if (!selectedElement) {return}
|
|
103
|
+
if (!selectedElement) { return }
|
|
104
104
|
|
|
105
105
|
// Scroll the selected item into view
|
|
106
106
|
selectedElement.scrollIntoView({
|
|
@@ -110,22 +110,22 @@ function scrollToSelectedItem() {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
function getLabel(option: Option) {
|
|
113
|
-
if (
|
|
114
|
-
if ('object'
|
|
115
|
-
if ('boolean'
|
|
113
|
+
if (option == null) { return '' }
|
|
114
|
+
if (typeof option === 'object') { return option.label ?? String((option as any).value ?? '') }
|
|
115
|
+
if (typeof option === 'boolean') { return option ? 'Yes' : 'No' }
|
|
116
116
|
return String(option)
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function getValue(option?: Option): Primitive | undefined {
|
|
120
|
-
if (
|
|
121
|
-
if ('object'
|
|
120
|
+
if (option == null) { return }
|
|
121
|
+
if (typeof option === 'object') { return option.value as Primitive }
|
|
122
122
|
return option as Primitive
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function focusInput() {
|
|
126
126
|
open = true
|
|
127
127
|
setTimeout(() => {
|
|
128
|
-
if (searchInput) {searchInput.focus()}
|
|
128
|
+
if (searchInput) { searchInput.focus() }
|
|
129
129
|
}, 10)
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -134,7 +134,7 @@ function select(option: Option) {
|
|
|
134
134
|
const existingIndex = selectedItems.findIndex(
|
|
135
135
|
item => getValue(item) === getValue(option),
|
|
136
136
|
)
|
|
137
|
-
if (-1
|
|
137
|
+
if (existingIndex > -1) {
|
|
138
138
|
selectedItems.splice(existingIndex, 1)
|
|
139
139
|
}
|
|
140
140
|
else if (props.multiselect) {
|
|
@@ -148,7 +148,7 @@ function select(option: Option) {
|
|
|
148
148
|
|
|
149
149
|
// Move focus away from popper content before it gets aria-hidden
|
|
150
150
|
const active = document.activeElement as HTMLElement | null
|
|
151
|
-
if (active && selectOptions?.contains(active)) {active.blur()}
|
|
151
|
+
if (active && selectOptions?.contains(active)) { active.blur() }
|
|
152
152
|
|
|
153
153
|
if (!props.multiselect) {
|
|
154
154
|
open = false
|
|
@@ -169,7 +169,7 @@ function emitUpdate() {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
function compareArrays(arr1: Option[], arr2: Option[]) {
|
|
172
|
-
if (arr1.length !== arr2.length) {return false}
|
|
172
|
+
if (arr1.length !== arr2.length) { return false }
|
|
173
173
|
const s1 = arr1.map(getValue).filter(Boolean).map(String).sort()
|
|
174
174
|
const s2 = arr2.map(getValue).filter(Boolean).map(String).sort()
|
|
175
175
|
return s1.every((v, i) => v === s2[i])
|
|
@@ -182,7 +182,7 @@ watch(
|
|
|
182
182
|
const newOption = Array.isArray(props.options)
|
|
183
183
|
? (props.options.find(o => getValue(o) === newVal) ?? newVal)
|
|
184
184
|
: newVal
|
|
185
|
-
if (newOption && !isSelected(newOption)) {selectedItems = [newOption]}
|
|
185
|
+
if (newOption && !isSelected(newOption)) { selectedItems = [newOption] }
|
|
186
186
|
} else {
|
|
187
187
|
const newData = [newVal].flat()
|
|
188
188
|
const isSame = compareArrays(newData, selectedItems)
|
|
@@ -206,13 +206,13 @@ watch(
|
|
|
206
206
|
() => props.options,
|
|
207
207
|
() => {
|
|
208
208
|
const opts = props.options
|
|
209
|
-
if (!Array.isArray(opts)) {return}
|
|
209
|
+
if (!Array.isArray(opts)) { return }
|
|
210
210
|
selectedItems.forEach((option, i) => {
|
|
211
211
|
const exists = opts.find(
|
|
212
212
|
(o: Option) => getValue(o) === getValue(option),
|
|
213
213
|
)
|
|
214
|
-
if (exists === undefined) {selectedItems.splice(i, 1)}
|
|
215
|
-
else {selectedItems.splice(i, 1, exists)}
|
|
214
|
+
if (exists === undefined) { selectedItems.splice(i, 1) }
|
|
215
|
+
else { selectedItems.splice(i, 1, exists) }
|
|
216
216
|
})
|
|
217
217
|
// const original = JSON.stringify(props.options.map(getValue));
|
|
218
218
|
// const newSelection = JSON.stringify(selectedItems.map(getValue));
|
|
@@ -225,11 +225,11 @@ watch(
|
|
|
225
225
|
watch(
|
|
226
226
|
() => results.value,
|
|
227
227
|
(newResults) => {
|
|
228
|
-
if (isAsyncSource(props.options) &&
|
|
228
|
+
if (isAsyncSource(props.options) && newResults.length > 0) {
|
|
229
229
|
selectedItems.forEach((option, i) => {
|
|
230
230
|
const optionValue = getValue(option)
|
|
231
231
|
// If the selected item is just a primitive value (no label), find the full option
|
|
232
|
-
if ('object'
|
|
232
|
+
if (typeof option !== 'object' || !option.label) {
|
|
233
233
|
const fullOption = newResults.find(
|
|
234
234
|
(o: Option) => getValue(o) === optionValue,
|
|
235
235
|
)
|
|
@@ -250,7 +250,7 @@ onMounted(() => {
|
|
|
250
250
|
(o: Option) => getValue(o) === getValue(props.defaultValue),
|
|
251
251
|
)
|
|
252
252
|
|
|
253
|
-
if (defaultOption === undefined) {return}
|
|
253
|
+
if (defaultOption === undefined) { return }
|
|
254
254
|
|
|
255
255
|
selectedItems = [defaultOption]
|
|
256
256
|
}
|
|
@@ -411,7 +411,7 @@ onMounted(() => {
|
|
|
411
411
|
.v-popper--theme-dropdown .v-popper__inner {
|
|
412
412
|
border: none;
|
|
413
413
|
/* background: transparent; if anyone is changing this please talk to me first*/
|
|
414
|
-
border-radius: var(--
|
|
414
|
+
border-radius: var(--popper-border-radius);
|
|
415
415
|
color: var(--dropdown-color);
|
|
416
416
|
}
|
|
417
417
|
</style>
|
package/src/styles/text.css
CHANGED
|
@@ -1391,6 +1391,22 @@
|
|
|
1391
1391
|
white-space: nowrap;
|
|
1392
1392
|
}
|
|
1393
1393
|
|
|
1394
|
+
.white-space-break-spaces {
|
|
1395
|
+
white-space: break-spaces;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
.white-space-pre {
|
|
1399
|
+
white-space: pre;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
.white-space-pre-line {
|
|
1403
|
+
white-space: pre-line;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
.white-space-pre-wrap {
|
|
1407
|
+
white-space: pre-wrap;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1394
1410
|
.notranslate {
|
|
1395
1411
|
translate: none !important;
|
|
1396
1412
|
-webkit-translate: none !important;
|
|
@@ -2791,4 +2807,24 @@
|
|
|
2791
2807
|
.m_capitalize {
|
|
2792
2808
|
text-transform: capitalize;
|
|
2793
2809
|
}
|
|
2810
|
+
|
|
2811
|
+
.m_white-space {
|
|
2812
|
+
white-space: nowrap;
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2815
|
+
.m_white-space-break-spaces {
|
|
2816
|
+
white-space: break-spaces;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
.m_white-space-pre {
|
|
2820
|
+
white-space: pre;
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
.m_white-space-pre-line {
|
|
2824
|
+
white-space: pre-line;
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
.m_white-space-pre-wrap {
|
|
2828
|
+
white-space: pre-wrap;
|
|
2829
|
+
}
|
|
2794
2830
|
}
|
package/src/styles/theme.css
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
--bgl-box-bg: var(--bgl-white);
|
|
25
25
|
--bgl-popup-bg: var(--bgl-white);
|
|
26
26
|
--bgl-popup-text: var(--bgl-black);
|
|
27
|
+
--popper-border-radius: var(--card-border-radius);
|
|
27
28
|
--bgl-text-color: var(--bgl-black);
|
|
28
29
|
--bgl-light-text: var(--bgl-white);
|
|
29
30
|
--bgl-richtext-color: var(--bgl-white);
|