{
  "name": "vue-ui-search",
  "title": "vue-ui-search",
  "type": "registry:component",
  "description": "",
  "registryDependencies": [
    "https://unpkg.com/prosekit-registry/dist/r/vue-ui-button.json"
  ],
  "dependencies": [
    "@egoist/tailwindcss-icons",
    "@iconify-json/lucide",
    "prosekit@^0.22.0"
  ],
  "files": [
    {
      "path": "registry/src/vue/ui/search/index.ts",
      "type": "registry:component",
      "target": "components/editor/ui/search/index.ts",
      "content": "export { default as Search } from './search.vue'\n"
    },
    {
      "path": "registry/src/vue/ui/search/search.vue",
      "type": "registry:component",
      "target": "components/editor/ui/search/search.vue",
      "content": "<script setup lang=\"ts\">\nimport { defineSearchStatusHandler, type SearchCommandsExtension, type SearchStatus } from 'prosekit/extensions/search'\nimport { useEditor, useExtension } from 'prosekit/vue'\nimport { ref, watchEffect } from 'vue'\n\nimport { Button } from '../button/index.ts'\n\nconst props = defineProps<{ onClose?: () => void }>()\n\nconst showReplace = ref(false)\nconst searchText = ref('')\nconst replaceText = ref('')\nconst caseSensitive = ref(false)\nconst wholeWord = ref(false)\nconst regexp = ref(false)\nconst literal = ref(false)\n\nconst searchStatus = ref<SearchStatus>({ total: 0, active: 0 })\nuseExtension(\n  defineSearchStatusHandler((status) => {\n    searchStatus.value = status\n  }),\n)\n\nconst editor = useEditor<SearchCommandsExtension>()\n\nwatchEffect(() => {\n  editor.value.commands.setSearchQuery({\n    search: searchText.value,\n    replace: replaceText.value,\n    caseSensitive: caseSensitive.value,\n    wholeWord: wholeWord.value,\n    regexp: regexp.value,\n    literal: literal.value,\n  })\n})\n\nfunction toggleReplace() {\n  showReplace.value = !showReplace.value\n}\n\nfunction isPlainEnter(event: KeyboardEvent) {\n  return (\n    event.key === 'Enter'\n    && !event.shiftKey\n    && !event.metaKey\n    && !event.altKey\n    && !event.ctrlKey\n    && !event.isComposing\n  )\n}\n\nfunction isShiftEnter(event: KeyboardEvent) {\n  return (\n    event.key === 'Enter'\n    && event.shiftKey\n    && !event.metaKey\n    && !event.altKey\n    && !event.ctrlKey\n    && !event.isComposing\n  )\n}\n\nfunction handleSearchKeyDown(event: KeyboardEvent) {\n  if (isPlainEnter(event)) {\n    event.preventDefault()\n    editor.value.commands.findNext()\n  } else if (isShiftEnter(event)) {\n    event.preventDefault()\n    editor.value.commands.findPrev()\n  }\n}\n\nfunction handleReplaceKeyDown(event: KeyboardEvent) {\n  if (isPlainEnter(event)) {\n    event.preventDefault()\n    editor.value.commands.replaceNext()\n  } else if (isShiftEnter(event)) {\n    event.preventDefault()\n    editor.value.commands.replaceAll()\n  }\n}\n</script>\n\n<template>\n  <div class=\"z-2 box-border border-gray-200 dark:border-gray-800 border-solid border-l-0 border-r-0 border-t-0 border-b grid grid-cols-[min-content_1fr_min-content] gap-2 p-2\">\n    <Button tooltip=\"Toggle Replace\" @click=\"toggleReplace\">\n      <span\n        :data-rotate=\"showReplace ? '' : undefined\"\n        class=\"i-lucide-chevron-right size-5 block transition-transform data-rotate:rotate-90\"\n      />\n    </Button>\n    <input\n      v-model=\"searchText\"\n      placeholder=\"Search\"\n      type=\"text\"\n      class=\"flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2\"\n      @keydown=\"handleSearchKeyDown\"\n    >\n    <div class=\"flex items-center justify-between gap-1\">\n      <span\n        v-if=\"searchText\"\n        class=\"flex items-center px-1 text-sm whitespace-nowrap tabular-nums text-gray-500 dark:text-gray-500\"\n      >\n        {{ searchStatus.active }} / {{ searchStatus.total }}\n      </span>\n      <Button\n        tooltip=\"Previous (Shift Enter)\"\n        @click=\"editor.commands.findPrev\"\n      >\n        <span class=\"i-lucide-arrow-left size-5 block\" />\n      </Button>\n      <Button\n        tooltip=\"Next (Enter)\"\n        @click=\"editor.commands.findNext\"\n      >\n        <span class=\"i-lucide-arrow-right size-5 block\" />\n      </Button>\n      <Button tooltip=\"Close\" @click=\"props.onClose\">\n        <span class=\"i-lucide-x size-5 block\" />\n      </Button>\n      <Button\n        :pressed=\"caseSensitive\"\n        tooltip=\"Case Sensitive\"\n        @click=\"caseSensitive = !caseSensitive\"\n      >\n        <span class=\"i-lucide-case-sensitive size-5 block\" />\n      </Button>\n      <Button\n        :pressed=\"wholeWord\"\n        tooltip=\"Whole Word\"\n        @click=\"wholeWord = !wholeWord\"\n      >\n        <span class=\"i-lucide-whole-word size-5 block\" />\n      </Button>\n      <Button\n        :pressed=\"regexp\"\n        tooltip=\"Regular Expression\"\n        @click=\"regexp = !regexp\"\n      >\n        <span class=\"i-lucide-braces size-5 block\" />\n      </Button>\n      <Button\n        :pressed=\"literal\"\n        tooltip=\"Literal Escape Sequences\"\n        @click=\"literal = !literal\"\n      >\n        <span class=\"i-lucide-quote size-5 block\" />\n      </Button>\n    </div>\n    <template v-if=\"showReplace\">\n      <input\n        v-model=\"replaceText\"\n        placeholder=\"Replace\"\n        type=\"text\"\n        class=\"flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2\"\n        @keydown=\"handleReplaceKeyDown\"\n      >\n      <div class=\"flex items-center justify-between gap-1\">\n        <Button\n          tooltip=\"Replace (Enter)\"\n          @click=\"editor.commands.replaceNext\"\n        >\n          Replace\n        </Button>\n        <Button\n          tooltip=\"Replace All (Shift Enter)\"\n          @click=\"editor.commands.replaceAll\"\n        >\n          All\n        </Button>\n      </div>\n    </template>\n  </div>\n</template>\n"
    }
  ],
  "meta": {
    "hasIcons": true,
    "hidden": false,
    "story": "",
    "framework": "vue",
    "accumulatedFiles": [
      "registry/src/vue/ui/button/button.vue",
      "registry/src/vue/ui/button/index.ts",
      "registry/src/vue/ui/search/index.ts",
      "registry/src/vue/ui/search/search.vue"
    ],
    "internalDependencies": [
      "vue-ui-button"
    ]
  },
  "css": {
    "@plugin @egoist/tailwindcss-icons": {}
  },
  "$schema": "https://ui.shadcn.com/schema/registry-item.json"
}
