@hina-ui/vue 1.7.9 → 1.7.10

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 (36) hide show
  1. package/dist/index.js +197 -38
  2. package/dist/index.js.map +1 -1
  3. package/dist/shared/lib/command-palette/match.ts +17 -4
  4. package/dist/shared/lib/virtual/choices.ts +2 -1
  5. package/dist/shared/variants/command-palette.ts +12 -0
  6. package/dist/shared/variants/virtual-list.ts +8 -0
  7. package/dist/types/shared/src/lib/command-palette/match.d.ts +9 -0
  8. package/dist/types/shared/src/lib/command-palette/match.d.ts.map +1 -1
  9. package/dist/types/shared/src/lib/virtual/choices.d.ts +4 -0
  10. package/dist/types/shared/src/lib/virtual/choices.d.ts.map +1 -1
  11. package/dist/types/shared/src/variants/command-palette.d.ts +3 -0
  12. package/dist/types/shared/src/variants/command-palette.d.ts.map +1 -1
  13. package/dist/types/shared/src/variants/virtual-list.d.ts +2 -0
  14. package/dist/types/shared/src/variants/virtual-list.d.ts.map +1 -1
  15. package/dist/types/vue/src/components/command-palette/CommandPalette.vue.d.ts +2 -1
  16. package/dist/types/vue/src/components/command-palette/CommandPalette.vue.d.ts.map +1 -1
  17. package/dist/types/vue/src/components/command-palette/CommandPalettePanel.vue.d.ts +2 -1
  18. package/dist/types/vue/src/components/command-palette/CommandPalettePanel.vue.d.ts.map +1 -1
  19. package/dist/types/vue/src/components/command-palette/composables/useCommandItems.d.ts +6 -1
  20. package/dist/types/vue/src/components/command-palette/composables/useCommandItems.d.ts.map +1 -1
  21. package/dist/types/vue/src/components/command-palette/types.d.ts +3 -0
  22. package/dist/types/vue/src/components/command-palette/types.d.ts.map +1 -1
  23. package/dist/types/vue/src/components/command-palette/utils/match.d.ts +1 -1
  24. package/dist/types/vue/src/components/command-palette/utils/match.d.ts.map +1 -1
  25. package/dist/types/vue/src/components/virtual-list/VirtualChoices.vue.d.ts +4 -1
  26. package/dist/types/vue/src/components/virtual-list/VirtualChoices.vue.d.ts.map +1 -1
  27. package/dist/types/vue/src/index.d.ts +1 -1
  28. package/dist/types/vue/src/index.d.ts.map +1 -1
  29. package/package.json +1 -1
  30. package/src/components/command-palette/CommandPalette.vue +8 -0
  31. package/src/components/command-palette/CommandPalettePanel.vue +85 -3
  32. package/src/components/command-palette/composables/useCommandItems.ts +19 -13
  33. package/src/components/command-palette/types.ts +4 -0
  34. package/src/components/command-palette/utils/match.ts +1 -0
  35. package/src/components/virtual-list/VirtualChoices.vue +39 -6
  36. package/src/index.ts +1 -0
@@ -1,29 +1,35 @@
1
1
  import { computed } from 'vue'
2
- import type { CommandItems } from '../types'
2
+ import type { CommandGroup, CommandItems } from '../types'
3
3
  import { filterCommands } from '../utils/match'
4
4
  import type { CommandMatch } from '../utils/match'
5
5
  import type { SelectItems, SelectOption } from '../../select/types'
6
6
 
7
7
  type CommandOption<T> = SelectOption & { match: CommandMatch<T> }
8
8
 
9
+ export interface CommandOptionGroup<T> {
10
+ label: string
11
+ options: CommandOption<T>[]
12
+ group: CommandGroup<T>
13
+ }
14
+
9
15
  export function useCommandItems<T>(
10
16
  props: { items: CommandItems<T>; ignoreFilter?: boolean },
11
17
  search: () => string,
12
18
  ) {
13
19
  const sections = computed(() => filterCommands(props.items, props.ignoreFilter ? '' : search()))
14
20
  const options = computed<SelectItems<CommandOption<T>>>(() =>
15
- sections.value.flatMap<CommandOption<T> | { label: string; options: CommandOption<T>[] }>(
16
- section => {
17
- const options = section.matches.map(match => ({
18
- value: match.item.id,
19
- label: match.item.label,
20
- disabled: match.item.disabled,
21
- description: match.item.description,
22
- match,
23
- }))
24
- return section.label ? [{ label: section.label, options }] : options
25
- },
26
- ),
21
+ sections.value.flatMap<CommandOption<T> | CommandOptionGroup<T>>(section => {
22
+ const options = section.matches.map(match => ({
23
+ value: match.item.id,
24
+ label: match.item.label,
25
+ disabled: match.item.disabled,
26
+ description: match.item.description,
27
+ match,
28
+ }))
29
+ return section.group
30
+ ? [{ label: section.group.label, options, group: section.group as CommandGroup<T> }]
31
+ : options
32
+ }),
27
33
  )
28
34
  return { sections, options }
29
35
  }
@@ -32,6 +32,10 @@ export interface CommandEmptySlotProps {
32
32
  search: string
33
33
  }
34
34
 
35
+ export interface CommandHeadingSlotProps<T = unknown> {
36
+ group: CommandGroup<T>
37
+ }
38
+
35
39
  export function isCommandGroup<T>(
36
40
  entry: CommandItem<T> | CommandGroup<T>,
37
41
  ): entry is CommandGroup<T> {
@@ -4,6 +4,7 @@ import type * as Shared from '../../../../../shared/src/lib/command-palette/matc
4
4
  export {
5
5
  commandMatchRange,
6
6
  filterCommands,
7
+ layoutCommandSections,
7
8
  } from '../../../../../shared/src/lib/command-palette/match'
8
9
  export type CommandMatch<T = unknown> = Shared.CommandMatch<CommandItem<T>>
9
10
  export type CommandSection<T = unknown> = Shared.CommandSection<CommandItem<T>>
@@ -1,11 +1,18 @@
1
1
  <script setup lang="ts" generic="T extends SelectOption = SelectOption">
2
+ import { computed } from 'vue'
3
+ import { cn } from '../../lib/cn'
2
4
  import { useUiLocale } from '../../locale'
3
5
  import { useVirtualChoices } from '../../lib/reka/useVirtualChoices'
4
6
  import type { VirtualizeOptions } from '../../lib/virtual/types'
5
7
  import ScrollArea from '../scroll-area/ScrollArea.vue'
6
8
  import { selectEmpty, selectLabel } from '../select/select.variants'
7
- import type { SelectItems, SelectOption } from '../select/types'
8
- import { virtualListContent, virtualListItem } from './virtual-list.variants'
9
+ import type { SelectItems, SelectOption, SelectOptionGroup } from '../select/types'
10
+ import {
11
+ virtualChoiceHeading,
12
+ virtualChoiceHeadings,
13
+ virtualListContent,
14
+ virtualListItem,
15
+ } from './virtual-list.variants'
9
16
 
10
17
  defineOptions({ name: 'HnVirtualChoices', inheritAttrs: false })
11
18
  const props = defineProps<{
@@ -20,10 +27,15 @@
20
27
  const t = useUiLocale()
21
28
  const { area, body, rows, entries, bodyStyle, measure, itemAttrs, labelId } =
22
29
  useVirtualChoices(props)
23
- defineSlots<{
30
+ const slots = defineSlots<{
24
31
  default(props: { option: T; attrs: ReturnType<typeof itemAttrs> }): unknown
32
+ group?(props: { group: SelectOptionGroup<T> }): unknown
25
33
  empty?(): unknown
26
34
  }>()
35
+ const held = (index: number) => !!slots.group && !rows.value[index]!.option
36
+ const origin = computed(() =>
37
+ entries.value[0] ? entries.value[0].start - parseFloat(bodyStyle.value.paddingBlockStart) : 0,
38
+ )
27
39
  </script>
28
40
 
29
41
  <template>
@@ -34,7 +46,7 @@
34
46
  maxHeight: typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight,
35
47
  }"
36
48
  >
37
- <div :class="props.padded === false ? undefined : 'p-1'">
49
+ <div :class="cn(slots.group && 'relative', props.padded !== false && 'p-1') || undefined">
38
50
  <div
39
51
  ref="body"
40
52
  v-bind="$attrs"
@@ -45,17 +57,23 @@
45
57
  <div
46
58
  v-for="entry in entries"
47
59
  :key="entry.key"
48
- :ref="measure"
60
+ :ref="held(entry.index) ? undefined : measure"
49
61
  :data-index="entry.index"
50
62
  role="presentation"
51
63
  :class="virtualListItem({ orientation: 'vertical' })"
52
- :style="{ marginBlockStart: `${entry.gapBefore}px` }"
64
+ :style="{
65
+ marginBlockStart: `${entry.gapBefore}px`,
66
+ height: held(entry.index) ? `${entry.size}px` : undefined,
67
+ }"
53
68
  >
54
69
  <slot
55
70
  v-if="rows[entry.index]!.option"
56
71
  :option="rows[entry.index]!.option!"
57
72
  :attrs="itemAttrs(entry.index)"
58
73
  />
74
+ <span v-else-if="slots.group" :id="labelId(entry.index)" hidden>
75
+ {{ rows[entry.index]!.label }}
76
+ </span>
59
77
  <div v-else :id="labelId(entry.index)" :class="selectLabel()">
60
78
  {{ rows[entry.index]!.label }}
61
79
  </div>
@@ -64,6 +82,21 @@
64
82
  <div v-if="!rows.length" :class="selectEmpty()">
65
83
  <slot name="empty">{{ t.select.empty }}</slot>
66
84
  </div>
85
+ <div v-else-if="slots.group" :class="virtualChoiceHeadings()">
86
+ <div class="relative">
87
+ <template v-for="entry in entries" :key="entry.key">
88
+ <div
89
+ v-if="rows[entry.index]!.source"
90
+ :ref="measure"
91
+ :data-index="entry.index"
92
+ :class="virtualChoiceHeading()"
93
+ :style="{ top: `${entry.start - origin}px` }"
94
+ >
95
+ <slot name="group" :group="rows[entry.index]!.source!" />
96
+ </div>
97
+ </template>
98
+ </div>
99
+ </div>
67
100
  </div>
68
101
  </ScrollArea>
69
102
  </template>
package/src/index.ts CHANGED
@@ -82,6 +82,7 @@ export type {
82
82
  CommandItemMatch,
83
83
  CommandItemSlotProps,
84
84
  CommandEmptySlotProps,
85
+ CommandHeadingSlotProps,
85
86
  } from './components/command-palette/types'
86
87
  export { default as Listbox } from './components/listbox/Listbox.vue'
87
88
  export type { ListboxVariants } from './components/listbox/listbox.variants'