@indielayer/ui 1.9.3 → 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/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/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"
|
|
@@ -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>
|