@nuxt/ui 0.4.1 → 2.8.1

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 (143) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +63 -50
  3. package/dist/module.cjs +5 -0
  4. package/dist/module.d.mts +1234 -0
  5. package/dist/module.d.ts +1234 -0
  6. package/dist/module.json +8 -0
  7. package/dist/module.mjs +407 -0
  8. package/dist/runtime/app.config.d.ts +1203 -0
  9. package/dist/runtime/app.config.mjs +1057 -0
  10. package/dist/runtime/components/data/Table.vue +251 -0
  11. package/dist/runtime/components/data/Table.vue.d.ts +215 -0
  12. package/dist/runtime/components/elements/Accordion.vue +138 -0
  13. package/dist/runtime/components/elements/Accordion.vue.d.ts +80 -0
  14. package/dist/runtime/components/elements/Alert.vue +120 -0
  15. package/dist/runtime/components/elements/Alert.vue.d.ts +107 -0
  16. package/dist/runtime/components/elements/Avatar.vue +149 -0
  17. package/dist/runtime/components/elements/Avatar.vue.d.ts +115 -0
  18. package/dist/runtime/components/elements/AvatarGroup.d.ts +37 -0
  19. package/dist/runtime/components/elements/AvatarGroup.mjs +53 -0
  20. package/dist/runtime/components/elements/Badge.vue +69 -0
  21. package/dist/runtime/components/elements/Badge.vue.d.ts +63 -0
  22. package/dist/runtime/components/elements/Button.vue +182 -0
  23. package/dist/runtime/components/elements/Button.vue.d.ts +187 -0
  24. package/dist/runtime/components/elements/ButtonGroup.d.ts +39 -0
  25. package/dist/runtime/components/elements/ButtonGroup.mjs +70 -0
  26. package/dist/runtime/components/elements/Dropdown.vue +172 -0
  27. package/dist/runtime/components/elements/Dropdown.vue.d.ts +96 -0
  28. package/dist/runtime/components/elements/Icon.vue +15 -0
  29. package/dist/runtime/components/elements/Icon.vue.d.ts +12 -0
  30. package/dist/runtime/components/elements/Kbd.vue +55 -0
  31. package/dist/runtime/components/elements/Kbd.vue.d.ts +42 -0
  32. package/dist/runtime/components/elements/Link.vue +80 -0
  33. package/dist/runtime/components/elements/Link.vue.d.ts +9 -0
  34. package/dist/runtime/components/forms/Checkbox.vue +136 -0
  35. package/dist/runtime/components/forms/Checkbox.vue.d.ts +129 -0
  36. package/dist/runtime/components/forms/Form.vue +185 -0
  37. package/dist/runtime/components/forms/Form.vue.d.ts +50 -0
  38. package/dist/runtime/components/forms/FormGroup.vue +97 -0
  39. package/dist/runtime/components/forms/FormGroup.vue.d.ts +98 -0
  40. package/dist/runtime/components/forms/Input.vue +250 -0
  41. package/dist/runtime/components/forms/Input.vue.d.ts +214 -0
  42. package/dist/runtime/components/forms/Radio.vue +122 -0
  43. package/dist/runtime/components/forms/Radio.vue.d.ts +109 -0
  44. package/dist/runtime/components/forms/Range.vue +163 -0
  45. package/dist/runtime/components/forms/Range.vue.d.ts +119 -0
  46. package/dist/runtime/components/forms/Select.vue +307 -0
  47. package/dist/runtime/components/forms/Select.vue.d.ts +229 -0
  48. package/dist/runtime/components/forms/SelectMenu.vue +429 -0
  49. package/dist/runtime/components/forms/SelectMenu.vue.d.ts +330 -0
  50. package/dist/runtime/components/forms/Textarea.vue +184 -0
  51. package/dist/runtime/components/forms/Textarea.vue.d.ts +161 -0
  52. package/dist/runtime/components/forms/Toggle.vue +113 -0
  53. package/dist/runtime/components/forms/Toggle.vue.d.ts +83 -0
  54. package/dist/runtime/components/layout/Card.vue +58 -0
  55. package/dist/runtime/components/layout/Card.vue.d.ts +31 -0
  56. package/dist/runtime/components/layout/Container.vue +43 -0
  57. package/dist/runtime/components/layout/Container.vue.d.ts +31 -0
  58. package/dist/runtime/components/layout/Skeleton.vue +37 -0
  59. package/dist/runtime/components/layout/Skeleton.vue.d.ts +22 -0
  60. package/dist/runtime/components/navigation/CommandPalette.vue +304 -0
  61. package/dist/runtime/components/navigation/CommandPalette.vue.d.ts +224 -0
  62. package/dist/runtime/components/navigation/CommandPaletteGroup.vue +152 -0
  63. package/dist/runtime/components/navigation/CommandPaletteGroup.vue.d.ts +63 -0
  64. package/dist/runtime/components/navigation/Pagination.vue +197 -0
  65. package/dist/runtime/components/navigation/Pagination.vue.d.ts +125 -0
  66. package/dist/runtime/components/navigation/Tabs.vue +138 -0
  67. package/dist/runtime/components/navigation/Tabs.vue.d.ts +69 -0
  68. package/dist/runtime/components/navigation/VerticalNavigation.vue +79 -0
  69. package/dist/runtime/components/navigation/VerticalNavigation.vue.d.ts +37 -0
  70. package/dist/runtime/components/overlays/ContextMenu.vue +74 -0
  71. package/dist/runtime/components/overlays/ContextMenu.vue.d.ts +54 -0
  72. package/dist/runtime/components/overlays/Modal.vue +113 -0
  73. package/dist/runtime/components/overlays/Modal.vue.d.ts +82 -0
  74. package/dist/runtime/components/overlays/Notification.vue +197 -0
  75. package/dist/runtime/components/overlays/Notification.vue.d.ts +126 -0
  76. package/dist/runtime/components/overlays/Notifications.vue +61 -0
  77. package/dist/runtime/components/overlays/Notifications.vue.d.ts +41 -0
  78. package/dist/runtime/components/overlays/Popover.vue +139 -0
  79. package/dist/runtime/components/overlays/Popover.vue.d.ts +82 -0
  80. package/dist/runtime/components/overlays/Slideover.vue +103 -0
  81. package/dist/runtime/components/overlays/Slideover.vue.d.ts +84 -0
  82. package/dist/runtime/components/overlays/Tooltip.vue +118 -0
  83. package/dist/runtime/components/overlays/Tooltip.vue.d.ts +82 -0
  84. package/dist/runtime/composables/defineShortcuts.d.ts +13 -0
  85. package/dist/runtime/composables/defineShortcuts.mjs +108 -0
  86. package/dist/runtime/composables/useCopyToClipboard.d.ts +10 -0
  87. package/dist/runtime/composables/useCopyToClipboard.mjs +26 -0
  88. package/dist/runtime/composables/useFormGroup.d.ts +6 -0
  89. package/dist/runtime/composables/useFormGroup.mjs +30 -0
  90. package/dist/runtime/composables/usePopper.d.ts +232 -0
  91. package/dist/runtime/composables/usePopper.mjs +78 -0
  92. package/dist/runtime/composables/useShortcuts.d.ts +12 -0
  93. package/dist/runtime/composables/useShortcuts.mjs +24 -0
  94. package/dist/runtime/composables/useTimer.d.ts +8 -0
  95. package/dist/runtime/composables/useTimer.mjs +51 -0
  96. package/dist/runtime/composables/useToast.d.ts +18 -0
  97. package/dist/runtime/composables/useToast.mjs +22 -0
  98. package/dist/runtime/plugins/colors.d.ts +2 -0
  99. package/dist/runtime/plugins/colors.mjs +46 -0
  100. package/dist/runtime/types/accordion.d.ts +9 -0
  101. package/dist/runtime/types/avatar.d.ts +9 -0
  102. package/dist/runtime/types/button.d.ts +23 -0
  103. package/dist/runtime/types/clipboard.d.ts +3 -0
  104. package/dist/runtime/types/command-palette.d.ts +26 -0
  105. package/dist/runtime/types/dropdown.d.ts +13 -0
  106. package/dist/runtime/types/form.d.ts +21 -0
  107. package/dist/runtime/types/index.d.ts +12 -0
  108. package/dist/runtime/types/link.d.ts +8 -0
  109. package/dist/runtime/types/notification.d.ts +22 -0
  110. package/dist/runtime/types/popper.d.ts +14 -0
  111. package/dist/runtime/types/tabs.d.ts +6 -0
  112. package/dist/runtime/types/vertical-navigation.d.ts +11 -0
  113. package/dist/runtime/ui.css +13 -0
  114. package/dist/runtime/utils/StateEmitter.d.ts +17 -0
  115. package/dist/runtime/utils/StateEmitter.mjs +21 -0
  116. package/dist/runtime/utils/index.d.ts +11 -0
  117. package/dist/runtime/utils/index.mjs +33 -0
  118. package/dist/types.d.mts +15 -0
  119. package/dist/types.d.ts +15 -0
  120. package/package.json +56 -39
  121. package/LICENSE +0 -21
  122. package/dist/assets/styles.css +0 -14
  123. package/dist/components/NButton.vue +0 -22
  124. package/dist/components/NCard.vue +0 -5
  125. package/dist/components/NCheckbox.vue +0 -35
  126. package/dist/components/NDarkToggle.vue +0 -28
  127. package/dist/components/NDialog.vue +0 -59
  128. package/dist/components/NDropdown.vue +0 -31
  129. package/dist/components/NIcon.vue +0 -9
  130. package/dist/components/NLink.vue +0 -20
  131. package/dist/components/NRadio.vue +0 -40
  132. package/dist/components/NSwitch.vue +0 -37
  133. package/dist/components/NTextInput.vue +0 -34
  134. package/dist/components/NTip.vue +0 -16
  135. package/dist/components/NuxtContentLogo.vue +0 -7
  136. package/dist/components/NuxtExampleLayout.vue +0 -82
  137. package/dist/components/NuxtLogo.vue +0 -20
  138. package/dist/components/nuxt/NDarkToggle.vue +0 -28
  139. package/dist/nuxt.d.ts +0 -16
  140. package/dist/nuxt.mjs +0 -36
  141. package/dist/unocss.d.ts +0 -7
  142. package/dist/unocss.mjs +0 -127
  143. package/nuxt.cjs +0 -7
@@ -0,0 +1,304 @@
1
+ <template>
2
+ <HCombobox
3
+ :by="by"
4
+ :model-value="modelValue"
5
+ :multiple="multiple"
6
+ :nullable="nullable"
7
+ :class="wrapperClass"
8
+ v-bind="attrs"
9
+ as="div"
10
+ @update:model-value="onSelect"
11
+ >
12
+ <div v-show="searchable" :class="ui.input.wrapper">
13
+ <UIcon v-if="iconName" :name="iconName" :class="iconClass" aria-hidden="true" />
14
+ <HComboboxInput
15
+ ref="comboboxInput"
16
+ :value="query"
17
+ :class="[ui.input.base, ui.input.size, ui.input.height, ui.input.padding, icon && ui.input.icon.padding]"
18
+ :placeholder="placeholder"
19
+ autocomplete="off"
20
+ @change="query = $event.target.value"
21
+ />
22
+
23
+ <UButton
24
+ v-if="closeButton"
25
+ v-bind="{ ...ui.default.closeButton, ...closeButton }"
26
+ :class="ui.input.closeButton"
27
+ aria-label="Close"
28
+ @click="onClear"
29
+ />
30
+ </div>
31
+
32
+ <HComboboxOptions
33
+ v-if="groups.length"
34
+ static
35
+ hold
36
+ as="div"
37
+ aria-label="Commands"
38
+ :class="ui.container"
39
+ >
40
+ <CommandPaletteGroup
41
+ v-for="group of groups"
42
+ :key="group.key"
43
+ :query="query"
44
+ :group="group"
45
+ :group-attribute="groupAttribute"
46
+ :command-attribute="commandAttribute"
47
+ :selected-icon="selectedIcon"
48
+ :ui="ui"
49
+ >
50
+ <template v-for="(_, name) in $slots" #[name]="slotData">
51
+ <slot :name="name" v-bind="slotData" />
52
+ </template>
53
+ </CommandPaletteGroup>
54
+ </HComboboxOptions>
55
+
56
+ <template v-else-if="emptyState">
57
+ <slot name="empty-state">
58
+ <div :class="ui.emptyState.wrapper">
59
+ <UIcon v-if="emptyState.icon" :name="emptyState.icon" :class="ui.emptyState.icon" aria-hidden="true" />
60
+ <p :class="query ? ui.emptyState.queryLabel : ui.emptyState.label">
61
+ {{ query ? emptyState.queryLabel : emptyState.label }}
62
+ </p>
63
+ </div>
64
+ </slot>
65
+ </template>
66
+ </HCombobox>
67
+ </template>
68
+
69
+ <script>
70
+ import { ref, computed, watch, onMounted, defineComponent } from "vue";
71
+ import { Combobox as HCombobox, ComboboxInput as HComboboxInput, ComboboxOptions as HComboboxOptions } from "@headlessui/vue";
72
+ import { useDebounceFn } from "@vueuse/core";
73
+ import { useFuse } from "@vueuse/integrations/useFuse";
74
+ import { twMerge, twJoin } from "tailwind-merge";
75
+ import { groupBy, map, omit } from "lodash-es";
76
+ import { defu } from "defu";
77
+ import UIcon from "../elements/Icon.vue";
78
+ import UButton from "../elements/Button.vue";
79
+ import CommandPaletteGroup from "./CommandPaletteGroup.vue";
80
+ import { defuTwMerge } from "../../utils";
81
+ import { useAppConfig } from "#imports";
82
+ import appConfig from "#build/app.config";
83
+ export default defineComponent({
84
+ components: {
85
+ HCombobox,
86
+ HComboboxInput,
87
+ HComboboxOptions,
88
+ UIcon,
89
+ UButton,
90
+ CommandPaletteGroup
91
+ },
92
+ inheritAttrs: false,
93
+ props: {
94
+ modelValue: {
95
+ type: [String, Number, Object, Array],
96
+ default: null
97
+ },
98
+ by: {
99
+ type: String,
100
+ default: "id"
101
+ },
102
+ multiple: {
103
+ type: Boolean,
104
+ default: false
105
+ },
106
+ nullable: {
107
+ type: Boolean,
108
+ default: false
109
+ },
110
+ searchable: {
111
+ type: Boolean,
112
+ default: true
113
+ },
114
+ loading: {
115
+ type: Boolean,
116
+ default: false
117
+ },
118
+ groups: {
119
+ type: Array,
120
+ default: () => []
121
+ },
122
+ icon: {
123
+ type: String,
124
+ default: () => appConfig.ui.commandPalette.default.icon
125
+ },
126
+ loadingIcon: {
127
+ type: String,
128
+ default: () => appConfig.ui.commandPalette.default.loadingIcon
129
+ },
130
+ selectedIcon: {
131
+ type: String,
132
+ default: () => appConfig.ui.commandPalette.default.selectedIcon
133
+ },
134
+ closeButton: {
135
+ type: Object,
136
+ default: () => appConfig.ui.commandPalette.default.closeButton
137
+ },
138
+ emptyState: {
139
+ type: Object,
140
+ default: () => appConfig.ui.commandPalette.default.emptyState
141
+ },
142
+ placeholder: {
143
+ type: String,
144
+ default: "Search..."
145
+ },
146
+ groupAttribute: {
147
+ type: String,
148
+ default: "label"
149
+ },
150
+ commandAttribute: {
151
+ type: String,
152
+ default: "label"
153
+ },
154
+ autoselect: {
155
+ type: Boolean,
156
+ default: true
157
+ },
158
+ autoclear: {
159
+ type: Boolean,
160
+ default: true
161
+ },
162
+ debounce: {
163
+ type: Number,
164
+ default: 200
165
+ },
166
+ fuse: {
167
+ type: Object,
168
+ default: () => ({})
169
+ },
170
+ ui: {
171
+ type: Object,
172
+ default: () => ({})
173
+ }
174
+ },
175
+ emits: ["update:modelValue", "close"],
176
+ setup(props, { emit, attrs, expose }) {
177
+ const appConfig2 = useAppConfig();
178
+ const ui = computed(() => defuTwMerge({}, props.ui, appConfig2.ui.commandPalette));
179
+ const query = ref("");
180
+ const comboboxInput = ref();
181
+ const comboboxApi = ref(null);
182
+ const isLoading = ref(false);
183
+ onMounted(() => {
184
+ if (props.autoselect) {
185
+ activateFirstOption();
186
+ }
187
+ });
188
+ onMounted(() => {
189
+ setTimeout(() => {
190
+ const popoverProvides = comboboxInput.value?.$.provides;
191
+ if (!popoverProvides) {
192
+ return;
193
+ }
194
+ const popoverProvidesSymbols = Object.getOwnPropertySymbols(popoverProvides);
195
+ comboboxApi.value = popoverProvidesSymbols.length && popoverProvides[popoverProvidesSymbols[0]];
196
+ }, 200);
197
+ });
198
+ const options = computed(() => defu({}, props.fuse, {
199
+ fuseOptions: {
200
+ keys: [props.commandAttribute]
201
+ },
202
+ resultLimit: 12,
203
+ matchAllWhenSearchEmpty: true
204
+ }));
205
+ const commands = computed(() => props.groups.filter((group) => !group.search).reduce((acc, group) => {
206
+ return acc.concat(group.commands.map((command) => ({ ...command, group: group.key })));
207
+ }, []));
208
+ const searchResults = ref({});
209
+ const { results } = useFuse(query, commands, options);
210
+ const groups = computed(() => [
211
+ ...map(groupBy(results.value, (command) => command.item.group), (results2, key) => {
212
+ const commands2 = results2.map((result) => {
213
+ const { item, ...data } = result;
214
+ return {
215
+ ...item,
216
+ ...data
217
+ };
218
+ });
219
+ return {
220
+ ...props.groups.find((group) => group.key === key),
221
+ commands: commands2.slice(0, options.value.resultLimit)
222
+ };
223
+ }),
224
+ ...props.groups.filter((group) => !!group.search).map((group) => ({ ...group, commands: (searchResults.value[group.key] || []).slice(0, options.value.resultLimit) })).filter((group) => group.commands.length)
225
+ ]);
226
+ const debouncedSearch = useDebounceFn(async () => {
227
+ const searchableGroups = props.groups.filter((group) => !!group.search);
228
+ if (!searchableGroups.length) {
229
+ return;
230
+ }
231
+ isLoading.value = true;
232
+ await Promise.all(searchableGroups.map(async (group) => {
233
+ searchResults.value[group.key] = await group.search(query.value);
234
+ }));
235
+ isLoading.value = false;
236
+ }, props.debounce);
237
+ watch(query, () => {
238
+ debouncedSearch();
239
+ setTimeout(() => {
240
+ comboboxInput.value?.$el.dispatchEvent(new KeyboardEvent("keydown", { key: "PageUp" }));
241
+ }, 0);
242
+ });
243
+ const wrapperClass = computed(() => twMerge(ui.value.wrapper, attrs.class));
244
+ const iconName = computed(() => {
245
+ if ((props.loading || isLoading.value) && props.loadingIcon) {
246
+ return props.loadingIcon;
247
+ }
248
+ return props.icon;
249
+ });
250
+ const iconClass = computed(() => {
251
+ return twJoin(
252
+ ui.value.input.icon.base,
253
+ ui.value.input.icon.size,
254
+ (props.loading || isLoading.value) && props.loadingIcon && "animate-spin"
255
+ );
256
+ });
257
+ const emptyState = computed(() => ({ ...ui.value.default.emptyState, ...props.emptyState }));
258
+ function activateFirstOption() {
259
+ setTimeout(() => {
260
+ comboboxInput.value?.$el.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowDown" }));
261
+ }, 0);
262
+ }
263
+ function onSelect(option) {
264
+ emit("update:modelValue", option, { query: query.value });
265
+ if (props.autoclear) {
266
+ setTimeout(() => {
267
+ query.value = "";
268
+ }, 0);
269
+ }
270
+ }
271
+ function onClear() {
272
+ if (query.value) {
273
+ query.value = "";
274
+ } else {
275
+ emit("close");
276
+ }
277
+ }
278
+ expose({
279
+ query,
280
+ updateQuery: (q) => {
281
+ query.value = q;
282
+ },
283
+ comboboxApi,
284
+ results
285
+ });
286
+ return {
287
+ attrs: omit(attrs, ["class"]),
288
+ // eslint-disable-next-line vue/no-dupe-keys
289
+ ui,
290
+ // eslint-disable-next-line vue/no-dupe-keys
291
+ groups,
292
+ comboboxInput,
293
+ query,
294
+ wrapperClass,
295
+ iconName,
296
+ iconClass,
297
+ // eslint-disable-next-line vue/no-dupe-keys
298
+ emptyState,
299
+ onSelect,
300
+ onClear
301
+ };
302
+ }
303
+ });
304
+ </script>
@@ -0,0 +1,224 @@
1
+ /// <reference types="lodash" />
2
+ import type { ComputedRef, PropType, ComponentPublicInstance } from 'vue';
3
+ import type { UseFuseOptions } from '@vueuse/integrations/useFuse';
4
+ import type { Group, Command } from '../../types/command-palette';
5
+ import type { Button } from '../../types/button';
6
+ declare const _default: import("vue").DefineComponent<{
7
+ modelValue: {
8
+ type: (ObjectConstructor | ArrayConstructor | StringConstructor | NumberConstructor)[];
9
+ default: null;
10
+ };
11
+ by: {
12
+ type: StringConstructor;
13
+ default: string;
14
+ };
15
+ multiple: {
16
+ type: BooleanConstructor;
17
+ default: boolean;
18
+ };
19
+ nullable: {
20
+ type: BooleanConstructor;
21
+ default: boolean;
22
+ };
23
+ searchable: {
24
+ type: BooleanConstructor;
25
+ default: boolean;
26
+ };
27
+ loading: {
28
+ type: BooleanConstructor;
29
+ default: boolean;
30
+ };
31
+ groups: {
32
+ type: PropType<Group[]>;
33
+ default: () => never[];
34
+ };
35
+ icon: {
36
+ type: StringConstructor;
37
+ default: () => any;
38
+ };
39
+ loadingIcon: {
40
+ type: StringConstructor;
41
+ default: () => any;
42
+ };
43
+ selectedIcon: {
44
+ type: StringConstructor;
45
+ default: () => any;
46
+ };
47
+ closeButton: {
48
+ type: PropType<Button>;
49
+ default: () => any;
50
+ };
51
+ emptyState: {
52
+ type: PropType<{
53
+ icon: string;
54
+ label: string;
55
+ queryLabel: string;
56
+ }>;
57
+ default: () => any;
58
+ };
59
+ placeholder: {
60
+ type: StringConstructor;
61
+ default: string;
62
+ };
63
+ groupAttribute: {
64
+ type: StringConstructor;
65
+ default: string;
66
+ };
67
+ commandAttribute: {
68
+ type: StringConstructor;
69
+ default: string;
70
+ };
71
+ autoselect: {
72
+ type: BooleanConstructor;
73
+ default: boolean;
74
+ };
75
+ autoclear: {
76
+ type: BooleanConstructor;
77
+ default: boolean;
78
+ };
79
+ debounce: {
80
+ type: NumberConstructor;
81
+ default: number;
82
+ };
83
+ fuse: {
84
+ type: PropType<UseFuseOptions<Command>>;
85
+ default: () => {};
86
+ };
87
+ ui: {
88
+ type: PropType<any>;
89
+ default: () => {};
90
+ };
91
+ }, {
92
+ attrs: import("lodash").Omit<{
93
+ [x: string]: unknown;
94
+ }, "class">;
95
+ ui: ComputedRef<any>;
96
+ groups: ComputedRef<{
97
+ commands: any;
98
+ key: string;
99
+ active?: string | undefined;
100
+ inactive?: string | undefined;
101
+ }[]>;
102
+ comboboxInput: import("vue").Ref<ComponentPublicInstance<HTMLInputElement> | undefined>;
103
+ query: import("vue").Ref<string>;
104
+ wrapperClass: ComputedRef<string>;
105
+ iconName: ComputedRef<string | undefined>;
106
+ iconClass: ComputedRef<string>;
107
+ emptyState: ComputedRef<any>;
108
+ onSelect: (option: Command | Command[]) => void;
109
+ onClear: () => void;
110
+ }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("close" | "update:modelValue")[], "close" | "update:modelValue", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
111
+ modelValue: {
112
+ type: (ObjectConstructor | ArrayConstructor | StringConstructor | NumberConstructor)[];
113
+ default: null;
114
+ };
115
+ by: {
116
+ type: StringConstructor;
117
+ default: string;
118
+ };
119
+ multiple: {
120
+ type: BooleanConstructor;
121
+ default: boolean;
122
+ };
123
+ nullable: {
124
+ type: BooleanConstructor;
125
+ default: boolean;
126
+ };
127
+ searchable: {
128
+ type: BooleanConstructor;
129
+ default: boolean;
130
+ };
131
+ loading: {
132
+ type: BooleanConstructor;
133
+ default: boolean;
134
+ };
135
+ groups: {
136
+ type: PropType<Group[]>;
137
+ default: () => never[];
138
+ };
139
+ icon: {
140
+ type: StringConstructor;
141
+ default: () => any;
142
+ };
143
+ loadingIcon: {
144
+ type: StringConstructor;
145
+ default: () => any;
146
+ };
147
+ selectedIcon: {
148
+ type: StringConstructor;
149
+ default: () => any;
150
+ };
151
+ closeButton: {
152
+ type: PropType<Button>;
153
+ default: () => any;
154
+ };
155
+ emptyState: {
156
+ type: PropType<{
157
+ icon: string;
158
+ label: string;
159
+ queryLabel: string;
160
+ }>;
161
+ default: () => any;
162
+ };
163
+ placeholder: {
164
+ type: StringConstructor;
165
+ default: string;
166
+ };
167
+ groupAttribute: {
168
+ type: StringConstructor;
169
+ default: string;
170
+ };
171
+ commandAttribute: {
172
+ type: StringConstructor;
173
+ default: string;
174
+ };
175
+ autoselect: {
176
+ type: BooleanConstructor;
177
+ default: boolean;
178
+ };
179
+ autoclear: {
180
+ type: BooleanConstructor;
181
+ default: boolean;
182
+ };
183
+ debounce: {
184
+ type: NumberConstructor;
185
+ default: number;
186
+ };
187
+ fuse: {
188
+ type: PropType<UseFuseOptions<Command>>;
189
+ default: () => {};
190
+ };
191
+ ui: {
192
+ type: PropType<any>;
193
+ default: () => {};
194
+ };
195
+ }>> & {
196
+ onClose?: ((...args: any[]) => any) | undefined;
197
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
198
+ }, {
199
+ icon: string;
200
+ closeButton: Button;
201
+ ui: any;
202
+ modelValue: string | number | unknown[] | Record<string, any>;
203
+ by: string;
204
+ loading: boolean;
205
+ emptyState: {
206
+ icon: string;
207
+ label: string;
208
+ queryLabel: string;
209
+ };
210
+ multiple: boolean;
211
+ placeholder: string;
212
+ loadingIcon: string;
213
+ nullable: boolean;
214
+ selectedIcon: string;
215
+ searchable: boolean;
216
+ debounce: number;
217
+ groups: Group[];
218
+ groupAttribute: string;
219
+ commandAttribute: string;
220
+ autoselect: boolean;
221
+ autoclear: boolean;
222
+ fuse: UseFuseOptions<Command>;
223
+ }, {}>;
224
+ export default _default;
@@ -0,0 +1,152 @@
1
+ <template>
2
+ <div :class="ui.group.wrapper" role="option">
3
+ <h2 v-if="label" :class="ui.group.label">
4
+ {{ label }}
5
+ </h2>
6
+
7
+ <div :class="ui.group.container" role="listbox" :aria-label="group[groupAttribute]">
8
+ <HComboboxOption
9
+ v-for="(command, index) of group.commands"
10
+ :key="`${group.key}-${index}`"
11
+ v-slot="{ active, selected }"
12
+ :value="command"
13
+ :disabled="command.disabled"
14
+ as="template"
15
+ >
16
+ <div :class="[ui.group.command.base, active ? ui.group.command.active : ui.group.command.inactive, command.disabled ? 'cursor-not-allowed' : 'cursor-pointer']">
17
+ <div :class="ui.group.command.container">
18
+ <slot :name="`${group.key}-icon`" :group="group" :command="command" :active="active" :selected="selected">
19
+ <UIcon v-if="command.icon" :name="command.icon" :class="[ui.group.command.icon.base, active ? ui.group.command.icon.active : ui.group.command.icon.inactive, command.iconClass]" aria-hidden="true" />
20
+ <UAvatar
21
+ v-else-if="command.avatar"
22
+ v-bind="{ size: ui.group.command.avatar.size, ...command.avatar }"
23
+ :class="ui.group.command.avatar.base"
24
+ aria-hidden="true"
25
+ />
26
+ <span v-else-if="command.chip" :class="ui.group.command.chip.base" :style="{ background: `#${command.chip}` }" />
27
+ </slot>
28
+
29
+ <div :class="[ui.group.command.label, command.disabled && ui.group.command.disabled]">
30
+ <slot :name="`${group.key}-command`" :group="group" :command="command" :active="active" :selected="selected">
31
+ <span v-if="command.prefix" class="flex-shrink-0" :class="command.prefixClass || ui.group.command.prefix">{{ command.prefix }}</span>
32
+
33
+ <span class="truncate" :class="{ 'flex-none': command.suffix || command.matches?.length }">{{ command[commandAttribute] }}</span>
34
+
35
+ <!-- eslint-disable-next-line vue/no-v-html -->
36
+ <span v-if="command.matches?.length" class="truncate" :class="command.suffixClass || ui.group.command.suffix" v-html="highlight(command[commandAttribute], command.matches[0])" />
37
+ <span v-else-if="command.suffix" class="truncate" :class="command.suffixClass || ui.group.command.suffix">{{ command.suffix }}</span>
38
+ </slot>
39
+ </div>
40
+ </div>
41
+
42
+ <UIcon v-if="selected" :name="selectedIcon" :class="ui.group.command.selectedIcon.base" aria-hidden="true" />
43
+ <slot
44
+ v-else-if="active && (group.active || $slots[`${group.key}-active`])"
45
+ :name="`${group.key}-active`"
46
+ :group="group"
47
+ :command="command"
48
+ :active="active"
49
+ :selected="selected"
50
+ >
51
+ <span v-if="group.active" :class="ui.group.active">{{ group.active }}</span>
52
+ </slot>
53
+ <slot
54
+ v-else
55
+ :name="`${group.key}-inactive`"
56
+ :group="group"
57
+ :command="command"
58
+ :active="active"
59
+ :selected="selected"
60
+ >
61
+ <span v-if="command.shortcuts?.length" :class="ui.group.command.shortcuts">
62
+ <UKbd v-for="shortcut of command.shortcuts" :key="shortcut">{{ shortcut }}</UKbd>
63
+ </span>
64
+ <span v-else-if="!command.disabled && group.inactive" :class="ui.group.inactive">{{ group.inactive }}</span>
65
+ </slot>
66
+ </div>
67
+ </HComboboxOption>
68
+ </div>
69
+ </div>
70
+ </template>
71
+
72
+ <script>
73
+ import { computed, defineComponent } from "vue";
74
+ import { ComboboxOption as HComboboxOption } from "@headlessui/vue";
75
+ import UIcon from "../elements/Icon.vue";
76
+ import UAvatar from "../elements/Avatar.vue";
77
+ import UKbd from "../elements/Kbd.vue";
78
+ export default defineComponent({
79
+ components: {
80
+ HComboboxOption,
81
+ UIcon,
82
+ UAvatar,
83
+ UKbd
84
+ },
85
+ props: {
86
+ group: {
87
+ type: Object,
88
+ required: true
89
+ },
90
+ query: {
91
+ type: String,
92
+ default: ""
93
+ },
94
+ groupAttribute: {
95
+ type: String,
96
+ required: true
97
+ },
98
+ commandAttribute: {
99
+ type: String,
100
+ required: true
101
+ },
102
+ selectedIcon: {
103
+ type: String,
104
+ required: true
105
+ },
106
+ ui: {
107
+ type: Object,
108
+ default: () => ({})
109
+ }
110
+ },
111
+ setup(props) {
112
+ const label = computed(() => {
113
+ const label2 = props.group[props.groupAttribute];
114
+ return typeof label2 === "function" ? label2(props.query) : label2;
115
+ });
116
+ function highlight(text, { indices, value }) {
117
+ if (text === value) {
118
+ return "";
119
+ }
120
+ let content = "";
121
+ let nextUnhighlightedIndiceStartingIndex = 0;
122
+ indices.forEach((indice) => {
123
+ const lastIndiceNextIndex = indice[1] + 1;
124
+ const isMatched = lastIndiceNextIndex - indice[0] >= props.query.length;
125
+ content += [
126
+ value.substring(nextUnhighlightedIndiceStartingIndex, indice[0]),
127
+ isMatched && "<mark>",
128
+ value.substring(indice[0], lastIndiceNextIndex),
129
+ isMatched && "</mark>"
130
+ ].filter(Boolean).join("");
131
+ nextUnhighlightedIndiceStartingIndex = lastIndiceNextIndex;
132
+ });
133
+ content += value.substring(nextUnhighlightedIndiceStartingIndex);
134
+ const index = content.indexOf("<mark>");
135
+ if (index > 60) {
136
+ content = `...${content.substring(index - 60)}`;
137
+ }
138
+ return content;
139
+ }
140
+ return {
141
+ label,
142
+ highlight
143
+ };
144
+ }
145
+ });
146
+ </script>
147
+
148
+ <style>
149
+ mark {
150
+ @apply bg-primary-400;
151
+ }
152
+ </style>