@indielayer/ui 1.9.2 → 1.10.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/components/menu/DocsMenu.vue +1 -0
- package/docs/pages/component/form/usage.vue +2 -0
- package/docs/pages/component/menu/usage.vue +2 -0
- package/docs/pages/component/select/index.vue +7 -0
- package/docs/pages/component/select/multiple.vue +42 -0
- package/docs/pages/component/select/usage.vue +8 -12
- package/docs/pages/component/table/virtual.vue +19 -6
- package/docs/pages/component/toggle/index.vue +1 -1
- package/docs/pages/component/tooltip/index.vue +1 -1
- package/docs/pages/component/upload/index.vue +29 -0
- package/docs/pages/component/upload/usage.vue +115 -0
- package/docs/search/components.json +1 -1
- package/lib/common/icons.d.ts +2 -0
- package/lib/common/icons.js +17 -15
- package/lib/components/checkbox/Checkbox.vue2.js +9 -9
- package/lib/components/datepicker/Datepicker.vue.d.ts +4 -4
- package/lib/components/datepicker/Datepicker.vue.js +1 -1
- package/lib/components/drawer/Drawer.vue.js +1 -17
- package/lib/components/form/Form.vue.d.ts +4 -4
- package/lib/components/form/Form.vue.js +34 -34
- package/lib/components/formGroup/FormGroup.vue.d.ts +1 -1
- package/lib/components/formGroup/FormGroup.vue.js +39 -37
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +68 -66
- package/lib/components/label/theme/Label.base.theme.js +7 -7
- package/lib/components/menu/Menu.vue.d.ts +2 -0
- package/lib/components/menu/MenuItem.vue.d.ts +15 -3
- package/lib/components/menu/MenuItem.vue.js +1 -1
- package/lib/components/menu/MenuItem.vue2.js +43 -37
- package/lib/components/modal/Modal.vue.d.ts +4 -4
- package/lib/components/modal/Modal.vue.js +38 -34
- package/lib/components/notifications/Notifications.vue.d.ts +15 -0
- package/lib/components/notifications/Notifications.vue.js +149 -127
- package/lib/components/progress/Progress.vue.d.ts +4 -4
- package/lib/components/progress/Progress.vue.js +7 -7
- package/lib/components/scroll/Scroll.vue2.js +1 -1
- package/lib/components/select/Select.vue.d.ts +43 -1
- package/lib/components/select/Select.vue.js +358 -258
- package/lib/components/select/theme/Select.base.theme.js +1 -0
- package/lib/components/tab/Tab.vue.js +1 -1
- package/lib/components/tab/TabGroup.vue.js +2 -2
- package/lib/components/table/Table.vue.d.ts +4 -4
- package/lib/components/table/Table.vue.js +37 -37
- package/lib/components/table/TableCell.vue.d.ts +1 -1
- package/lib/components/tag/Tag.vue.js +23 -21
- package/lib/components/textarea/Textarea.vue.js +1 -1
- package/lib/components/upload/Upload.vue.d.ts +195 -0
- package/lib/components/upload/Upload.vue.js +264 -0
- package/lib/components/upload/Upload.vue2.js +4 -0
- package/lib/components/upload/__tests__/Upload.spec.d.ts +1 -0
- package/lib/components/upload/index.d.ts +2 -0
- package/lib/components/upload/theme/Upload.base.theme.d.ts +3 -0
- package/lib/components/upload/theme/Upload.base.theme.js +8 -0
- package/lib/components/upload/theme/Upload.carbon.theme.d.ts +3 -0
- package/lib/components/upload/theme/Upload.carbon.theme.js +5 -0
- package/lib/composables/useVirtualList.js +56 -53
- package/lib/index.js +43 -41
- package/lib/index.umd.js +4 -4
- package/lib/node_modules/.pnpm/@vueuse_core@11.1.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/core/index.js +501 -0
- package/lib/node_modules/.pnpm/@vueuse_shared@11.1.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/shared/index.js +96 -0
- package/lib/theme.d.ts +2 -1
- package/lib/themes/base/components.d.ts +1 -0
- package/lib/themes/base/components.js +23 -21
- package/lib/themes/carbon/components.d.ts +1 -0
- package/lib/themes/carbon/components.js +23 -21
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +3 -3
- package/src/common/icons.ts +2 -0
- package/src/components/checkbox/Checkbox.vue +5 -5
- package/src/components/drawer/Drawer.vue +0 -16
- package/src/components/form/Form.vue +10 -4
- package/src/components/formGroup/FormGroup.vue +2 -0
- package/src/components/index.ts +1 -0
- package/src/components/label/theme/Label.base.theme.ts +7 -5
- package/src/components/menu/Menu.vue +2 -0
- package/src/components/menu/MenuItem.vue +8 -6
- package/src/components/modal/Modal.vue +6 -1
- package/src/components/notifications/Notifications.vue +34 -4
- package/src/components/progress/Progress.vue +2 -2
- package/src/components/select/Select.vue +165 -67
- package/src/components/select/theme/Select.base.theme.ts +2 -0
- package/src/components/table/Table.vue +2 -3
- package/src/components/tag/Tag.vue +11 -9
- package/src/components/upload/Upload.vue +365 -0
- package/src/components/upload/__tests__/Upload.spec.ts +11 -0
- package/src/components/upload/index.ts +2 -0
- package/src/components/upload/theme/Upload.base.theme.ts +9 -0
- package/src/components/upload/theme/Upload.carbon.theme.ts +7 -0
- package/src/composables/useInputtable.ts +1 -1
- package/src/composables/useVirtualList.ts +8 -5
- package/src/theme.ts +2 -0
- package/src/themes/base/components.ts +1 -0
- package/src/themes/carbon/components.ts +1 -0
- package/src/version.ts +1 -1
- package/volar.d.ts +1 -0
- package/lib/node_modules/.pnpm/@vueuse_core@10.2.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/core/index.js +0 -412
- package/lib/node_modules/.pnpm/@vueuse_shared@10.2.0_vue@3.5.10_typescript@5.2.2_/node_modules/@vueuse/shared/index.js +0 -90
|
@@ -7,6 +7,7 @@ const selectProps = {
|
|
|
7
7
|
placeholder: String,
|
|
8
8
|
options: Array as PropType<SelectOption[]>,
|
|
9
9
|
multiple: Boolean,
|
|
10
|
+
truncate: Boolean,
|
|
10
11
|
flat: Boolean,
|
|
11
12
|
native: Boolean,
|
|
12
13
|
filterable: Boolean,
|
|
@@ -30,12 +31,14 @@ const selectProps = {
|
|
|
30
31
|
export type SelectOption = {
|
|
31
32
|
value: number | string;
|
|
32
33
|
label: string;
|
|
34
|
+
prefix?: string;
|
|
35
|
+
suffix?: string;
|
|
33
36
|
disabled?: boolean;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export type SelectProps = ExtractPublicPropTypes<typeof selectProps>
|
|
37
40
|
|
|
38
|
-
type InternalClasses = 'wrapper' | 'box' | 'content' | 'search' | 'contentBody' | 'iconWrapper' | 'icon'
|
|
41
|
+
type InternalClasses = 'wrapper' | 'box' | 'truncateCounter' | 'content' | 'search' | 'contentBody' | 'iconWrapper' | 'icon'
|
|
39
42
|
type InternalExtraData = { errorInternal: Ref<boolean>; }
|
|
40
43
|
export interface SelectTheme extends ThemeComponent<SelectProps, InternalClasses, InternalExtraData> {}
|
|
41
44
|
|
|
@@ -49,7 +52,7 @@ export default {
|
|
|
49
52
|
|
|
50
53
|
<script setup lang="ts">
|
|
51
54
|
import { computed, ref, watch, type PropType, type ExtractPublicPropTypes, type Ref, nextTick, unref, onUnmounted } from 'vue'
|
|
52
|
-
import { useEventListener } from '@vueuse/core'
|
|
55
|
+
import { useEventListener, useResizeObserver, useThrottleFn } from '@vueuse/core'
|
|
53
56
|
import { useColors } from '../../composables/useColors'
|
|
54
57
|
import { useCommon } from '../../composables/useCommon'
|
|
55
58
|
import { useInputtable } from '../../composables/useInputtable'
|
|
@@ -66,7 +69,7 @@ import XSpinner from '../spinner/Spinner.vue'
|
|
|
66
69
|
import XPopover from '../popover/Popover.vue'
|
|
67
70
|
import XPopoverContainer from '../popover/PopoverContainer.vue'
|
|
68
71
|
import XInputFooter from '../inputFooter/InputFooter.vue'
|
|
69
|
-
import
|
|
72
|
+
import XInput from '../input/Input.vue'
|
|
70
73
|
|
|
71
74
|
const props = defineProps(selectProps)
|
|
72
75
|
|
|
@@ -116,6 +119,8 @@ const internalOptions = computed(() => {
|
|
|
116
119
|
value: option.value,
|
|
117
120
|
label: option.label,
|
|
118
121
|
active: isActive,
|
|
122
|
+
prefix: option.prefix,
|
|
123
|
+
suffix: option.suffix,
|
|
119
124
|
disabled: option.disabled,
|
|
120
125
|
iconRight: isActive ? checkIcon : undefined,
|
|
121
126
|
onClick: () => handleOptionClick(option.value),
|
|
@@ -372,6 +377,59 @@ function handleKeyNavigation(e: KeyboardEvent) {
|
|
|
372
377
|
}
|
|
373
378
|
}
|
|
374
379
|
|
|
380
|
+
const tagsRef = ref<HTMLElement | null>(null)
|
|
381
|
+
const multipleHiddenRef = ref<InstanceType<typeof XPopover> | null>(null)
|
|
382
|
+
const showCountTag = ref(false)
|
|
383
|
+
const hiddenTags = ref(0)
|
|
384
|
+
|
|
385
|
+
const handleTruncate = useThrottleFn(() => {
|
|
386
|
+
if (props.multiple && props.truncate) {
|
|
387
|
+
nextTick(() => {
|
|
388
|
+
const maxTags = calcMaxTags()
|
|
389
|
+
|
|
390
|
+
if (maxTags < selected.value.length) {
|
|
391
|
+
showCountTag.value = true
|
|
392
|
+
hiddenTags.value = selected.value.length - maxTags
|
|
393
|
+
} else {
|
|
394
|
+
showCountTag.value = false
|
|
395
|
+
hiddenTags.value = 0
|
|
396
|
+
}
|
|
397
|
+
})
|
|
398
|
+
}
|
|
399
|
+
}, 100, true)
|
|
400
|
+
|
|
401
|
+
useResizeObserver(tagsRef, () => { handleTruncate() })
|
|
402
|
+
|
|
403
|
+
// Calculate max tags that can be displayed, and display: none the rest
|
|
404
|
+
function calcMaxTags() {
|
|
405
|
+
if (!tagsRef.value) return 0
|
|
406
|
+
|
|
407
|
+
const tags = tagsRef.value.querySelectorAll('.x-tag')
|
|
408
|
+
const tagsArray = Array.from(tags)
|
|
409
|
+
|
|
410
|
+
let totalWidth = 0
|
|
411
|
+
let tagsCount = 0
|
|
412
|
+
|
|
413
|
+
const maxWidth = tagsRef.value.offsetWidth - 30
|
|
414
|
+
|
|
415
|
+
for (let i = 0; i < tagsArray.length; i++) {
|
|
416
|
+
const tag = tagsArray[i] as HTMLElement
|
|
417
|
+
|
|
418
|
+
tag.style.display = 'flex'
|
|
419
|
+
|
|
420
|
+
totalWidth += tag.offsetWidth
|
|
421
|
+
|
|
422
|
+
if (totalWidth < maxWidth) tagsCount++
|
|
423
|
+
else tag.style.display = 'none'
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return tagsCount
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
watch(selected, (val) => {
|
|
430
|
+
handleTruncate()
|
|
431
|
+
}, { immediate: true, deep: true })
|
|
432
|
+
|
|
375
433
|
const { styles, classes, className } = useTheme('Select', {}, props, { errorInternal })
|
|
376
434
|
|
|
377
435
|
defineExpose({ focus, blur, reset, validate, setError })
|
|
@@ -406,18 +464,109 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
406
464
|
<div v-else> </div>
|
|
407
465
|
</template>
|
|
408
466
|
</div>
|
|
409
|
-
<
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
467
|
+
<template v-else>
|
|
468
|
+
<x-popover
|
|
469
|
+
ref="popoverRef"
|
|
470
|
+
:disabled="isDisabled"
|
|
471
|
+
>
|
|
472
|
+
<div
|
|
473
|
+
:class="[classes.box]"
|
|
474
|
+
>
|
|
475
|
+
<template v-if="multiple && Array.isArray(selected) && selected.length > 0">
|
|
476
|
+
<div
|
|
477
|
+
ref="tagsRef"
|
|
478
|
+
class="flex gap-1 relative"
|
|
479
|
+
:class="{
|
|
480
|
+
'flex-wrap': !truncate,
|
|
481
|
+
'overflow-hidden': truncate,
|
|
482
|
+
}"
|
|
483
|
+
>
|
|
484
|
+
<x-tag
|
|
485
|
+
v-for="value in selected"
|
|
486
|
+
:key="value"
|
|
487
|
+
size="xs"
|
|
488
|
+
removable
|
|
489
|
+
:outlined="!(isDisabled || options?.find((i) => i.value === value)?.disabled)"
|
|
490
|
+
:disabled="isDisabled || options?.find((i) => i.value === value)?.disabled"
|
|
491
|
+
@remove="(e: Event) => { handleRemove(e, value) }"
|
|
492
|
+
>{{ getLabel(value) }}</x-tag>
|
|
493
|
+
|
|
494
|
+
<div
|
|
495
|
+
v-if="showCountTag"
|
|
496
|
+
:class="classes.truncateCounter"
|
|
497
|
+
@click.stop="multipleHiddenRef?.toggle()"
|
|
498
|
+
>+{{ hiddenTags }}</div>
|
|
499
|
+
</div>
|
|
500
|
+
</template>
|
|
501
|
+
<template v-else-if="!multiple && !isEmpty(selected)">
|
|
502
|
+
{{ getLabel(selected) }}
|
|
503
|
+
</template>
|
|
504
|
+
|
|
505
|
+
<template v-else>
|
|
506
|
+
<div
|
|
507
|
+
v-if="placeholder"
|
|
508
|
+
class="text-secondary-400 dark:text-secondary-500"
|
|
509
|
+
>
|
|
510
|
+
{{ placeholder }}
|
|
511
|
+
</div>
|
|
512
|
+
<div v-else> </div>
|
|
513
|
+
</template>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
516
|
+
<template #content>
|
|
517
|
+
<x-popover-container
|
|
518
|
+
:class="classes.content"
|
|
519
|
+
>
|
|
520
|
+
<slot name="content-header">
|
|
521
|
+
<div v-if="filterable" :class="classes.search">
|
|
522
|
+
<x-input
|
|
523
|
+
ref="filterRef"
|
|
524
|
+
v-model="filter"
|
|
525
|
+
:placeholder="filterPlaceholder"
|
|
526
|
+
skip-form-registry
|
|
527
|
+
size="sm"
|
|
528
|
+
/>
|
|
529
|
+
</div>
|
|
530
|
+
</slot>
|
|
531
|
+
<div v-bind="containerProps" :class="classes.contentBody">
|
|
532
|
+
<div v-bind="wrapperProps">
|
|
533
|
+
<x-menu-item
|
|
534
|
+
v-for="item in list"
|
|
535
|
+
:key="item.index"
|
|
536
|
+
ref="itemsRef"
|
|
537
|
+
:item="item.data"
|
|
538
|
+
:size="size"
|
|
539
|
+
:disabled="item.data.disabled"
|
|
540
|
+
:selected="item.index === selectedIndex"
|
|
541
|
+
:color="color"
|
|
542
|
+
filled
|
|
543
|
+
@click="() => !multiple && popoverRef?.hide()"
|
|
544
|
+
>
|
|
545
|
+
<template #prefix><slot name="prefix" :item="item.data">{{ item.data.prefix }}</slot></template>
|
|
546
|
+
<slot name="label" :item="item.data"></slot>
|
|
547
|
+
<template #suffix><slot name="suffix" :item="item.data">{{ item.data.suffix }}</slot></template>
|
|
548
|
+
</x-menu-item>
|
|
549
|
+
</div>
|
|
550
|
+
<div v-if="list.length === 0" class="p-2 text-center text-secondary-400">
|
|
551
|
+
No options
|
|
552
|
+
</div>
|
|
553
|
+
</div>
|
|
554
|
+
<slot name="content-footer"></slot>
|
|
555
|
+
</x-popover-container>
|
|
556
|
+
</template>
|
|
557
|
+
</x-popover>
|
|
558
|
+
<x-popover
|
|
559
|
+
v-if="multiple && truncate && showCountTag"
|
|
560
|
+
ref="multipleHiddenRef"
|
|
561
|
+
:popper-show-triggers="[]"
|
|
562
|
+
:popper-hide-triggers="[]"
|
|
563
|
+
class="inline-block !absolute right-0"
|
|
564
|
+
placement="auto-start"
|
|
416
565
|
>
|
|
417
|
-
<template
|
|
418
|
-
<
|
|
566
|
+
<template #content>
|
|
567
|
+
<x-popover-container class="p-2 flex gap-2 flex-wrap">
|
|
419
568
|
<x-tag
|
|
420
|
-
v-for="value in selected"
|
|
569
|
+
v-for="value in selected?.slice(selected.length - hiddenTags)"
|
|
421
570
|
:key="value"
|
|
422
571
|
size="xs"
|
|
423
572
|
removable
|
|
@@ -425,61 +574,10 @@ defineExpose({ focus, blur, reset, validate, setError })
|
|
|
425
574
|
:disabled="isDisabled || options?.find((i) => i.value === value)?.disabled"
|
|
426
575
|
@remove="(e: Event) => { handleRemove(e, value) }"
|
|
427
576
|
>{{ getLabel(value) }}</x-tag>
|
|
428
|
-
</
|
|
577
|
+
</x-popover-container>
|
|
429
578
|
</template>
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
</template>
|
|
433
|
-
|
|
434
|
-
<template v-else>
|
|
435
|
-
<div
|
|
436
|
-
v-if="placeholder"
|
|
437
|
-
class="text-secondary-400 dark:text-secondary-500"
|
|
438
|
-
>
|
|
439
|
-
{{ placeholder }}
|
|
440
|
-
</div>
|
|
441
|
-
<div v-else> </div>
|
|
442
|
-
</template>
|
|
443
|
-
</div>
|
|
444
|
-
|
|
445
|
-
<template #content>
|
|
446
|
-
<x-popover-container
|
|
447
|
-
:class="classes.content"
|
|
448
|
-
>
|
|
449
|
-
<slot name="content-header">
|
|
450
|
-
<div v-if="filterable" :class="classes.search">
|
|
451
|
-
<x-input
|
|
452
|
-
ref="filterRef"
|
|
453
|
-
v-model="filter"
|
|
454
|
-
:placeholder="filterPlaceholder"
|
|
455
|
-
skip-form-registry
|
|
456
|
-
size="sm"
|
|
457
|
-
/>
|
|
458
|
-
</div>
|
|
459
|
-
</slot>
|
|
460
|
-
<div v-bind="containerProps" :class="classes.contentBody">
|
|
461
|
-
<div v-bind="wrapperProps">
|
|
462
|
-
<x-menu-item
|
|
463
|
-
v-for="item in list"
|
|
464
|
-
:key="item.index"
|
|
465
|
-
ref="itemsRef"
|
|
466
|
-
:item="item.data"
|
|
467
|
-
:size="size"
|
|
468
|
-
:disabled="item.data.disabled"
|
|
469
|
-
:selected="item.index === selectedIndex"
|
|
470
|
-
:color="color"
|
|
471
|
-
filled
|
|
472
|
-
@click="() => !multiple && popoverRef?.hide()"
|
|
473
|
-
/>
|
|
474
|
-
</div>
|
|
475
|
-
<div v-if="list.length === 0" class="p-2 text-center text-secondary-400">
|
|
476
|
-
No options
|
|
477
|
-
</div>
|
|
478
|
-
</div>
|
|
479
|
-
<slot name="content-footer"></slot>
|
|
480
|
-
</x-popover-container>
|
|
481
|
-
</template>
|
|
482
|
-
</x-popover>
|
|
579
|
+
</x-popover>
|
|
580
|
+
</template>
|
|
483
581
|
|
|
484
582
|
<select
|
|
485
583
|
:id="id"
|
|
@@ -91,9 +91,8 @@ const props = defineProps({
|
|
|
91
91
|
},
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
const selected = defineModel<number |
|
|
95
|
-
|
|
96
|
-
const hasSelected = computed(() => typeof selected.value === 'number')
|
|
94
|
+
const selected = defineModel<number | string>('selected')
|
|
95
|
+
const hasSelected = computed(() => typeof selected.value !== 'undefined')
|
|
97
96
|
|
|
98
97
|
type internalT = T & {
|
|
99
98
|
__expanded?: boolean;
|
|
@@ -53,7 +53,7 @@ const { styles, classes, className } = useTheme('Tag', {}, props)
|
|
|
53
53
|
<template>
|
|
54
54
|
<component
|
|
55
55
|
:is="tag"
|
|
56
|
-
class="text-[color:var(--x-tag-text)] dark:text-[color:var(--x-tag-dark-text)] border"
|
|
56
|
+
class="text-[color:var(--x-tag-text)] dark:text-[color:var(--x-tag-dark-text)] border relative"
|
|
57
57
|
:style="styles"
|
|
58
58
|
:class="
|
|
59
59
|
[
|
|
@@ -67,16 +67,18 @@ const { styles, classes, className } = useTheme('Tag', {}, props)
|
|
|
67
67
|
>
|
|
68
68
|
<span
|
|
69
69
|
v-if="removable"
|
|
70
|
-
class="max-w-full truncate"
|
|
70
|
+
class="max-w-full truncate pr-4"
|
|
71
71
|
>
|
|
72
72
|
<slot></slot>
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
<div class="absolute right-1.5 top-0 h-full flex items-center">
|
|
74
|
+
<x-icon
|
|
75
|
+
:size="closeIconSize"
|
|
76
|
+
:icon="closeIcon"
|
|
77
|
+
class="cursor-pointer transition-colors duration-150"
|
|
78
|
+
:class="[disabled ? 'text-secondary-400' : 'hover:text-secondary-500']"
|
|
79
|
+
@click="(e: Event) => !disabled && $emit('remove', e)"
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
80
82
|
</span>
|
|
81
83
|
|
|
82
84
|
<slot v-else></slot>
|