@indielayer/ui 1.10.5 → 1.12.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 +43 -13
- package/docs/pages/component/tag/usage.vue +26 -0
- 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 +297 -265
- package/lib/components/tag/Tag.vue.d.ts +1 -0
- package/lib/components/tag/Tag.vue.js +42 -35
- package/lib/index.js +1 -1
- package/lib/index.umd.js +4 -4
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- 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 +73 -45
- package/src/components/tag/Tag.vue +11 -6
- 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.12.0";
|
|
2
2
|
export default _default;
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -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,
|
|
@@ -26,6 +27,7 @@ const selectProps = {
|
|
|
26
27
|
type: Number,
|
|
27
28
|
default: 5,
|
|
28
29
|
},
|
|
30
|
+
placement: String as PropType<PopoverPlacement>,
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export type SelectOption = {
|
|
@@ -34,6 +36,8 @@ export type SelectOption = {
|
|
|
34
36
|
prefix?: string;
|
|
35
37
|
suffix?: string;
|
|
36
38
|
disabled?: boolean;
|
|
39
|
+
keepOpenOnClick?: boolean;
|
|
40
|
+
onClick?: () => void | undefined;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
export type SelectProps = ExtractPublicPropTypes<typeof selectProps>
|
|
@@ -66,14 +70,16 @@ import XTag from '../tag/Tag.vue'
|
|
|
66
70
|
import XIcon from '../icon/Icon.vue'
|
|
67
71
|
import XMenuItem from '../menu/MenuItem.vue'
|
|
68
72
|
import XSpinner from '../spinner/Spinner.vue'
|
|
69
|
-
import XPopover from '../popover/Popover.vue'
|
|
73
|
+
import XPopover, { type PopoverPlacement } from '../popover/Popover.vue'
|
|
70
74
|
import XPopoverContainer from '../popover/PopoverContainer.vue'
|
|
71
75
|
import XInputFooter from '../inputFooter/InputFooter.vue'
|
|
72
76
|
import XInput from '../input/Input.vue'
|
|
73
77
|
|
|
74
|
-
const
|
|
78
|
+
const props = defineProps(selectProps)
|
|
75
79
|
|
|
76
|
-
const emit = defineEmits(useInputtable.emits())
|
|
80
|
+
const emit = defineEmits([...useInputtable.emits(), 'close'])
|
|
81
|
+
|
|
82
|
+
const internalMultiple = computed(() => props.multiple || props.multipleCheckbox)
|
|
77
83
|
|
|
78
84
|
const elRef = ref<HTMLElement | null>(null)
|
|
79
85
|
const labelRef = ref<InstanceType<typeof XLabel> | null>(null)
|
|
@@ -81,14 +87,14 @@ const itemsRef = ref<InstanceType<typeof XMenuItem>[] | null>(null)
|
|
|
81
87
|
const popoverRef = ref<InstanceType<typeof XPopover> | null>(null)
|
|
82
88
|
const selectedIndex = ref<number | undefined>()
|
|
83
89
|
|
|
84
|
-
const filter =
|
|
90
|
+
const filter = defineModel('filter', { default : '' })
|
|
85
91
|
const filterRef = ref<InstanceType<typeof XInput> | null>(null)
|
|
86
92
|
|
|
87
93
|
const isDisabled = computed(() => props.disabled || props.loading || props.readonly)
|
|
88
94
|
|
|
89
95
|
const selected = computed<any | any[]>({
|
|
90
96
|
get() {
|
|
91
|
-
if (
|
|
97
|
+
if (internalMultiple.value) {
|
|
92
98
|
if (!props.modelValue) return []
|
|
93
99
|
if (Array.isArray(props.modelValue)) return props.modelValue
|
|
94
100
|
else return [props.modelValue]
|
|
@@ -109,7 +115,7 @@ const internalOptions = computed(() => {
|
|
|
109
115
|
.map((option) => {
|
|
110
116
|
let isActive = false
|
|
111
117
|
|
|
112
|
-
if (
|
|
118
|
+
if (internalMultiple.value && Array.isArray(selected.value)) {
|
|
113
119
|
isActive = selected.value.includes(option.value)
|
|
114
120
|
} else {
|
|
115
121
|
isActive = option.value === selected.value
|
|
@@ -122,7 +128,8 @@ const internalOptions = computed(() => {
|
|
|
122
128
|
prefix: option.prefix,
|
|
123
129
|
suffix: option.suffix,
|
|
124
130
|
disabled: option.disabled,
|
|
125
|
-
iconRight: isActive ? checkIcon : undefined,
|
|
131
|
+
iconRight: !props.multipleCheckbox && isActive ? checkIcon : undefined,
|
|
132
|
+
keepOpenOnClick: option.keepOpenOnClick,
|
|
126
133
|
onClick: () => handleOptionClick(option.value),
|
|
127
134
|
}
|
|
128
135
|
})
|
|
@@ -154,7 +161,7 @@ watch(isOpen, (isOpenValue) => {
|
|
|
154
161
|
if (isOpenValue) {
|
|
155
162
|
findSelectedIndex()
|
|
156
163
|
|
|
157
|
-
if (
|
|
164
|
+
if (internalMultiple.value || typeof selectedIndex.value === 'undefined') {
|
|
158
165
|
findSelectableIndex(-1)
|
|
159
166
|
}
|
|
160
167
|
|
|
@@ -168,11 +175,12 @@ watch(isOpen, (isOpenValue) => {
|
|
|
168
175
|
|
|
169
176
|
} else {
|
|
170
177
|
if (props.filterable) filter.value = ''
|
|
178
|
+
emit('close')
|
|
171
179
|
}
|
|
172
180
|
})
|
|
173
181
|
|
|
174
182
|
function findSelectedIndex() {
|
|
175
|
-
if (
|
|
183
|
+
if (internalMultiple.value) {
|
|
176
184
|
if (Array.isArray(selected.value) && selected.value.length > 0) {
|
|
177
185
|
const index = internalOptions.value.findIndex((option) => option.value === selected.value[0])
|
|
178
186
|
|
|
@@ -229,32 +237,37 @@ function handleOptionClick(value: string | number) {
|
|
|
229
237
|
|
|
230
238
|
if (!option || option.disabled) return
|
|
231
239
|
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
+
if (option.onClick) {
|
|
241
|
+
option.onClick()
|
|
242
|
+
} else {
|
|
243
|
+
if (internalMultiple.value) {
|
|
244
|
+
if (Array.isArray(selected.value)) {
|
|
245
|
+
const index = selected.value.indexOf(value)
|
|
246
|
+
|
|
247
|
+
if (index !== -1) selected.value.splice(index, 1)
|
|
248
|
+
else {
|
|
249
|
+
selected.value.push(value)
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
selected.value = [value]
|
|
240
253
|
}
|
|
254
|
+
|
|
255
|
+
emit('update:modelValue', selected.value)
|
|
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"
|
|
@@ -494,7 +511,12 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
494
511
|
:outlined="!(isDisabled || options?.find((i) => i.value === value)?.disabled)"
|
|
495
512
|
:disabled="isDisabled || options?.find((i) => i.value === value)?.disabled"
|
|
496
513
|
@remove="(e: Event) => { handleRemove(e, value) }"
|
|
497
|
-
>
|
|
514
|
+
>
|
|
515
|
+
<template #prefix>
|
|
516
|
+
<slot name="tag-prefix" :item="options?.find((i) => i.value === value)"></slot>
|
|
517
|
+
</template>
|
|
518
|
+
{{ getLabel(value) }}
|
|
519
|
+
</x-tag>
|
|
498
520
|
|
|
499
521
|
<div
|
|
500
522
|
v-if="showCountTag"
|
|
@@ -503,7 +525,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
503
525
|
>+{{ hiddenTags }}</div>
|
|
504
526
|
</div>
|
|
505
527
|
</template>
|
|
506
|
-
<template v-else-if="!
|
|
528
|
+
<template v-else-if="!internalMultiple && !isEmpty(selected)">
|
|
507
529
|
{{ getLabel(selected) }}
|
|
508
530
|
</template>
|
|
509
531
|
|
|
@@ -530,6 +552,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
530
552
|
v-model="filter"
|
|
531
553
|
:placeholder="filterPlaceholder"
|
|
532
554
|
skip-form-registry
|
|
555
|
+
data-1p-ignore
|
|
533
556
|
size="sm"
|
|
534
557
|
/>
|
|
535
558
|
</div>
|
|
@@ -544,9 +567,10 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
544
567
|
:size="size"
|
|
545
568
|
:disabled="item.data.disabled"
|
|
546
569
|
:selected="item.index === selectedIndex"
|
|
570
|
+
:checkbox="multipleCheckbox && !item.data.keepOpenOnClick"
|
|
547
571
|
:color="color"
|
|
548
572
|
filled
|
|
549
|
-
@click="() => !
|
|
573
|
+
@click="() => !item.data.keepOpenOnClick && (!internalMultiple || multipleCheckbox) && popoverRef?.hide()"
|
|
550
574
|
>
|
|
551
575
|
<template v-if="$slots.prefix || item.data.prefix" #prefix><slot name="prefix" :item="item.data">{{ item.data.prefix }}</slot></template>
|
|
552
576
|
<slot name="label" :item="item.data"></slot>
|
|
@@ -562,7 +586,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
562
586
|
</template>
|
|
563
587
|
</x-popover>
|
|
564
588
|
<x-popover
|
|
565
|
-
v-if="
|
|
589
|
+
v-if="internalMultiple && truncate && showCountTag"
|
|
566
590
|
ref="multipleHiddenRef"
|
|
567
591
|
:popper-show-triggers="[]"
|
|
568
592
|
:popper-hide-triggers="[]"
|
|
@@ -579,7 +603,12 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
579
603
|
:outlined="!(isDisabled || options?.find((i) => i.value === value)?.disabled)"
|
|
580
604
|
:disabled="isDisabled || options?.find((i) => i.value === value)?.disabled"
|
|
581
605
|
@remove="(e: Event) => { handleRemove(e, value) }"
|
|
582
|
-
>
|
|
606
|
+
>
|
|
607
|
+
<template #prefix>
|
|
608
|
+
<slot name="tag-prefix" :item="options?.find((i) => i.value === value)"></slot>
|
|
609
|
+
</template>
|
|
610
|
+
{{ getLabel(value) }}
|
|
611
|
+
</x-tag>
|
|
583
612
|
</x-popover-container>
|
|
584
613
|
</template>
|
|
585
614
|
</x-popover>
|
|
@@ -590,10 +619,10 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
590
619
|
ref="elRef"
|
|
591
620
|
v-model="selected"
|
|
592
621
|
tabindex="-1"
|
|
593
|
-
:class="native && !
|
|
622
|
+
:class="native && !internalMultiple ? 'absolute inset-0 w-full h-full cursor-pointer opacity-0' : 'hidden'"
|
|
594
623
|
:name="name"
|
|
595
624
|
:disabled="disabled || loading"
|
|
596
|
-
:multiple="
|
|
625
|
+
:multiple="internalMultiple"
|
|
597
626
|
:readonly="readonly"
|
|
598
627
|
v-on="inputListeners"
|
|
599
628
|
>
|
|
@@ -609,7 +638,7 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
609
638
|
</template>
|
|
610
639
|
</select>
|
|
611
640
|
|
|
612
|
-
<div :class="classes.iconWrapper">
|
|
641
|
+
<div v-if="!$slots.input" :class="classes.iconWrapper">
|
|
613
642
|
<x-spinner v-if="loading" :size="size" />
|
|
614
643
|
<slot v-else name="icon">
|
|
615
644
|
<x-icon
|
|
@@ -617,7 +646,6 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
617
646
|
:class="[classes.icon]"
|
|
618
647
|
/>
|
|
619
648
|
</slot>
|
|
620
|
-
|
|
621
649
|
</div>
|
|
622
650
|
</div>
|
|
623
651
|
|
|
@@ -67,11 +67,18 @@ const { styles, classes, className } = useTheme('Tag', {}, props)
|
|
|
67
67
|
]"
|
|
68
68
|
>
|
|
69
69
|
<span
|
|
70
|
-
|
|
71
|
-
class="
|
|
70
|
+
class="max-w-full"
|
|
71
|
+
:class="{'pr-4': removable }"
|
|
72
72
|
>
|
|
73
|
-
<
|
|
74
|
-
|
|
73
|
+
<div class="flex items-center gap-2">
|
|
74
|
+
<slot name="prefix"></slot>
|
|
75
|
+
|
|
76
|
+
<div class="truncate">
|
|
77
|
+
<slot></slot>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div v-if="removable" class="absolute right-1.5 top-0 h-full flex items-center">
|
|
75
82
|
<x-icon
|
|
76
83
|
:size="closeIconSize"
|
|
77
84
|
:icon="closeIcon"
|
|
@@ -81,7 +88,5 @@ const { styles, classes, className } = useTheme('Tag', {}, props)
|
|
|
81
88
|
/>
|
|
82
89
|
</div>
|
|
83
90
|
</span>
|
|
84
|
-
|
|
85
|
-
<slot v-else></slot>
|
|
86
91
|
</component>
|
|
87
92
|
</template>
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.
|
|
1
|
+
export default '1.12.0'
|