{
  "name": "command",
  "type": "registry:ui",
  "dependencies": [
    "@vueuse/core",
    "reka-ui"
  ],
  "registryDependencies": [
    "dialog",
    "input-group"
  ],
  "files": [
    {
      "path": "ui/command/Command.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { ListboxRootEmits, ListboxRootProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { ListboxRoot, useFilter, useForwardPropsEmits } from \"reka-ui\"\nimport { reactive, ref, watch } from \"vue\"\nimport { cn } from \"@/lib/utils\"\nimport { provideCommandContext } from \".\"\n\nconst props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes[\"class\"] }>(), {\n  modelValue: \"\",\n  highlightOnHover: true,\n})\n\nconst emits = defineEmits<ListboxRootEmits>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\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\nwatch(() => filterState.search, () => {\n  filterItems()\n})\n\nprovideCommandContext({\n  allItems,\n  allGroups,\n  filterState,\n})\n</script>\n\n<template>\n  <ListboxRoot\n    data-slot=\"command\"\n    v-bind=\"forwarded\"\n    :class=\"cn('cn-command flex size-full flex-col overflow-hidden', props.class)\"\n  >\n    <slot />\n  </ListboxRoot>\n</template>\n"
    },
    {
      "path": "ui/command/CommandDialog.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { DialogRootEmits, DialogRootProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { useForwardPropsEmits } from \"reka-ui\"\nimport { cn } from \"@/lib/utils\"\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"@/components/ui/dialog\"\nimport Command from \"./Command.vue\"\n\nconst props = withDefaults(defineProps<DialogRootProps & {\n  title?: string\n  description?: string\n  class?: HTMLAttributes[\"class\"]\n  showCloseButton?: boolean\n}>(), {\n  title: \"Command Palette\",\n  description: \"Search for a command to run...\",\n  showCloseButton: false,\n})\nconst emits = defineEmits<DialogRootEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n  <Dialog v-slot=\"slotProps\" v-bind=\"forwarded\">\n    <DialogContent\n      :class=\"cn('cn-command-dialog top-1/3 translate-y-0 overflow-hidden p-0', props.class)\"\n      :show-close-button=\"showCloseButton\"\n    >\n      <DialogHeader class=\"sr-only\">\n        <DialogTitle>{{ title }}</DialogTitle>\n        <DialogDescription>{{ description }}</DialogDescription>\n      </DialogHeader>\n      <Command>\n        <slot v-bind=\"slotProps\" />\n      </Command>\n    </DialogContent>\n  </Dialog>\n</template>\n"
    },
    {
      "path": "ui/command/CommandEmpty.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { Primitive } from \"reka-ui\"\nimport { computed } from \"vue\"\nimport { cn } from \"@/lib/utils\"\nimport { useCommand } from \".\"\n\nconst props = defineProps<PrimitiveProps & { class?: HTMLAttributes[\"class\"] }>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n\nconst { filterState } = useCommand()\nconst isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,\n)\n</script>\n\n<template>\n  <Primitive\n    v-if=\"isRender\"\n    data-slot=\"command-empty\"\n    v-bind=\"delegatedProps\"\n    :class=\"cn('cn-command-empty', props.class)\"\n  >\n    <slot />\n  </Primitive>\n</template>\n"
    },
    {
      "path": "ui/command/CommandGroup.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { ListboxGroupProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { ListboxGroup, ListboxGroupLabel, useId } from \"reka-ui\"\nimport { computed, onMounted, onUnmounted } from \"vue\"\nimport { cn } from \"@/lib/utils\"\nimport { provideCommandGroupContext, useCommand } from \".\"\n\nconst props = defineProps<ListboxGroupProps & {\n  class?: HTMLAttributes[\"class\"]\n  heading?: string\n}>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\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    data-slot=\"command-group\"\n    :class=\"cn('cn-command-group', props.class)\"\n    :hidden=\"isRender ? undefined : true\"\n  >\n    <ListboxGroupLabel v-if=\"heading\" data-slot=\"command-group-heading\" class=\"cn-command-group-heading\">\n      {{ heading }}\n    </ListboxGroupLabel>\n    <slot />\n  </ListboxGroup>\n</template>\n"
    },
    {
      "path": "ui/command/CommandInput.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { ListboxFilterProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { ListboxFilter, useForwardProps } from \"reka-ui\"\nimport { cn } from \"@/lib/utils\"\nimport IconPlaceholder from \"@/components/docs/icon-placeholder/IconPlaceholder.vue\"\nimport { InputGroup, InputGroupAddon } from \"@/components/ui/input-group\"\nimport { useCommand } from \".\"\n\ndefineOptions({\n  inheritAttrs: false,\n})\n\nconst props = defineProps<ListboxFilterProps & {\n  class?: HTMLAttributes[\"class\"]\n}>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n\nconst forwardedProps = useForwardProps(delegatedProps)\n\nconst { filterState } = useCommand()\n</script>\n\n<template>\n  <div\n    data-slot=\"command-input-wrapper\"\n    class=\"cn-command-input-wrapper\"\n  >\n    <InputGroup class=\"cn-command-input-group\">\n      <ListboxFilter\n        v-bind=\"{ ...forwardedProps, ...$attrs }\"\n        v-model=\"filterState.search\"\n        data-slot=\"command-input\"\n        auto-focus\n        :class=\"cn('cn-command-input outline-hidden disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n      />\n      <InputGroupAddon>\n        <IconPlaceholder\n          lucide=\"SearchIcon\"\n          tabler=\"IconSearch\"\n          hugeicons=\"SearchIcon\"\n          phosphor=\"MagnifyingGlassIcon\"\n          remixicon=\"RiSearchLine\"\n          class=\"cn-command-input-icon\"\n        />\n      </InputGroupAddon>\n    </InputGroup>\n  </div>\n</template>\n"
    },
    {
      "path": "ui/command/CommandItem.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { ListboxItemEmits, ListboxItemProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit, useCurrentElement } from \"@vueuse/core\"\nimport { ListboxItem, useForwardPropsEmits, useId } from \"reka-ui\"\nimport { computed, onMounted, onUnmounted, ref } from \"vue\"\nimport { cn } from \"@/lib/utils\"\nimport IconPlaceholder from \"@/components/docs/icon-placeholder/IconPlaceholder.vue\"\nimport { useCommand, useCommandGroup } from \".\"\n\nconst props = defineProps<ListboxItemProps & { class?: HTMLAttributes[\"class\"] }>()\nconst emits = defineEmits<ListboxItemEmits>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\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    data-slot=\"command-item\"\n    :class=\"cn('cn-command-item group/command-item data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0', props.class)\"\n    @select=\"() => {\n      filterState.search = ''\n    }\"\n  >\n    <slot />\n    <IconPlaceholder\n      lucide=\"CheckIcon\"\n      tabler=\"IconCheck\"\n      hugeicons=\"Tick02Icon\"\n      phosphor=\"CheckIcon\"\n      remixicon=\"RiCheckLine\"\n      class=\"cn-command-item-indicator ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100\"\n    />\n  </ListboxItem>\n</template>\n"
    },
    {
      "path": "ui/command/CommandList.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { ListboxContentProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { ListboxContent, useForwardProps } from \"reka-ui\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<ListboxContentProps & { class?: HTMLAttributes[\"class\"] }>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n\nconst forwarded = useForwardProps(delegatedProps)\n</script>\n\n<template>\n  <ListboxContent\n    data-slot=\"command-list\"\n    v-bind=\"forwarded\"\n    :class=\"cn('cn-command-list overflow-x-hidden overflow-y-auto', props.class)\"\n  >\n    <div role=\"presentation\">\n      <slot />\n    </div>\n  </ListboxContent>\n</template>\n"
    },
    {
      "path": "ui/command/CommandSeparator.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { SeparatorProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { Separator } from \"reka-ui\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<SeparatorProps & { class?: HTMLAttributes[\"class\"] }>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n</script>\n\n<template>\n  <Separator\n    data-slot=\"command-separator\"\n    v-bind=\"delegatedProps\"\n    :class=\"cn('cn-command-separator', props.class)\"\n  >\n    <slot />\n  </Separator>\n</template>\n"
    },
    {
      "path": "ui/command/CommandShortcut.vue",
      "type": "registry:ui",
      "content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<{\n  class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n  <span\n    data-slot=\"command-shortcut\"\n    :class=\"cn('cn-command-shortcut', props.class)\"\n  >\n    <slot />\n  </span>\n</template>\n"
    },
    {
      "path": "ui/command/index.ts",
      "type": "registry:ui",
      "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"
    }
  ]
}
