refactor(Command): adapt command component to use listbox
This commit is contained in:
parent
b5cf49e8ae
commit
d7c4f34bab
|
|
@ -171,22 +171,22 @@
|
|||
* Table
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
.vp-doc table {
|
||||
.vp-doc table:not(:where(.not-docs *)) {
|
||||
@apply relative w-full overflow-hidden border-none text-sm;
|
||||
}
|
||||
|
||||
.vp-doc tr {
|
||||
.vp-doc tr:not(:where(.not-docs *)) {
|
||||
@apply m-0 border-b;
|
||||
}
|
||||
.vp-doc tbody tr:last-child {
|
||||
.vp-doc tbody:not(:where(.not-docs *)) tr:last-child {
|
||||
@apply border-b-0;
|
||||
}
|
||||
|
||||
.vp-doc th {
|
||||
.vp-doc th:not(:where(.not-docs *)) {
|
||||
@apply px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right;
|
||||
}
|
||||
|
||||
.vp-doc td {
|
||||
.vp-doc td:not(:where(.not-docs *)) {
|
||||
@apply px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -660,7 +660,8 @@
|
|||
"name": "command",
|
||||
"type": "registry:ui",
|
||||
"dependencies": [
|
||||
"reka-ui"
|
||||
"reka-ui",
|
||||
"@vueuse/core"
|
||||
],
|
||||
"registryDependencies": [
|
||||
"utils",
|
||||
|
|
@ -2783,7 +2784,8 @@
|
|||
"name": "command",
|
||||
"type": "registry:ui",
|
||||
"dependencies": [
|
||||
"reka-ui"
|
||||
"reka-ui",
|
||||
"@vueuse/core"
|
||||
],
|
||||
"registryDependencies": [
|
||||
"utils",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
"name": "command",
|
||||
"type": "registry:ui",
|
||||
"dependencies": [
|
||||
"reka-ui"
|
||||
"reka-ui",
|
||||
"@vueuse/core"
|
||||
],
|
||||
"registryDependencies": [
|
||||
"utils",
|
||||
|
|
@ -11,7 +12,7 @@
|
|||
"files": [
|
||||
{
|
||||
"path": "ui/command/Command.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxRootEmits, ComboboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxRoot, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n open: true,\n modelValue: '',\n})\n\nconst emits = defineEmits<ComboboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ComboboxRoot>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes, reactive, ref, watch } from 'vue'\nimport { provideCommandContext } from '.'\n\nconst props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n modelValue: '',\n})\n\nconst emits = defineEmits<ListboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst allItems = ref<Map<string, string>>(new Map())\nconst allGroups = ref<Map<string, Set<string>>>(new Map())\n\nconst { contains } = useFilter({ sensitivity: 'base' })\nconst filterState = reactive({\n search: '',\n filtered: {\n /** The count of all visible items. */\n count: 0,\n /** Map from visible item id to its search score. */\n items: new Map() as Map<string, number>,\n /** Set of groups with at least one visible item. */\n groups: new Set() as Set<string>,\n },\n})\n\nfunction filterItems() {\n if (!filterState.search) {\n filterState.filtered.count = allItems.value.size\n // Do nothing, each item will know to show itself because search is empty\n return\n }\n\n // Reset the groups\n filterState.filtered.groups = new Set()\n let itemCount = 0\n\n // Check which items should be included\n for (const [id, value] of allItems.value) {\n const score = contains(value, filterState.search)\n filterState.filtered.items.set(id, score ? 1 : 0)\n if (score)\n itemCount++\n }\n\n // Check which groups have at least 1 item shown\n for (const [groupId, group] of allGroups.value) {\n for (const itemId of group) {\n if (filterState.filtered.items.get(itemId)! > 0) {\n filterState.filtered.groups.add(groupId)\n break\n }\n }\n }\n\n filterState.filtered.count = itemCount\n}\n\nfunction handleSelect() {\n filterState.search = ''\n}\n\nwatch(() => filterState.search, () => {\n filterItems()\n})\n\nprovideCommandContext({\n allItems,\n allGroups,\n filterState,\n})\n</script>\n\n<template>\n <ListboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ListboxRoot>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -23,37 +24,37 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/CommandEmpty.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxEmptyProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxEmpty } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </ComboboxEmpty>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Primitive } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\nconst props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { filterState } = useCommand()\nconst isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,\n)\n</script>\n\n<template>\n <Primitive v-if=\"isRender\" v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </Primitive>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandGroup.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxGroup, ComboboxLabel } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxGroup\n v-bind=\"delegatedProps\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n >\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ComboboxLabel>\n <slot />\n </ComboboxGroup>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxGroup, ListboxGroupLabel, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted } from 'vue'\nimport { provideCommandGroupContext, useCommand } from '.'\n\nconst props = defineProps<ListboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { allGroups, filterState } = useCommand()\nconst id = useId()\n\nconst isRender = computed(() => !filterState.search ? true : filterState.filtered.groups.has(id))\n\nprovideCommandGroupContext({ id })\nonMounted(() => {\n if (!allGroups.value.has(id))\n allGroups.value.set(id, new Set())\n})\nonUnmounted(() => {\n allGroups.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxGroup\n v-bind=\"delegatedProps\"\n :id=\"id\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n :hidden=\"isRender ? undefined : true\"\n >\n <ListboxGroupLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ListboxGroupLabel>\n <slot />\n </ListboxGroup>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandInput.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ComboboxInput, type ComboboxInputProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ComboboxInputProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ComboboxInput\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n auto-focus\n :class=\"cn('flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ListboxFilter, type ListboxFilterProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ListboxFilterProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n\nconst { filterState } = useCommand()\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ListboxFilter\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n v-model=\"filterState.search\"\n auto-focus\n :class=\"cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandItem.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxItemEmits, ComboboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxItem, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ComboboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxItem\n v-bind=\"forwarded\"\n :class=\"cn('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', props.class)\"\n >\n <slot />\n </ComboboxItem>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { useCurrentElement } from '@vueuse/core'\nimport { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted, ref } from 'vue'\nimport { useCommand, useCommandGroup } from '.'\n\nconst props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ListboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst id = useId()\nconst { filterState, allItems, allGroups } = useCommand()\nconst groupContext = useCommandGroup()\n\nconst isRender = computed(() => {\n if (!filterState.search) {\n return true\n }\n else {\n const filteredCurrentItem = filterState.filtered.items.get(id)\n // If the filtered items is undefined means not in the all times map yet\n // Do the first render to add into the map\n if (filteredCurrentItem === undefined) {\n return true\n }\n\n // Check with filter\n return filteredCurrentItem > 0\n }\n})\n\nconst itemRef = ref()\nconst currentElement = useCurrentElement(itemRef)\nonMounted(() => {\n if (!(currentElement.value instanceof HTMLElement))\n return\n\n // textValue to perform filter\n allItems.value.set(id, currentElement.value.textContent ?? props.value.toString())\n\n const groupId = groupContext?.id\n if (groupId) {\n if (!allGroups.value.has(groupId)) {\n allGroups.value.set(groupId, new Set([id]))\n }\n else {\n allGroups.value.get(groupId)?.add(id)\n }\n }\n})\nonUnmounted(() => {\n allItems.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxItem\n v-if=\"isRender\"\n v-bind=\"forwarded\"\n :id=\"id\"\n ref=\"itemRef\"\n :class=\"cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)\"\n @select=\"() => {\n filterState.search = ''\n }\"\n >\n <slot />\n </ListboxItem>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandList.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxContentEmits, ComboboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxContent, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {\n dismissable: false,\n})\nconst emits = defineEmits<ComboboxContentEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ComboboxContent>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxContent, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ListboxContentProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <ListboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ListboxContent>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandSeparator.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxSeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxSeparator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxSeparator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </ComboboxSeparator>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { SeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Separator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <Separator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -65,7 +66,7 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/index.ts",
|
||||
"content": "export { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n",
|
||||
"content": "import type { Ref } from 'vue'\nimport { createContext } from 'reka-ui'\n\nexport { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n\nexport const [useCommand, provideCommandContext] = createContext<{\n allItems: Ref<Map<string, string>>\n allGroups: Ref<Map<string, Set<string>>>\n filterState: {\n search: string\n filtered: { count: number, items: Map<string, number>, groups: Set<string> }\n }\n}>('Command')\n\nexport const [useCommandGroup, provideCommandGroupContext] = createContext<{\n id?: string\n}>('CommandGroup')\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
"name": "command",
|
||||
"type": "registry:ui",
|
||||
"dependencies": [
|
||||
"reka-ui"
|
||||
"reka-ui",
|
||||
"@vueuse/core"
|
||||
],
|
||||
"registryDependencies": [
|
||||
"utils",
|
||||
|
|
@ -11,7 +12,7 @@
|
|||
"files": [
|
||||
{
|
||||
"path": "ui/command/Command.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxRootEmits, ComboboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxRoot, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n open: true,\n modelValue: '',\n})\n\nconst emits = defineEmits<ComboboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ComboboxRoot>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes, reactive, ref, watch } from 'vue'\nimport { provideCommandContext } from '.'\n\nconst props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n modelValue: '',\n})\n\nconst emits = defineEmits<ListboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst allItems = ref<Map<string, string>>(new Map())\nconst allGroups = ref<Map<string, Set<string>>>(new Map())\n\nconst { contains } = useFilter({ sensitivity: 'base' })\nconst filterState = reactive({\n search: '',\n filtered: {\n /** The count of all visible items. */\n count: 0,\n /** Map from visible item id to its search score. */\n items: new Map() as Map<string, number>,\n /** Set of groups with at least one visible item. */\n groups: new Set() as Set<string>,\n },\n})\n\nfunction filterItems() {\n if (!filterState.search) {\n filterState.filtered.count = allItems.value.size\n // Do nothing, each item will know to show itself because search is empty\n return\n }\n\n // Reset the groups\n filterState.filtered.groups = new Set()\n let itemCount = 0\n\n // Check which items should be included\n for (const [id, value] of allItems.value) {\n const score = contains(value, filterState.search)\n filterState.filtered.items.set(id, score ? 1 : 0)\n if (score)\n itemCount++\n }\n\n // Check which groups have at least 1 item shown\n for (const [groupId, group] of allGroups.value) {\n for (const itemId of group) {\n if (filterState.filtered.items.get(itemId)! > 0) {\n filterState.filtered.groups.add(groupId)\n break\n }\n }\n }\n\n filterState.filtered.count = itemCount\n}\n\nfunction handleSelect() {\n filterState.search = ''\n}\n\nwatch(() => filterState.search, () => {\n filterItems()\n})\n\nprovideCommandContext({\n allItems,\n allGroups,\n filterState,\n})\n</script>\n\n<template>\n <ListboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ListboxRoot>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -23,37 +24,37 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/CommandEmpty.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxEmptyProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxEmpty } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </ComboboxEmpty>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Primitive } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\nconst props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { filterState } = useCommand()\nconst isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,\n)\n</script>\n\n<template>\n <Primitive v-if=\"isRender\" v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </Primitive>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandGroup.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxGroup, ComboboxLabel } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxGroup\n v-bind=\"delegatedProps\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n >\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ComboboxLabel>\n <slot />\n </ComboboxGroup>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxGroup, ListboxGroupLabel, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted } from 'vue'\nimport { provideCommandGroupContext, useCommand } from '.'\n\nconst props = defineProps<ListboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { allGroups, filterState } = useCommand()\nconst id = useId()\n\nconst isRender = computed(() => !filterState.search ? true : filterState.filtered.groups.has(id))\n\nprovideCommandGroupContext({ id })\nonMounted(() => {\n if (!allGroups.value.has(id))\n allGroups.value.set(id, new Set())\n})\nonUnmounted(() => {\n allGroups.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxGroup\n v-bind=\"delegatedProps\"\n :id=\"id\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n :hidden=\"isRender ? undefined : true\"\n >\n <ListboxGroupLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ListboxGroupLabel>\n <slot />\n </ListboxGroup>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandInput.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ComboboxInput, type ComboboxInputProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ComboboxInputProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ComboboxInput\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n auto-focus\n :class=\"cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ListboxFilter, type ListboxFilterProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ListboxFilterProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n\nconst { filterState } = useCommand()\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ListboxFilter\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n v-model=\"filterState.search\"\n auto-focus\n :class=\"cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandItem.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxItemEmits, ComboboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxItem, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ComboboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxItem\n v-bind=\"forwarded\"\n :class=\"cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)\"\n >\n <slot />\n </ComboboxItem>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { useCurrentElement } from '@vueuse/core'\nimport { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted, ref } from 'vue'\nimport { useCommand, useCommandGroup } from '.'\n\nconst props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ListboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst id = useId()\nconst { filterState, allItems, allGroups } = useCommand()\nconst groupContext = useCommandGroup()\n\nconst isRender = computed(() => {\n if (!filterState.search) {\n return true\n }\n else {\n const filteredCurrentItem = filterState.filtered.items.get(id)\n // If the filtered items is undefined means not in the all times map yet\n // Do the first render to add into the map\n if (filteredCurrentItem === undefined) {\n return true\n }\n\n // Check with filter\n return filteredCurrentItem > 0\n }\n})\n\nconst itemRef = ref()\nconst currentElement = useCurrentElement(itemRef)\nonMounted(() => {\n if (!(currentElement.value instanceof HTMLElement))\n return\n\n // textValue to perform filter\n allItems.value.set(id, currentElement.value.textContent ?? props.value.toString())\n\n const groupId = groupContext?.id\n if (groupId) {\n if (!allGroups.value.has(groupId)) {\n allGroups.value.set(groupId, new Set([id]))\n }\n else {\n allGroups.value.get(groupId)?.add(id)\n }\n }\n})\nonUnmounted(() => {\n allItems.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxItem\n v-if=\"isRender\"\n v-bind=\"forwarded\"\n :id=\"id\"\n ref=\"itemRef\"\n :class=\"cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)\"\n @select=\"() => {\n filterState.search = ''\n }\"\n >\n <slot />\n </ListboxItem>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandList.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxContentEmits, ComboboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxContent, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {\n dismissable: false,\n})\nconst emits = defineEmits<ComboboxContentEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ComboboxContent>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxContent, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ListboxContentProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <ListboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ListboxContent>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandSeparator.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxSeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxSeparator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxSeparator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </ComboboxSeparator>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { SeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Separator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <Separator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -65,7 +66,7 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/index.ts",
|
||||
"content": "export { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n",
|
||||
"content": "import type { Ref } from 'vue'\nimport { createContext } from 'reka-ui'\n\nexport { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n\nexport const [useCommand, provideCommandContext] = createContext<{\n allItems: Ref<Map<string, string>>\n allGroups: Ref<Map<string, Set<string>>>\n filterState: {\n search: string\n filtered: { count: number, items: Map<string, number>, groups: Set<string> }\n }\n}>('Command')\n\nexport const [useCommandGroup, provideCommandGroupContext] = createContext<{\n id?: string\n}>('CommandGroup')\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/radio-group/RadioGroupItem.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Check } from 'lucide-vue-next'\nimport {\n RadioGroupIndicator,\n RadioGroupItem,\n type RadioGroupItemProps,\n useForwardProps,\n} from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<RadioGroupItemProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RadioGroupItem\n v-bind=\"forwardedProps\"\n :class=\"\n cn(\n 'aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n props.class,\n )\n \"\n >\n <RadioGroupIndicator class=\"flex items-center justify-center\">\n <Check class=\"h-3.5 w-3.5 fill-primary\" />\n </RadioGroupIndicator>\n </RadioGroupItem>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Check } from 'lucide-vue-next'\nimport {\n RadioGroupIndicator,\n RadioGroupItem,\n type RadioGroupItemProps,\n useForwardProps,\n} from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<RadioGroupItemProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RadioGroupItem\n v-bind=\"forwardedProps\"\n :class=\"\n cn(\n 'aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n props.class,\n )\n \"\n >\n <RadioGroupIndicator class=\"flex items-center justify-center\">\n <Check class=\"h-3.5 w-3.5 text-primary\" />\n </RadioGroupIndicator>\n </RadioGroupItem>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1050,7 +1050,8 @@
|
|||
"name": "command",
|
||||
"type": "registry:ui",
|
||||
"dependencies": [
|
||||
"reka-ui"
|
||||
"reka-ui",
|
||||
"@vueuse/core"
|
||||
],
|
||||
"registryDependencies": [
|
||||
"utils",
|
||||
|
|
@ -1059,7 +1060,7 @@
|
|||
"files": [
|
||||
{
|
||||
"path": "ui/command/Command.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxRootEmits, ComboboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxRoot, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n open: true,\n modelValue: '',\n})\n\nconst emits = defineEmits<ComboboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ComboboxRoot>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes, reactive, ref, watch } from 'vue'\nimport { provideCommandContext } from '.'\n\nconst props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n modelValue: '',\n})\n\nconst emits = defineEmits<ListboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst allItems = ref<Map<string, string>>(new Map())\nconst allGroups = ref<Map<string, Set<string>>>(new Map())\n\nconst { contains } = useFilter({ sensitivity: 'base' })\nconst filterState = reactive({\n search: '',\n filtered: {\n /** The count of all visible items. */\n count: 0,\n /** Map from visible item id to its search score. */\n items: new Map() as Map<string, number>,\n /** Set of groups with at least one visible item. */\n groups: new Set() as Set<string>,\n },\n})\n\nfunction filterItems() {\n if (!filterState.search) {\n filterState.filtered.count = allItems.value.size\n // Do nothing, each item will know to show itself because search is empty\n return\n }\n\n // Reset the groups\n filterState.filtered.groups = new Set()\n let itemCount = 0\n\n // Check which items should be included\n for (const [id, value] of allItems.value) {\n const score = contains(value, filterState.search)\n filterState.filtered.items.set(id, score ? 1 : 0)\n if (score)\n itemCount++\n }\n\n // Check which groups have at least 1 item shown\n for (const [groupId, group] of allGroups.value) {\n for (const itemId of group) {\n if (filterState.filtered.items.get(itemId)! > 0) {\n filterState.filtered.groups.add(groupId)\n break\n }\n }\n }\n\n filterState.filtered.count = itemCount\n}\n\nfunction handleSelect() {\n filterState.search = ''\n}\n\nwatch(() => filterState.search, () => {\n filterItems()\n})\n\nprovideCommandContext({\n allItems,\n allGroups,\n filterState,\n})\n</script>\n\n<template>\n <ListboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ListboxRoot>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -1071,37 +1072,37 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/CommandEmpty.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxEmptyProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxEmpty } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </ComboboxEmpty>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Primitive } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\nconst props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { filterState } = useCommand()\nconst isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,\n)\n</script>\n\n<template>\n <Primitive v-if=\"isRender\" v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </Primitive>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandGroup.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxGroup, ComboboxLabel } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxGroup\n v-bind=\"delegatedProps\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n >\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ComboboxLabel>\n <slot />\n </ComboboxGroup>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxGroup, ListboxGroupLabel, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted } from 'vue'\nimport { provideCommandGroupContext, useCommand } from '.'\n\nconst props = defineProps<ListboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { allGroups, filterState } = useCommand()\nconst id = useId()\n\nconst isRender = computed(() => !filterState.search ? true : filterState.filtered.groups.has(id))\n\nprovideCommandGroupContext({ id })\nonMounted(() => {\n if (!allGroups.value.has(id))\n allGroups.value.set(id, new Set())\n})\nonUnmounted(() => {\n allGroups.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxGroup\n v-bind=\"delegatedProps\"\n :id=\"id\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n :hidden=\"isRender ? undefined : true\"\n >\n <ListboxGroupLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ListboxGroupLabel>\n <slot />\n </ListboxGroup>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandInput.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ComboboxInput, type ComboboxInputProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ComboboxInputProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ComboboxInput\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n auto-focus\n :class=\"cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ListboxFilter, type ListboxFilterProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ListboxFilterProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n\nconst { filterState } = useCommand()\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ListboxFilter\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n v-model=\"filterState.search\"\n auto-focus\n :class=\"cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandItem.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxItemEmits, ComboboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxItem, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ComboboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxItem\n v-bind=\"forwarded\"\n :class=\"cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)\"\n >\n <slot />\n </ComboboxItem>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { useCurrentElement } from '@vueuse/core'\nimport { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted, ref } from 'vue'\nimport { useCommand, useCommandGroup } from '.'\n\nconst props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ListboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst id = useId()\nconst { filterState, allItems, allGroups } = useCommand()\nconst groupContext = useCommandGroup()\n\nconst isRender = computed(() => {\n if (!filterState.search) {\n return true\n }\n else {\n const filteredCurrentItem = filterState.filtered.items.get(id)\n // If the filtered items is undefined means not in the all times map yet\n // Do the first render to add into the map\n if (filteredCurrentItem === undefined) {\n return true\n }\n\n // Check with filter\n return filteredCurrentItem > 0\n }\n})\n\nconst itemRef = ref()\nconst currentElement = useCurrentElement(itemRef)\nonMounted(() => {\n if (!(currentElement.value instanceof HTMLElement))\n return\n\n // textValue to perform filter\n allItems.value.set(id, currentElement.value.textContent ?? props.value.toString())\n\n const groupId = groupContext?.id\n if (groupId) {\n if (!allGroups.value.has(groupId)) {\n allGroups.value.set(groupId, new Set([id]))\n }\n else {\n allGroups.value.get(groupId)?.add(id)\n }\n }\n})\nonUnmounted(() => {\n allItems.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxItem\n v-if=\"isRender\"\n v-bind=\"forwarded\"\n :id=\"id\"\n ref=\"itemRef\"\n :class=\"cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)\"\n @select=\"() => {\n filterState.search = ''\n }\"\n >\n <slot />\n </ListboxItem>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandList.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxContentEmits, ComboboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxContent, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {\n dismissable: false,\n})\nconst emits = defineEmits<ComboboxContentEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ComboboxContent>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxContent, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ListboxContentProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <ListboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ListboxContent>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandSeparator.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxSeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxSeparator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxSeparator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </ComboboxSeparator>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { SeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Separator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <Separator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -1113,7 +1114,7 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/index.ts",
|
||||
"content": "export { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n",
|
||||
"content": "import type { Ref } from 'vue'\nimport { createContext } from 'reka-ui'\n\nexport { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n\nexport const [useCommand, provideCommandContext] = createContext<{\n allItems: Ref<Map<string, string>>\n allGroups: Ref<Map<string, Set<string>>>\n filterState: {\n search: string\n filtered: { count: number, items: Map<string, number>, groups: Set<string> }\n }\n}>('Command')\n\nexport const [useCommandGroup, provideCommandGroupContext] = createContext<{\n id?: string\n}>('CommandGroup')\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
}
|
||||
|
|
@ -2001,7 +2002,7 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/radio-group/RadioGroupItem.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Check } from 'lucide-vue-next'\nimport {\n RadioGroupIndicator,\n RadioGroupItem,\n type RadioGroupItemProps,\n useForwardProps,\n} from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<RadioGroupItemProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RadioGroupItem\n v-bind=\"forwardedProps\"\n :class=\"\n cn(\n 'aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n props.class,\n )\n \"\n >\n <RadioGroupIndicator class=\"flex items-center justify-center\">\n <Check class=\"h-3.5 w-3.5 fill-primary\" />\n </RadioGroupIndicator>\n </RadioGroupItem>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Check } from 'lucide-vue-next'\nimport {\n RadioGroupIndicator,\n RadioGroupItem,\n type RadioGroupItemProps,\n useForwardProps,\n} from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<RadioGroupItemProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <RadioGroupItem\n v-bind=\"forwardedProps\"\n :class=\"\n cn(\n 'aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',\n props.class,\n )\n \"\n >\n <RadioGroupIndicator class=\"flex items-center justify-center\">\n <Check class=\"h-3.5 w-3.5 text-primary\" />\n </RadioGroupIndicator>\n </RadioGroupItem>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -8342,7 +8343,8 @@
|
|||
"name": "command",
|
||||
"type": "registry:ui",
|
||||
"dependencies": [
|
||||
"reka-ui"
|
||||
"reka-ui",
|
||||
"@vueuse/core"
|
||||
],
|
||||
"registryDependencies": [
|
||||
"utils",
|
||||
|
|
@ -8351,7 +8353,7 @@
|
|||
"files": [
|
||||
{
|
||||
"path": "ui/command/Command.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxRootEmits, ComboboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxRoot, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n open: true,\n modelValue: '',\n})\n\nconst emits = defineEmits<ComboboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ComboboxRoot>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes, reactive, ref, watch } from 'vue'\nimport { provideCommandContext } from '.'\n\nconst props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {\n modelValue: '',\n})\n\nconst emits = defineEmits<ListboxRootEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst allItems = ref<Map<string, string>>(new Map())\nconst allGroups = ref<Map<string, Set<string>>>(new Map())\n\nconst { contains } = useFilter({ sensitivity: 'base' })\nconst filterState = reactive({\n search: '',\n filtered: {\n /** The count of all visible items. */\n count: 0,\n /** Map from visible item id to its search score. */\n items: new Map() as Map<string, number>,\n /** Set of groups with at least one visible item. */\n groups: new Set() as Set<string>,\n },\n})\n\nfunction filterItems() {\n if (!filterState.search) {\n filterState.filtered.count = allItems.value.size\n // Do nothing, each item will know to show itself because search is empty\n return\n }\n\n // Reset the groups\n filterState.filtered.groups = new Set()\n let itemCount = 0\n\n // Check which items should be included\n for (const [id, value] of allItems.value) {\n const score = contains(value, filterState.search)\n filterState.filtered.items.set(id, score ? 1 : 0)\n if (score)\n itemCount++\n }\n\n // Check which groups have at least 1 item shown\n for (const [groupId, group] of allGroups.value) {\n for (const itemId of group) {\n if (filterState.filtered.items.get(itemId)! > 0) {\n filterState.filtered.groups.add(groupId)\n break\n }\n }\n }\n\n filterState.filtered.count = itemCount\n}\n\nfunction handleSelect() {\n filterState.search = ''\n}\n\nwatch(() => filterState.search, () => {\n filterItems()\n})\n\nprovideCommandContext({\n allItems,\n allGroups,\n filterState,\n})\n</script>\n\n<template>\n <ListboxRoot\n v-bind=\"forwarded\"\n :class=\"cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)\"\n >\n <slot />\n </ListboxRoot>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -8363,37 +8365,37 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/CommandEmpty.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxEmptyProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxEmpty } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </ComboboxEmpty>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Primitive } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\nconst props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { filterState } = useCommand()\nconst isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,\n)\n</script>\n\n<template>\n <Primitive v-if=\"isRender\" v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </Primitive>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandGroup.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxGroup, ComboboxLabel } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxGroup\n v-bind=\"delegatedProps\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n >\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ComboboxLabel>\n <slot />\n </ComboboxGroup>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxGroupProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxGroup, ListboxGroupLabel, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted } from 'vue'\nimport { provideCommandGroupContext, useCommand } from '.'\n\nconst props = defineProps<ListboxGroupProps & {\n class?: HTMLAttributes['class']\n heading?: string\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst { allGroups, filterState } = useCommand()\nconst id = useId()\n\nconst isRender = computed(() => !filterState.search ? true : filterState.filtered.groups.has(id))\n\nprovideCommandGroupContext({ id })\nonMounted(() => {\n if (!allGroups.value.has(id))\n allGroups.value.set(id, new Set())\n})\nonUnmounted(() => {\n allGroups.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxGroup\n v-bind=\"delegatedProps\"\n :id=\"id\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n :hidden=\"isRender ? undefined : true\"\n >\n <ListboxGroupLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ListboxGroupLabel>\n <slot />\n </ListboxGroup>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandInput.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ComboboxInput, type ComboboxInputProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ComboboxInputProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ComboboxInput\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n auto-focus\n :class=\"cn('flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport { Search } from 'lucide-vue-next'\nimport { ListboxFilter, type ListboxFilterProps, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\nimport { useCommand } from '.'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = defineProps<ListboxFilterProps & {\n class?: HTMLAttributes['class']\n}>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwardedProps = useForwardProps(delegatedProps)\n\nconst { filterState } = useCommand()\n</script>\n\n<template>\n <div class=\"flex items-center border-b px-3\" cmdk-input-wrapper>\n <Search class=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <ListboxFilter\n v-bind=\"{ ...forwardedProps, ...$attrs }\"\n v-model=\"filterState.search\"\n auto-focus\n :class=\"cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n />\n </div>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandItem.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxItemEmits, ComboboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxItem, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ComboboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxItem\n v-bind=\"forwarded\"\n :class=\"cn('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', props.class)\"\n >\n <slot />\n </ComboboxItem>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { useCurrentElement } from '@vueuse/core'\nimport { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'\nimport { computed, type HTMLAttributes, onMounted, onUnmounted, ref } from 'vue'\nimport { useCommand, useCommandGroup } from '.'\n\nconst props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()\nconst emits = defineEmits<ListboxItemEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\nconst id = useId()\nconst { filterState, allItems, allGroups } = useCommand()\nconst groupContext = useCommandGroup()\n\nconst isRender = computed(() => {\n if (!filterState.search) {\n return true\n }\n else {\n const filteredCurrentItem = filterState.filtered.items.get(id)\n // If the filtered items is undefined means not in the all times map yet\n // Do the first render to add into the map\n if (filteredCurrentItem === undefined) {\n return true\n }\n\n // Check with filter\n return filteredCurrentItem > 0\n }\n})\n\nconst itemRef = ref()\nconst currentElement = useCurrentElement(itemRef)\nonMounted(() => {\n if (!(currentElement.value instanceof HTMLElement))\n return\n\n // textValue to perform filter\n allItems.value.set(id, currentElement.value.textContent ?? props.value.toString())\n\n const groupId = groupContext?.id\n if (groupId) {\n if (!allGroups.value.has(groupId)) {\n allGroups.value.set(groupId, new Set([id]))\n }\n else {\n allGroups.value.get(groupId)?.add(id)\n }\n }\n})\nonUnmounted(() => {\n allItems.value.delete(id)\n})\n</script>\n\n<template>\n <ListboxItem\n v-if=\"isRender\"\n v-bind=\"forwarded\"\n :id=\"id\"\n ref=\"itemRef\"\n :class=\"cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)\"\n @select=\"() => {\n filterState.search = ''\n }\"\n >\n <slot />\n </ListboxItem>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandList.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxContentEmits, ComboboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxContent, useForwardPropsEmits } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {\n dismissable: false,\n})\nconst emits = defineEmits<ComboboxContentEmits>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ComboboxContent>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ListboxContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ListboxContent, useForwardProps } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ListboxContentProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n\nconst forwarded = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <ListboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ListboxContent>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
{
|
||||
"path": "ui/command/CommandSeparator.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxSeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { ComboboxSeparator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <ComboboxSeparator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </ComboboxSeparator>\n</template>\n",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { SeparatorProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { Separator } from 'reka-ui'\nimport { computed, type HTMLAttributes } from 'vue'\n\nconst props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()\n\nconst delegatedProps = computed(() => {\n const { class: _, ...delegated } = props\n\n return delegated\n})\n</script>\n\n<template>\n <Separator\n v-bind=\"delegatedProps\"\n :class=\"cn('-mx-1 h-px bg-border', props.class)\"\n >\n <slot />\n </Separator>\n</template>\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
},
|
||||
|
|
@ -8405,7 +8407,7 @@
|
|||
},
|
||||
{
|
||||
"path": "ui/command/index.ts",
|
||||
"content": "export { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n",
|
||||
"content": "import type { Ref } from 'vue'\nimport { createContext } from 'reka-ui'\n\nexport { default as Command } from './Command.vue'\nexport { default as CommandDialog } from './CommandDialog.vue'\nexport { default as CommandEmpty } from './CommandEmpty.vue'\nexport { default as CommandGroup } from './CommandGroup.vue'\nexport { default as CommandInput } from './CommandInput.vue'\nexport { default as CommandItem } from './CommandItem.vue'\nexport { default as CommandList } from './CommandList.vue'\nexport { default as CommandSeparator } from './CommandSeparator.vue'\nexport { default as CommandShortcut } from './CommandShortcut.vue'\n\nexport const [useCommand, provideCommandContext] = createContext<{\n allItems: Ref<Map<string, string>>\n allGroups: Ref<Map<string, Set<string>>>\n filterState: {\n search: string\n filtered: { count: number, items: Map<string, number>, groups: Set<string> }\n }\n}>('Command')\n\nexport const [useCommandGroup, provideCommandGroupContext] = createContext<{\n id?: string\n}>('CommandGroup')\n",
|
||||
"type": "registry:ui",
|
||||
"target": ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxRootEmits, ComboboxRootProps } from 'reka-ui'
|
||||
import type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxRoot, useForwardPropsEmits } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes, reactive, ref, watch } from 'vue'
|
||||
import { provideCommandContext } from '.'
|
||||
|
||||
const props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
open: true,
|
||||
const props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
modelValue: '',
|
||||
})
|
||||
|
||||
const emits = defineEmits<ComboboxRootEmits>()
|
||||
const emits = defineEmits<ListboxRootEmits>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -18,13 +18,75 @@ const delegatedProps = computed(() => {
|
|||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
|
||||
const allItems = ref<Map<string, string>>(new Map())
|
||||
const allGroups = ref<Map<string, Set<string>>>(new Map())
|
||||
|
||||
const { contains } = useFilter({ sensitivity: 'base' })
|
||||
const filterState = reactive({
|
||||
search: '',
|
||||
filtered: {
|
||||
/** The count of all visible items. */
|
||||
count: 0,
|
||||
/** Map from visible item id to its search score. */
|
||||
items: new Map() as Map<string, number>,
|
||||
/** Set of groups with at least one visible item. */
|
||||
groups: new Set() as Set<string>,
|
||||
},
|
||||
})
|
||||
|
||||
function filterItems() {
|
||||
if (!filterState.search) {
|
||||
filterState.filtered.count = allItems.value.size
|
||||
// Do nothing, each item will know to show itself because search is empty
|
||||
return
|
||||
}
|
||||
|
||||
// Reset the groups
|
||||
filterState.filtered.groups = new Set()
|
||||
let itemCount = 0
|
||||
|
||||
// Check which items should be included
|
||||
for (const [id, value] of allItems.value) {
|
||||
const score = contains(value, filterState.search)
|
||||
filterState.filtered.items.set(id, score ? 1 : 0)
|
||||
if (score)
|
||||
itemCount++
|
||||
}
|
||||
|
||||
// Check which groups have at least 1 item shown
|
||||
for (const [groupId, group] of allGroups.value) {
|
||||
for (const itemId of group) {
|
||||
if (filterState.filtered.items.get(itemId)! > 0) {
|
||||
filterState.filtered.groups.add(groupId)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterState.filtered.count = itemCount
|
||||
}
|
||||
|
||||
function handleSelect() {
|
||||
filterState.search = ''
|
||||
}
|
||||
|
||||
watch(() => filterState.search, () => {
|
||||
filterItems()
|
||||
})
|
||||
|
||||
provideCommandContext({
|
||||
allItems,
|
||||
allGroups,
|
||||
filterState,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxRoot
|
||||
<ListboxRoot
|
||||
v-bind="forwarded"
|
||||
:class="cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxRoot>
|
||||
</ListboxRoot>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,25 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxEmptyProps } from 'reka-ui'
|
||||
import type { PrimitiveProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxEmpty } from 'reka-ui'
|
||||
import { Primitive } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { useCommand } from '.'
|
||||
|
||||
const props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes['class'] }>()
|
||||
const props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const { filterState } = useCommand()
|
||||
const isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxEmpty v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)">
|
||||
<Primitive v-if="isRender" v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)">
|
||||
<slot />
|
||||
</ComboboxEmpty>
|
||||
</Primitive>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxGroupProps } from 'reka-ui'
|
||||
import type { ListboxGroupProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxGroup, ComboboxLabel } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { ListboxGroup, ListboxGroupLabel, useId } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes, onMounted, onUnmounted } from 'vue'
|
||||
import { provideCommandGroupContext, useCommand } from '.'
|
||||
|
||||
const props = defineProps<ComboboxGroupProps & {
|
||||
const props = defineProps<ListboxGroupProps & {
|
||||
class?: HTMLAttributes['class']
|
||||
heading?: string
|
||||
}>()
|
||||
|
|
@ -14,16 +15,32 @@ const delegatedProps = computed(() => {
|
|||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const { allGroups, filterState } = useCommand()
|
||||
const id = useId()
|
||||
|
||||
const isRender = computed(() => !filterState.search ? true : filterState.filtered.groups.has(id))
|
||||
|
||||
provideCommandGroupContext({ id })
|
||||
onMounted(() => {
|
||||
if (!allGroups.value.has(id))
|
||||
allGroups.value.set(id, new Set())
|
||||
})
|
||||
onUnmounted(() => {
|
||||
allGroups.value.delete(id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxGroup
|
||||
<ListboxGroup
|
||||
v-bind="delegatedProps"
|
||||
:id="id"
|
||||
:class="cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)"
|
||||
:hidden="isRender ? undefined : true"
|
||||
>
|
||||
<ComboboxLabel v-if="heading" class="px-2 py-1.5 text-xs font-medium text-muted-foreground">
|
||||
<ListboxGroupLabel v-if="heading" class="px-2 py-1.5 text-xs font-medium text-muted-foreground">
|
||||
{{ heading }}
|
||||
</ComboboxLabel>
|
||||
</ListboxGroupLabel>
|
||||
<slot />
|
||||
</ComboboxGroup>
|
||||
</ListboxGroup>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Search } from 'lucide-vue-next'
|
||||
import { ComboboxInput, type ComboboxInputProps, useForwardProps } from 'reka-ui'
|
||||
import { ListboxFilter, type ListboxFilterProps, useForwardProps } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { useCommand } from '.'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<ComboboxInputProps & {
|
||||
const props = defineProps<ListboxFilterProps & {
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
|
||||
|
|
@ -19,15 +20,18 @@ const delegatedProps = computed(() => {
|
|||
})
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
|
||||
const { filterState } = useCommand()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center border-b px-3" cmdk-input-wrapper>
|
||||
<Search class="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<ComboboxInput
|
||||
<ListboxFilter
|
||||
v-bind="{ ...forwardedProps, ...$attrs }"
|
||||
v-model="filterState.search"
|
||||
auto-focus
|
||||
:class="cn('flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)"
|
||||
:class="cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxItemEmits, ComboboxItemProps } from 'reka-ui'
|
||||
import type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxItem, useForwardPropsEmits } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { useCurrentElement } from '@vueuse/core'
|
||||
import { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useCommand, useCommandGroup } from '.'
|
||||
|
||||
const props = defineProps<ComboboxItemProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<ComboboxItemEmits>()
|
||||
const props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<ListboxItemEmits>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -14,13 +16,63 @@ const delegatedProps = computed(() => {
|
|||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
|
||||
const id = useId()
|
||||
const { filterState, allItems, allGroups } = useCommand()
|
||||
const groupContext = useCommandGroup()
|
||||
|
||||
const isRender = computed(() => {
|
||||
if (!filterState.search) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
const filteredCurrentItem = filterState.filtered.items.get(id)
|
||||
// If the filtered items is undefined means not in the all times map yet
|
||||
// Do the first render to add into the map
|
||||
if (filteredCurrentItem === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check with filter
|
||||
return filteredCurrentItem > 0
|
||||
}
|
||||
})
|
||||
|
||||
const itemRef = ref()
|
||||
const currentElement = useCurrentElement(itemRef)
|
||||
onMounted(() => {
|
||||
if (!(currentElement.value instanceof HTMLElement))
|
||||
return
|
||||
|
||||
// textValue to perform filter
|
||||
allItems.value.set(id, currentElement.value.textContent ?? props.value.toString())
|
||||
|
||||
const groupId = groupContext?.id
|
||||
if (groupId) {
|
||||
if (!allGroups.value.has(groupId)) {
|
||||
allGroups.value.set(groupId, new Set([id]))
|
||||
}
|
||||
else {
|
||||
allGroups.value.get(groupId)?.add(id)
|
||||
}
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
allItems.value.delete(id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxItem
|
||||
<ListboxItem
|
||||
v-if="isRender"
|
||||
v-bind="forwarded"
|
||||
:class="cn('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', props.class)"
|
||||
:id="id"
|
||||
ref="itemRef"
|
||||
:class="cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)"
|
||||
@select="() => {
|
||||
filterState.search = ''
|
||||
}"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxItem>
|
||||
</ListboxItem>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxContentEmits, ComboboxContentProps } from 'reka-ui'
|
||||
import type { ListboxContentProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxContent, useForwardPropsEmits } from 'reka-ui'
|
||||
import { ListboxContent, useForwardProps } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
dismissable: false,
|
||||
})
|
||||
const emits = defineEmits<ComboboxContentEmits>()
|
||||
const props = defineProps<ListboxContentProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -15,13 +12,13 @@ const delegatedProps = computed(() => {
|
|||
return delegated
|
||||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
const forwarded = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)">
|
||||
<ListboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)">
|
||||
<div role="presentation">
|
||||
<slot />
|
||||
</div>
|
||||
</ComboboxContent>
|
||||
</ListboxContent>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxSeparatorProps } from 'reka-ui'
|
||||
import type { SeparatorProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxSeparator } from 'reka-ui'
|
||||
import { Separator } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
|
||||
const props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes['class'] }>()
|
||||
const props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -14,10 +14,10 @@ const delegatedProps = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxSeparator
|
||||
<Separator
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('-mx-1 h-px bg-border', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxSeparator>
|
||||
</Separator>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import type { Ref } from 'vue'
|
||||
import { createContext } from 'reka-ui'
|
||||
|
||||
export { default as Command } from './Command.vue'
|
||||
export { default as CommandDialog } from './CommandDialog.vue'
|
||||
export { default as CommandEmpty } from './CommandEmpty.vue'
|
||||
|
|
@ -7,3 +10,16 @@ export { default as CommandItem } from './CommandItem.vue'
|
|||
export { default as CommandList } from './CommandList.vue'
|
||||
export { default as CommandSeparator } from './CommandSeparator.vue'
|
||||
export { default as CommandShortcut } from './CommandShortcut.vue'
|
||||
|
||||
export const [useCommand, provideCommandContext] = createContext<{
|
||||
allItems: Ref<Map<string, string>>
|
||||
allGroups: Ref<Map<string, Set<string>>>
|
||||
filterState: {
|
||||
search: string
|
||||
filtered: { count: number, items: Map<string, number>, groups: Set<string> }
|
||||
}
|
||||
}>('Command')
|
||||
|
||||
export const [useCommandGroup, provideCommandGroupContext] = createContext<{
|
||||
id?: string
|
||||
}>('CommandGroup')
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxRootEmits, ComboboxRootProps } from 'reka-ui'
|
||||
import type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxRoot, useForwardPropsEmits } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes, reactive, ref, watch } from 'vue'
|
||||
import { provideCommandContext } from '.'
|
||||
|
||||
const props = withDefaults(defineProps<ComboboxRootProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
open: true,
|
||||
const props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
modelValue: '',
|
||||
})
|
||||
|
||||
const emits = defineEmits<ComboboxRootEmits>()
|
||||
const emits = defineEmits<ListboxRootEmits>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -18,13 +18,75 @@ const delegatedProps = computed(() => {
|
|||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
|
||||
const allItems = ref<Map<string, string>>(new Map())
|
||||
const allGroups = ref<Map<string, Set<string>>>(new Map())
|
||||
|
||||
const { contains } = useFilter({ sensitivity: 'base' })
|
||||
const filterState = reactive({
|
||||
search: '',
|
||||
filtered: {
|
||||
/** The count of all visible items. */
|
||||
count: 0,
|
||||
/** Map from visible item id to its search score. */
|
||||
items: new Map() as Map<string, number>,
|
||||
/** Set of groups with at least one visible item. */
|
||||
groups: new Set() as Set<string>,
|
||||
},
|
||||
})
|
||||
|
||||
function filterItems() {
|
||||
if (!filterState.search) {
|
||||
filterState.filtered.count = allItems.value.size
|
||||
// Do nothing, each item will know to show itself because search is empty
|
||||
return
|
||||
}
|
||||
|
||||
// Reset the groups
|
||||
filterState.filtered.groups = new Set()
|
||||
let itemCount = 0
|
||||
|
||||
// Check which items should be included
|
||||
for (const [id, value] of allItems.value) {
|
||||
const score = contains(value, filterState.search)
|
||||
filterState.filtered.items.set(id, score ? 1 : 0)
|
||||
if (score)
|
||||
itemCount++
|
||||
}
|
||||
|
||||
// Check which groups have at least 1 item shown
|
||||
for (const [groupId, group] of allGroups.value) {
|
||||
for (const itemId of group) {
|
||||
if (filterState.filtered.items.get(itemId)! > 0) {
|
||||
filterState.filtered.groups.add(groupId)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterState.filtered.count = itemCount
|
||||
}
|
||||
|
||||
function handleSelect() {
|
||||
filterState.search = ''
|
||||
}
|
||||
|
||||
watch(() => filterState.search, () => {
|
||||
filterItems()
|
||||
})
|
||||
|
||||
provideCommandContext({
|
||||
allItems,
|
||||
allGroups,
|
||||
filterState,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxRoot
|
||||
<ListboxRoot
|
||||
v-bind="forwarded"
|
||||
:class="cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxRoot>
|
||||
</ListboxRoot>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,25 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxEmptyProps } from 'reka-ui'
|
||||
import type { PrimitiveProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxEmpty } from 'reka-ui'
|
||||
import { Primitive } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { useCommand } from '.'
|
||||
|
||||
const props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes['class'] }>()
|
||||
const props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const { filterState } = useCommand()
|
||||
const isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxEmpty v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)">
|
||||
<Primitive v-if="isRender" v-bind="delegatedProps" :class="cn('py-6 text-center text-sm', props.class)">
|
||||
<slot />
|
||||
</ComboboxEmpty>
|
||||
</Primitive>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxGroupProps } from 'reka-ui'
|
||||
import type { ListboxGroupProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxGroup, ComboboxLabel } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { ListboxGroup, ListboxGroupLabel, useId } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes, onMounted, onUnmounted } from 'vue'
|
||||
import { provideCommandGroupContext, useCommand } from '.'
|
||||
|
||||
const props = defineProps<ComboboxGroupProps & {
|
||||
const props = defineProps<ListboxGroupProps & {
|
||||
class?: HTMLAttributes['class']
|
||||
heading?: string
|
||||
}>()
|
||||
|
|
@ -14,16 +15,32 @@ const delegatedProps = computed(() => {
|
|||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const { allGroups, filterState } = useCommand()
|
||||
const id = useId()
|
||||
|
||||
const isRender = computed(() => !filterState.search ? true : filterState.filtered.groups.has(id))
|
||||
|
||||
provideCommandGroupContext({ id })
|
||||
onMounted(() => {
|
||||
if (!allGroups.value.has(id))
|
||||
allGroups.value.set(id, new Set())
|
||||
})
|
||||
onUnmounted(() => {
|
||||
allGroups.value.delete(id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxGroup
|
||||
<ListboxGroup
|
||||
v-bind="delegatedProps"
|
||||
:id="id"
|
||||
:class="cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)"
|
||||
:hidden="isRender ? undefined : true"
|
||||
>
|
||||
<ComboboxLabel v-if="heading" class="px-2 py-1.5 text-xs font-medium text-muted-foreground">
|
||||
<ListboxGroupLabel v-if="heading" class="px-2 py-1.5 text-xs font-medium text-muted-foreground">
|
||||
{{ heading }}
|
||||
</ComboboxLabel>
|
||||
</ListboxGroupLabel>
|
||||
<slot />
|
||||
</ComboboxGroup>
|
||||
</ListboxGroup>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Search } from 'lucide-vue-next'
|
||||
import { ComboboxInput, type ComboboxInputProps, useForwardProps } from 'reka-ui'
|
||||
import { ListboxFilter, type ListboxFilterProps, useForwardProps } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { useCommand } from '.'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<ComboboxInputProps & {
|
||||
const props = defineProps<ListboxFilterProps & {
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
|
||||
|
|
@ -19,13 +20,16 @@ const delegatedProps = computed(() => {
|
|||
})
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
|
||||
const { filterState } = useCommand()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center border-b px-3" cmdk-input-wrapper>
|
||||
<Search class="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<ComboboxInput
|
||||
<ListboxFilter
|
||||
v-bind="{ ...forwardedProps, ...$attrs }"
|
||||
v-model="filterState.search"
|
||||
auto-focus
|
||||
:class="cn('flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxItemEmits, ComboboxItemProps } from 'reka-ui'
|
||||
import type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxItem, useForwardPropsEmits } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
import { useCurrentElement } from '@vueuse/core'
|
||||
import { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useCommand, useCommandGroup } from '.'
|
||||
|
||||
const props = defineProps<ComboboxItemProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<ComboboxItemEmits>()
|
||||
const props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<ListboxItemEmits>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -14,13 +16,63 @@ const delegatedProps = computed(() => {
|
|||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
|
||||
const id = useId()
|
||||
const { filterState, allItems, allGroups } = useCommand()
|
||||
const groupContext = useCommandGroup()
|
||||
|
||||
const isRender = computed(() => {
|
||||
if (!filterState.search) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
const filteredCurrentItem = filterState.filtered.items.get(id)
|
||||
// If the filtered items is undefined means not in the all times map yet
|
||||
// Do the first render to add into the map
|
||||
if (filteredCurrentItem === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check with filter
|
||||
return filteredCurrentItem > 0
|
||||
}
|
||||
})
|
||||
|
||||
const itemRef = ref()
|
||||
const currentElement = useCurrentElement(itemRef)
|
||||
onMounted(() => {
|
||||
if (!(currentElement.value instanceof HTMLElement))
|
||||
return
|
||||
|
||||
// textValue to perform filter
|
||||
allItems.value.set(id, currentElement.value.textContent ?? props.value.toString())
|
||||
|
||||
const groupId = groupContext?.id
|
||||
if (groupId) {
|
||||
if (!allGroups.value.has(groupId)) {
|
||||
allGroups.value.set(groupId, new Set([id]))
|
||||
}
|
||||
else {
|
||||
allGroups.value.get(groupId)?.add(id)
|
||||
}
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
allItems.value.delete(id)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxItem
|
||||
<ListboxItem
|
||||
v-if="isRender"
|
||||
v-bind="forwarded"
|
||||
:id="id"
|
||||
ref="itemRef"
|
||||
:class="cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)"
|
||||
@select="() => {
|
||||
filterState.search = ''
|
||||
}"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxItem>
|
||||
</ListboxItem>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxContentEmits, ComboboxContentProps } from 'reka-ui'
|
||||
import type { ListboxContentProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxContent, useForwardPropsEmits } from 'reka-ui'
|
||||
import { ListboxContent, useForwardProps } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
dismissable: false,
|
||||
})
|
||||
const emits = defineEmits<ComboboxContentEmits>()
|
||||
const props = defineProps<ListboxContentProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -15,13 +12,13 @@ const delegatedProps = computed(() => {
|
|||
return delegated
|
||||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
const forwarded = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)">
|
||||
<ListboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', props.class)">
|
||||
<div role="presentation">
|
||||
<slot />
|
||||
</div>
|
||||
</ComboboxContent>
|
||||
</ListboxContent>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxSeparatorProps } from 'reka-ui'
|
||||
import type { SeparatorProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComboboxSeparator } from 'reka-ui'
|
||||
import { Separator } from 'reka-ui'
|
||||
import { computed, type HTMLAttributes } from 'vue'
|
||||
|
||||
const props = defineProps<ComboboxSeparatorProps & { class?: HTMLAttributes['class'] }>()
|
||||
const props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
|
@ -14,10 +14,10 @@ const delegatedProps = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxSeparator
|
||||
<Separator
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('-mx-1 h-px bg-border', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxSeparator>
|
||||
</Separator>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import type { Ref } from 'vue'
|
||||
import { createContext } from 'reka-ui'
|
||||
|
||||
export { default as Command } from './Command.vue'
|
||||
export { default as CommandDialog } from './CommandDialog.vue'
|
||||
export { default as CommandEmpty } from './CommandEmpty.vue'
|
||||
|
|
@ -7,3 +10,16 @@ export { default as CommandItem } from './CommandItem.vue'
|
|||
export { default as CommandList } from './CommandList.vue'
|
||||
export { default as CommandSeparator } from './CommandSeparator.vue'
|
||||
export { default as CommandShortcut } from './CommandShortcut.vue'
|
||||
|
||||
export const [useCommand, provideCommandContext] = createContext<{
|
||||
allItems: Ref<Map<string, string>>
|
||||
allGroups: Ref<Map<string, Set<string>>>
|
||||
filterState: {
|
||||
search: string
|
||||
filtered: { count: number, items: Map<string, number>, groups: Set<string> }
|
||||
}
|
||||
}>('Command')
|
||||
|
||||
export const [useCommandGroup, provideCommandGroupContext] = createContext<{
|
||||
id?: string
|
||||
}>('CommandGroup')
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const forwardedProps = useForwardProps(delegatedProps)
|
|||
"
|
||||
>
|
||||
<RadioGroupIndicator class="flex items-center justify-center">
|
||||
<Check class="h-3.5 w-3.5 fill-primary" />
|
||||
<Check class="h-3.5 w-3.5 text-primary" />
|
||||
</RadioGroupIndicator>
|
||||
</RadioGroupItem>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user