@dolanske/vui 0.4.0 → 1.0.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/README.md +6 -13
- package/dist/components/Alert/Alert.vue.d.ts +7 -1
- package/dist/components/Avatar/Avatar.vue.d.ts +15 -1
- package/dist/components/Badge/Badge.vue.d.ts +1 -1
- package/dist/components/Breadcrumbs/BreadcrumbItem.vue.d.ts +1 -1
- package/dist/components/Button/Button.vue.d.ts +5 -15
- package/dist/components/ButtonGroup/ButtonGroup.vue.d.ts +2 -0
- package/dist/components/Calendar/Calendar.vue.d.ts +1 -1
- package/dist/components/Checkbox/Checkbox.vue.d.ts +1 -0
- package/dist/components/Dropdown/Dropdown.vue.d.ts +19 -4
- package/dist/components/Dropdown/DropdownTitle.vue.d.ts +5 -1
- package/dist/components/Flex/Flex.vue.d.ts +3 -1
- package/dist/components/Grid/Grid.vue.d.ts +7 -2
- package/dist/components/Input/Dropzone.vue.d.ts +1 -1
- package/dist/components/Input/Input.vue.d.ts +2 -2
- package/dist/components/Kbd/KbdGroup.vue.d.ts +3 -11
- package/dist/components/Modal/Confirm.vue.d.ts +1 -1
- package/dist/components/Modal/Modal.vue.d.ts +1 -1
- package/dist/components/Pagination/Pagination.vue.d.ts +3 -0
- package/dist/components/Popout/Popout.vue.d.ts +8 -1
- package/dist/components/Progress/Progress.vue.d.ts +2 -0
- package/dist/components/Radio/Radio.vue.d.ts +1 -0
- package/dist/components/Select/Select.vue.d.ts +2 -0
- package/dist/components/Sheet/Sheet.vue.d.ts +3 -0
- package/dist/components/Switch/Switch.vue.d.ts +1 -0
- package/dist/components/Table/index.d.ts +6 -0
- package/dist/components/Table/table.d.ts +1 -1
- package/dist/components/Tabs/Tab.vue.d.ts +16 -3
- package/dist/components/Tabs/Tabs.vue.d.ts +4 -0
- package/dist/components/Toast/toast.d.ts +245 -0
- package/dist/index.d.ts +2 -7
- package/dist/shared/helpers.d.ts +9 -0
- package/dist/shared/theme.d.ts +3 -0
- package/dist/style.css +1 -1
- package/dist/vui.js +6423 -6046
- package/package.json +8 -4
- package/src/App.vue +89 -192
- package/src/components/Accordion/accordion.scss +2 -0
- package/src/components/Alert/Alert.vue +11 -5
- package/src/components/Alert/alert.scss +104 -23
- package/src/components/Avatar/Avatar.vue +4 -1
- package/src/components/Avatar/avatar.scss +1 -1
- package/src/components/Badge/Badge.vue +1 -1
- package/src/components/Badge/badge.scss +134 -17
- package/src/components/Breadcrumbs/BreadcrumbItem.vue +2 -2
- package/src/components/Breadcrumbs/Breadcrumbs.vue +1 -2
- package/src/components/Breadcrumbs/breadcrumbs.scss +2 -1
- package/src/components/Button/Button.vue +16 -21
- package/src/components/Button/button.scss +159 -56
- package/src/components/ButtonGroup/ButtonGroup.vue +4 -1
- package/src/components/ButtonGroup/button-group.scss +2 -2
- package/src/components/Calendar/Calendar.vue +9 -3
- package/src/components/Calendar/calendar.scss +29 -2
- package/src/components/Card/Card.vue +2 -2
- package/src/components/Card/card.scss +4 -4
- package/src/components/Checkbox/Checkbox.vue +7 -5
- package/src/components/Checkbox/checkbox.scss +27 -13
- package/src/components/CopyClipboard/CopyClipboard.vue +15 -6
- package/src/components/CopyClipboard/copy-clipboard.scss +10 -2
- package/src/components/Drawer/Drawer.vue +4 -4
- package/src/components/Drawer/drawer.scss +1 -0
- package/src/components/Dropdown/Dropdown.vue +44 -20
- package/src/components/Dropdown/DropdownItem.vue +5 -4
- package/src/components/Dropdown/DropdownTitle.vue +7 -1
- package/src/components/Dropdown/dropdown-item.scss +84 -0
- package/src/components/Dropdown/dropdown.scss +21 -86
- package/src/components/Flex/Flex.vue +4 -1
- package/src/components/Grid/Grid.vue +25 -2
- package/src/components/Input/Color.vue +26 -0
- package/src/components/Input/Counter.vue +12 -16
- package/src/components/Input/Dropzone.vue +1 -1
- package/src/components/Input/File.vue +1 -1
- package/src/components/Input/Input.vue +8 -6
- package/src/components/Input/Password.vue +1 -13
- package/src/components/Input/Textarea.vue +4 -2
- package/src/components/Input/input.scss +113 -19
- package/src/components/Kbd/KbdGroup.vue +2 -6
- package/src/components/Kbd/kbd.scss +7 -6
- package/src/components/Modal/Confirm.vue +1 -1
- package/src/components/Modal/Modal.vue +23 -15
- package/src/components/Modal/modal.scss +11 -6
- package/src/components/OTP/otp.scss +8 -7
- package/src/components/Pagination/Pagination.vue +6 -3
- package/src/components/Popout/Popout.vue +15 -5
- package/src/components/Popout/popout.scss +8 -1
- package/src/components/Progress/Progress.vue +18 -5
- package/src/components/Progress/progress.scss +7 -1
- package/src/components/Radio/Radio.vue +4 -2
- package/src/components/Radio/radio.scss +28 -9
- package/src/components/Select/Select.vue +49 -18
- package/src/components/Select/select.scss +35 -2
- package/src/components/Sheet/Sheet.vue +8 -2
- package/src/components/Sheet/sheet.scss +9 -0
- package/src/components/Sidebar/Sidebar.vue +46 -16
- package/src/components/Sidebar/sidebar.scss +6 -5
- package/src/components/Spinner/spinner.scss +2 -1
- package/src/components/Switch/Switch.vue +4 -3
- package/src/components/Switch/switch.scss +48 -7
- package/src/components/Table/{Header.vue → Head.vue} +5 -5
- package/src/components/Table/{Table.vue → Root.vue} +2 -2
- package/src/components/Table/SelectRow.vue +2 -1
- package/src/components/Table/index.ts +7 -0
- package/src/components/Table/table.scss +25 -5
- package/src/components/Table/table.ts +7 -3
- package/src/components/Tabs/Tab.vue +7 -9
- package/src/components/Tabs/Tabs.vue +9 -2
- package/src/components/Tabs/tabs.scss +11 -3
- package/src/components/Toast/Toasts.vue +5 -0
- package/src/components/Toast/toast.scss +6 -2
- package/src/components/Toast/toast.ts +7 -0
- package/src/components/Tooltip/Tooltip.vue +9 -9
- package/src/components/Tooltip/tooltip.scss +4 -0
- package/src/examples/ExampleAccordions.vue +58 -0
- package/src/examples/ExampleAlerts.vue +78 -0
- package/src/examples/ExampleAvatars.vue +44 -0
- package/src/examples/ExampleBadges.vue +48 -0
- package/src/examples/ExampleBreadcrumbs.vue +46 -0
- package/src/examples/ExampleButtons.vue +140 -0
- package/src/examples/ExampleCalendars.vue +40 -0
- package/src/examples/ExampleCards.vue +94 -0
- package/src/examples/ExampleCheckboxes.vue +123 -0
- package/src/examples/ExampleCopyClipboard.vue +47 -0
- package/src/examples/ExampleDividers.vue +39 -0
- package/src/examples/ExampleDrawers.vue +67 -0
- package/src/examples/ExampleDropdowns.vue +114 -0
- package/src/examples/ExampleFlexGrid.vue +122 -0
- package/src/examples/ExampleInputs.vue +234 -0
- package/src/examples/ExampleKBD.vue +65 -0
- package/src/examples/ExampleModals.vue +143 -0
- package/src/examples/ExamplePalette.vue +159 -0
- package/src/examples/ExamplePopouts.vue +41 -0
- package/src/examples/ExampleSheets.vue +77 -0
- package/src/examples/ExampleSidebars.vue +270 -0
- package/src/examples/ExampleSkeletons.vue +26 -0
- package/src/examples/ExampleSpinners.vue +78 -0
- package/src/examples/ExampleTables.vue +195 -0
- package/src/examples/ExampleTabs.vue +119 -0
- package/src/examples/ExampleToasts.vue +96 -0
- package/src/examples/ExampleTooltips.vue +70 -0
- package/src/examples/shared/ExampleColor.vue +28 -0
- package/src/index.ts +4 -11
- package/src/internal/Backdrop/backdrop.scss +7 -1
- package/src/shared/helpers.ts +43 -0
- package/src/shared/theme.ts +22 -0
- package/src/style/animation.scss +1 -0
- package/src/style/core.scss +34 -57
- package/src/style/layout.scss +102 -5
- package/src/style/{fonts.scss → text.scss} +39 -0
- package/src/style/theme.scss +195 -0
- package/src/style/tooltip.scss +22 -4
- package/src/style/typography.scss +95 -18
- package/dist/components/Table/Row.vue.d.ts +0 -16
- package/src/components/Table/Row.vue +0 -9
- /package/dist/components/Table/{Header.vue.d.ts → Head.vue.d.ts} +0 -0
- /package/dist/components/Table/{Table.vue.d.ts → Root.vue.d.ts} +0 -0
|
@@ -8,7 +8,7 @@ import Card from '../Card/Card.vue'
|
|
|
8
8
|
import './modal.scss'
|
|
9
9
|
|
|
10
10
|
export interface ModalProps {
|
|
11
|
-
size?: Sizes | 'full'
|
|
11
|
+
size?: Sizes | 'full' | 'screen'
|
|
12
12
|
/**
|
|
13
13
|
* Modal wraps a floating card. You can optinally pass in any props you'd pass
|
|
14
14
|
* into the <Card /> component.
|
|
@@ -43,32 +43,40 @@ function close() {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
const attrs = useAttrs()
|
|
46
|
+
|
|
47
|
+
function tryClose() {
|
|
48
|
+
if (canDismiss) {
|
|
49
|
+
close()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
46
52
|
</script>
|
|
47
53
|
|
|
48
54
|
<template>
|
|
49
55
|
<Teleport to="body">
|
|
50
56
|
<Transition appear name="modal">
|
|
51
|
-
<Backdrop v-if="open" @close="
|
|
52
|
-
<div class="vui-modal" :class="[`vui-modal-size-${size}`, { scrollable, centered }]" v-bind="attrs">
|
|
53
|
-
<Button
|
|
54
|
-
v-if="canDismiss"
|
|
55
|
-
class="vui-modal-close"
|
|
56
|
-
plain
|
|
57
|
-
square
|
|
58
|
-
icon="ph:x"
|
|
59
|
-
@click="open = false"
|
|
60
|
-
/>
|
|
57
|
+
<Backdrop v-if="open" :class="{ 'p-0': size === 'screen' }" @close="tryClose">
|
|
58
|
+
<div class="vui-modal" :class="[`vui-modal-size-${size}`, { scrollable: scrollable || size === 'screen', centered }]" v-bind="attrs" @click.self="tryClose">
|
|
61
59
|
<Card v-bind="card">
|
|
62
60
|
<template v-if="$slots.header" #header>
|
|
63
|
-
<slot name="header" :close />
|
|
61
|
+
<slot name="header" :close="close" />
|
|
62
|
+
</template>
|
|
63
|
+
<template #header-end>
|
|
64
|
+
<Button
|
|
65
|
+
v-if="canDismiss"
|
|
66
|
+
class="vui-modal-close"
|
|
67
|
+
plain
|
|
68
|
+
square
|
|
69
|
+
icon="ph:x"
|
|
70
|
+
@click="open = false"
|
|
71
|
+
/>
|
|
64
72
|
</template>
|
|
65
73
|
<template v-if="$slots.default" #default>
|
|
66
74
|
<div>
|
|
67
|
-
<slot name="default" :close />
|
|
75
|
+
<slot name="default" :close="close" />
|
|
68
76
|
</div>
|
|
69
77
|
</template>
|
|
70
78
|
<template v-if="$slots.footer" #footer>
|
|
71
|
-
<slot name="footer" :close />
|
|
79
|
+
<slot name="footer" :close="close" />
|
|
72
80
|
</template>
|
|
73
81
|
</Card>
|
|
74
82
|
</div>
|
|
@@ -86,6 +94,6 @@ const attrs = useAttrs()
|
|
|
86
94
|
.modal-enter-from,
|
|
87
95
|
.modal-leave-to {
|
|
88
96
|
opacity: 0;
|
|
89
|
-
transform: scale(
|
|
97
|
+
transform: scale(1.025);
|
|
90
98
|
}
|
|
91
99
|
</style>
|
|
@@ -4,12 +4,6 @@
|
|
|
4
4
|
height: 100%;
|
|
5
5
|
position: relative;
|
|
6
6
|
|
|
7
|
-
.vui-modal-close {
|
|
8
|
-
position: absolute;
|
|
9
|
-
top: 16px;
|
|
10
|
-
right: 16px;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
7
|
&.centered {
|
|
14
8
|
display: flex;
|
|
15
9
|
align-items: center;
|
|
@@ -27,6 +21,17 @@
|
|
|
27
21
|
max-width: 728px;
|
|
28
22
|
}
|
|
29
23
|
|
|
24
|
+
&.vui-modal-size-screen {
|
|
25
|
+
position: fixed;
|
|
26
|
+
inset: 0;
|
|
27
|
+
|
|
28
|
+
& > .vui-card {
|
|
29
|
+
border-radius: 0;
|
|
30
|
+
border: none;
|
|
31
|
+
height: 100vh;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
&.scrollable {
|
|
31
36
|
& > .vui-card {
|
|
32
37
|
display: flex;
|
|
@@ -10,21 +10,22 @@
|
|
|
10
10
|
display: flex;
|
|
11
11
|
align-items: center;
|
|
12
12
|
justify-content: center;
|
|
13
|
-
width:
|
|
14
|
-
height:
|
|
13
|
+
width: var(--interactive-el-height);
|
|
14
|
+
height: var(--interactive-el-height);
|
|
15
15
|
border: 1px solid var(--color-border-strong);
|
|
16
16
|
color: var(--color-text);
|
|
17
17
|
z-index: 1;
|
|
18
18
|
font-size: var(--font-size-m);
|
|
19
19
|
outline: 0 solid var(--color-text-light);
|
|
20
|
-
transition: var(--transition);
|
|
20
|
+
transition: var(--transition-fast);
|
|
21
21
|
|
|
22
22
|
.blinker {
|
|
23
|
-
display:
|
|
23
|
+
display: block;
|
|
24
24
|
height: 16px;
|
|
25
25
|
width: 1px;
|
|
26
26
|
background-color: var(--color-text);
|
|
27
|
-
animation: blink
|
|
27
|
+
animation: blink 1s ease-out infinite;
|
|
28
|
+
visibility: hidden;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
@keyframes blink {
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
&.has-value {
|
|
43
|
-
background-color: var(--color-bg-
|
|
44
|
+
background-color: var(--color-bg-medium);
|
|
44
45
|
|
|
45
46
|
.blinker {
|
|
46
47
|
display: none !important;
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
outline-width: 2px;
|
|
53
54
|
|
|
54
55
|
.blinker {
|
|
55
|
-
|
|
56
|
+
visibility: visible;
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang='ts'>
|
|
2
|
+
import type { Variants } from '../Button/Button.vue'
|
|
2
3
|
import type { Pagination } from './pagination'
|
|
3
4
|
import { computed } from 'vue'
|
|
4
5
|
import Button from '../Button/Button.vue'
|
|
@@ -9,12 +10,14 @@ interface Props {
|
|
|
9
10
|
pagination: Pagination
|
|
10
11
|
prevNext?: boolean
|
|
11
12
|
firstLast?: boolean
|
|
13
|
+
variant?: Variants
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
const props = withDefaults(defineProps<Props>(), {
|
|
15
17
|
numbers: true,
|
|
16
18
|
prevNext: true,
|
|
17
19
|
firstLast: true,
|
|
20
|
+
variant: 'gray',
|
|
18
21
|
})
|
|
19
22
|
|
|
20
23
|
const emit = defineEmits<{
|
|
@@ -34,7 +37,7 @@ function setPrev() {
|
|
|
34
37
|
</script>
|
|
35
38
|
|
|
36
39
|
<template>
|
|
37
|
-
<Flex inline class="vui-pagination" gap="
|
|
40
|
+
<Flex inline class="vui-pagination" gap="xxs">
|
|
38
41
|
<slot name="start">
|
|
39
42
|
<Button v-if="props.firstLast" data-title-top="First page" plain :disabled="props.pagination.startPage === props.pagination.currentPage" square icon="ph:caret-double-left" @click="emit('change', props.pagination.startPage)" />
|
|
40
43
|
</slot>
|
|
@@ -44,13 +47,13 @@ function setPrev() {
|
|
|
44
47
|
</slot>
|
|
45
48
|
|
|
46
49
|
<template v-if="props.numbers">
|
|
47
|
-
<Flex gap="
|
|
50
|
+
<Flex gap="xxs">
|
|
48
51
|
<Button
|
|
49
52
|
v-for="page in props.pagination.pages"
|
|
50
53
|
:key="page"
|
|
51
54
|
square
|
|
52
55
|
:plain="props.pagination.currentPage !== page"
|
|
53
|
-
|
|
56
|
+
variant="gray"
|
|
54
57
|
@click="emit('change', page)"
|
|
55
58
|
>
|
|
56
59
|
{{ page }}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
<script setup lang='ts'>
|
|
2
2
|
import type { Placement, PopoutMaybeElement } from '../../shared/types'
|
|
3
|
-
import {
|
|
3
|
+
import { flip, offset, shift, useFloating } from '@floating-ui/vue'
|
|
4
|
+
import { onClickOutside } from '@vueuse/core'
|
|
4
5
|
import { toRef, useTemplateRef } from 'vue'
|
|
5
6
|
import './popout.scss'
|
|
6
7
|
|
|
7
8
|
export interface Props {
|
|
9
|
+
/**
|
|
10
|
+
* Reference to the HTML element the Popout is anchored to
|
|
11
|
+
*/
|
|
8
12
|
anchor: PopoutMaybeElement<HTMLElement>
|
|
9
13
|
/**
|
|
10
14
|
* Override the autoPlacement option
|
|
@@ -20,19 +24,25 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
20
24
|
offset: 8,
|
|
21
25
|
})
|
|
22
26
|
|
|
27
|
+
const emit = defineEmits<{
|
|
28
|
+
clickOutside: []
|
|
29
|
+
}>()
|
|
23
30
|
const popoutRef = useTemplateRef('popout')
|
|
24
31
|
const anchorRef = toRef(props.anchor)
|
|
25
32
|
|
|
26
33
|
const { floatingStyles } = useFloating(anchorRef, popoutRef, {
|
|
27
34
|
placement: props.placement,
|
|
28
35
|
middleware: [
|
|
29
|
-
...(props.placement
|
|
36
|
+
// ...(props.placement
|
|
37
|
+
// ? []
|
|
38
|
+
// : [autoPlacement()]),
|
|
39
|
+
shift({ padding: 8 }),
|
|
40
|
+
flip(),
|
|
30
41
|
offset(props.offset),
|
|
31
|
-
shift({
|
|
32
|
-
padding: 8,
|
|
33
|
-
}),
|
|
34
42
|
],
|
|
35
43
|
})
|
|
44
|
+
|
|
45
|
+
onClickOutside(popoutRef, () => emit('clickOutside'))
|
|
36
46
|
</script>
|
|
37
47
|
|
|
38
48
|
<template>
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
border-radius: var(--border-radius);
|
|
3
3
|
box-shadow: var(--box-shadow);
|
|
4
4
|
min-width: 80px;
|
|
5
|
-
background-color: var(--color-bg-
|
|
5
|
+
background-color: var(--color-bg-medium);
|
|
6
6
|
border-radius: var(--border-radius-m);
|
|
7
7
|
z-index: 1000;
|
|
8
8
|
}
|
|
9
|
+
|
|
10
|
+
:root.light {
|
|
11
|
+
.vui-popout {
|
|
12
|
+
background-color: var(--color-bg);
|
|
13
|
+
box-shadow: var(--box-shadow-strong);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang='ts'>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { whenever } from '@vueuse/core'
|
|
3
|
+
import { computed, onMounted, useTemplateRef, watch, watchEffect } from 'vue'
|
|
4
|
+
import { clamp, delay, formatUnitValue, isNil, randomMinMax } from '../../shared/helpers'
|
|
4
5
|
import './progress.scss'
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
@@ -30,10 +31,14 @@ const {
|
|
|
30
31
|
height,
|
|
31
32
|
} = defineProps<Props>()
|
|
32
33
|
|
|
34
|
+
const emit = defineEmits<{
|
|
35
|
+
done: []
|
|
36
|
+
}>()
|
|
37
|
+
|
|
33
38
|
const progressAmount = defineModel<number>({
|
|
34
39
|
default: 0,
|
|
35
40
|
set(value) {
|
|
36
|
-
return
|
|
41
|
+
return clamp(0, 100, value)
|
|
37
42
|
},
|
|
38
43
|
})
|
|
39
44
|
|
|
@@ -49,6 +54,8 @@ watchEffect(() => {
|
|
|
49
54
|
}
|
|
50
55
|
})
|
|
51
56
|
|
|
57
|
+
whenever(() => fake, fakeIncrement)
|
|
58
|
+
|
|
52
59
|
// Automatically / randomly increment but never reach 100% until
|
|
53
60
|
async function fakeIncrement() {
|
|
54
61
|
if (fake && progressAmount.value < 100) {
|
|
@@ -59,15 +66,21 @@ async function fakeIncrement() {
|
|
|
59
66
|
}
|
|
60
67
|
else {
|
|
61
68
|
progressAmount.value += randomMinMax(1, 10)
|
|
62
|
-
await delay(randomMinMax(200,
|
|
69
|
+
await delay(randomMinMax(200, 12000))
|
|
63
70
|
}
|
|
64
71
|
fakeIncrement()
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
74
|
|
|
75
|
+
watch(progressAmount, (v) => {
|
|
76
|
+
if (v >= 100) {
|
|
77
|
+
emit('done')
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
68
81
|
onMounted(fakeIncrement)
|
|
69
82
|
|
|
70
|
-
const w = computed(() => `${progressAmount.value}%`)
|
|
83
|
+
const w = computed(() => `${clamp(0, 100, progressAmount.value)}%`)
|
|
71
84
|
const bC = computed(() => color)
|
|
72
85
|
</script>
|
|
73
86
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
width: 100%;
|
|
6
6
|
position: relative;
|
|
7
7
|
border-radius: 999px;
|
|
8
|
-
background-color: var(--color-bg-
|
|
8
|
+
background-color: var(--color-bg-raised);
|
|
9
9
|
overflow: hidden;
|
|
10
10
|
height: var(--vui-progress-height);
|
|
11
11
|
|
|
@@ -39,3 +39,9 @@
|
|
|
39
39
|
transition: var(--transition-slow);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
:root.light {
|
|
44
|
+
.vui-progress-indicator {
|
|
45
|
+
background-color: var(--);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -7,12 +7,14 @@ export interface RadioProps {
|
|
|
7
7
|
label?: string
|
|
8
8
|
disabled?: boolean
|
|
9
9
|
value: any
|
|
10
|
+
accent?: boolean
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const {
|
|
13
14
|
label,
|
|
14
15
|
disabled,
|
|
15
16
|
value,
|
|
17
|
+
accent,
|
|
16
18
|
} = defineProps<RadioProps>()
|
|
17
19
|
const slots = defineSlots()
|
|
18
20
|
const checked = defineModel()
|
|
@@ -21,8 +23,8 @@ const isChecked = computed(() => value === checked.value)
|
|
|
21
23
|
</script>
|
|
22
24
|
|
|
23
25
|
<template>
|
|
24
|
-
<div class="vui-radio" :class="{ disabled: !!disabled, checked: isChecked }">
|
|
25
|
-
<input :id v-model="checked" type="radio" :value :checked="isChecked">
|
|
26
|
+
<div class="vui-radio" :class="{ disabled: !!disabled, checked: isChecked, accent }">
|
|
27
|
+
<input :id v-model="checked" type="radio" :value :checked="isChecked" :disabled>
|
|
26
28
|
<label :for="id">
|
|
27
29
|
<span class="vui-radio-icon">
|
|
28
30
|
<Icon :icon="isChecked ? 'ph:radio-button-fill' : 'ph:circle'" />
|
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
.vui-radio-icon svg {
|
|
6
6
|
color: var(--color-text);
|
|
7
7
|
}
|
|
8
|
+
|
|
9
|
+
&.accent .vui-radio-icon svg {
|
|
10
|
+
color: var(--color-accent);
|
|
11
|
+
}
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
&.disabled {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.vui-radio-icon svg path {
|
|
15
|
-
color: var(--color-text-lighter) !important;
|
|
15
|
+
.vui-radio-icon {
|
|
16
|
+
opacity: 0.25;
|
|
17
|
+
cursor: not-allowed;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
input + label
|
|
19
|
-
|
|
20
|
+
input + label .vui-radio-content {
|
|
21
|
+
opacity: 0.4;
|
|
22
|
+
cursor: not-allowed;
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -33,7 +36,17 @@
|
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
input {
|
|
36
|
-
|
|
39
|
+
width: 1px;
|
|
40
|
+
height: 1px;
|
|
41
|
+
position: absolute;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
outline: none !important;
|
|
44
|
+
opacity: 0;
|
|
45
|
+
|
|
46
|
+
&:focus-visible + label .vui-radio-icon {
|
|
47
|
+
outline: 2px solid var(--color-text);
|
|
48
|
+
border-radius: 999px;
|
|
49
|
+
}
|
|
37
50
|
|
|
38
51
|
& + label {
|
|
39
52
|
display: grid;
|
|
@@ -50,10 +63,16 @@
|
|
|
50
63
|
display: flex;
|
|
51
64
|
align-items: center;
|
|
52
65
|
min-height: var(--radio-size);
|
|
53
|
-
font-size: var(--font-size-
|
|
66
|
+
font-size: var(--font-size-m);
|
|
54
67
|
// line-height: var(--radio-size);
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
70
|
}
|
|
58
71
|
}
|
|
59
72
|
}
|
|
73
|
+
|
|
74
|
+
:root.light {
|
|
75
|
+
.vui-radio.checked.accent .vui-radio-icon svg {
|
|
76
|
+
color: var(--color-accent);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- eslint-disable ts/consistent-type-definitions -->
|
|
2
2
|
<script setup lang='ts' generic="T">
|
|
3
3
|
import { Icon } from '@iconify/vue'
|
|
4
|
-
import { computed, onMounted, ref, useTemplateRef } from 'vue'
|
|
4
|
+
import { computed, onMounted, ref, useId, useTemplateRef } from 'vue'
|
|
5
5
|
import { searchString } from '../../shared/helpers'
|
|
6
6
|
import Button from '../Button/Button.vue'
|
|
7
7
|
import Dropdown from '../Dropdown/Dropdown.vue'
|
|
@@ -28,6 +28,8 @@ type Props = {
|
|
|
28
28
|
search?: boolean
|
|
29
29
|
maxActiveOptions?: number
|
|
30
30
|
showClear?: boolean
|
|
31
|
+
disabled?: boolean
|
|
32
|
+
errors?: string[]
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
const {
|
|
@@ -39,11 +41,14 @@ const {
|
|
|
39
41
|
options,
|
|
40
42
|
single = true,
|
|
41
43
|
search,
|
|
42
|
-
maxActiveOptions
|
|
44
|
+
maxActiveOptions,
|
|
43
45
|
showClear,
|
|
46
|
+
disabled,
|
|
47
|
+
errors = [] as string[],
|
|
44
48
|
} = defineProps<Props>()
|
|
45
49
|
|
|
46
50
|
const selected = defineModel<SelectOption[] | undefined>()
|
|
51
|
+
const trigger = useTemplateRef('trigger')
|
|
47
52
|
|
|
48
53
|
//
|
|
49
54
|
function setValue(option: SelectOption) {
|
|
@@ -68,7 +73,7 @@ function setValue(option: SelectOption) {
|
|
|
68
73
|
if (!selected.value) {
|
|
69
74
|
selected.value = [option]
|
|
70
75
|
}
|
|
71
|
-
else {
|
|
76
|
+
else if (!maxActiveOptions || (selected.value.length < maxActiveOptions)) {
|
|
72
77
|
selected.value?.push(option)
|
|
73
78
|
}
|
|
74
79
|
}
|
|
@@ -97,7 +102,7 @@ const renderPlaceholder = computed(() => {
|
|
|
97
102
|
return selected.value[0].label
|
|
98
103
|
|
|
99
104
|
// If amount of selected exceeds the active capacity
|
|
100
|
-
if (selected.value.length >
|
|
105
|
+
if (selected.value.length > 3) {
|
|
101
106
|
return `${selected.value.length} selected`
|
|
102
107
|
}
|
|
103
108
|
|
|
@@ -117,42 +122,59 @@ function clearValue() {
|
|
|
117
122
|
selected.value = undefined
|
|
118
123
|
dropdownRef.value?.close()
|
|
119
124
|
}
|
|
125
|
+
|
|
126
|
+
const id = useId()
|
|
120
127
|
</script>
|
|
121
128
|
|
|
122
129
|
<template>
|
|
123
|
-
<div class="vui-input-container vui-select" :class="{ expand, required, readonly }">
|
|
124
|
-
<Dropdown ref="dropdown" :expand>
|
|
130
|
+
<div class="vui-input-container vui-select" :class="{ expand, required, readonly, disabled, 'has-errors': errors.length > 0 }">
|
|
131
|
+
<Dropdown ref="dropdown" :expand @close="trigger?.focus({ preventScroll: true })">
|
|
125
132
|
<template #trigger="{ toggle, isOpen }">
|
|
126
133
|
<div class="vui-input vui-select-trigger-content">
|
|
127
|
-
<label v-if="label" for="id">{{ label }}</label>
|
|
134
|
+
<label v-if="label" :for="id">{{ label }}</label>
|
|
128
135
|
<p v-if="hint" class="vui-input-hint">
|
|
129
136
|
{{ hint }}
|
|
130
137
|
</p>
|
|
131
138
|
|
|
132
|
-
<button
|
|
139
|
+
<button
|
|
140
|
+
:id
|
|
141
|
+
ref="trigger"
|
|
142
|
+
class="vui-input-style vui-select-trigger-container"
|
|
143
|
+
:class="{ 'has-value': selected && selected.length > 0 }"
|
|
144
|
+
:disabled
|
|
145
|
+
@click="toggle"
|
|
146
|
+
>
|
|
133
147
|
<span>
|
|
134
148
|
{{ renderPlaceholder }}
|
|
135
149
|
</span>
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
150
|
+
<template v-if="showClear && !required && selected">
|
|
151
|
+
<div class="flex-1" />
|
|
152
|
+
<Button
|
|
153
|
+
plain
|
|
154
|
+
icon="ph:x"
|
|
155
|
+
square
|
|
156
|
+
size="s"
|
|
157
|
+
|
|
158
|
+
@click.stop="clearValue"
|
|
159
|
+
/>
|
|
160
|
+
</template>
|
|
144
161
|
<Icon :icon="isOpen ? 'ph:caret-up' : 'ph:caret-down'" />
|
|
145
162
|
</button>
|
|
146
163
|
</div>
|
|
147
164
|
</template>
|
|
148
165
|
|
|
149
166
|
<template #default="{ close, isOpen }">
|
|
150
|
-
<DropdownTitle v-if="search">
|
|
167
|
+
<DropdownTitle v-if="search" sticky>
|
|
151
168
|
<Input
|
|
152
169
|
v-model="searchStr"
|
|
153
170
|
placeholder="Search..."
|
|
154
171
|
:focus="isOpen"
|
|
155
|
-
|
|
172
|
+
expand
|
|
173
|
+
>
|
|
174
|
+
<template #start>
|
|
175
|
+
<Icon icon="ph:magnifying-glass" />
|
|
176
|
+
</template>
|
|
177
|
+
</Input>
|
|
156
178
|
</DropdownTitle>
|
|
157
179
|
|
|
158
180
|
<p v-if="filteredOptions.length === 0" class="vue-select-no-results">
|
|
@@ -176,5 +198,14 @@ function clearValue() {
|
|
|
176
198
|
</DropdownItem>
|
|
177
199
|
</template>
|
|
178
200
|
</Dropdown>
|
|
201
|
+
|
|
202
|
+
<p v-if="maxActiveOptions && !single" class="vui-input-limit">
|
|
203
|
+
{{ `${selected ? selected.length : 0}/${maxActiveOptions}` }}
|
|
204
|
+
</p>
|
|
205
|
+
<ul v-if="errors.length > 0" class="vui-input-errors">
|
|
206
|
+
<li v-for="err in errors" :key="err">
|
|
207
|
+
{{ err }}
|
|
208
|
+
</li>
|
|
209
|
+
</ul>
|
|
179
210
|
</div>
|
|
180
211
|
</template>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
.vui-input-container {
|
|
2
2
|
&.vui-select {
|
|
3
|
+
width: auto;
|
|
4
|
+
|
|
3
5
|
&.expand {
|
|
4
6
|
.vui-dropdown-trigger-wrap,
|
|
5
7
|
.vui-dropdown-trigger-content {
|
|
@@ -7,7 +9,22 @@
|
|
|
7
9
|
}
|
|
8
10
|
}
|
|
9
11
|
|
|
12
|
+
&.disabled {
|
|
13
|
+
.vui-input-style {
|
|
14
|
+
cursor: not-allowed;
|
|
15
|
+
|
|
16
|
+
&:hover {
|
|
17
|
+
border-color: var(--color-border);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
.vui-select-trigger-container {
|
|
23
|
+
&.has-value span {
|
|
24
|
+
color: var(--color-text);
|
|
25
|
+
font-weight: var(--font-weight-medium);
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
span {
|
|
12
29
|
white-space: nowrap;
|
|
13
30
|
text-overflow: ellipsis;
|
|
@@ -30,8 +47,6 @@
|
|
|
30
47
|
margin-right: -6px;
|
|
31
48
|
|
|
32
49
|
.vui-button-slot svg {
|
|
33
|
-
width: 14px;
|
|
34
|
-
height: 14px;
|
|
35
50
|
color: var(--color-text-light);
|
|
36
51
|
}
|
|
37
52
|
}
|
|
@@ -42,3 +57,21 @@
|
|
|
42
57
|
}
|
|
43
58
|
}
|
|
44
59
|
}
|
|
60
|
+
|
|
61
|
+
select {
|
|
62
|
+
display: block;
|
|
63
|
+
height: var(--interactive-el-height);
|
|
64
|
+
line-height: var(--interactive-el-height);
|
|
65
|
+
background-color: var(--color-bg);
|
|
66
|
+
border: 1px solid var(--color-border);
|
|
67
|
+
border-radius: var(--border-radius-s);
|
|
68
|
+
padding-inline: var(--space-xs);
|
|
69
|
+
transition: var(--transition-fast);
|
|
70
|
+
z-index: 1;
|
|
71
|
+
font-size: var(--font-size-m);
|
|
72
|
+
color: var(--color-text);
|
|
73
|
+
|
|
74
|
+
&:hover {
|
|
75
|
+
border-color: var(--color-border-strong);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -55,14 +55,20 @@ const baseTransform = computed(() => {
|
|
|
55
55
|
<div class="flex-1">
|
|
56
56
|
<slot name="header" :close />
|
|
57
57
|
</div>
|
|
58
|
-
<Button square icon="ph:x" @click="open = false" />
|
|
58
|
+
<Button plain square icon="ph:x" @click="open = false" />
|
|
59
59
|
</div>
|
|
60
60
|
|
|
61
|
-
<Divider v-if="separator && $slots.header" :
|
|
61
|
+
<Divider v-if="separator && $slots.header" :size="1" />
|
|
62
62
|
|
|
63
63
|
<div v-if="$slots.default" class="vui-sheet-content">
|
|
64
64
|
<slot :close />
|
|
65
65
|
</div>
|
|
66
|
+
|
|
67
|
+
<Divider v-if="separator && $slots.footer" :size="1" />
|
|
68
|
+
|
|
69
|
+
<div class="vui-sheet-footer">
|
|
70
|
+
<slot name="footer" :close />
|
|
71
|
+
</div>
|
|
66
72
|
</div>
|
|
67
73
|
</Backdrop>
|
|
68
74
|
</Transition>
|