{
  "name": "solid-ui-search",
  "title": "solid-ui-search",
  "type": "registry:component",
  "description": "",
  "registryDependencies": [
    "https://unpkg.com/prosekit-registry/dist/r/solid-ui-button.json"
  ],
  "dependencies": [
    "@egoist/tailwindcss-icons",
    "@iconify-json/lucide",
    "prosekit@^0.22.0"
  ],
  "files": [
    {
      "path": "registry/src/solid/ui/search/index.ts",
      "type": "registry:component",
      "target": "components/editor/ui/search/index.ts",
      "content": "export { default as Search } from './search.tsx'\n"
    },
    {
      "path": "registry/src/solid/ui/search/search.tsx",
      "type": "registry:component",
      "target": "components/editor/ui/search/search.tsx",
      "content": "import { defineSearchStatusHandler, type SearchCommandsExtension, type SearchStatus } from 'prosekit/extensions/search'\nimport { useEditor, useExtension } from 'prosekit/solid'\nimport { createEffect, createSignal, type JSX } from 'solid-js'\n\nimport { Button } from '../button/index.ts'\n\nexport default function Search(props: { onClose?: VoidFunction }): JSX.Element {\n  const [showReplace, setShowReplace] = createSignal(false)\n  const toggleReplace = () => setShowReplace((value) => !value)\n\n  const [searchText, setSearchText] = createSignal('')\n  const [replaceText, setReplaceText] = createSignal('')\n  const [caseSensitive, setCaseSensitive] = createSignal(false)\n  const [wholeWord, setWholeWord] = createSignal(false)\n  const [regexp, setRegexp] = createSignal(false)\n  const [literal, setLiteral] = createSignal(false)\n\n  const [searchStatus, setSearchStatus] = createSignal<SearchStatus>({\n    total: 0,\n    active: 0,\n  })\n  const statusHandler = defineSearchStatusHandler(setSearchStatus)\n  useExtension(() => statusHandler)\n\n  const editor = useEditor<SearchCommandsExtension>()\n\n  createEffect(() => {\n    editor().commands.setSearchQuery({\n      search: searchText(),\n      replace: replaceText(),\n      caseSensitive: caseSensitive(),\n      wholeWord: wholeWord(),\n      regexp: regexp(),\n      literal: literal(),\n    })\n  })\n\n  const handleSearchKeyDown = (event: KeyboardEvent) => {\n    if (isEnter(event)) {\n      event.preventDefault()\n      editor().commands.findNext()\n    } else if (isShiftEnter(event)) {\n      event.preventDefault()\n      editor().commands.findPrev()\n    }\n  }\n\n  const handleReplaceKeyDown = (event: KeyboardEvent) => {\n    if (isEnter(event)) {\n      event.preventDefault()\n      editor().commands.replaceNext()\n    } else if (isShiftEnter(event)) {\n      event.preventDefault()\n      editor().commands.replaceAll()\n    }\n  }\n\n  return (\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\" onClick={toggleReplace}>\n        <span\n          attr: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        placeholder=\"Search\"\n        type=\"text\"\n        value={searchText()}\n        onInput={(event) => setSearchText(event.currentTarget.value)}\n        onKeyDown={handleSearchKeyDown}\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      />\n      <div class=\"flex items-center justify-between gap-1\">\n        {searchText()\n          ? (\n            <span class=\"flex items-center px-1 text-sm whitespace-nowrap tabular-nums text-gray-500 dark:text-gray-500\">\n              {searchStatus().active} / {searchStatus().total}\n            </span>\n          )\n          : null}\n        <Button\n          tooltip=\"Previous (Shift Enter)\"\n          onClick={() => editor().commands.findPrev()}\n        >\n          <span class=\"i-lucide-arrow-left size-5 block\" />\n        </Button>\n        <Button tooltip=\"Next (Enter)\" onClick={() => editor().commands.findNext()}>\n          <span class=\"i-lucide-arrow-right size-5 block\" />\n        </Button>\n        <Button tooltip=\"Close\" onClick={() => props.onClose?.()}>\n          <span class=\"i-lucide-x size-5 block\" />\n        </Button>\n        <Button\n          pressed={caseSensitive()}\n          tooltip=\"Case Sensitive\"\n          onClick={() => setCaseSensitive((value) => !value)}\n        >\n          <span class=\"i-lucide-case-sensitive size-5 block\" />\n        </Button>\n        <Button\n          pressed={wholeWord()}\n          tooltip=\"Whole Word\"\n          onClick={() => setWholeWord((value) => !value)}\n        >\n          <span class=\"i-lucide-whole-word size-5 block\" />\n        </Button>\n        <Button\n          pressed={regexp()}\n          tooltip=\"Regular Expression\"\n          onClick={() => setRegexp((value) => !value)}\n        >\n          <span class=\"i-lucide-braces size-5 block\" />\n        </Button>\n        <Button\n          pressed={literal()}\n          tooltip=\"Literal Escape Sequences\"\n          onClick={() => setLiteral((value) => !value)}\n        >\n          <span class=\"i-lucide-quote size-5 block\" />\n        </Button>\n      </div>\n      {showReplace() && (\n        <input\n          placeholder=\"Replace\"\n          type=\"text\"\n          value={replaceText()}\n          onInput={(event) => setReplaceText(event.currentTarget.value)}\n          onKeyDown={handleReplaceKeyDown}\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        />\n      )}\n      {showReplace() && (\n        <div class=\"flex items-center justify-between gap-1\">\n          <Button tooltip=\"Replace (Enter)\" onClick={() => editor().commands.replaceNext()}>\n            Replace\n          </Button>\n          <Button\n            tooltip=\"Replace All (Shift Enter)\"\n            onClick={() => editor().commands.replaceAll()}\n          >\n            All\n          </Button>\n        </div>\n      )}\n    </div>\n  )\n}\n\nfunction isEnter(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"
    }
  ],
  "meta": {
    "hasIcons": true,
    "hidden": false,
    "story": "",
    "framework": "solid",
    "accumulatedFiles": [
      "registry/src/solid/ui/button/button.tsx",
      "registry/src/solid/ui/button/index.ts",
      "registry/src/solid/ui/search/index.ts",
      "registry/src/solid/ui/search/search.tsx"
    ],
    "internalDependencies": [
      "solid-ui-button"
    ]
  },
  "css": {
    "@plugin @egoist/tailwindcss-icons": {}
  },
  "$schema": "https://ui.shadcn.com/schema/registry-item.json"
}
