@indielayer/ui 1.10.4 → 1.11.0
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/docs/pages/component/select/multiple.vue +8 -0
- package/lib/components/button/theme/Button.base.theme.js +1 -1
- package/lib/components/menu/MenuItem.vue.d.ts +6 -1
- package/lib/components/menu/MenuItem.vue.js +2 -2
- package/lib/components/menu/MenuItem.vue2.js +110 -99
- package/lib/components/menu/theme/MenuItem.base.theme.js +15 -15
- package/lib/components/select/Select.vue.d.ts +676 -0
- package/lib/components/select/Select.vue.js +275 -258
- package/lib/components/table/theme/TableCell.base.theme.js +1 -1
- package/lib/components/tooltip/Tooltip.vue.d.ts +3 -0
- package/lib/components/tooltip/Tooltip.vue.js +12 -9
- package/lib/index.js +1 -1
- package/lib/index.umd.js +3 -3
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/components/button/theme/Button.base.theme.ts +3 -3
- package/src/components/menu/MenuItem.vue +14 -5
- package/src/components/menu/theme/MenuItem.base.theme.ts +1 -1
- package/src/components/select/Select.vue +62 -43
- package/src/components/table/theme/TableCell.base.theme.ts +1 -1
- package/src/components/tooltip/Tooltip.vue +2 -1
- package/src/version.ts +1 -1
package/lib/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "1.
|
|
1
|
+
declare const _default: "1.11.0";
|
|
2
2
|
export default _default;
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -14,9 +14,9 @@ const theme: ButtonTheme = {
|
|
|
14
14
|
// size
|
|
15
15
|
if (props.size === 'xs') classes.push(slots.default ? `py-1 text-xs ${props.icon ? 'px-2' : 'px-2'}` : 'leading-none p-1')
|
|
16
16
|
else if (props.size === 'sm') classes.push(slots.default ? `py-1.5 text-sm ${props.icon ? 'px-3' : 'px-3'}` : 'leading-none p-1.5')
|
|
17
|
-
else if (props.size === 'lg') classes.push(slots.default ? `py-3 text-lg ${props.icon ? 'px-4' : 'px-
|
|
18
|
-
else if (props.size === 'xl') classes.push(slots.default ?
|
|
19
|
-
else classes.push(slots.default ?
|
|
17
|
+
else if (props.size === 'lg') classes.push(slots.default ? `py-3 text-lg ${props.icon ? 'px-4' : 'px-5'}` : 'leading-none p-3')
|
|
18
|
+
else if (props.size === 'xl') classes.push(slots.default ? 'py-4 text-xl px-6' : 'leading-none p-3.5')
|
|
19
|
+
else classes.push(slots.default ? 'py-2 px-4' : 'leading-none p-[0.532rem]')
|
|
20
20
|
|
|
21
21
|
// cursor
|
|
22
22
|
if (props.disabled) classes.push('cursor-not-allowed')
|
|
@@ -34,6 +34,7 @@ const menuItemProps = {
|
|
|
34
34
|
minimal: Boolean,
|
|
35
35
|
prefix: String,
|
|
36
36
|
suffix: String,
|
|
37
|
+
checkbox: Boolean,
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export type MenuItemProps = ExtractPublicPropTypes<typeof menuItemProps>
|
|
@@ -64,7 +65,7 @@ import type { MenuArrayItem } from './Menu.vue'
|
|
|
64
65
|
|
|
65
66
|
const props = defineProps(menuItemProps)
|
|
66
67
|
|
|
67
|
-
const emit = defineEmits(['active', 'click'])
|
|
68
|
+
const emit = defineEmits(['active', 'click', 'checkbox-click'])
|
|
68
69
|
|
|
69
70
|
const elRef = ref()
|
|
70
71
|
const isActive = ref(false)
|
|
@@ -92,7 +93,7 @@ onMounted(() => {
|
|
|
92
93
|
})
|
|
93
94
|
})
|
|
94
95
|
|
|
95
|
-
function onItemClick(e: Event) {
|
|
96
|
+
function onItemClick(e: Event, eventName: 'click' | 'checkbox-click') {
|
|
96
97
|
if (computedProps.value.disabled) {
|
|
97
98
|
e.stopPropagation()
|
|
98
99
|
e.preventDefault()
|
|
@@ -101,7 +102,7 @@ function onItemClick(e: Event) {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
computedProps.value.onClick && computedProps.value.onClick(e)
|
|
104
|
-
emit(
|
|
105
|
+
emit(eventName, e)
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
function check() {
|
|
@@ -140,7 +141,7 @@ const { styles, classes, className } = useTheme('MenuItem', {}, computedProps, {
|
|
|
140
141
|
:class="[
|
|
141
142
|
className,
|
|
142
143
|
$style['menu-item'],
|
|
143
|
-
[isActive ? $style['menu-item--active'] : ''],
|
|
144
|
+
[isActive && !checkbox ? $style['menu-item--active'] : ''],
|
|
144
145
|
classes.wrapper,
|
|
145
146
|
{
|
|
146
147
|
'flex items-center': $slots.prefix || $slots.suffix
|
|
@@ -148,8 +149,16 @@ const { styles, classes, className } = useTheme('MenuItem', {}, computedProps, {
|
|
|
148
149
|
]"
|
|
149
150
|
:title="computedProps.label"
|
|
150
151
|
:alt="computedProps.label"
|
|
151
|
-
@click="onItemClick"
|
|
152
|
+
@click="onItemClick($event, 'click')"
|
|
152
153
|
>
|
|
154
|
+
<x-checkbox
|
|
155
|
+
v-if="checkbox"
|
|
156
|
+
:model-value="computedProps.active"
|
|
157
|
+
hide-footer
|
|
158
|
+
skip-form-registry
|
|
159
|
+
@click.stop.prevent="onItemClick($event, 'checkbox-click')"
|
|
160
|
+
/>
|
|
161
|
+
|
|
153
162
|
<span v-if="$slots.prefix || computedProps.prefix" class="mr-2 shrink-0">
|
|
154
163
|
<slot name="prefix" :item="computedProps">{{ computedProps.prefix }}</slot>
|
|
155
164
|
</span>
|
|
@@ -33,7 +33,7 @@ const theme: MenuItemTheme = {
|
|
|
33
33
|
if (props.filled) {
|
|
34
34
|
if (data.isActive) {
|
|
35
35
|
return css.variables({
|
|
36
|
-
bg: props.selected ? color[100] : color[200],
|
|
36
|
+
bg: props.selected ? color[100] : props.checkbox ? 'transparent' : color[200],
|
|
37
37
|
text: color[800],
|
|
38
38
|
hover: {
|
|
39
39
|
bg: props.selected ? color[200] : color[200],
|
|
@@ -7,6 +7,7 @@ const selectProps = {
|
|
|
7
7
|
placeholder: String,
|
|
8
8
|
options: Array as PropType<SelectOption[]>,
|
|
9
9
|
multiple: Boolean,
|
|
10
|
+
multipleCheckbox: Boolean,
|
|
10
11
|
truncate: Boolean,
|
|
11
12
|
flat: Boolean,
|
|
12
13
|
native: Boolean,
|
|
@@ -15,6 +16,7 @@ const selectProps = {
|
|
|
15
16
|
type: String,
|
|
16
17
|
default: 'Filter by...',
|
|
17
18
|
},
|
|
19
|
+
filterInputProps: Object,
|
|
18
20
|
virtualList: Boolean,
|
|
19
21
|
virtualListOffsetTop: Number,
|
|
20
22
|
virtualListOffsetBottom: Number,
|
|
@@ -26,6 +28,7 @@ const selectProps = {
|
|
|
26
28
|
type: Number,
|
|
27
29
|
default: 5,
|
|
28
30
|
},
|
|
31
|
+
placement: String as PropType<PopoverPlacement>,
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
export type SelectOption = {
|
|
@@ -34,6 +37,8 @@ export type SelectOption = {
|
|
|
34
37
|
prefix?: string;
|
|
35
38
|
suffix?: string;
|
|
36
39
|
disabled?: boolean;
|
|
40
|
+
keepOpenOnClick?: boolean;
|
|
41
|
+
onClick?: () => void | undefined;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
export type SelectProps = ExtractPublicPropTypes<typeof selectProps>
|
|
@@ -66,14 +71,16 @@ import XTag from '../tag/Tag.vue'
|
|
|
66
71
|
import XIcon from '../icon/Icon.vue'
|
|
67
72
|
import XMenuItem from '../menu/MenuItem.vue'
|
|
68
73
|
import XSpinner from '../spinner/Spinner.vue'
|
|
69
|
-
import XPopover from '../popover/Popover.vue'
|
|
74
|
+
import XPopover, { type PopoverPlacement } from '../popover/Popover.vue'
|
|
70
75
|
import XPopoverContainer from '../popover/PopoverContainer.vue'
|
|
71
76
|
import XInputFooter from '../inputFooter/InputFooter.vue'
|
|
72
77
|
import XInput from '../input/Input.vue'
|
|
73
78
|
|
|
74
|
-
const
|
|
79
|
+
const props = defineProps(selectProps)
|
|
75
80
|
|
|
76
|
-
const emit = defineEmits(useInputtable.emits())
|
|
81
|
+
const emit = defineEmits([...useInputtable.emits(), 'close'])
|
|
82
|
+
|
|
83
|
+
const internalMultiple = computed(() => props.multiple || props.multipleCheckbox)
|
|
77
84
|
|
|
78
85
|
const elRef = ref<HTMLElement | null>(null)
|
|
79
86
|
const labelRef = ref<InstanceType<typeof XLabel> | null>(null)
|
|
@@ -81,14 +88,14 @@ const itemsRef = ref<InstanceType<typeof XMenuItem>[] | null>(null)
|
|
|
81
88
|
const popoverRef = ref<InstanceType<typeof XPopover> | null>(null)
|
|
82
89
|
const selectedIndex = ref<number | undefined>()
|
|
83
90
|
|
|
84
|
-
const filter =
|
|
91
|
+
const filter = defineModel('filter', { default : '' })
|
|
85
92
|
const filterRef = ref<InstanceType<typeof XInput> | null>(null)
|
|
86
93
|
|
|
87
94
|
const isDisabled = computed(() => props.disabled || props.loading || props.readonly)
|
|
88
95
|
|
|
89
96
|
const selected = computed<any | any[]>({
|
|
90
97
|
get() {
|
|
91
|
-
if (
|
|
98
|
+
if (internalMultiple.value) {
|
|
92
99
|
if (!props.modelValue) return []
|
|
93
100
|
if (Array.isArray(props.modelValue)) return props.modelValue
|
|
94
101
|
else return [props.modelValue]
|
|
@@ -109,7 +116,7 @@ const internalOptions = computed(() => {
|
|
|
109
116
|
.map((option) => {
|
|
110
117
|
let isActive = false
|
|
111
118
|
|
|
112
|
-
if (
|
|
119
|
+
if (internalMultiple.value && Array.isArray(selected.value)) {
|
|
113
120
|
isActive = selected.value.includes(option.value)
|
|
114
121
|
} else {
|
|
115
122
|
isActive = option.value === selected.value
|
|
@@ -122,7 +129,8 @@ const internalOptions = computed(() => {
|
|
|
122
129
|
prefix: option.prefix,
|
|
123
130
|
suffix: option.suffix,
|
|
124
131
|
disabled: option.disabled,
|
|
125
|
-
iconRight: isActive ? checkIcon : undefined,
|
|
132
|
+
iconRight: !props.multipleCheckbox && isActive ? checkIcon : undefined,
|
|
133
|
+
keepOpenOnClick: option.keepOpenOnClick,
|
|
126
134
|
onClick: () => handleOptionClick(option.value),
|
|
127
135
|
}
|
|
128
136
|
})
|
|
@@ -154,7 +162,7 @@ watch(isOpen, (isOpenValue) => {
|
|
|
154
162
|
if (isOpenValue) {
|
|
155
163
|
findSelectedIndex()
|
|
156
164
|
|
|
157
|
-
if (
|
|
165
|
+
if (internalMultiple.value || typeof selectedIndex.value === 'undefined') {
|
|
158
166
|
findSelectableIndex(-1)
|
|
159
167
|
}
|
|
160
168
|
|
|
@@ -168,11 +176,12 @@ watch(isOpen, (isOpenValue) => {
|
|
|
168
176
|
|
|
169
177
|
} else {
|
|
170
178
|
if (props.filterable) filter.value = ''
|
|
179
|
+
emit('close')
|
|
171
180
|
}
|
|
172
181
|
})
|
|
173
182
|
|
|
174
183
|
function findSelectedIndex() {
|
|
175
|
-
if (
|
|
184
|
+
if (internalMultiple.value) {
|
|
176
185
|
if (Array.isArray(selected.value) && selected.value.length > 0) {
|
|
177
186
|
const index = internalOptions.value.findIndex((option) => option.value === selected.value[0])
|
|
178
187
|
|
|
@@ -229,32 +238,36 @@ function handleOptionClick(value: string | number) {
|
|
|
229
238
|
|
|
230
239
|
if (!option || option.disabled) return
|
|
231
240
|
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
if (option.onClick) {
|
|
242
|
+
option.onClick()
|
|
243
|
+
} else {
|
|
244
|
+
if (internalMultiple.value) {
|
|
245
|
+
if (Array.isArray(selected.value)) {
|
|
246
|
+
const index = selected.value.indexOf(value)
|
|
247
|
+
|
|
248
|
+
if (index !== -1) selected.value.splice(index, 1)
|
|
249
|
+
else {
|
|
250
|
+
selected.value.push(value)
|
|
251
|
+
emit('update:modelValue', selected.value)
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
selected.value = [value]
|
|
240
255
|
}
|
|
256
|
+
|
|
257
|
+
if (props.filterable)
|
|
258
|
+
setTimeout(() => {
|
|
259
|
+
filterRef.value?.focus()
|
|
260
|
+
})
|
|
241
261
|
} else {
|
|
242
|
-
selected.value =
|
|
262
|
+
selected.value = value
|
|
243
263
|
}
|
|
244
264
|
|
|
245
|
-
if (props.
|
|
246
|
-
|
|
247
|
-
|
|
265
|
+
if (!props.native) {
|
|
266
|
+
nextTick(() => {
|
|
267
|
+
validate()
|
|
268
|
+
labelRef.value?.$el.focus()
|
|
248
269
|
})
|
|
249
|
-
|
|
250
|
-
selected.value = value
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (!props.native) {
|
|
254
|
-
nextTick(() => {
|
|
255
|
-
validate()
|
|
256
|
-
labelRef.value?.$el.focus()
|
|
257
|
-
})
|
|
270
|
+
}
|
|
258
271
|
}
|
|
259
272
|
}
|
|
260
273
|
|
|
@@ -360,8 +373,11 @@ function handleKeyNavigation(e: KeyboardEvent) {
|
|
|
360
373
|
return
|
|
361
374
|
}
|
|
362
375
|
if (typeof selectedIndex.value !== 'undefined' && internalOptions.value[selectedIndex.value]) {
|
|
363
|
-
|
|
364
|
-
|
|
376
|
+
const selectedItemInternalOptions = internalOptions.value[selectedIndex.value]
|
|
377
|
+
|
|
378
|
+
handleOptionClick(selectedItemInternalOptions.value)
|
|
379
|
+
|
|
380
|
+
if (!selectedItemInternalOptions.keepOpenOnClick && (!internalMultiple.value || props.multipleCheckbox)) popoverRef.value?.hide()
|
|
365
381
|
}
|
|
366
382
|
} else if (e.code === 'Tab') {
|
|
367
383
|
if (isOpen.value) {
|
|
@@ -383,7 +399,7 @@ const showCountTag = ref(false)
|
|
|
383
399
|
const hiddenTags = ref(0)
|
|
384
400
|
|
|
385
401
|
const handleTruncate = useThrottleFn(() => {
|
|
386
|
-
if (
|
|
402
|
+
if (internalMultiple.value && props.truncate) {
|
|
387
403
|
nextTick(() => {
|
|
388
404
|
const maxTags = calcMaxTags()
|
|
389
405
|
|
|
@@ -432,7 +448,7 @@ watch(selected, (val) => {
|
|
|
432
448
|
|
|
433
449
|
const { styles, classes, className } = useTheme('Select', {}, props, { errorInternal })
|
|
434
450
|
|
|
435
|
-
defineExpose({ focus, blur, reset, validate, setError })
|
|
451
|
+
defineExpose({ focus, blur, reset, validate, setError, filterRef })
|
|
436
452
|
</script>
|
|
437
453
|
|
|
438
454
|
<template>
|
|
@@ -453,7 +469,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
453
469
|
v-on="labelListeners"
|
|
454
470
|
>
|
|
455
471
|
<div class="relative">
|
|
456
|
-
<div v-if="native && !
|
|
472
|
+
<div v-if="native && !internalMultiple" :class="classes.box" @click="elRef?.click()">
|
|
457
473
|
<template v-if="!isEmpty(selected)">
|
|
458
474
|
{{ getLabel(selected) }}
|
|
459
475
|
</template>
|
|
@@ -468,6 +484,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
468
484
|
<x-popover
|
|
469
485
|
ref="popoverRef"
|
|
470
486
|
:disabled="isDisabled"
|
|
487
|
+
:placement="placement"
|
|
471
488
|
>
|
|
472
489
|
<slot
|
|
473
490
|
name="input"
|
|
@@ -477,7 +494,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
477
494
|
:label="getLabel(selected)"
|
|
478
495
|
>
|
|
479
496
|
<div :class="[classes.box]">
|
|
480
|
-
<template v-if="
|
|
497
|
+
<template v-if="internalMultiple && Array.isArray(selected) && selected.length > 0">
|
|
481
498
|
<div
|
|
482
499
|
ref="tagsRef"
|
|
483
500
|
class="flex gap-1 relative"
|
|
@@ -503,7 +520,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
503
520
|
>+{{ hiddenTags }}</div>
|
|
504
521
|
</div>
|
|
505
522
|
</template>
|
|
506
|
-
<template v-else-if="!
|
|
523
|
+
<template v-else-if="!internalMultiple && !isEmpty(selected)">
|
|
507
524
|
{{ getLabel(selected) }}
|
|
508
525
|
</template>
|
|
509
526
|
|
|
@@ -530,7 +547,9 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
530
547
|
v-model="filter"
|
|
531
548
|
:placeholder="filterPlaceholder"
|
|
532
549
|
skip-form-registry
|
|
550
|
+
data-1p-ignore
|
|
533
551
|
size="sm"
|
|
552
|
+
v-bind="filterInputProps"
|
|
534
553
|
/>
|
|
535
554
|
</div>
|
|
536
555
|
</slot>
|
|
@@ -544,9 +563,10 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
544
563
|
:size="size"
|
|
545
564
|
:disabled="item.data.disabled"
|
|
546
565
|
:selected="item.index === selectedIndex"
|
|
566
|
+
:checkbox="multipleCheckbox && !item.data.keepOpenOnClick"
|
|
547
567
|
:color="color"
|
|
548
568
|
filled
|
|
549
|
-
@click="() => !
|
|
569
|
+
@click="() => !item.data.keepOpenOnClick && (!internalMultiple || multipleCheckbox) && popoverRef?.hide()"
|
|
550
570
|
>
|
|
551
571
|
<template v-if="$slots.prefix || item.data.prefix" #prefix><slot name="prefix" :item="item.data">{{ item.data.prefix }}</slot></template>
|
|
552
572
|
<slot name="label" :item="item.data"></slot>
|
|
@@ -562,7 +582,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
562
582
|
</template>
|
|
563
583
|
</x-popover>
|
|
564
584
|
<x-popover
|
|
565
|
-
v-if="
|
|
585
|
+
v-if="internalMultiple && truncate && showCountTag"
|
|
566
586
|
ref="multipleHiddenRef"
|
|
567
587
|
:popper-show-triggers="[]"
|
|
568
588
|
:popper-hide-triggers="[]"
|
|
@@ -590,10 +610,10 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
590
610
|
ref="elRef"
|
|
591
611
|
v-model="selected"
|
|
592
612
|
tabindex="-1"
|
|
593
|
-
:class="native && !
|
|
613
|
+
:class="native && !internalMultiple ? 'absolute inset-0 w-full h-full cursor-pointer opacity-0' : 'hidden'"
|
|
594
614
|
:name="name"
|
|
595
615
|
:disabled="disabled || loading"
|
|
596
|
-
:multiple="
|
|
616
|
+
:multiple="internalMultiple"
|
|
597
617
|
:readonly="readonly"
|
|
598
618
|
v-on="inputListeners"
|
|
599
619
|
>
|
|
@@ -609,7 +629,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
609
629
|
</template>
|
|
610
630
|
</select>
|
|
611
631
|
|
|
612
|
-
<div :class="classes.iconWrapper">
|
|
632
|
+
<div v-if="!$slots.input" :class="classes.iconWrapper">
|
|
613
633
|
<x-spinner v-if="loading" :size="size" />
|
|
614
634
|
<slot v-else name="icon">
|
|
615
635
|
<x-icon
|
|
@@ -617,7 +637,6 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
617
637
|
:class="[classes.icon]"
|
|
618
638
|
/>
|
|
619
639
|
</slot>
|
|
620
|
-
|
|
621
640
|
</div>
|
|
622
641
|
</div>
|
|
623
642
|
|
|
@@ -5,7 +5,7 @@ const theme: TableCellTheme = {
|
|
|
5
5
|
wrapper: ({ props }) => {
|
|
6
6
|
const c = ['px-3']
|
|
7
7
|
|
|
8
|
-
c.push(props.dense ? 'py-
|
|
8
|
+
c.push(props.dense ? 'h-9 py-0.5' : 'h-11 py-1')
|
|
9
9
|
|
|
10
10
|
if (props.textAlign === 'left') c.push('text-left')
|
|
11
11
|
else if (props.textAlign === 'center') c.push('text-center')
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
const tooltipProps = {
|
|
3
|
+
tooltip: String,
|
|
3
4
|
placement: {
|
|
4
5
|
type: String as PropType<PopoverPlacement>,
|
|
5
6
|
default: 'bottom',
|
|
@@ -28,7 +29,7 @@ const props = defineProps(tooltipProps)
|
|
|
28
29
|
<template #content>
|
|
29
30
|
<div class="dark">
|
|
30
31
|
<x-popover-container class="p-2 text-white text-xs w-max max-w-xs">
|
|
31
|
-
<slot name="tooltip"
|
|
32
|
+
<slot name="tooltip">{{ tooltip }}</slot>
|
|
32
33
|
</x-popover-container>
|
|
33
34
|
</div>
|
|
34
35
|
</template>
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.
|
|
1
|
+
export default '1.11.0'
|