@dolanske/vui 0.3.2 → 0.3.4

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.
Files changed (108) hide show
  1. package/LICENSE +673 -673
  2. package/README.md +40 -40
  3. package/dist/components/Avatar/Avatar.vue.d.ts +1 -0
  4. package/dist/style.css +1 -1
  5. package/dist/vui.js +825 -809
  6. package/package.json +68 -68
  7. package/src/App.vue +175 -160
  8. package/src/components/Accordion/Accordion.vue +91 -91
  9. package/src/components/Accordion/AccordionGroup.vue +43 -43
  10. package/src/components/Accordion/accordion.scss +80 -80
  11. package/src/components/Alert/Alert.vue +53 -53
  12. package/src/components/Alert/alert.scss +80 -80
  13. package/src/components/Avatar/Avatar.vue +50 -43
  14. package/src/components/Avatar/avatar.scss +52 -50
  15. package/src/components/Badge/Badge.vue +21 -21
  16. package/src/components/Badge/badge.scss +89 -89
  17. package/src/components/Breadcrumbs/BreadcrumbItem.vue +26 -26
  18. package/src/components/Breadcrumbs/Breadcrumbs.vue +33 -33
  19. package/src/components/Breadcrumbs/breadcrumbs.scss +30 -30
  20. package/src/components/Button/Button.vue +90 -90
  21. package/src/components/Button/button.scss +176 -176
  22. package/src/components/ButtonGroup/ButtonGroup.vue +25 -25
  23. package/src/components/ButtonGroup/button-group.scss +51 -51
  24. package/src/components/Calendar/Calendar.vue +60 -60
  25. package/src/components/Calendar/calendar.scss +56 -56
  26. package/src/components/Card/Card.vue +48 -48
  27. package/src/components/Card/card.scss +53 -53
  28. package/src/components/Checkbox/Checkbox.vue +52 -52
  29. package/src/components/Checkbox/checkbox.scss +66 -66
  30. package/src/components/CopyClipboard/CopyClipboard.vue +82 -82
  31. package/src/components/CopyClipboard/copy-clipboard.scss +17 -17
  32. package/src/components/Divider/Divider.vue +44 -44
  33. package/src/components/Divider/divider.scss +35 -35
  34. package/src/components/Drawer/Drawer.vue +97 -97
  35. package/src/components/Drawer/drawer.scss +36 -36
  36. package/src/components/Dropdown/Dropdown.vue +111 -110
  37. package/src/components/Dropdown/DropdownItem.vue +29 -29
  38. package/src/components/Dropdown/DropdownTitle.vue +8 -8
  39. package/src/components/Dropdown/dropdown.scss +117 -116
  40. package/src/components/Flex/Flex.vue +106 -106
  41. package/src/components/Grid/Grid.vue +54 -54
  42. package/src/components/Input/Counter.vue +70 -70
  43. package/src/components/Input/Dropzone.vue +65 -65
  44. package/src/components/Input/File.vue +15 -15
  45. package/src/components/Input/Input.vue +121 -121
  46. package/src/components/Input/Password.vue +47 -47
  47. package/src/components/Input/Textarea.vue +76 -76
  48. package/src/components/Input/input.scss +208 -208
  49. package/src/components/Kbd/Kbd.vue +48 -48
  50. package/src/components/Kbd/KbdGroup.vue +31 -31
  51. package/src/components/Kbd/kbd.scss +18 -18
  52. package/src/components/Modal/Confirm.vue +56 -56
  53. package/src/components/Modal/Modal.vue +91 -91
  54. package/src/components/Modal/modal.scss +49 -49
  55. package/src/components/OTP/OTP.vue +133 -133
  56. package/src/components/OTP/OTPItem.vue +37 -37
  57. package/src/components/OTP/otp.scss +83 -83
  58. package/src/components/Pagination/Pagination.vue +74 -74
  59. package/src/components/Pagination/pagination.ts +78 -78
  60. package/src/components/Popout/Popout.vue +42 -39
  61. package/src/components/Popout/popout.scss +8 -8
  62. package/src/components/Progress/Progress.vue +90 -90
  63. package/src/components/Progress/progress.scss +41 -41
  64. package/src/components/Radio/Radio.vue +36 -36
  65. package/src/components/Radio/RadioGroup.vue +40 -40
  66. package/src/components/Radio/radio.scss +59 -59
  67. package/src/components/Select/Select.vue +180 -180
  68. package/src/components/Select/select.scss +44 -44
  69. package/src/components/Sheet/Sheet.vue +92 -92
  70. package/src/components/Sheet/sheet.scss +60 -60
  71. package/src/components/Skeleton/Skeleton.vue +43 -43
  72. package/src/components/Skeleton/skeleton.scss +14 -14
  73. package/src/components/Spinner/Spinner.vue +42 -42
  74. package/src/components/Spinner/spinner.scss +46 -46
  75. package/src/components/Switch/Switch.vue +30 -30
  76. package/src/components/Switch/switch.scss +52 -52
  77. package/src/components/Table/Cell.vue +23 -23
  78. package/src/components/Table/Header.vue +59 -59
  79. package/src/components/Table/Row.vue +9 -9
  80. package/src/components/Table/SelectAll.vue +23 -23
  81. package/src/components/Table/SelectRow.vue +29 -29
  82. package/src/components/Table/Table.vue +66 -66
  83. package/src/components/Table/table.scss +134 -134
  84. package/src/components/Table/table.ts +244 -244
  85. package/src/components/Tabs/Tab.vue +27 -27
  86. package/src/components/Tabs/Tabs.vue +82 -80
  87. package/src/components/Tabs/tabs.scss +79 -79
  88. package/src/components/Toast/Toasts.vue +47 -47
  89. package/src/components/Toast/toast.scss +41 -41
  90. package/src/components/Toast/toast.ts +68 -68
  91. package/src/components/Tooltip/Tooltip.vue +86 -84
  92. package/src/components/Tooltip/tooltip.scss +4 -4
  93. package/src/index.scss +1 -1
  94. package/src/index.ts +119 -119
  95. package/src/internal/Backdrop/Backdrop.vue +22 -22
  96. package/src/internal/Backdrop/backdrop.scss +28 -28
  97. package/src/main.ts +5 -5
  98. package/src/shared/helpers.ts +74 -74
  99. package/src/shared/types.ts +29 -29
  100. package/src/style/animation.scss +21 -21
  101. package/src/style/core.scss +148 -146
  102. package/src/style/fonts.scss +53 -53
  103. package/src/style/layout.scss +136 -136
  104. package/src/style/media-query.scss +29 -29
  105. package/src/style/reset.scss +135 -135
  106. package/src/style/tooltip.scss +128 -128
  107. package/src/style/typography.scss +338 -338
  108. package/src/style/utils.scss +36 -36
@@ -1,76 +1,76 @@
1
- <script setup lang="ts">
2
- import type { InputProps } from './Input.vue'
3
- import { computed, useId } from 'vue'
4
- import '../Input/input.scss'
5
-
6
- type Props = Omit<InputProps, 'type'> & {
7
- resize?: boolean | 'vertical' | 'horizontal'
8
- autoResize?: boolean
9
- }
10
-
11
- const {
12
- limit,
13
- label,
14
- expand = false,
15
- hint,
16
- placeholder,
17
- required,
18
- modelValue = '',
19
- readonly,
20
- resize = 'vertical',
21
- autoResize,
22
- errors = [] as string[],
23
- } = defineProps<Props>()
24
-
25
- const model = defineModel<string>({
26
- default: '',
27
- set(newValue) {
28
- if (readonly)
29
- return modelValue
30
-
31
- if (newValue.length > Number(limit)) {
32
- return modelValue
33
- }
34
- return newValue
35
- },
36
- })
37
- const id = useId()
38
-
39
- const r = computed(() => resize === true ? 'both' : (resize || 'initial'))
40
- const fS = computed(() => autoResize ? 'content' : 'auto')
41
- </script>
42
-
43
- <template>
44
- <div class="vui-input-container" :class="{ expand, required, readonly, 'has-errors': errors.length > 0 }">
45
- <slot name="before" />
46
- <div class="vui-input">
47
- <label v-if="label" for="id">{{ label }}</label>
48
- <p v-if="hint" class="vui-input-hint">
49
- {{ hint }}
50
- </p>
51
- <textarea
52
- :id
53
- v-model="model"
54
- :readonly
55
- name="id"
56
- :placeholder
57
- :required
58
- :max="limit"
59
- :style="{
60
- resize: r,
61
- // @ts-expect-error Early-adoption CSS attribute
62
- fieldSizing: fS,
63
- }"
64
- />
65
- </div>
66
- <p v-if="limit" class="vui-input-limit">
67
- {{ `${model.length}/${limit}` }}
68
- </p>
69
- <ul v-if="errors.length > 0" class="vui-input-errors">
70
- <li v-for="err in errors" :key="err">
71
- {{ err }}
72
- </li>
73
- </ul>
74
- <slot name="after" />
75
- </div>
76
- </template>
1
+ <script setup lang="ts">
2
+ import type { InputProps } from './Input.vue'
3
+ import { computed, useId } from 'vue'
4
+ import '../Input/input.scss'
5
+
6
+ type Props = Omit<InputProps, 'type'> & {
7
+ resize?: boolean | 'vertical' | 'horizontal'
8
+ autoResize?: boolean
9
+ }
10
+
11
+ const {
12
+ limit,
13
+ label,
14
+ expand = false,
15
+ hint,
16
+ placeholder,
17
+ required,
18
+ modelValue = '',
19
+ readonly,
20
+ resize = 'vertical',
21
+ autoResize,
22
+ errors = [] as string[],
23
+ } = defineProps<Props>()
24
+
25
+ const model = defineModel<string>({
26
+ default: '',
27
+ set(newValue) {
28
+ if (readonly)
29
+ return modelValue
30
+
31
+ if (newValue.length > Number(limit)) {
32
+ return modelValue
33
+ }
34
+ return newValue
35
+ },
36
+ })
37
+ const id = useId()
38
+
39
+ const r = computed(() => resize === true ? 'both' : (resize || 'initial'))
40
+ const fS = computed(() => autoResize ? 'content' : 'auto')
41
+ </script>
42
+
43
+ <template>
44
+ <div class="vui-input-container" :class="{ expand, required, readonly, 'has-errors': errors.length > 0 }">
45
+ <slot name="before" />
46
+ <div class="vui-input">
47
+ <label v-if="label" for="id">{{ label }}</label>
48
+ <p v-if="hint" class="vui-input-hint">
49
+ {{ hint }}
50
+ </p>
51
+ <textarea
52
+ :id
53
+ v-model="model"
54
+ :readonly
55
+ name="id"
56
+ :placeholder
57
+ :required
58
+ :max="limit"
59
+ :style="{
60
+ resize: r,
61
+ // @ts-expect-error Early-adoption CSS attribute
62
+ fieldSizing: fS,
63
+ }"
64
+ />
65
+ </div>
66
+ <p v-if="limit" class="vui-input-limit">
67
+ {{ `${model.length}/${limit}` }}
68
+ </p>
69
+ <ul v-if="errors.length > 0" class="vui-input-errors">
70
+ <li v-for="err in errors" :key="err">
71
+ {{ err }}
72
+ </li>
73
+ </ul>
74
+ <slot name="after" />
75
+ </div>
76
+ </template>
@@ -1,208 +1,208 @@
1
- .vui-input-container {
2
- // Each component should have its own specification as it allows more granual
3
- // modification via CSS variables if needed
4
- --input-color-text-red: var(--color-text-red);
5
- --input-color-text: var(--color-text);
6
- --input-color-text-light: var(--color-text-light);
7
- --input-color-text-lighter: var(--color-text-lighter);
8
- --input-color-border: var(--color-border);
9
- --input-color-border-strong: var(--color-border-strong);
10
- --input-color-border-weak: var(--color-border-weak);
11
-
12
- --input-height: 34px;
13
- --input-padding: 8px;
14
- --textarea-padding: 8px;
15
-
16
- //
17
-
18
- width: 224px;
19
-
20
- &.disabled input,
21
- &.disabled textarea {
22
- cursor: not-allowed;
23
- }
24
-
25
- &.expand {
26
- width: 100%;
27
- }
28
-
29
- &.required .vui-input > label:after {
30
- content: '*';
31
- color: var(--input-color-text-red);
32
- }
33
-
34
- &.readonly .vui-input {
35
- input,
36
- textarea,
37
- .vui-input-style {
38
- pointer-events: none;
39
- color: var(--input-color-text-light);
40
- border-color: var(--input-color-border-weak);
41
- }
42
- }
43
-
44
- &.has-errors {
45
- .vui-input {
46
- .vui-input-style,
47
- textarea {
48
- border-color: var(--color-text-red) !important;
49
- }
50
- }
51
- }
52
-
53
- .vui-input {
54
- label {
55
- display: block;
56
- text-align: left;
57
- margin-bottom: 8px;
58
- font-size: var(--font-size-ms);
59
- color: var(--input-color-text);
60
- }
61
-
62
- .vui-input-hint {
63
- margin-bottom: 8px;
64
- margin-top: -4px;
65
- color: var(--input-color-text-lighter);
66
- font-size: var(--font-size-s);
67
- display: block;
68
- text-align: left;
69
- }
70
-
71
- ::placeholder {
72
- font-weight: 400;
73
- color: var(--color-text-lighter);
74
- font-family: var(--global-font);
75
- }
76
-
77
- .vui-input-style,
78
- textarea {
79
- display: block;
80
- border-radius: var(--border-radius-s);
81
- border: 1px solid var(--input-color-border);
82
- background: transparent;
83
- height: var(--input-height);
84
- line-height: var(--input-height);
85
- color: var(--color-text);
86
- outline: none !important;
87
- padding-inline: var(--input-padding);
88
- font-size: var(--font-size-ms);
89
- width: 100%;
90
- transition: var(--transition);
91
-
92
- &:has(input:focus-visible),
93
- &:focus-visible {
94
- border-color: var(--input-color-border-strong);
95
- }
96
- }
97
-
98
- input,
99
- textarea {
100
- font-family: var(--global-font);
101
- }
102
-
103
- input[type='file']::file-selector-button {
104
- background-color: var(--color-bg);
105
- color: var(--color-text);
106
- border: none;
107
- }
108
-
109
- input[type='range'] {
110
- -webkit-appearance: none; /* Override default CSS styles */
111
- appearance: none;
112
- height: 4px;
113
- border-radius: 2px;
114
- background-color: var(--color-border);
115
- }
116
-
117
- ::-moz-range-thumb,
118
- ::-webkit-slider-thumb {
119
- width: 16px;
120
- height: 16px;
121
- background-color: var(--color-text-light);
122
- border: none;
123
- }
124
-
125
- input {
126
- display: block;
127
- width: 100%;
128
- border: none;
129
- height: calc(var(--input-height) - 1px);
130
- line-height: calc(var(--input-height) - 1px);
131
- background: transparent;
132
- outline: none;
133
- font-size: var(--font-size-ms);
134
- color: var(--color-text);
135
-
136
- &:-webkit-autofill {
137
- box-shadow: 0 0 0px 1000px var(--color-bg) inset;
138
- -webkit-text-fill-color: var(--color-text);
139
- }
140
- }
141
-
142
- textarea {
143
- line-height: 1.3em;
144
- height: auto;
145
- min-height: 4lh;
146
- field-sizing: content;
147
- padding: var(--textarea-padding);
148
- transition: none;
149
- }
150
- }
151
-
152
- .vui-input-limit {
153
- display: block;
154
- margin-top: 6px;
155
- text-align: left;
156
- font-size: var(--font-size-xs);
157
- color: var(--input-color-text-lighter);
158
- }
159
-
160
- .vui-input-errors {
161
- display: flex;
162
- flex-direction: column;
163
- gap: 6px;
164
- padding-top: 6px;
165
-
166
- li {
167
- display: block;
168
- font-size: var(--font-size-s);
169
- color: var(--color-text-red);
170
- }
171
- }
172
-
173
- &.vui-dropzone {
174
- &.dragging .vui-input .vui-input-style {
175
- border-color: var(--color-border-accent);
176
-
177
- &:hover {
178
- border-color: var(--color-border);
179
- }
180
- }
181
- .vui-input {
182
- .vui-input-style {
183
- height: unset;
184
- border-width: 2px;
185
- border-style: dashed;
186
- border-radius: var(--border-radius-m);
187
- line-height: 1.2em;
188
-
189
- &:hover {
190
- border-color: var(--color-border-strong);
191
- }
192
-
193
- input {
194
- display: none;
195
-
196
- & + label {
197
- display: flex;
198
- align-items: center;
199
- justify-content: center;
200
- width: 100%;
201
- min-height: 96px;
202
- color: var(--color-text-light);
203
- }
204
- }
205
- }
206
- }
207
- }
208
- }
1
+ .vui-input-container {
2
+ // Each component should have its own specification as it allows more granual
3
+ // modification via CSS variables if needed
4
+ --input-color-text-red: var(--color-text-red);
5
+ --input-color-text: var(--color-text);
6
+ --input-color-text-light: var(--color-text-light);
7
+ --input-color-text-lighter: var(--color-text-lighter);
8
+ --input-color-border: var(--color-border);
9
+ --input-color-border-strong: var(--color-border-strong);
10
+ --input-color-border-weak: var(--color-border-weak);
11
+
12
+ --input-height: 34px;
13
+ --input-padding: 8px;
14
+ --textarea-padding: 8px;
15
+
16
+ //
17
+
18
+ width: 224px;
19
+
20
+ &.disabled input,
21
+ &.disabled textarea {
22
+ cursor: not-allowed;
23
+ }
24
+
25
+ &.expand {
26
+ width: 100%;
27
+ }
28
+
29
+ &.required .vui-input > label:after {
30
+ content: '*';
31
+ color: var(--input-color-text-red);
32
+ }
33
+
34
+ &.readonly .vui-input {
35
+ input,
36
+ textarea,
37
+ .vui-input-style {
38
+ pointer-events: none;
39
+ color: var(--input-color-text-light);
40
+ border-color: var(--input-color-border-weak);
41
+ }
42
+ }
43
+
44
+ &.has-errors {
45
+ .vui-input {
46
+ .vui-input-style,
47
+ textarea {
48
+ border-color: var(--color-text-red) !important;
49
+ }
50
+ }
51
+ }
52
+
53
+ .vui-input {
54
+ label {
55
+ display: block;
56
+ text-align: left;
57
+ margin-bottom: 8px;
58
+ font-size: var(--font-size-ms);
59
+ color: var(--input-color-text);
60
+ }
61
+
62
+ .vui-input-hint {
63
+ margin-bottom: 8px;
64
+ margin-top: -4px;
65
+ color: var(--input-color-text-lighter);
66
+ font-size: var(--font-size-s);
67
+ display: block;
68
+ text-align: left;
69
+ }
70
+
71
+ ::placeholder {
72
+ font-weight: 400;
73
+ color: var(--color-text-lighter);
74
+ font-family: var(--global-font);
75
+ }
76
+
77
+ .vui-input-style,
78
+ textarea {
79
+ display: block;
80
+ border-radius: var(--border-radius-s);
81
+ border: 1px solid var(--input-color-border);
82
+ background: transparent;
83
+ height: var(--input-height);
84
+ line-height: var(--input-height);
85
+ color: var(--color-text);
86
+ outline: none !important;
87
+ padding-inline: var(--input-padding);
88
+ font-size: var(--font-size-ms);
89
+ width: 100%;
90
+ transition: var(--transition);
91
+
92
+ &:has(input:focus-visible),
93
+ &:focus-visible {
94
+ border-color: var(--input-color-border-strong);
95
+ }
96
+ }
97
+
98
+ input,
99
+ textarea {
100
+ font-family: var(--global-font);
101
+ }
102
+
103
+ input[type='file']::file-selector-button {
104
+ background-color: var(--color-bg);
105
+ color: var(--color-text);
106
+ border: none;
107
+ }
108
+
109
+ input[type='range'] {
110
+ -webkit-appearance: none; /* Override default CSS styles */
111
+ appearance: none;
112
+ height: 4px;
113
+ border-radius: 2px;
114
+ background-color: var(--color-border);
115
+ }
116
+
117
+ ::-moz-range-thumb,
118
+ ::-webkit-slider-thumb {
119
+ width: 16px;
120
+ height: 16px;
121
+ background-color: var(--color-text-light);
122
+ border: none;
123
+ }
124
+
125
+ input {
126
+ display: block;
127
+ width: 100%;
128
+ border: none;
129
+ height: calc(var(--input-height) - 1px);
130
+ line-height: calc(var(--input-height) - 1px);
131
+ background: transparent;
132
+ outline: none;
133
+ font-size: var(--font-size-ms);
134
+ color: var(--color-text);
135
+
136
+ &:-webkit-autofill {
137
+ box-shadow: 0 0 0px 1000px var(--color-bg) inset;
138
+ -webkit-text-fill-color: var(--color-text);
139
+ }
140
+ }
141
+
142
+ textarea {
143
+ line-height: 1.3em;
144
+ height: auto;
145
+ min-height: 4lh;
146
+ field-sizing: content;
147
+ padding: var(--textarea-padding);
148
+ transition: none;
149
+ }
150
+ }
151
+
152
+ .vui-input-limit {
153
+ display: block;
154
+ margin-top: 6px;
155
+ text-align: left;
156
+ font-size: var(--font-size-xs);
157
+ color: var(--input-color-text-lighter);
158
+ }
159
+
160
+ .vui-input-errors {
161
+ display: flex;
162
+ flex-direction: column;
163
+ gap: 6px;
164
+ padding-top: 6px;
165
+
166
+ li {
167
+ display: block;
168
+ font-size: var(--font-size-s);
169
+ color: var(--color-text-red);
170
+ }
171
+ }
172
+
173
+ &.vui-dropzone {
174
+ &.dragging .vui-input .vui-input-style {
175
+ border-color: var(--color-border-accent);
176
+
177
+ &:hover {
178
+ border-color: var(--color-border);
179
+ }
180
+ }
181
+ .vui-input {
182
+ .vui-input-style {
183
+ height: unset;
184
+ border-width: 2px;
185
+ border-style: dashed;
186
+ border-radius: var(--border-radius-m);
187
+ line-height: 1.2em;
188
+
189
+ &:hover {
190
+ border-color: var(--color-border-strong);
191
+ }
192
+
193
+ input {
194
+ display: none;
195
+
196
+ & + label {
197
+ display: flex;
198
+ align-items: center;
199
+ justify-content: center;
200
+ width: 100%;
201
+ min-height: 96px;
202
+ color: var(--color-text-light);
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
@@ -1,48 +1,48 @@
1
- <script setup lang='ts'>
2
- import { useMagicKeys, whenever } from '@vueuse/core'
3
- import { computed } from 'vue'
4
- import './kbd.scss'
5
-
6
- interface Props {
7
- /**
8
- * Specify the key or the combination of keys connected with "+". Make sure
9
- * there are no white spaces between letters.
10
- *
11
- * keys="Escape" keys="Ctrl+A"
12
- */
13
- keys: string
14
- /**
15
- * Display custom label instead of the automatically formatted keys.
16
- */
17
- label?: string
18
- /**
19
- * Show active state when this combination of keys is pressed.
20
- */
21
- highlight?: boolean
22
- }
23
-
24
- const props = defineProps<Props>()
25
- const emits = defineEmits<{
26
- trigger: []
27
- }>()
28
- const keyHandler = useMagicKeys()
29
-
30
- whenever(keyHandler[props.keys], () => {
31
- emits('trigger')
32
- })
33
-
34
- const isActive = computed(() => {
35
- if (!props.highlight)
36
- return false
37
-
38
- return props.keys.split('+').every((key) => {
39
- return keyHandler.current.has(key.toLowerCase())
40
- })
41
- })
42
- </script>
43
-
44
- <template>
45
- <kbd class="vui-kbd" :class="{ active: isActive }">
46
- {{ props.label ?? props.keys.replaceAll("+", " + ") }}
47
- </kbd>
48
- </template>
1
+ <script setup lang='ts'>
2
+ import { useMagicKeys, whenever } from '@vueuse/core'
3
+ import { computed } from 'vue'
4
+ import './kbd.scss'
5
+
6
+ interface Props {
7
+ /**
8
+ * Specify the key or the combination of keys connected with "+". Make sure
9
+ * there are no white spaces between letters.
10
+ *
11
+ * keys="Escape" keys="Ctrl+A"
12
+ */
13
+ keys: string
14
+ /**
15
+ * Display custom label instead of the automatically formatted keys.
16
+ */
17
+ label?: string
18
+ /**
19
+ * Show active state when this combination of keys is pressed.
20
+ */
21
+ highlight?: boolean
22
+ }
23
+
24
+ const props = defineProps<Props>()
25
+ const emits = defineEmits<{
26
+ trigger: []
27
+ }>()
28
+ const keyHandler = useMagicKeys()
29
+
30
+ whenever(keyHandler[props.keys], () => {
31
+ emits('trigger')
32
+ })
33
+
34
+ const isActive = computed(() => {
35
+ if (!props.highlight)
36
+ return false
37
+
38
+ return props.keys.split('+').every((key) => {
39
+ return keyHandler.current.has(key.toLowerCase())
40
+ })
41
+ })
42
+ </script>
43
+
44
+ <template>
45
+ <kbd class="vui-kbd" :class="{ active: isActive }">
46
+ {{ props.label ?? props.keys.replaceAll("+", " + ") }}
47
+ </kbd>
48
+ </template>