[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: pacocoursey\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Run E2E tests\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: pnpm/action-setup@v4 # respects packageManager in package.json\n\n      - uses: actions/setup-node@v4\n        with:\n          cache: 'pnpm'\n\n      - run: pnpm install\n        env:\n          CI: true\n\n      - run: pnpm build\n      - run: pnpm test:format\n      - run: pnpm playwright install --with-deps\n      - run: pnpm test || exit 1\n\n      - name: Upload test results\n        uses: actions/upload-artifact@v4\n        with:\n          name: playwright-report\n          path: playwright-report.json\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.idea\n.env\n.env.local\n.env.development\n.env.development.local\n*.log\nyalc.lock\n\n.vercel/\n.turbo/\n.next/\n.yalc/\nbuild/\ndist/\nnode_modules/\n.vercel\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\npnpm lint-staged\n"
  },
  {
    "path": ".prettierignore",
    "content": ".next\ndist\npnpm-lock.yaml\n.pnpm-store\n.vercel\n"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n  semi: false,\n  singleQuote: true,\n  tabWidth: 2,\n  trailingComma: 'all',\n  printWidth: 120,\n}\n"
  },
  {
    "path": "ARCHITECTURE.md",
    "content": "# Architecture\n\n> Document is a work in progress!\n\n⌘K is born from a simple constraint: can you write a combobox with filtering and sorting using the [compound component](https://kentcdodds.com/blog/compound-components-with-react-hooks) approach? We didn't want to render items manually from an array:\n\n```tsx\n// No\n<>\n  {items.map((item) => {\n    return <div>{item}</div>\n  })}\n</>\n```\n\nWe didn't want to provide a render prop:\n\n```tsx\n// No\nonItemRender={({ item }) => {\n  return <div>{item}</div>\n}}\n```\n\nInstead, we wanted to render components:\n\n```tsx\n// Yes\n<Item>My item</Item>\n```\n\nEspecially, we wanted full component composition:\n\n```tsx\n// YES\n<>\n  <BlogItems />\n  {staticItems}\n</>\n```\n\nCompound components are natural and easy to write. A few months after exploring this library, we were pleased to see [Radix UI](https://www.radix-ui.com) released using this exact approach of component structure – setting the standard for ease of use and composability.\n\nHowever, for a combobox, it is a terrible, terrible constraint that we've spent 2 years fighting.\n\n## Approach\n\n⌘K always keeps every item and group rendered in the React tree. Each item and group adds or removes itself from the DOM based on the search input. The DOM is authoritative. Item selection order is based on the DOM order, which is based on the React render order, which the consumer provides.\n\n### Discarded approach\n\nWe did not use `React.Children` iteration because it will not support component composition. There is no way to \"peek inside\" the items contained within `<BlogItems />`, so those items cannot be filtered.\n\nWe did not use an object-based data array for each item, like `{ name: \"Logout\", action: () => logout() }` because this is strict and limiting. In reality, the interface of those objects grows with edge-cases, like `image`, `detailedSubTitle`, `hideWhenRootSearch`, etc. We prefer that you have full control of item rendering, including icons, keyboard shortcuts, and styling. Don't want an item shown? Don't render it. Only want to show an item under condition xyz? Render it.\n\nWe did not use a render prop because they are an inelegant pattern and quickly fall to long, centralised if-else logic chains. For example, if you want a fancy sparkle rainbow item, you need a new if statement to render that item specially.\n\nThe original approach for tracking which item was selected was to keep an index 0..n. But it's impossible to know which Item is in which position within the React tree when React Strict Mode is enabled, because `useEffect` runs twice and `useRef` cannot be used for stable IDs. <sup>This may be possible with `useId`, now.</sup> We created [use-descendants](https://github.com/pacocoursey/use-descendants) to track relative component indeces, but abandoned it because it could not work in Strict Mode, and will be incompatible with upcoming concurrent mode. Now, we track the selected item with its value, because it is stable across item mounts and unmounts.\n\n## Example\n\n```tsx\n<Input value=\"b\" />\n<List>\n  <Item>A</Item>\n  <Item>B</Item>\n</List>\n```\n\nThe \"A\" item should not be shown! But we cannot remove it from the React tree, because the user controls it. In most cases, this is easy because the rendered items is sourced from a backing data array:\n\n```tsx\n<>\n  {['A', 'B'].map((item) => {\n    if (matches(item, search)) {\n      return <Item>{item}</Item>\n    }\n  })}\n</>\n```\n\nBut in our case, the item will remain in the React tree and just be removed from the DOM:\n\n```tsx\n<List>\n  {/* returns `null`, no DOM created */}\n  <Item>A</Item>\n  <Item>B</Item>\n</List>\n```\n\n## Performance\n\nThis is more expensive memory wise, because if there are 2,000 items but the list is filtered to only 2 items, we still allocate memory for 2,000 instances of the Item component. But it's our only option! Thankfully we can still keep the DOM size to 2 items.\n\n## Groups\n\nItem mount informs both the root and the parent group, which keeps track of items within it. Each group informs the root.\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2022 Paco Coursey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n<img src=\"./website/public/og.png\" />\n</p>\n\n# ⌘K [![cmdk minzip package size](https://img.shields.io/bundlephobia/minzip/cmdk)](https://www.npmjs.com/package/cmdk?activeTab=code) [![cmdk package version](https://img.shields.io/npm/v/cmdk.svg?colorB=green)](https://www.npmjs.com/package/cmdk)\n\n⌘K is a command menu React component that can also be used as an accessible combobox. You render items, it filters and sorts them automatically. ⌘K supports a fully composable API <sup><sup>[How?](/ARCHITECTURE.md)</sup></sup>, so you can wrap items in other components or even as static JSX.\n\n## Install\n\n```bash\npnpm install cmdk\n```\n\n## Use\n\n```tsx\nimport { Command } from 'cmdk'\n\nconst CommandMenu = () => {\n  return (\n    <Command label=\"Command Menu\">\n      <Command.Input />\n      <Command.List>\n        <Command.Empty>No results found.</Command.Empty>\n\n        <Command.Group heading=\"Letters\">\n          <Command.Item>a</Command.Item>\n          <Command.Item>b</Command.Item>\n          <Command.Separator />\n          <Command.Item>c</Command.Item>\n        </Command.Group>\n\n        <Command.Item>Apple</Command.Item>\n      </Command.List>\n    </Command>\n  )\n}\n```\n\nOr in a dialog:\n\n```tsx\nimport { Command } from 'cmdk'\n\nconst CommandMenu = () => {\n  const [open, setOpen] = React.useState(false)\n\n  // Toggle the menu when ⌘K is pressed\n  React.useEffect(() => {\n    const down = (e) => {\n      if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {\n        e.preventDefault()\n        setOpen((open) => !open)\n      }\n    }\n\n    document.addEventListener('keydown', down)\n    return () => document.removeEventListener('keydown', down)\n  }, [])\n\n  return (\n    <Command.Dialog open={open} onOpenChange={setOpen} label=\"Global Command Menu\">\n      <Command.Input />\n      <Command.List>\n        <Command.Empty>No results found.</Command.Empty>\n\n        <Command.Group heading=\"Letters\">\n          <Command.Item>a</Command.Item>\n          <Command.Item>b</Command.Item>\n          <Command.Separator />\n          <Command.Item>c</Command.Item>\n        </Command.Group>\n\n        <Command.Item>Apple</Command.Item>\n      </Command.List>\n    </Command.Dialog>\n  )\n}\n```\n\n## Parts and styling\n\nAll parts forward props, including `ref`, to an appropriate element. Each part has a specific data-attribute (starting with `cmdk-`) that can be used for styling.\n\n### Command `[cmdk-root]`\n\nRender this to show the command menu inline, or use [Dialog](#dialog-cmdk-dialog-cmdk-overlay) to render in a elevated context. Can be controlled with the `value` and `onValueChange` props.\n\n> **Note**\n>\n> Values are always trimmed with the [trim()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim) method.\n\n```tsx\nconst [value, setValue] = React.useState('apple')\n\nreturn (\n  <Command value={value} onValueChange={setValue}>\n    <Command.Input />\n    <Command.List>\n      <Command.Item>Orange</Command.Item>\n      <Command.Item>Apple</Command.Item>\n    </Command.List>\n  </Command>\n)\n```\n\nYou can provide a custom `filter` function that is called to rank each item. Note that the value will be trimmed.\n\n```tsx\n<Command\n  filter={(value, search) => {\n    if (value.includes(search)) return 1\n    return 0\n  }}\n/>\n```\n\nA third argument, `keywords`, can also be provided to the filter function. Keywords act as aliases for the item value, and can also affect the rank of the item. Keywords are trimmed.\n\n```tsx\n<Command\n  filter={(value, search, keywords) => {\n    const extendValue = value + ' ' + keywords.join(' ')\n    if (extendValue.includes(search)) return 1\n    return 0\n  }}\n/>\n```\n\nOr disable filtering and sorting entirely:\n\n```tsx\n<Command shouldFilter={false}>\n  <Command.List>\n    {filteredItems.map((item) => {\n      return (\n        <Command.Item key={item} value={item}>\n          {item}\n        </Command.Item>\n      )\n    })}\n  </Command.List>\n</Command>\n```\n\nYou can make the arrow keys wrap around the list (when you reach the end, it goes back to the first item) by setting the `loop` prop:\n\n```tsx\n<Command loop />\n```\n\n### Dialog `[cmdk-dialog]` `[cmdk-overlay]`\n\nProps are forwarded to [Command](#command-cmdk-root). Composes Radix UI's Dialog component. The overlay is always rendered. See the [Radix Documentation](https://www.radix-ui.com/docs/primitives/components/dialog) for more information. Can be controlled with the `open` and `onOpenChange` props.\n\n```tsx\nconst [open, setOpen] = React.useState(false)\n\nreturn (\n  <Command.Dialog open={open} onOpenChange={setOpen}>\n    ...\n  </Command.Dialog>\n)\n```\n\nYou can provide a `container` prop that accepts an HTML element that is forwarded to Radix UI's Dialog Portal component to specify which element the Dialog should portal into (defaults to `body`). See the [Radix Documentation](https://www.radix-ui.com/docs/primitives/components/dialog#portal) for more information.\n\n```tsx\nconst containerElement = React.useRef(null)\n\nreturn (\n  <>\n    <Command.Dialog container={containerElement.current} />\n    <div ref={containerElement} />\n  </>\n)\n```\n\n### Input `[cmdk-input]`\n\nAll props are forwarded to the underlying `input` element. Can be controlled with the `value` and `onValueChange` props.\n\n```tsx\nconst [search, setSearch] = React.useState('')\n\nreturn <Command.Input value={search} onValueChange={setSearch} />\n```\n\n### List `[cmdk-list]`\n\nContains items and groups. Animate height using the `--cmdk-list-height` CSS variable.\n\n```css\n[cmdk-list] {\n  min-height: 300px;\n  height: var(--cmdk-list-height);\n  max-height: 500px;\n  transition: height 100ms ease;\n}\n```\n\nTo scroll item into view earlier near the edges of the viewport, use scroll-padding:\n\n```css\n[cmdk-list] {\n  scroll-padding-block-start: 8px;\n  scroll-padding-block-end: 8px;\n}\n```\n\n### Item `[cmdk-item]` `[data-disabled?]` `[data-selected?]`\n\nItem that becomes active on pointer enter. You should provide a unique `value` for each item, but it will be automatically inferred from the `.textContent`.\n\n```tsx\n<Command.Item\n  onSelect={(value) => console.log('Selected', value)}\n  // Value is implicity \"apple\" because of the provided text content\n>\n  Apple\n</Command.Item>\n```\n\nYou can also provide a `keywords` prop to help with filtering. Keywords are trimmed.\n\n```tsx\n<Command.Item keywords={['fruit', 'apple']}>Apple</Command.Item>\n```\n\n```tsx\n<Command.Item\n  onSelect={(value) => console.log('Selected', value)}\n  // Value is implicity \"apple\" because of the provided text content\n>\n  Apple\n</Command.Item>\n```\n\nYou can force an item to always render, regardless of filtering, by passing the `forceMount` prop.\n\n### Group `[cmdk-group]` `[hidden?]`\n\nGroups items together with the given `heading` (`[cmdk-group-heading]`).\n\n```tsx\n<Command.Group heading=\"Fruit\">\n  <Command.Item>Apple</Command.Item>\n</Command.Group>\n```\n\nGroups will not unmount from the DOM, rather the `hidden` attribute is applied to hide it from view. This may be relevant in your styling.\n\nYou can force a group to always render, regardless of filtering, by passing the `forceMount` prop.\n\n### Separator `[cmdk-separator]`\n\nVisible when the search query is empty or `alwaysRender` is true, hidden otherwise.\n\n### Empty `[cmdk-empty]`\n\nAutomatically renders when there are no results for the search query.\n\n### Loading `[cmdk-loading]`\n\nYou should conditionally render this with `progress` while loading asynchronous items.\n\n```tsx\nconst [loading, setLoading] = React.useState(false)\n\nreturn <Command.List>{loading && <Command.Loading>Hang on…</Command.Loading>}</Command.List>\n```\n\n### `useCommandState(state => state.selectedField)`\n\nHook that composes [`useSyncExternalStore`](https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore). Pass a function that returns a slice of the command menu state to re-render when that slice changes. This hook is provided for advanced use cases and should not be commonly used.\n\nA good use case would be to render a more detailed empty state, like so:\n\n```tsx\nconst search = useCommandState((state) => state.search)\nreturn <Command.Empty>No results found for \"{search}\".</Command.Empty>\n```\n\n## Examples\n\nCode snippets for common use cases.\n\n### Nested items\n\nOften selecting one item should navigate deeper, with a more refined set of items. For example selecting \"Change theme…\" should show new items \"Dark theme\" and \"Light theme\". We call these sets of items \"pages\", and they can be implemented with simple state:\n\n```tsx\nconst ref = React.useRef(null)\nconst [open, setOpen] = React.useState(false)\nconst [search, setSearch] = React.useState('')\nconst [pages, setPages] = React.useState([])\nconst page = pages[pages.length - 1]\n\nreturn (\n  <Command\n    onKeyDown={(e) => {\n      // Escape goes to previous page\n      // Backspace goes to previous page when search is empty\n      if (e.key === 'Escape' || (e.key === 'Backspace' && !search)) {\n        e.preventDefault()\n        setPages((pages) => pages.slice(0, -1))\n      }\n    }}\n  >\n    <Command.Input value={search} onValueChange={setSearch} />\n    <Command.List>\n      {!page && (\n        <>\n          <Command.Item onSelect={() => setPages([...pages, 'projects'])}>Search projects…</Command.Item>\n          <Command.Item onSelect={() => setPages([...pages, 'teams'])}>Join a team…</Command.Item>\n        </>\n      )}\n\n      {page === 'projects' && (\n        <>\n          <Command.Item>Project A</Command.Item>\n          <Command.Item>Project B</Command.Item>\n        </>\n      )}\n\n      {page === 'teams' && (\n        <>\n          <Command.Item>Team 1</Command.Item>\n          <Command.Item>Team 2</Command.Item>\n        </>\n      )}\n    </Command.List>\n  </Command>\n)\n```\n\n### Show sub-items when searching\n\nIf your items have nested sub-items that you only want to reveal when searching, render based on the search state:\n\n```tsx\nconst SubItem = (props) => {\n  const search = useCommandState((state) => state.search)\n  if (!search) return null\n  return <Command.Item {...props} />\n}\n\nreturn (\n  <Command>\n    <Command.Input />\n    <Command.List>\n      <Command.Item>Change theme…</Command.Item>\n      <SubItem>Change theme to dark</SubItem>\n      <SubItem>Change theme to light</SubItem>\n    </Command.List>\n  </Command>\n)\n```\n\n### Asynchronous results\n\nRender the items as they become available. Filtering and sorting will happen automatically.\n\n```tsx\nconst [loading, setLoading] = React.useState(false)\nconst [items, setItems] = React.useState([])\n\nReact.useEffect(() => {\n  async function getItems() {\n    setLoading(true)\n    const res = await api.get('/dictionary')\n    setItems(res)\n    setLoading(false)\n  }\n\n  getItems()\n}, [])\n\nreturn (\n  <Command>\n    <Command.Input />\n    <Command.List>\n      {loading && <Command.Loading>Fetching words…</Command.Loading>}\n      {items.map((item) => {\n        return (\n          <Command.Item key={`word-${item}`} value={item}>\n            {item}\n          </Command.Item>\n        )\n      })}\n    </Command.List>\n  </Command>\n)\n```\n\n### Use inside Popover\n\nWe recommend using the [Radix UI popover](https://www.radix-ui.com/docs/primitives/components/popover) component. ⌘K relies on the Radix UI Dialog component, so this will reduce your bundle size a bit due to shared dependencies.\n\n```bash\n$ pnpm install @radix-ui/react-popover\n```\n\nRender `Command` inside of the popover content:\n\n```tsx\nimport * as Popover from '@radix-ui/react-popover'\n\nreturn (\n  <Popover.Root>\n    <Popover.Trigger>Toggle popover</Popover.Trigger>\n\n    <Popover.Content>\n      <Command>\n        <Command.Input />\n        <Command.List>\n          <Command.Item>Apple</Command.Item>\n        </Command.List>\n      </Command>\n    </Popover.Content>\n  </Popover.Root>\n)\n```\n\n### Drop in stylesheets\n\nYou can find global stylesheets to drop in as a starting point for styling. See [website/styles/cmdk](website/styles/cmdk) for examples.\n\n## FAQ\n\n**Accessible?** Yes. Labeling, aria attributes, and DOM ordering tested with Voice Over and Chrome DevTools. [Dialog](#dialog-cmdk-dialog-cmdk-overlay) composes an accessible Dialog implementation.\n\n**Virtualization?** No. Good performance up to 2,000-3,000 items, though. Read below to bring your own.\n\n**Filter/sort items manually?** Yes. Pass `shouldFilter={false}` to [Command](#command-cmdk-root). Better memory usage and performance. Bring your own virtualization this way.\n\n**React 18 safe?** Yes, required. Uses React 18 hooks like `useId` and `useSyncExternalStore`.\n\n**Unstyled?** Yes, use the listed CSS selectors.\n\n**Hydration mismatch?** No, likely a bug in your code. Ensure the `open` prop to `Command.Dialog` is `false` on the server.\n\n**React strict mode safe?** Yes. Open an issue if you notice an issue.\n\n**Weird/wrong behavior?** Make sure your `Command.Item` has a `key` and unique `value`.\n\n**Concurrent mode safe?** Maybe, but concurrent mode is not yet real. Uses risky approaches like manual DOM ordering.\n\n**React server component?** No, it's a client component.\n\n**Listen for ⌘K automatically?** No, do it yourself to have full control over keybind context.\n\n**React Native?** No, and no plans to support it. If you build a React Native version, let us know and we'll link your repository here.\n\n## History\n\nWritten in 2019 by Paco ([@pacocoursey](https://twitter.com/pacocoursey)) to see if a composable combobox API was possible. Used for the Vercel command menu and autocomplete by Rauno ([@raunofreiberg](https://twitter.com/raunofreiberg)) in 2020. Re-written independently in 2022 with a simpler and more performant approach. Ideas and help from Shu ([@shuding\\_](https://twitter.com/shuding_)).\n\n[use-descendants](https://github.com/pacocoursey/use-descendants) was extracted from the 2019 version.\n\n## Testing\n\nFirst, install dependencies and Playwright browsers:\n\n```bash\npnpm install\npnpm playwright install\n```\n\nThen ensure you've built the library:\n\n```bash\npnpm build\n```\n\nThen run the tests using your local build against real browser engines:\n\n```bash\npnpm test\n```\n"
  },
  {
    "path": "cmdk/package.json",
    "content": "{\n  \"name\": \"cmdk\",\n  \"version\": \"1.1.1\",\n  \"license\": \"MIT\",\n  \"main\": \"./dist/index.js\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.mjs\",\n      \"require\": \"./dist/index.js\"\n    }\n  },\n  \"scripts\": {\n    \"prepublishOnly\": \"cp ../README.md . && pnpm build\",\n    \"postpublish\": \"rm README.md\",\n    \"build\": \"tsup src\",\n    \"dev\": \"tsup src --watch\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^18 || ^19 || ^19.0.0-rc\",\n    \"react-dom\": \"^18 || ^19 || ^19.0.0-rc\"\n  },\n  \"dependencies\": {\n    \"@radix-ui/react-compose-refs\": \"^1.1.1\",\n    \"@radix-ui/react-dialog\": \"^1.1.6\",\n    \"@radix-ui/react-id\": \"^1.1.0\",\n    \"@radix-ui/react-primitive\": \"^2.0.2\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"18.0.15\"\n  },\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/pacocoursey/cmdk.git\",\n    \"directory\": \"cmdk\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/pacocoursey/cmdk/issues\"\n  },\n  \"homepage\": \"https://github.com/pacocoursey/cmdk#readme\",\n  \"author\": {\n    \"name\": \"Paco\",\n    \"url\": \"https://github.com/pacocoursey\"\n  }\n}\n"
  },
  {
    "path": "cmdk/src/command-score.ts",
    "content": "// The scores are arranged so that a continuous match of characters will\n// result in a total score of 1.\n//\n// The best case, this character is a match, and either this is the start\n// of the string, or the previous character was also a match.\nvar SCORE_CONTINUE_MATCH = 1,\n  // A new match at the start of a word scores better than a new match\n  // elsewhere as it's more likely that the user will type the starts\n  // of fragments.\n  // NOTE: We score word jumps between spaces slightly higher than slashes, brackets\n  // hyphens, etc.\n  SCORE_SPACE_WORD_JUMP = 0.9,\n  SCORE_NON_SPACE_WORD_JUMP = 0.8,\n  // Any other match isn't ideal, but we include it for completeness.\n  SCORE_CHARACTER_JUMP = 0.17,\n  // If the user transposed two letters, it should be significantly penalized.\n  //\n  // i.e. \"ouch\" is more likely than \"curtain\" when \"uc\" is typed.\n  SCORE_TRANSPOSITION = 0.1,\n  // The goodness of a match should decay slightly with each missing\n  // character.\n  //\n  // i.e. \"bad\" is more likely than \"bard\" when \"bd\" is typed.\n  //\n  // This will not change the order of suggestions based on SCORE_* until\n  // 100 characters are inserted between matches.\n  PENALTY_SKIPPED = 0.999,\n  // The goodness of an exact-case match should be higher than a\n  // case-insensitive match by a small amount.\n  //\n  // i.e. \"HTML\" is more likely than \"haml\" when \"HM\" is typed.\n  //\n  // This will not change the order of suggestions based on SCORE_* until\n  // 1000 characters are inserted between matches.\n  PENALTY_CASE_MISMATCH = 0.9999,\n  // Match higher for letters closer to the beginning of the word\n  PENALTY_DISTANCE_FROM_START = 0.9,\n  // If the word has more characters than the user typed, it should\n  // be penalised slightly.\n  //\n  // i.e. \"html\" is more likely than \"html5\" if I type \"html\".\n  //\n  // However, it may well be the case that there's a sensible secondary\n  // ordering (like alphabetical) that it makes sense to rely on when\n  // there are many prefix matches, so we don't make the penalty increase\n  // with the number of tokens.\n  PENALTY_NOT_COMPLETE = 0.99\n\nvar IS_GAP_REGEXP = /[\\\\\\/_+.#\"@\\[\\(\\{&]/,\n  COUNT_GAPS_REGEXP = /[\\\\\\/_+.#\"@\\[\\(\\{&]/g,\n  IS_SPACE_REGEXP = /[\\s-]/,\n  COUNT_SPACE_REGEXP = /[\\s-]/g\n\nfunction commandScoreInner(\n  string,\n  abbreviation,\n  lowerString,\n  lowerAbbreviation,\n  stringIndex,\n  abbreviationIndex,\n  memoizedResults,\n) {\n  if (abbreviationIndex === abbreviation.length) {\n    if (stringIndex === string.length) {\n      return SCORE_CONTINUE_MATCH\n    }\n    return PENALTY_NOT_COMPLETE\n  }\n\n  var memoizeKey = `${stringIndex},${abbreviationIndex}`\n  if (memoizedResults[memoizeKey] !== undefined) {\n    return memoizedResults[memoizeKey]\n  }\n\n  var abbreviationChar = lowerAbbreviation.charAt(abbreviationIndex)\n  var index = lowerString.indexOf(abbreviationChar, stringIndex)\n  var highScore = 0\n\n  var score, transposedScore, wordBreaks, spaceBreaks\n\n  while (index >= 0) {\n    score = commandScoreInner(\n      string,\n      abbreviation,\n      lowerString,\n      lowerAbbreviation,\n      index + 1,\n      abbreviationIndex + 1,\n      memoizedResults,\n    )\n    if (score > highScore) {\n      if (index === stringIndex) {\n        score *= SCORE_CONTINUE_MATCH\n      } else if (IS_GAP_REGEXP.test(string.charAt(index - 1))) {\n        score *= SCORE_NON_SPACE_WORD_JUMP\n        wordBreaks = string.slice(stringIndex, index - 1).match(COUNT_GAPS_REGEXP)\n        if (wordBreaks && stringIndex > 0) {\n          score *= Math.pow(PENALTY_SKIPPED, wordBreaks.length)\n        }\n      } else if (IS_SPACE_REGEXP.test(string.charAt(index - 1))) {\n        score *= SCORE_SPACE_WORD_JUMP\n        spaceBreaks = string.slice(stringIndex, index - 1).match(COUNT_SPACE_REGEXP)\n        if (spaceBreaks && stringIndex > 0) {\n          score *= Math.pow(PENALTY_SKIPPED, spaceBreaks.length)\n        }\n      } else {\n        score *= SCORE_CHARACTER_JUMP\n        if (stringIndex > 0) {\n          score *= Math.pow(PENALTY_SKIPPED, index - stringIndex)\n        }\n      }\n\n      if (string.charAt(index) !== abbreviation.charAt(abbreviationIndex)) {\n        score *= PENALTY_CASE_MISMATCH\n      }\n    }\n\n    if (\n      (score < SCORE_TRANSPOSITION &&\n        lowerString.charAt(index - 1) === lowerAbbreviation.charAt(abbreviationIndex + 1)) ||\n      (lowerAbbreviation.charAt(abbreviationIndex + 1) === lowerAbbreviation.charAt(abbreviationIndex) && // allow duplicate letters. Ref #7428\n        lowerString.charAt(index - 1) !== lowerAbbreviation.charAt(abbreviationIndex))\n    ) {\n      transposedScore = commandScoreInner(\n        string,\n        abbreviation,\n        lowerString,\n        lowerAbbreviation,\n        index + 1,\n        abbreviationIndex + 2,\n        memoizedResults,\n      )\n\n      if (transposedScore * SCORE_TRANSPOSITION > score) {\n        score = transposedScore * SCORE_TRANSPOSITION\n      }\n    }\n\n    if (score > highScore) {\n      highScore = score\n    }\n\n    index = lowerString.indexOf(abbreviationChar, index + 1)\n  }\n\n  memoizedResults[memoizeKey] = highScore\n  return highScore\n}\n\nfunction formatInput(string) {\n  // convert all valid space characters to space so they match each other\n  return string.toLowerCase().replace(COUNT_SPACE_REGEXP, ' ')\n}\n\nexport function commandScore(string: string, abbreviation: string, aliases: string[]): number {\n  /* NOTE:\n   * in the original, we used to do the lower-casing on each recursive call, but this meant that toLowerCase()\n   * was the dominating cost in the algorithm, passing both is a little ugly, but considerably faster.\n   */\n  string = aliases && aliases.length > 0 ? `${string + ' ' + aliases.join(' ')}` : string\n  return commandScoreInner(string, abbreviation, formatInput(string), formatInput(abbreviation), 0, 0, {})\n}\n"
  },
  {
    "path": "cmdk/src/index.tsx",
    "content": "'use client'\n\nimport * as RadixDialog from '@radix-ui/react-dialog'\nimport * as React from 'react'\nimport { commandScore } from './command-score'\nimport { Primitive } from '@radix-ui/react-primitive'\nimport { useId } from '@radix-ui/react-id'\nimport { composeRefs } from '@radix-ui/react-compose-refs'\n\ntype Children = { children?: React.ReactNode }\ntype DivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>\n\ntype LoadingProps = Children &\n  DivProps & {\n    /** Estimated progress of loading asynchronous options. */\n    progress?: number\n    /**\n     * Accessible label for this loading progressbar. Not shown visibly.\n     */\n    label?: string\n  }\n\ntype EmptyProps = Children & DivProps & {}\ntype SeparatorProps = DivProps & {\n  /** Whether this separator should always be rendered. Useful if you disable automatic filtering. */\n  alwaysRender?: boolean\n}\ntype DialogProps = RadixDialog.DialogProps &\n  CommandProps & {\n    /** Provide a className to the Dialog overlay. */\n    overlayClassName?: string\n    /** Provide a className to the Dialog content. */\n    contentClassName?: string\n    /** Provide a custom element the Dialog should portal into. */\n    container?: HTMLElement\n  }\ntype ListProps = Children &\n  DivProps & {\n    /**\n     * Accessible label for this List of suggestions. Not shown visibly.\n     */\n    label?: string\n  }\ntype ItemProps = Children &\n  Omit<DivProps, 'disabled' | 'onSelect' | 'value'> & {\n    /** Whether this item is currently disabled. */\n    disabled?: boolean\n    /** Event handler for when this item is selected, either via click or keyboard selection. */\n    onSelect?: (value: string) => void\n    /**\n     * A unique value for this item.\n     * If no value is provided, it will be inferred from `children` or the rendered `textContent`. If your `textContent` changes between renders, you _must_ provide a stable, unique `value`.\n     */\n    value?: string\n    /** Optional keywords to match against when filtering. */\n    keywords?: string[]\n    /** Whether this item is forcibly rendered regardless of filtering. */\n    forceMount?: boolean\n  }\ntype GroupProps = Children &\n  Omit<DivProps, 'heading' | 'value'> & {\n    /** Optional heading to render for this group. */\n    heading?: React.ReactNode\n    /** If no heading is provided, you must provide a value that is unique for this group. */\n    value?: string\n    /** Whether this group is forcibly rendered regardless of filtering. */\n    forceMount?: boolean\n  }\ntype InputProps = Omit<React.ComponentPropsWithoutRef<typeof Primitive.input>, 'value' | 'onChange' | 'type'> & {\n  /**\n   * Optional controlled state for the value of the search input.\n   */\n  value?: string\n  /**\n   * Event handler called when the search value changes.\n   */\n  onValueChange?: (search: string) => void\n}\ntype CommandFilter = (value: string, search: string, keywords?: string[]) => number\ntype CommandProps = Children &\n  DivProps & {\n    /**\n     * Accessible label for this command menu. Not shown visibly.\n     */\n    label?: string\n    /**\n     * Optionally set to `false` to turn off the automatic filtering and sorting.\n     * If `false`, you must conditionally render valid items based on the search query yourself.\n     */\n    shouldFilter?: boolean\n    /**\n     * Custom filter function for whether each command menu item should matches the given search query.\n     * It should return a number between 0 and 1, with 1 being the best match and 0 being hidden entirely.\n     * By default, uses the `command-score` library.\n     */\n    filter?: CommandFilter\n    /**\n     * Optional default item value when it is initially rendered.\n     */\n    defaultValue?: string\n    /**\n     * Optional controlled state of the selected command menu item.\n     */\n    value?: string\n    /**\n     * Event handler called when the selected item of the menu changes.\n     */\n    onValueChange?: (value: string) => void\n    /**\n     * Optionally set to `true` to turn on looping around when using the arrow keys.\n     */\n    loop?: boolean\n    /**\n     * Optionally set to `true` to disable selection via pointer events.\n     */\n    disablePointerSelection?: boolean\n    /**\n     * Set to `false` to disable ctrl+n/j/p/k shortcuts. Defaults to `true`.\n     */\n    vimBindings?: boolean\n  }\n\ntype Context = {\n  value: (id: string, value: string, keywords?: string[]) => void\n  item: (id: string, groupId: string) => () => void\n  group: (id: string) => () => void\n  filter: () => boolean\n  label: string\n  getDisablePointerSelection: () => boolean\n  // Ids\n  listId: string\n  labelId: string\n  inputId: string\n  // Refs\n  listInnerRef: React.RefObject<HTMLDivElement | null>\n}\ntype State = {\n  search: string\n  value: string\n  selectedItemId?: string\n  filtered: { count: number; items: Map<string, number>; groups: Set<string> }\n}\ntype Store = {\n  subscribe: (callback: () => void) => () => void\n  snapshot: () => State\n  setState: <K extends keyof State>(key: K, value: State[K], opts?: any) => void\n  emit: () => void\n}\ntype Group = {\n  id: string\n  forceMount?: boolean\n}\n\nconst GROUP_SELECTOR = `[cmdk-group=\"\"]`\nconst GROUP_ITEMS_SELECTOR = `[cmdk-group-items=\"\"]`\nconst GROUP_HEADING_SELECTOR = `[cmdk-group-heading=\"\"]`\nconst ITEM_SELECTOR = `[cmdk-item=\"\"]`\nconst VALID_ITEM_SELECTOR = `${ITEM_SELECTOR}:not([aria-disabled=\"true\"])`\nconst SELECT_EVENT = `cmdk-item-select`\nconst VALUE_ATTR = `data-value`\nconst defaultFilter: CommandFilter = (value, search, keywords) => commandScore(value, search, keywords)\n\nconst CommandContext = React.createContext<Context>(undefined)\nconst useCommand = () => React.useContext(CommandContext)\nconst StoreContext = React.createContext<Store>(undefined)\nconst useStore = () => React.useContext(StoreContext)\nconst GroupContext = React.createContext<Group>(undefined)\n\nconst Command = React.forwardRef<HTMLDivElement, CommandProps>((props, forwardedRef) => {\n  const state = useLazyRef<State>(() => ({\n    /** Value of the search query. */\n    search: '',\n    /** Currently selected item value. */\n    value: props.value ?? props.defaultValue ?? '',\n    /** Currently selected item id. */\n    selectedItemId: undefined,\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(),\n      /** Set of groups with at least one visible item. */\n      groups: new Set(),\n    },\n  }))\n  const allItems = useLazyRef<Set<string>>(() => new Set()) // [...itemIds]\n  const allGroups = useLazyRef<Map<string, Set<string>>>(() => new Map()) // groupId → [...itemIds]\n  const ids = useLazyRef<Map<string, { value: string; keywords?: string[] }>>(() => new Map()) // id → { value, keywords }\n  const listeners = useLazyRef<Set<() => void>>(() => new Set()) // [...rerenders]\n  const propsRef = useAsRef(props)\n  const {\n    label,\n    children,\n    value,\n    onValueChange,\n    filter,\n    shouldFilter,\n    loop,\n    disablePointerSelection = false,\n    vimBindings = true,\n    ...etc\n  } = props\n\n  const listId = useId()\n  const labelId = useId()\n  const inputId = useId()\n\n  const listInnerRef = React.useRef<HTMLDivElement>(null)\n\n  const schedule = useScheduleLayoutEffect()\n\n  /** Controlled mode `value` handling. */\n  useLayoutEffect(() => {\n    if (value !== undefined) {\n      const v = value.trim()\n      state.current.value = v\n      store.emit()\n    }\n  }, [value])\n\n  useLayoutEffect(() => {\n    schedule(6, scrollSelectedIntoView)\n  }, [])\n\n  const store: Store = React.useMemo(() => {\n    return {\n      subscribe: (cb) => {\n        listeners.current.add(cb)\n        return () => listeners.current.delete(cb)\n      },\n      snapshot: () => {\n        return state.current\n      },\n      setState: (key, value, opts) => {\n        if (Object.is(state.current[key], value)) return\n        state.current[key] = value\n\n        if (key === 'search') {\n          // Filter synchronously before emitting back to children\n          filterItems()\n          sort()\n          schedule(1, selectFirstItem)\n        } else if (key === 'value') {\n          // Force focus input or root so accessibility works\n          if (document.activeElement.hasAttribute('cmdk-input') || document.activeElement.hasAttribute('cmdk-root')) {\n            const input = document.getElementById(inputId)\n            if (input) input.focus()\n            else document.getElementById(listId)?.focus()\n          }\n\n          schedule(7, () => {\n            state.current.selectedItemId = getSelectedItem()?.id\n            store.emit()\n          })\n\n          // opts is a boolean referring to whether it should NOT be scrolled into view\n          if (!opts) {\n            // Scroll the selected item into view\n            schedule(5, scrollSelectedIntoView)\n          }\n          if (propsRef.current?.value !== undefined) {\n            // If controlled, just call the callback instead of updating state internally\n            const newValue = (value ?? '') as string\n            propsRef.current.onValueChange?.(newValue)\n            return\n          }\n        }\n\n        // Notify subscribers that state has changed\n        store.emit()\n      },\n      emit: () => {\n        listeners.current.forEach((l) => l())\n      },\n    }\n  }, [])\n\n  const context: Context = React.useMemo(\n    () => ({\n      // Keep id → {value, keywords} mapping up-to-date\n      value: (id, value, keywords) => {\n        if (value !== ids.current.get(id)?.value) {\n          ids.current.set(id, { value, keywords })\n          state.current.filtered.items.set(id, score(value, keywords))\n          schedule(2, () => {\n            sort()\n            store.emit()\n          })\n        }\n      },\n      // Track item lifecycle (mount, unmount)\n      item: (id, groupId) => {\n        allItems.current.add(id)\n\n        // Track this item within the group\n        if (groupId) {\n          if (!allGroups.current.has(groupId)) {\n            allGroups.current.set(groupId, new Set([id]))\n          } else {\n            allGroups.current.get(groupId).add(id)\n          }\n        }\n\n        // Batch this, multiple items can mount in one pass\n        // and we should not be filtering/sorting/emitting each time\n        schedule(3, () => {\n          filterItems()\n          sort()\n\n          // Could be initial mount, select the first item if none already selected\n          if (!state.current.value) {\n            selectFirstItem()\n          }\n\n          store.emit()\n        })\n\n        return () => {\n          ids.current.delete(id)\n          allItems.current.delete(id)\n          state.current.filtered.items.delete(id)\n          const selectedItem = getSelectedItem()\n\n          // Batch this, multiple items could be removed in one pass\n          schedule(4, () => {\n            filterItems()\n\n            // The item removed have been the selected one,\n            // so selection should be moved to the first\n            if (selectedItem?.getAttribute('id') === id) selectFirstItem()\n\n            store.emit()\n          })\n        }\n      },\n      // Track group lifecycle (mount, unmount)\n      group: (id) => {\n        if (!allGroups.current.has(id)) {\n          allGroups.current.set(id, new Set())\n        }\n\n        return () => {\n          ids.current.delete(id)\n          allGroups.current.delete(id)\n        }\n      },\n      filter: () => {\n        return propsRef.current.shouldFilter\n      },\n      label: label || props['aria-label'],\n      getDisablePointerSelection: () => {\n        return propsRef.current.disablePointerSelection\n      },\n      listId,\n      inputId,\n      labelId,\n      listInnerRef,\n    }),\n    [],\n  )\n\n  function score(value: string, keywords?: string[]) {\n    const filter = propsRef.current?.filter ?? defaultFilter\n    return value ? filter(value, state.current.search, keywords) : 0\n  }\n\n  /** Sorts items by score, and groups by highest item score. */\n  function sort() {\n    if (\n      !state.current.search ||\n      // Explicitly false, because true | undefined is the default\n      propsRef.current.shouldFilter === false\n    ) {\n      return\n    }\n\n    const scores = state.current.filtered.items\n\n    // Sort the groups\n    const groups: [string, number][] = []\n    state.current.filtered.groups.forEach((value) => {\n      const items = allGroups.current.get(value)\n\n      // Get the maximum score of the group's items\n      let max = 0\n      items.forEach((item) => {\n        const score = scores.get(item)\n        max = Math.max(score, max)\n      })\n\n      groups.push([value, max])\n    })\n\n    // Sort items within groups to bottom\n    // Sort items outside of groups\n    // Sort groups to bottom (pushes all non-grouped items to the top)\n    const listInsertionElement = listInnerRef.current\n\n    // Sort the items\n    getValidItems()\n      .sort((a, b) => {\n        const valueA = a.getAttribute('id')\n        const valueB = b.getAttribute('id')\n        return (scores.get(valueB) ?? 0) - (scores.get(valueA) ?? 0)\n      })\n      .forEach((item) => {\n        const group = item.closest(GROUP_ITEMS_SELECTOR)\n\n        if (group) {\n          group.appendChild(item.parentElement === group ? item : item.closest(`${GROUP_ITEMS_SELECTOR} > *`))\n        } else {\n          listInsertionElement.appendChild(\n            item.parentElement === listInsertionElement ? item : item.closest(`${GROUP_ITEMS_SELECTOR} > *`),\n          )\n        }\n      })\n\n    groups\n      .sort((a, b) => b[1] - a[1])\n      .forEach((group) => {\n        const element = listInnerRef.current?.querySelector(\n          `${GROUP_SELECTOR}[${VALUE_ATTR}=\"${encodeURIComponent(group[0])}\"]`,\n        )\n        element?.parentElement.appendChild(element)\n      })\n  }\n\n  function selectFirstItem() {\n    const item = getValidItems().find((item) => item.getAttribute('aria-disabled') !== 'true')\n    const value = item?.getAttribute(VALUE_ATTR)\n    store.setState('value', value || undefined)\n  }\n\n  /** Filters the current items. */\n  function filterItems() {\n    if (\n      !state.current.search ||\n      // Explicitly false, because true | undefined is the default\n      propsRef.current.shouldFilter === false\n    ) {\n      state.current.filtered.count = allItems.current.size\n      // Do nothing, each item will know to show itself because search is empty\n      return\n    }\n\n    // Reset the groups\n    state.current.filtered.groups = new Set()\n    let itemCount = 0\n\n    // Check which items should be included\n    for (const id of allItems.current) {\n      const value = ids.current.get(id)?.value ?? ''\n      const keywords = ids.current.get(id)?.keywords ?? []\n      const rank = score(value, keywords)\n      state.current.filtered.items.set(id, rank)\n      if (rank > 0) itemCount++\n    }\n\n    // Check which groups have at least 1 item shown\n    for (const [groupId, group] of allGroups.current) {\n      for (const itemId of group) {\n        if (state.current.filtered.items.get(itemId) > 0) {\n          state.current.filtered.groups.add(groupId)\n          break\n        }\n      }\n    }\n\n    state.current.filtered.count = itemCount\n  }\n\n  function scrollSelectedIntoView() {\n    const item = getSelectedItem()\n\n    if (item) {\n      if (item.parentElement?.firstChild === item) {\n        // First item in Group, ensure heading is in view\n        item.closest(GROUP_SELECTOR)?.querySelector(GROUP_HEADING_SELECTOR)?.scrollIntoView({ block: 'nearest' })\n      }\n\n      // Ensure the item is always in view\n      item.scrollIntoView({ block: 'nearest' })\n    }\n  }\n\n  /** Getters */\n\n  function getSelectedItem() {\n    return listInnerRef.current?.querySelector(`${ITEM_SELECTOR}[aria-selected=\"true\"]`)\n  }\n\n  function getValidItems() {\n    return Array.from(listInnerRef.current?.querySelectorAll(VALID_ITEM_SELECTOR) || [])\n  }\n\n  /** Setters */\n\n  function updateSelectedToIndex(index: number) {\n    const items = getValidItems()\n    const item = items[index]\n    if (item) store.setState('value', item.getAttribute(VALUE_ATTR))\n  }\n\n  function updateSelectedByItem(change: 1 | -1) {\n    const selected = getSelectedItem()\n    const items = getValidItems()\n    const index = items.findIndex((item) => item === selected)\n\n    // Get item at this index\n    let newSelected = items[index + change]\n\n    if (propsRef.current?.loop) {\n      newSelected =\n        index + change < 0\n          ? items[items.length - 1]\n          : index + change === items.length\n          ? items[0]\n          : items[index + change]\n    }\n\n    if (newSelected) store.setState('value', newSelected.getAttribute(VALUE_ATTR))\n  }\n\n  function updateSelectedByGroup(change: 1 | -1) {\n    const selected = getSelectedItem()\n    let group = selected?.closest(GROUP_SELECTOR)\n    let item: HTMLElement\n\n    while (group && !item) {\n      group = change > 0 ? findNextSibling(group, GROUP_SELECTOR) : findPreviousSibling(group, GROUP_SELECTOR)\n      item = group?.querySelector(VALID_ITEM_SELECTOR)\n    }\n\n    if (item) {\n      store.setState('value', item.getAttribute(VALUE_ATTR))\n    } else {\n      updateSelectedByItem(change)\n    }\n  }\n\n  const last = () => updateSelectedToIndex(getValidItems().length - 1)\n\n  const next = (e: React.KeyboardEvent) => {\n    e.preventDefault()\n\n    if (e.metaKey) {\n      // Last item\n      last()\n    } else if (e.altKey) {\n      // Next group\n      updateSelectedByGroup(1)\n    } else {\n      // Next item\n      updateSelectedByItem(1)\n    }\n  }\n\n  const prev = (e: React.KeyboardEvent) => {\n    e.preventDefault()\n\n    if (e.metaKey) {\n      // First item\n      updateSelectedToIndex(0)\n    } else if (e.altKey) {\n      // Previous group\n      updateSelectedByGroup(-1)\n    } else {\n      // Previous item\n      updateSelectedByItem(-1)\n    }\n  }\n\n  return (\n    <Primitive.div\n      ref={forwardedRef}\n      tabIndex={-1}\n      {...etc}\n      cmdk-root=\"\"\n      onKeyDown={(e) => {\n        etc.onKeyDown?.(e)\n\n        // Check if IME composition is finished before triggering key binds\n        // This prevents unwanted triggering while user is still inputting text with IME\n        // e.keyCode === 229 is for the CJK IME with Legacy Browser [https://w3c.github.io/uievents/#determine-keydown-keyup-keyCode]\n        // isComposing is for the CJK IME with Modern Browser [https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent/isComposing]\n        const isComposing = e.nativeEvent.isComposing || e.keyCode === 229\n\n        if (e.defaultPrevented || isComposing) {\n          return\n        }\n\n        switch (e.key) {\n          case 'n':\n          case 'j': {\n            // vim keybind down\n            if (vimBindings && e.ctrlKey) {\n              next(e)\n            }\n            break\n          }\n          case 'ArrowDown': {\n            next(e)\n            break\n          }\n          case 'p':\n          case 'k': {\n            // vim keybind up\n            if (vimBindings && e.ctrlKey) {\n              prev(e)\n            }\n            break\n          }\n          case 'ArrowUp': {\n            prev(e)\n            break\n          }\n          case 'Home': {\n            // First item\n            e.preventDefault()\n            updateSelectedToIndex(0)\n            break\n          }\n          case 'End': {\n            // Last item\n            e.preventDefault()\n            last()\n            break\n          }\n          case 'Enter': {\n            // Trigger item onSelect\n            e.preventDefault()\n            const item = getSelectedItem()\n            if (item) {\n              const event = new Event(SELECT_EVENT)\n              item.dispatchEvent(event)\n            }\n          }\n        }\n      }}\n    >\n      <label\n        cmdk-label=\"\"\n        htmlFor={context.inputId}\n        id={context.labelId}\n        // Screen reader only\n        style={srOnlyStyles}\n      >\n        {label}\n      </label>\n      {SlottableWithNestedChildren(props, (child) => (\n        <StoreContext.Provider value={store}>\n          <CommandContext.Provider value={context}>{child}</CommandContext.Provider>\n        </StoreContext.Provider>\n      ))}\n    </Primitive.div>\n  )\n})\n\n/**\n * Command menu item. Becomes active on pointer enter or through keyboard navigation.\n * Preferably pass a `value`, otherwise the value will be inferred from `children` or\n * the rendered item's `textContent`.\n */\nconst Item = React.forwardRef<HTMLDivElement, ItemProps>((props, forwardedRef) => {\n  const id = useId()\n  const ref = React.useRef<HTMLDivElement>(null)\n  const groupContext = React.useContext(GroupContext)\n  const context = useCommand()\n  const propsRef = useAsRef(props)\n  const forceMount = propsRef.current?.forceMount ?? groupContext?.forceMount\n\n  useLayoutEffect(() => {\n    if (!forceMount) {\n      return context.item(id, groupContext?.id)\n    }\n  }, [forceMount])\n\n  const value = useValue(id, ref, [props.value, props.children, ref], props.keywords)\n\n  const store = useStore()\n  const selected = useCmdk((state) => state.value && state.value === value.current)\n  const render = useCmdk((state) =>\n    forceMount ? true : context.filter() === false ? true : !state.search ? true : state.filtered.items.get(id) > 0,\n  )\n\n  React.useEffect(() => {\n    const element = ref.current\n    if (!element || props.disabled) return\n    element.addEventListener(SELECT_EVENT, onSelect)\n    return () => element.removeEventListener(SELECT_EVENT, onSelect)\n  }, [render, props.onSelect, props.disabled])\n\n  function onSelect() {\n    select()\n    propsRef.current.onSelect?.(value.current)\n  }\n\n  function select() {\n    store.setState('value', value.current, true)\n  }\n\n  if (!render) return null\n\n  const { disabled, value: _, onSelect: __, forceMount: ___, keywords: ____, ...etc } = props\n\n  return (\n    <Primitive.div\n      ref={composeRefs(ref, forwardedRef)}\n      {...etc}\n      id={id}\n      cmdk-item=\"\"\n      role=\"option\"\n      aria-disabled={Boolean(disabled)}\n      aria-selected={Boolean(selected)}\n      data-disabled={Boolean(disabled)}\n      data-selected={Boolean(selected)}\n      onPointerMove={disabled || context.getDisablePointerSelection() ? undefined : select}\n      onClick={disabled ? undefined : onSelect}\n    >\n      {props.children}\n    </Primitive.div>\n  )\n})\n\n/**\n * Group command menu items together with a heading.\n * Grouped items are always shown together.\n */\nconst Group = React.forwardRef<HTMLDivElement, GroupProps>((props, forwardedRef) => {\n  const { heading, children, forceMount, ...etc } = props\n  const id = useId()\n  const ref = React.useRef<HTMLDivElement>(null)\n  const headingRef = React.useRef<HTMLDivElement>(null)\n  const headingId = useId()\n  const context = useCommand()\n  const render = useCmdk((state) =>\n    forceMount ? true : context.filter() === false ? true : !state.search ? true : state.filtered.groups.has(id),\n  )\n\n  useLayoutEffect(() => {\n    return context.group(id)\n  }, [])\n\n  useValue(id, ref, [props.value, props.heading, headingRef])\n\n  const contextValue = React.useMemo(() => ({ id, forceMount }), [forceMount])\n\n  return (\n    <Primitive.div\n      ref={composeRefs(ref, forwardedRef)}\n      {...etc}\n      cmdk-group=\"\"\n      role=\"presentation\"\n      hidden={render ? undefined : true}\n    >\n      {heading && (\n        <div ref={headingRef} cmdk-group-heading=\"\" aria-hidden id={headingId}>\n          {heading}\n        </div>\n      )}\n      {SlottableWithNestedChildren(props, (child) => (\n        <div cmdk-group-items=\"\" role=\"group\" aria-labelledby={heading ? headingId : undefined}>\n          <GroupContext.Provider value={contextValue}>{child}</GroupContext.Provider>\n        </div>\n      ))}\n    </Primitive.div>\n  )\n})\n\n/**\n * A visual and semantic separator between items or groups.\n * Visible when the search query is empty or `alwaysRender` is true, hidden otherwise.\n */\nconst Separator = React.forwardRef<HTMLDivElement, SeparatorProps>((props, forwardedRef) => {\n  const { alwaysRender, ...etc } = props\n  const ref = React.useRef<HTMLDivElement>(null)\n  const render = useCmdk((state) => !state.search)\n\n  if (!alwaysRender && !render) return null\n  return <Primitive.div ref={composeRefs(ref, forwardedRef)} {...etc} cmdk-separator=\"\" role=\"separator\" />\n})\n\n/**\n * Command menu input.\n * All props are forwarded to the underyling `input` element.\n */\nconst Input = React.forwardRef<HTMLInputElement, InputProps>((props, forwardedRef) => {\n  const { onValueChange, ...etc } = props\n  const isControlled = props.value != null\n  const store = useStore()\n  const search = useCmdk((state) => state.search)\n  const selectedItemId = useCmdk((state) => state.selectedItemId)\n  const context = useCommand()\n\n  React.useEffect(() => {\n    if (props.value != null) {\n      store.setState('search', props.value)\n    }\n  }, [props.value])\n\n  return (\n    <Primitive.input\n      ref={forwardedRef}\n      {...etc}\n      cmdk-input=\"\"\n      autoComplete=\"off\"\n      autoCorrect=\"off\"\n      spellCheck={false}\n      aria-autocomplete=\"list\"\n      role=\"combobox\"\n      aria-expanded={true}\n      aria-controls={context.listId}\n      aria-labelledby={context.labelId}\n      aria-activedescendant={selectedItemId}\n      id={context.inputId}\n      type=\"text\"\n      value={isControlled ? props.value : search}\n      onChange={(e) => {\n        if (!isControlled) {\n          store.setState('search', e.target.value)\n        }\n\n        onValueChange?.(e.target.value)\n      }}\n    />\n  )\n})\n\n/**\n * Contains `Item`, `Group`, and `Separator`.\n * Use the `--cmdk-list-height` CSS variable to animate height based on the number of results.\n */\nconst List = React.forwardRef<HTMLDivElement, ListProps>((props, forwardedRef) => {\n  const { children, label = 'Suggestions', ...etc } = props\n  const ref = React.useRef<HTMLDivElement>(null)\n  const height = React.useRef<HTMLDivElement>(null)\n  const selectedItemId = useCmdk((state) => state.selectedItemId)\n  const context = useCommand()\n\n  React.useEffect(() => {\n    if (height.current && ref.current) {\n      const el = height.current\n      const wrapper = ref.current\n      let animationFrame\n      const observer = new ResizeObserver(() => {\n        animationFrame = requestAnimationFrame(() => {\n          const height = el.offsetHeight\n          wrapper.style.setProperty(`--cmdk-list-height`, height.toFixed(1) + 'px')\n        })\n      })\n      observer.observe(el)\n      return () => {\n        cancelAnimationFrame(animationFrame)\n        observer.unobserve(el)\n      }\n    }\n  }, [])\n\n  return (\n    <Primitive.div\n      ref={composeRefs(ref, forwardedRef)}\n      {...etc}\n      cmdk-list=\"\"\n      role=\"listbox\"\n      tabIndex={-1}\n      aria-activedescendant={selectedItemId}\n      aria-label={label}\n      id={context.listId}\n    >\n      {SlottableWithNestedChildren(props, (child) => (\n        <div ref={composeRefs(height, context.listInnerRef)} cmdk-list-sizer=\"\">\n          {child}\n        </div>\n      ))}\n    </Primitive.div>\n  )\n})\n\n/**\n * Renders the command menu in a Radix Dialog.\n */\nconst Dialog = React.forwardRef<HTMLDivElement, DialogProps>((props, forwardedRef) => {\n  const { open, onOpenChange, overlayClassName, contentClassName, container, ...etc } = props\n  return (\n    <RadixDialog.Root open={open} onOpenChange={onOpenChange}>\n      <RadixDialog.Portal container={container}>\n        <RadixDialog.Overlay cmdk-overlay=\"\" className={overlayClassName} />\n        <RadixDialog.Content aria-label={props.label} cmdk-dialog=\"\" className={contentClassName}>\n          <Command ref={forwardedRef} {...etc} />\n        </RadixDialog.Content>\n      </RadixDialog.Portal>\n    </RadixDialog.Root>\n  )\n})\n\n/**\n * Automatically renders when there are no results for the search query.\n */\nconst Empty = React.forwardRef<HTMLDivElement, EmptyProps>((props, forwardedRef) => {\n  const render = useCmdk((state) => state.filtered.count === 0)\n\n  if (!render) return null\n  return <Primitive.div ref={forwardedRef} {...props} cmdk-empty=\"\" role=\"presentation\" />\n})\n\n/**\n * You should conditionally render this with `progress` while loading asynchronous items.\n */\nconst Loading = React.forwardRef<HTMLDivElement, LoadingProps>((props, forwardedRef) => {\n  const { progress, children, label = 'Loading...', ...etc } = props\n\n  return (\n    <Primitive.div\n      ref={forwardedRef}\n      {...etc}\n      cmdk-loading=\"\"\n      role=\"progressbar\"\n      aria-valuenow={progress}\n      aria-valuemin={0}\n      aria-valuemax={100}\n      aria-label={label}\n    >\n      {SlottableWithNestedChildren(props, (child) => (\n        <div aria-hidden>{child}</div>\n      ))}\n    </Primitive.div>\n  )\n})\n\nconst pkg = Object.assign(Command, {\n  List,\n  Item,\n  Input,\n  Group,\n  Separator,\n  Dialog,\n  Empty,\n  Loading,\n})\n\nexport { useCmdk as useCommandState }\nexport { pkg as Command }\nexport { defaultFilter }\n\nexport { Command as CommandRoot }\nexport { List as CommandList }\nexport { Item as CommandItem }\nexport { Input as CommandInput }\nexport { Group as CommandGroup }\nexport { Separator as CommandSeparator }\nexport { Dialog as CommandDialog }\nexport { Empty as CommandEmpty }\nexport { Loading as CommandLoading }\n\n/**\n *\n *\n * Helpers\n *\n *\n */\n\nfunction findNextSibling(el: Element, selector: string) {\n  let sibling = el.nextElementSibling\n\n  while (sibling) {\n    if (sibling.matches(selector)) return sibling\n    sibling = sibling.nextElementSibling\n  }\n}\n\nfunction findPreviousSibling(el: Element, selector: string) {\n  let sibling = el.previousElementSibling\n\n  while (sibling) {\n    if (sibling.matches(selector)) return sibling\n    sibling = sibling.previousElementSibling\n  }\n}\n\nfunction useAsRef<T>(data: T) {\n  const ref = React.useRef<T>(data)\n\n  useLayoutEffect(() => {\n    ref.current = data\n  })\n\n  return ref\n}\n\nconst useLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect\n\nfunction useLazyRef<T>(fn: () => T) {\n  const ref = React.useRef<T>()\n\n  if (ref.current === undefined) {\n    ref.current = fn()\n  }\n\n  return ref as React.MutableRefObject<T>\n}\n\n/** Run a selector against the store state. */\nfunction useCmdk<T = any>(selector: (state: State) => T): T {\n  const store = useStore()\n  const cb = () => selector(store.snapshot())\n  return React.useSyncExternalStore(store.subscribe, cb, cb)\n}\n\nfunction useValue(\n  id: string,\n  ref: React.RefObject<HTMLElement>,\n  deps: (string | React.ReactNode | React.RefObject<HTMLElement>)[],\n  aliases: string[] = [],\n) {\n  const valueRef = React.useRef<string>()\n  const context = useCommand()\n\n  useLayoutEffect(() => {\n    const value = (() => {\n      for (const part of deps) {\n        if (typeof part === 'string') {\n          return part.trim()\n        }\n\n        if (typeof part === 'object' && 'current' in part) {\n          if (part.current) {\n            return part.current.textContent?.trim()\n          }\n          return valueRef.current\n        }\n      }\n    })()\n\n    const keywords = aliases.map((alias) => alias.trim())\n\n    context.value(id, value, keywords)\n    ref.current?.setAttribute(VALUE_ATTR, value)\n    valueRef.current = value\n  })\n\n  return valueRef\n}\n\n/** Imperatively run a function on the next layout effect cycle. */\nconst useScheduleLayoutEffect = () => {\n  const [s, ss] = React.useState<object>()\n  const fns = useLazyRef(() => new Map<string | number, () => void>())\n\n  useLayoutEffect(() => {\n    fns.current.forEach((f) => f())\n    fns.current = new Map()\n  }, [s])\n\n  return (id: string | number, cb: () => void) => {\n    fns.current.set(id, cb)\n    ss({})\n  }\n}\n\nfunction renderChildren(children: React.ReactElement) {\n  const childrenType = children.type as any\n  // The children is a component\n  if (typeof childrenType === 'function') return childrenType(children.props)\n  // The children is a component with `forwardRef`\n  else if ('render' in childrenType) return childrenType.render(children.props)\n  // It's a string, boolean, etc.\n  else return children\n}\n\nfunction SlottableWithNestedChildren(\n  { asChild, children }: { asChild?: boolean; children?: React.ReactNode },\n  render: (child: React.ReactNode) => JSX.Element,\n) {\n  if (asChild && React.isValidElement(children)) {\n    return React.cloneElement(renderChildren(children), { ref: (children as any).ref }, render(children.props.children))\n  }\n  return render(children)\n}\n\nconst srOnlyStyles = {\n  position: 'absolute',\n  width: '1px',\n  height: '1px',\n  padding: '0',\n  margin: '-1px',\n  overflow: 'hidden',\n  clip: 'rect(0, 0, 0, 0)',\n  whiteSpace: 'nowrap',\n  borderWidth: '0',\n} as const\n"
  },
  {
    "path": "cmdk/tsup.config.ts",
    "content": "import { defineConfig } from 'tsup'\n\nexport default defineConfig({\n  sourcemap: false,\n  minify: true,\n  dts: true,\n  format: ['esm', 'cjs'],\n  loader: {\n    '.js': 'jsx',\n  },\n})\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"cmdk-root\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"pnpm -F cmdk build\",\n    \"dev\": \"pnpm -F cmdk build --watch\",\n    \"website\": \"pnpm -F cmdk-website dev\",\n    \"testsite\": \"pnpm -F cmdk-tests dev\",\n    \"format\": \"prettier '**/*.{js,jsx,ts,tsx,json,md,mdx,css,scss,yaml,yml}' --write\",\n    \"preinstall\": \"npx only-allow pnpm\",\n    \"test:format\": \"prettier '**/*.{js,jsx,ts,tsx,json,md,mdx,css,scss,yaml,yml}' --check\",\n    \"test\": \"playwright test\"\n  },\n  \"devDependencies\": {\n    \"@playwright/test\": \"1.51.0\",\n    \"husky\": \"^8.0.1\",\n    \"lint-staged\": \"15.2.0\",\n    \"prettier\": \"2.7.1\",\n    \"tsup\": \"8.0.1\",\n    \"typescript\": \"4.6.4\"\n  },\n  \"packageManager\": \"pnpm@8.8.0\",\n  \"lint-staged\": {\n    \"**/*.{js,jsx,ts,tsx,json,md,mdx,css,scss,yaml,yml}\": [\n      \"prettier --write\"\n    ]\n  }\n}\n"
  },
  {
    "path": "playwright.config.ts",
    "content": "import { PlaywrightTestConfig, devices } from '@playwright/test'\n\nconst config: PlaywrightTestConfig = {\n  forbidOnly: !!process.env.CI,\n  retries: process.env.CI ? 2 : 0,\n  reporter: process.env.CI ? [['github'], ['json', { outputFile: 'playwright-report.json' }]] : 'list',\n  testDir: './test',\n  use: {\n    trace: 'on-first-retry',\n    baseURL: 'http://localhost:3000',\n  },\n  timeout: 5000,\n  webServer: {\n    command: 'npm run dev',\n    url: 'http://localhost:3000',\n    cwd: './test',\n    reuseExistingServer: !process.env.CI,\n  },\n  projects: [\n    {\n      name: 'webkit',\n      use: { ...devices['Desktop Safari'], headless: true },\n    },\n  ],\n}\n\nexport default config\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - 'website'\n  - 'test'\n  - 'cmdk'\n"
  },
  {
    "path": "test/basic.test.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('basic behavior', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/')\n  })\n\n  test('input props are forwarded', async ({ page }) => {\n    const input = page.locator(`input[placeholder=\"Search…\"]`)\n    await expect(input).toHaveCount(1)\n  })\n\n  test('item value is derived from textContent', async ({ page }) => {\n    const item = page.locator(`[cmdk-item][data-value=\"Item\"]`)\n    await expect(item).toHaveText('Item')\n  })\n\n  test('item value prop is preferred over textContent', async ({ page }) => {\n    const item = page.locator(`[cmdk-item][data-value=\"xxx\"]`)\n    await expect(item).toHaveText('Value')\n  })\n\n  test('item onSelect is called on click', async ({ page }) => {\n    const item = page.locator(`[cmdk-item][data-value=\"Item\"]`)\n    await item.click()\n    expect(await page.evaluate(() => (window as any).onSelect)).toEqual('Item selected')\n  })\n\n  test('first item is selected by default', async ({ page }) => {\n    const item = page.locator(`[cmdk-item][aria-selected=\"true\"]`)\n    await expect(item).toHaveText('Item')\n  })\n\n  test('first item is selected when search changes', async ({ page }) => {\n    const input = page.locator(`[cmdk-input]`)\n    await input.type('x')\n    const selected = page.locator(`[cmdk-item][aria-selected=\"true\"]`)\n    await expect(selected).toHaveText('Value')\n  })\n\n  test('items filter when searching', async ({ page }) => {\n    const input = page.locator(`[cmdk-input]`)\n    await input.type('x')\n    const removed = page.locator(`[cmdk-item][data-value=\"Item\"]`)\n    const remains = page.locator(`[cmdk-item][data-value=\"xxx\"]`)\n    await expect(removed).toHaveCount(0)\n    await expect(remains).toHaveCount(1)\n  })\n\n  test('items filter when searching by keywords', async ({ page }) => {\n    const input = page.locator(`[cmdk-input]`)\n    await input.type('key')\n    const removed = page.locator(`[cmdk-item][data-value=\"xxx\"]`)\n    const remains = page.locator(`[cmdk-item][data-value=\"Item\"]`)\n    await expect(removed).toHaveCount(0)\n    await expect(remains).toHaveCount(1)\n  })\n\n  test('empty component renders when there are no results', async ({ page }) => {\n    const input = page.locator('[cmdk-input]')\n    await input.type('z')\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(0)\n    await expect(page.locator(`[cmdk-empty]`)).toHaveText('No results.')\n  })\n\n  test('className is applied to each part', async ({ page }) => {\n    await expect(page.locator(`.root`)).toHaveCount(1)\n    await expect(page.locator(`.input`)).toHaveCount(1)\n    await expect(page.locator(`.list`)).toHaveCount(1)\n    await expect(page.locator(`.item`)).toHaveCount(2)\n    await page.locator('[cmdk-input]').type('zzzz')\n    await expect(page.locator(`.item`)).toHaveCount(0)\n    await expect(page.locator(`.empty`)).toHaveCount(1)\n  })\n})\n"
  },
  {
    "path": "test/dialog.test.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('dialog', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/dialog')\n  })\n\n  test('dialog renders in portal', async ({ page }) => {\n    await expect(page.locator(`[cmdk-dialog]`)).toHaveCount(1)\n    await expect(page.locator(`[cmdk-overlay]`)).toHaveCount(1)\n  })\n})\n"
  },
  {
    "path": "test/group.test.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('group', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/group')\n  })\n\n  test('groups are shown/hidden based on item matches', async ({ page }) => {\n    await page.locator(`[cmdk-input]`).type('z')\n    await expect(page.locator(`[cmdk-group][data-value=\"Animals\"]`)).not.toBeVisible()\n    await expect(page.locator(`[cmdk-group][data-value=\"Letters\"]`)).toBeVisible()\n  })\n\n  test('group can be progressively rendered', async ({ page }) => {\n    await expect(page.locator(`[cmdk-group][data-value=\"Numbers\"]`)).not.toBeVisible()\n    await page.locator(`[cmdk-input]`).type('t')\n    await expect(page.locator(`[cmdk-group][data-value=\"Animals\"]`)).not.toBeVisible()\n    await expect(page.locator(`[cmdk-group][data-value=\"Letters\"]`)).not.toBeVisible()\n    await expect(page.locator(`[cmdk-group][data-value=\"Numbers\"]`)).toBeVisible()\n  })\n\n  test('mounted group still rendered with filter using forceMount', async ({ page }) => {\n    await page.locator(`data-testid=forceMount`).click()\n    await page.locator(`[cmdk-input]`).type('Giraffe')\n    await expect(page.locator(`[cmdk-group][data-value=\"Letters\"]`)).toBeVisible()\n  })\n})\n"
  },
  {
    "path": "test/item.test.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('item', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/item')\n  })\n\n  test('mounted item matches search', async ({ page }) => {\n    await page.locator(`[cmdk-input]`).type('b')\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(0)\n    await page.locator(`data-testid=mount`).click()\n    await expect(page.locator(`[cmdk-item]`)).toHaveText('B')\n  })\n\n  test('mounted item does not match search', async ({ page }) => {\n    await page.locator(`[cmdk-input]`).type('z')\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(0)\n    await page.locator(`data-testid=mount`).click()\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(0)\n  })\n\n  test('unmount item that is selected', async ({ page }) => {\n    await page.locator(`data-testid=mount`).click()\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveText('A')\n    await page.locator(`data-testid=unmount`).click()\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(1)\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveText('B')\n  })\n\n  test('unmount item that is the only result', async ({ page }) => {\n    await page.locator(`data-testid=unmount`).click()\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(0)\n  })\n\n  test('mount item that is the only result', async ({ page }) => {\n    await page.locator(`data-testid=unmount`).click()\n    await expect(page.locator(`[cmdk-empty]`)).toHaveCount(1)\n    await page.locator(`data-testid=mount`).click()\n    await expect(page.locator(`[cmdk-empty]`)).toHaveCount(0)\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(1)\n  })\n\n  test('selected does not change when mounting new items', async ({ page }) => {\n    await page.locator(`data-testid=mount`).click()\n    await page.locator(`[cmdk-item][data-value=\"B\"]`).click()\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveText('B')\n    await page.locator(`data-testid=many`).click()\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveText('B')\n  })\n\n  test('mounted item still rendered with filter usingForceMount', async ({ page }) => {\n    await page.locator(`data-testid=forceMount`).click()\n    await page.locator(`[cmdk-input]`).type('z')\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(1)\n  })\n})\n\ntest.describe('item advanced', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/item-advanced')\n  })\n\n  test('re-rendering re-matches implicit textContent value', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(2)\n    await page.locator(`[cmdk-input]`).type('2')\n    const button = page.locator(`data-testid=increment`)\n    await button.click()\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(0)\n    await button.click()\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(2)\n  })\n})\n"
  },
  {
    "path": "test/keybind.test.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('arrow keybinds', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/keybinds')\n  })\n\n  test('arrow up/down changes selected item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('ArrowDown')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('ArrowUp')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n\n  test('meta arrow up/down goes to first and last item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Meta+ArrowDown')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'last')\n    await page.locator(`[cmdk-input]`).press('Meta+ArrowUp')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n\n  test('alt arrow up/down goes to next and prev item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Alt+ArrowDown')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Alt+ArrowDown')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'Apple')\n    await page.locator(`[cmdk-input]`).press('Alt+ArrowUp')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Alt+ArrowUp')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n})\n\ntest.describe('vim jk keybinds', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/keybinds')\n  })\n\n  test('ctrl j/k changes selected item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Control+j')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Control+k')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n\n  test('meta ctrl j/k goes to first and last item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Meta+Control+j')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'last')\n    await page.locator(`[cmdk-input]`).press('Meta+Control+k')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n\n  test('alt ctrl j/k goes to next and prev item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+j')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+j')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'Apple')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+k')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+k')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n})\n\ntest.describe('vim np keybinds', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/keybinds')\n  })\n\n  test('ctrl n/p changes selected item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Control+n')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Control+p')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n\n  test('meta ctrl n/p goes to first and last item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Meta+Control+n')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'last')\n    await page.locator(`[cmdk-input]`).press('Meta+Control+p')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n\n  test('alt ctrl n/p goes to next and prev item', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+n')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+n')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'Apple')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+p')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'A')\n    await page.locator(`[cmdk-input]`).press('Alt+Control+p')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n})\n\ntest.describe('no-vim keybinds', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/keybinds?noVim=true')\n  })\n\n  test('ctrl j/k does nothing', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Control+j')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Control+k')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n\n  test('ctrl n/p does nothing', async ({ page }) => {\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Control+n')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n    await page.locator(`[cmdk-input]`).press('Control+p')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'first')\n  })\n})\n"
  },
  {
    "path": "test/next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/basic-features/typescript for more information.\n"
  },
  {
    "path": "test/numeric.test.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('behavior for numeric values', async () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/numeric')\n  })\n\n  test('items filter correctly on numeric inputs', async ({ page }) => {\n    const input = page.locator(`[cmdk-input]`)\n    await input.type('112')\n    const removed = page.locator(`[cmdk-item][data-value=\"removed\"]`)\n    const remains = page.locator(`[cmdk-item][data-value=\"foo.bar112.value\"]`)\n    await expect(removed).toHaveCount(0)\n    await expect(remains).toHaveCount(1)\n  })\n\n  test('items filter correctly on non-numeric inputs', async ({ page }) => {\n    const input = page.locator(`[cmdk-input]`)\n    await input.type('bar')\n    const removed = page.locator(`[cmdk-item][data-value=\"removed\"]`)\n    const remains = page.locator(`[cmdk-item][data-value=\"foo.bar112.value\"]`)\n    await expect(removed).toHaveCount(0)\n    await expect(remains).toHaveCount(1)\n  })\n})\n"
  },
  {
    "path": "test/package.json",
    "content": "{\n  \"name\": \"cmdk-tests\",\n  \"version\": \"0.0.0\",\n  \"scripts\": {\n    \"dev\": \"next\"\n  },\n  \"dependencies\": {\n    \"@radix-ui/react-portal\": \"^1.0.4\",\n    \"@types/node\": \"18.0.4\",\n    \"@types/react\": \"18.0.15\",\n    \"@types/react-dom\": \"18.0.6\",\n    \"cmdk\": \"workspace:*\",\n    \"next\": \"13.5.1\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\",\n    \"typescript\": \"4.7.4\"\n  }\n}\n"
  },
  {
    "path": "test/pages/_app.tsx",
    "content": "import '../style.css'\n\nexport default function App({ Component, pageProps }) {\n  return <Component {...pageProps} />\n}\n"
  },
  {
    "path": "test/pages/dialog.tsx",
    "content": "import { Command } from 'cmdk'\nimport * as React from 'react'\n\nconst Page = () => {\n  const [open, setOpen] = React.useState(false)\n\n  React.useEffect(() => {\n    setOpen(true)\n  }, [])\n\n  return (\n    <div>\n      <Command.Dialog open={open} onOpenChange={setOpen}>\n        <Command.Input placeholder=\"Search…\" />\n        <Command.List>\n          <Command.Empty>No results.</Command.Empty>\n          <Command.Item onSelect={() => console.log('Item selected')}>Item</Command.Item>\n          <Command.Item value=\"xxx\">Value</Command.Item>\n        </Command.List>\n      </Command.Dialog>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/group.tsx",
    "content": "import { Command } from 'cmdk'\nimport * as React from 'react'\n\nconst Page = () => {\n  const [search, setSearch] = React.useState('')\n  const [forceMount, setForceMount] = React.useState(false)\n\n  return (\n    <div>\n      <button data-testid=\"forceMount\" onClick={() => setForceMount(!forceMount)}>\n        Force mount Group Letters\n      </button>\n\n      <Command>\n        <Command.Input placeholder=\"Search…\" value={search} onValueChange={setSearch} />\n        <Command.List>\n          <Command.Empty>No results.</Command.Empty>\n          <Command.Group heading=\"Animals\">\n            <Command.Item>Giraffe</Command.Item>\n            <Command.Item>Chicken</Command.Item>\n          </Command.Group>\n\n          <Command.Group forceMount={forceMount} heading=\"Letters\">\n            <Command.Item>A</Command.Item>\n            <Command.Item>B</Command.Item>\n            <Command.Item>Z</Command.Item>\n          </Command.Group>\n\n          {!!search && (\n            <Command.Group heading=\"Numbers\">\n              <Command.Item>One</Command.Item>\n              <Command.Item>Two</Command.Item>\n              <Command.Item>Three</Command.Item>\n            </Command.Group>\n          )}\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/huge.tsx",
    "content": "import { Command } from 'cmdk'\nimport * as React from 'react'\n\nconst items = new Array(1000).fill(0)\n\nconst Page = () => {\n  return (\n    <div>\n      <React.Profiler\n        id=\"huge-command\"\n        onRender={(id, phase, actualDuration, baseDuration, startTime, commitTime, interactions) => {\n          console.log({ phase, actualDuration, baseDuration })\n        }}\n      >\n        <Command>\n          <Command.Input placeholder=\"Search…\" />\n          <Command.List>\n            {items.map((_, i) => {\n              return <Item key={`item-${i}`} />\n            })}\n          </Command.List>\n        </Command>\n      </React.Profiler>\n    </div>\n  )\n}\n\nconst Item = () => {\n  const id = React.useId()\n\n  return <Command.Item key={id}>Item {id}</Command.Item>\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/index.tsx",
    "content": "import { Command } from 'cmdk'\n\nconst Page = () => {\n  return (\n    <div>\n      <Command className=\"root\">\n        <Command.Input placeholder=\"Search…\" className=\"input\" />\n        <Command.List className=\"list\">\n          <Command.Empty className=\"empty\">No results.</Command.Empty>\n          <Command.Item\n            keywords={['key']}\n            onSelect={() => {\n              ;(window as any).onSelect = 'Item selected'\n            }}\n            className=\"item\"\n          >\n            Item\n          </Command.Item>\n          <Command.Item value=\"xxx\" className=\"item\">\n            Value\n          </Command.Item>\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/item-advanced.tsx",
    "content": "import { Command } from 'cmdk'\nimport * as React from 'react'\n\nconst Page = () => {\n  const [count, setCount] = React.useState(0)\n\n  return (\n    <div>\n      <button data-testid=\"increment\" onClick={() => setCount((c) => c + 1)}>\n        Increment count\n      </button>\n\n      <Command>\n        <Command.Input placeholder=\"Search…\" />\n        <Command.List>\n          <Command.Empty>No results.</Command.Empty>\n          <Command.Item value={`Item A ${count}`}>Item A {count}</Command.Item>\n          <Command.Item value={`Item B ${count}`}>Item B {count}</Command.Item>\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/item.tsx",
    "content": "import { Command } from 'cmdk'\nimport * as React from 'react'\n\nconst Page = () => {\n  const [unmount, setUnmount] = React.useState(false)\n  const [mount, setMount] = React.useState(false)\n  const [many, setMany] = React.useState(false)\n  const [forceMount, setForceMount] = React.useState(false)\n\n  return (\n    <div>\n      <button data-testid=\"mount\" onClick={() => setMount(!mount)}>\n        Toggle item B\n      </button>\n\n      <button data-testid=\"unmount\" onClick={() => setUnmount(!unmount)}>\n        Toggle item A\n      </button>\n\n      <button data-testid=\"many\" onClick={() => setMany(!many)}>\n        Toggle many items\n      </button>\n\n      <button data-testid=\"forceMount\" onClick={() => setForceMount(!forceMount)}>\n        Force mount item A\n      </button>\n\n      <Command>\n        <Command.Input placeholder=\"Search…\" />\n        <Command.List>\n          <Command.Empty>No results.</Command.Empty>\n          {!unmount && <Command.Item forceMount={forceMount}>A</Command.Item>}\n          {many && (\n            <>\n              <Command.Item>1</Command.Item>\n              <Command.Item>2</Command.Item>\n              <Command.Item>3</Command.Item>\n            </>\n          )}\n          {mount && <Command.Item>B</Command.Item>}\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/keybinds.tsx",
    "content": "import { Command } from 'cmdk'\nimport { useRouter } from 'next/router'\nimport * as React from 'react'\n\nconst Page = () => {\n  const {\n    query: { noVim },\n  } = useRouter()\n  return (\n    <div>\n      <Command vimBindings={!noVim}>\n        <Command.Input />\n        <Command.List>\n          <Command.Empty>No results.</Command.Empty>\n\n          <Command.Item value=\"disabled\" disabled>\n            Disabled\n          </Command.Item>\n\n          <Command.Item value=\"first\">First</Command.Item>\n\n          <Command.Group heading=\"Letters\">\n            <Command.Item>A</Command.Item>\n            <Command.Item>B</Command.Item>\n            <Command.Item>Z</Command.Item>\n          </Command.Group>\n\n          <Command.Group heading=\"Fruits\">\n            <Command.Item>Apple</Command.Item>\n            <Command.Item>Banana</Command.Item>\n            <Command.Item>Orange</Command.Item>\n            <Command.Item disabled>Dragon Fruit</Command.Item>\n            <Command.Item>Pear</Command.Item>\n          </Command.Group>\n\n          <Command.Item value=\"last\">Last</Command.Item>\n\n          <Command.Item value=\"disabled-3\" disabled>\n            Disabled 3\n          </Command.Item>\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/numeric.tsx",
    "content": "import { Command } from 'cmdk'\n\nconst Page = () => {\n  return (\n    <div>\n      <Command className=\"root\">\n        <Command.Input placeholder=\"Search…\" className=\"input\" />\n        <Command.List className=\"list\">\n          <Command.Empty className=\"empty\">No results.</Command.Empty>\n          <Command.Item value=\"removed\" className=\"item\">\n            To be removed\n          </Command.Item>\n          <Command.Item value=\"foo.bar112.value\" className=\"item\">\n            Not to be removed\n          </Command.Item>\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/portal.tsx",
    "content": "import * as React from 'react'\nimport { Command } from 'cmdk'\nimport * as Portal from '@radix-ui/react-portal'\n\nconst Page = () => {\n  const [render, setRender] = React.useState(false)\n  const [search, setSearch] = React.useState('')\n  const [open, setOpen] = React.useState(true)\n  React.useEffect(() => setRender(true), [])\n  if (!render) return null\n\n  return (\n    <div>\n      <button data-testid=\"controlledSearch\" onClick={() => setSearch('eat')}>\n        Change search value\n      </button>\n      <button data-testid=\"openClosePopover\" onClick={() => setOpen((val) => !val)}>\n        {open ? 'Close' : 'Open'}\n      </button>\n      <Command className=\"root\">\n        <Command.Input value={search} onValueChange={setSearch} placeholder=\"Search…\" className=\"input\" />\n\n        <Portal.Root data-portal=\"true\">\n          {open && (\n            <Command.List className=\"list\">\n              <Command.Item className=\"item\">Apple</Command.Item>\n              <Command.Item className=\"item\">Banana</Command.Item>\n              <Command.Item className=\"item\">Cherry</Command.Item>\n              <Command.Item className=\"item\">Dragonfruit</Command.Item>\n              <Command.Item className=\"item\">Elderberry</Command.Item>\n              <Command.Item className=\"item\">Fig</Command.Item>\n              <Command.Item className=\"item\">Grape</Command.Item>\n              <Command.Item className=\"item\">Honeydew</Command.Item>\n              <Command.Item className=\"item\">Jackfruit</Command.Item>\n              <Command.Item className=\"item\">Kiwi</Command.Item>\n              <Command.Item className=\"item\">Lemon</Command.Item>\n              <Command.Item className=\"item\">Mango</Command.Item>\n              <Command.Item className=\"item\">Nectarine</Command.Item>\n              <Command.Item className=\"item\">Orange</Command.Item>\n              <Command.Item className=\"item\">Papaya</Command.Item>\n              <Command.Item className=\"item\">Quince</Command.Item>\n              <Command.Item className=\"item\">Raspberry</Command.Item>\n              <Command.Item className=\"item\">Strawberry</Command.Item>\n              <Command.Item className=\"item\">Tangerine</Command.Item>\n              <Command.Item className=\"item\">Ugli</Command.Item>\n              <Command.Item className=\"item\">Watermelon</Command.Item>\n              <Command.Item className=\"item\">Xigua</Command.Item>\n              <Command.Item className=\"item\">Yuzu</Command.Item>\n              <Command.Item className=\"item\">Zucchini</Command.Item>\n            </Command.List>\n          )}\n        </Portal.Root>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/pages/props.tsx",
    "content": "import { Command } from 'cmdk'\nimport { useRouter } from 'next/router'\nimport * as React from 'react'\n\nconst Page = () => {\n  const [value, setValue] = React.useState('ant')\n  const [search, setSearch] = React.useState('')\n  const [shouldFilter, setShouldFilter] = React.useState(true)\n  const [customFilter, setCustomFilter] = React.useState(false)\n  const router = useRouter()\n\n  React.useEffect(() => {\n    if (router.isReady) {\n      setShouldFilter(router.query.shouldFilter === 'false' ? false : true)\n      setCustomFilter(router.query.customFilter === 'true' ? true : false)\n      setValue((router.query.initialValue as string) ?? 'ant')\n    }\n  }, [router.isReady])\n\n  return (\n    <div>\n      <div data-testid=\"value\">{value}</div>\n      <div data-testid=\"search\">{search}</div>\n\n      <button data-testid=\"controlledValue\" onClick={() => setValue('anteater')}>\n        Change value\n      </button>\n      <button data-testid=\"controlledSearch\" onClick={() => setSearch('eat')}>\n        Change search value\n      </button>\n\n      <Command\n        shouldFilter={shouldFilter}\n        value={value}\n        onValueChange={setValue}\n        filter={\n          customFilter\n            ? (item: string | undefined, search: string | undefined) => {\n                console.log(item, search)\n                if (!search || !item) return 1\n                return item.endsWith(search) ? 1 : 0\n              }\n            : undefined\n        }\n      >\n        <Command.Input placeholder=\"Search…\" value={search} onValueChange={setSearch} />\n        <Command.List>\n          <Command.Item>ant</Command.Item>\n          <Command.Item>anteater</Command.Item>\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "test/props.test.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('props', async () => {\n  test('results do not change when filtering is disabled', async ({ page }) => {\n    await page.goto('/props?shouldFilter=false')\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(2)\n    await page.locator(`[cmdk-input]`).type('z')\n    await expect(page.locator(`[cmdk-item]`)).toHaveCount(2)\n  })\n\n  test('results match against custom filter', async ({ page }) => {\n    await page.goto('/props?customFilter=true')\n    await page.locator(`[cmdk-input]`).type(`ant`)\n    await expect(page.locator(`[cmdk-item]`)).toHaveAttribute('data-value', 'ant')\n  })\n\n  test('controlled value', async ({ page }) => {\n    await page.goto('/props')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'ant')\n    await page.locator(`data-testid=controlledValue`).click()\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'anteater')\n  })\n\n  test('keep controlled value if empty results', async ({ page }) => {\n    await page.goto('/props')\n    await expect(page.locator(`[data-testid=value]`)).toHaveText('ant')\n    await page.locator(`[cmdk-input]`).fill('d')\n    await expect(page.locator(`[data-testid=value]`)).toHaveText('')\n    await page.locator(`[cmdk-input]`).fill('ant')\n    await expect(page.locator(`[data-testid=value]`)).toHaveText('ant')\n  })\n\n  test('controlled search', async ({ page }) => {\n    await page.goto('/props')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'ant')\n    await page.locator(`data-testid=controlledSearch`).click()\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'anteater')\n  })\n\n  test('keep focus on the provided initial value', async ({ page }) => {\n    await page.goto('/props?initialValue=anteater')\n    await expect(page.locator(`[cmdk-item][aria-selected=\"true\"]`)).toHaveAttribute('data-value', 'anteater')\n  })\n})\n"
  },
  {
    "path": "test/style.css",
    "content": "[cmdk-item][aria-selected='true'] {\n  color: red;\n}\n"
  },
  {
    "path": "test/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": false,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"incremental\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\"\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \"../dialog.test.ts\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2018\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": false,\n    \"forceConsistentCasingInFileNames\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"react\",\n    \"noEmit\": true\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \"**/*.js\", \"**/*.jsx\"],\n  \"exclude\": [\"node_modules\", \"build\", \"dist\", \".next\"]\n}\n"
  },
  {
    "path": "website/.eslintrc.json",
    "content": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": "website/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.pnpm-debug.log*\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\n"
  },
  {
    "path": "website/README.md",
    "content": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\npnpm run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\nYou can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.\n\n[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.\n\nThe `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.\n\n## Learn More\n\nTo learn more about Next.js, take a look at the following resources:\n\n- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n\nYou can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!\n\n## Deploy on Vercel\n\nThe easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.\n\nCheck out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.\n"
  },
  {
    "path": "website/components/cmdk/framer.tsx",
    "content": "import { Command } from 'cmdk'\nimport React from 'react'\n\nexport function FramerCMDK() {\n  const [value, setValue] = React.useState('Button')\n  return (\n    <div className=\"framer\">\n      <Command value={value} onValueChange={(v) => setValue(v)}>\n        <div cmdk-framer-header=\"\">\n          <SearchIcon />\n          <Command.Input autoFocus placeholder=\"Find components, packages, and interactions...\" />\n        </div>\n        <Command.List>\n          <div cmdk-framer-items=\"\">\n            <div cmdk-framer-left=\"\">\n              <Command.Group heading=\"Components\">\n                <Item value=\"Button\" subtitle=\"Trigger actions\">\n                  <ButtonIcon />\n                </Item>\n                <Item value=\"Input\" subtitle=\"Retrieve user input\">\n                  <InputIcon />\n                </Item>\n                <Item value=\"Radio\" subtitle=\"Single choice input\">\n                  <RadioIcon />\n                </Item>\n                <Item value=\"Badge\" subtitle=\"Annotate context\">\n                  <BadgeIcon />\n                </Item>\n                <Item value=\"Slider\" subtitle=\"Free range picker\">\n                  <SliderIcon />\n                </Item>\n                <Item value=\"Avatar\" subtitle=\"Illustrate the user\">\n                  <AvatarIcon />\n                </Item>\n                <Item value=\"Container\" subtitle=\"Lay out items\">\n                  <ContainerIcon />\n                </Item>\n              </Command.Group>\n            </div>\n            <hr cmdk-framer-separator=\"\" />\n            <div cmdk-framer-right=\"\">\n              {value === 'Button' && <Button />}\n              {value === 'Input' && <Input />}\n              {value === 'Badge' && <Badge />}\n              {value === 'Radio' && <Radio />}\n              {value === 'Avatar' && <Avatar />}\n              {value === 'Slider' && <Slider />}\n              {value === 'Container' && <Container />}\n            </div>\n          </div>\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nfunction Button() {\n  return <button>Primary</button>\n}\n\nfunction Input() {\n  return <input type=\"text\" placeholder=\"Placeholder\" />\n}\n\nfunction Badge() {\n  return <div cmdk-framer-badge=\"\">Badge</div>\n}\n\nfunction Radio() {\n  return (\n    <label cmdk-framer-radio=\"\">\n      <input type=\"radio\" defaultChecked />\n      Radio Button\n    </label>\n  )\n}\n\nfunction Slider() {\n  return (\n    <div cmdk-framer-slider=\"\">\n      <div />\n    </div>\n  )\n}\n\nfunction Avatar() {\n  return <img src=\"/rauno.jpeg\" alt=\"Avatar of Rauno\" />\n}\n\nfunction Container() {\n  return <div cmdk-framer-container=\"\" />\n}\n\nfunction Item({ children, value, subtitle }: { children: React.ReactNode; value: string; subtitle: string }) {\n  return (\n    <Command.Item value={value} onSelect={() => {}}>\n      <div cmdk-framer-icon-wrapper=\"\">{children}</div>\n      <div cmdk-framer-item-meta=\"\">\n        {value}\n        <span cmdk-framer-item-subtitle=\"\">{subtitle}</span>\n      </div>\n    </Command.Item>\n  )\n}\n\nfunction ButtonIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M2 5H13C13.5523 5 14 5.44772 14 6V9C14 9.55228 13.5523 10 13 10H2C1.44772 10 1 9.55228 1 9V6C1 5.44772 1.44772 5 2 5ZM0 6C0 4.89543 0.895431 4 2 4H13C14.1046 4 15 4.89543 15 6V9C15 10.1046 14.1046 11 13 11H2C0.89543 11 0 10.1046 0 9V6ZM4.5 6.75C4.08579 6.75 3.75 7.08579 3.75 7.5C3.75 7.91421 4.08579 8.25 4.5 8.25C4.91421 8.25 5.25 7.91421 5.25 7.5C5.25 7.08579 4.91421 6.75 4.5 6.75ZM6.75 7.5C6.75 7.08579 7.08579 6.75 7.5 6.75C7.91421 6.75 8.25 7.08579 8.25 7.5C8.25 7.91421 7.91421 8.25 7.5 8.25C7.08579 8.25 6.75 7.91421 6.75 7.5ZM10.5 6.75C10.0858 6.75 9.75 7.08579 9.75 7.5C9.75 7.91421 10.0858 8.25 10.5 8.25C10.9142 8.25 11.25 7.91421 11.25 7.5C11.25 7.08579 10.9142 6.75 10.5 6.75Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n\nfunction InputIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M6.5 1C6.22386 1 6 1.22386 6 1.5C6 1.77614 6.22386 2 6.5 2C7.12671 2 7.45718 2.20028 7.65563 2.47812C7.8781 2.78957 8 3.28837 8 4V11C8 11.7116 7.8781 12.2104 7.65563 12.5219C7.45718 12.7997 7.12671 13 6.5 13C6.22386 13 6 13.2239 6 13.5C6 13.7761 6.22386 14 6.5 14C7.37329 14 8.04282 13.7003 8.46937 13.1031C8.47976 13.0886 8.48997 13.0739 8.5 13.0591C8.51003 13.0739 8.52024 13.0886 8.53063 13.1031C8.95718 13.7003 9.62671 14 10.5 14C10.7761 14 11 13.7761 11 13.5C11 13.2239 10.7761 13 10.5 13C9.87329 13 9.54282 12.7997 9.34437 12.5219C9.1219 12.2104 9 11.7116 9 11V4C9 3.28837 9.1219 2.78957 9.34437 2.47812C9.54282 2.20028 9.87329 2 10.5 2C10.7761 2 11 1.77614 11 1.5C11 1.22386 10.7761 1 10.5 1C9.62671 1 8.95718 1.29972 8.53063 1.89688C8.52024 1.91143 8.51003 1.92611 8.5 1.9409C8.48997 1.92611 8.47976 1.91143 8.46937 1.89688C8.04282 1.29972 7.37329 1 6.5 1ZM14 5H11V4H14C14.5523 4 15 4.44772 15 5V10C15 10.5523 14.5523 11 14 11H11V10H14V5ZM6 4V5H1L1 10H6V11H1C0.447715 11 0 10.5523 0 10V5C0 4.44772 0.447715 4 1 4H6Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n\nfunction RadioIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M7.49985 0.877045C3.84216 0.877045 0.877014 3.84219 0.877014 7.49988C0.877014 11.1575 3.84216 14.1227 7.49985 14.1227C11.1575 14.1227 14.1227 11.1575 14.1227 7.49988C14.1227 3.84219 11.1575 0.877045 7.49985 0.877045ZM1.82701 7.49988C1.82701 4.36686 4.36683 1.82704 7.49985 1.82704C10.6328 1.82704 13.1727 4.36686 13.1727 7.49988C13.1727 10.6329 10.6328 13.1727 7.49985 13.1727C4.36683 13.1727 1.82701 10.6329 1.82701 7.49988ZM7.49999 9.49999C8.60456 9.49999 9.49999 8.60456 9.49999 7.49999C9.49999 6.39542 8.60456 5.49999 7.49999 5.49999C6.39542 5.49999 5.49999 6.39542 5.49999 7.49999C5.49999 8.60456 6.39542 9.49999 7.49999 9.49999Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n\nfunction BadgeIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M3.5 6H11.5C12.3284 6 13 6.67157 13 7.5C13 8.32843 12.3284 9 11.5 9H3.5C2.67157 9 2 8.32843 2 7.5C2 6.67157 2.67157 6 3.5 6ZM1 7.5C1 6.11929 2.11929 5 3.5 5H11.5C12.8807 5 14 6.11929 14 7.5C14 8.88071 12.8807 10 11.5 10H3.5C2.11929 10 1 8.88071 1 7.5ZM4.5 7C4.22386 7 4 7.22386 4 7.5C4 7.77614 4.22386 8 4.5 8H10.5C10.7761 8 11 7.77614 11 7.5C11 7.22386 10.7761 7 10.5 7H4.5Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n\nfunction ToggleIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M10.5 4C8.567 4 7 5.567 7 7.5C7 9.433 8.567 11 10.5 11C12.433 11 14 9.433 14 7.5C14 5.567 12.433 4 10.5 4ZM7.67133 11C6.65183 10.175 6 8.91363 6 7.5C6 6.08637 6.65183 4.82498 7.67133 4H4.5C2.567 4 1 5.567 1 7.5C1 9.433 2.567 11 4.5 11H7.67133ZM0 7.5C0 5.01472 2.01472 3 4.5 3H10.5C12.9853 3 15 5.01472 15 7.5C15 9.98528 12.9853 12 10.5 12H4.5C2.01472 12 0 9.98528 0 7.5Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n\nfunction AvatarIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M0.877014 7.49988C0.877014 3.84219 3.84216 0.877045 7.49985 0.877045C11.1575 0.877045 14.1227 3.84219 14.1227 7.49988C14.1227 11.1575 11.1575 14.1227 7.49985 14.1227C3.84216 14.1227 0.877014 11.1575 0.877014 7.49988ZM7.49985 1.82704C4.36683 1.82704 1.82701 4.36686 1.82701 7.49988C1.82701 8.97196 2.38774 10.3131 3.30727 11.3213C4.19074 9.94119 5.73818 9.02499 7.50023 9.02499C9.26206 9.02499 10.8093 9.94097 11.6929 11.3208C12.6121 10.3127 13.1727 8.97172 13.1727 7.49988C13.1727 4.36686 10.6328 1.82704 7.49985 1.82704ZM10.9818 11.9787C10.2839 10.7795 8.9857 9.97499 7.50023 9.97499C6.01458 9.97499 4.71624 10.7797 4.01845 11.9791C4.97952 12.7272 6.18765 13.1727 7.49985 13.1727C8.81227 13.1727 10.0206 12.727 10.9818 11.9787ZM5.14999 6.50487C5.14999 5.207 6.20212 4.15487 7.49999 4.15487C8.79786 4.15487 9.84999 5.207 9.84999 6.50487C9.84999 7.80274 8.79786 8.85487 7.49999 8.85487C6.20212 8.85487 5.14999 7.80274 5.14999 6.50487ZM7.49999 5.10487C6.72679 5.10487 6.09999 5.73167 6.09999 6.50487C6.09999 7.27807 6.72679 7.90487 7.49999 7.90487C8.27319 7.90487 8.89999 7.27807 8.89999 6.50487C8.89999 5.73167 8.27319 5.10487 7.49999 5.10487Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n\nfunction ContainerIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M2 1.5C2 1.77614 1.77614 2 1.5 2C1.22386 2 1 1.77614 1 1.5C1 1.22386 1.22386 1 1.5 1C1.77614 1 2 1.22386 2 1.5ZM5 13H10V2L5 2L5 13ZM4 13C4 13.5523 4.44772 14 5 14H10C10.5523 14 11 13.5523 11 13V2C11 1.44772 10.5523 1 10 1H5C4.44772 1 4 1.44771 4 2V13ZM13.5 2C13.7761 2 14 1.77614 14 1.5C14 1.22386 13.7761 1 13.5 1C13.2239 1 13 1.22386 13 1.5C13 1.77614 13.2239 2 13.5 2ZM2 3.5C2 3.77614 1.77614 4 1.5 4C1.22386 4 1 3.77614 1 3.5C1 3.22386 1.22386 3 1.5 3C1.77614 3 2 3.22386 2 3.5ZM13.5 4C13.7761 4 14 3.77614 14 3.5C14 3.22386 13.7761 3 13.5 3C13.2239 3 13 3.22386 13 3.5C13 3.77614 13.2239 4 13.5 4ZM2 5.5C2 5.77614 1.77614 6 1.5 6C1.22386 6 1 5.77614 1 5.5C1 5.22386 1.22386 5 1.5 5C1.77614 5 2 5.22386 2 5.5ZM13.5 6C13.7761 6 14 5.77614 14 5.5C14 5.22386 13.7761 5 13.5 5C13.2239 5 13 5.22386 13 5.5C13 5.77614 13.2239 6 13.5 6ZM2 7.5C2 7.77614 1.77614 8 1.5 8C1.22386 8 1 7.77614 1 7.5C1 7.22386 1.22386 7 1.5 7C1.77614 7 2 7.22386 2 7.5ZM13.5 8C13.7761 8 14 7.77614 14 7.5C14 7.22386 13.7761 7 13.5 7C13.2239 7 13 7.22386 13 7.5C13 7.77614 13.2239 8 13.5 8ZM2 9.5C2 9.77614 1.77614 10 1.5 10C1.22386 10 1 9.77614 1 9.5C1 9.22386 1.22386 9 1.5 9C1.77614 9 2 9.22386 2 9.5ZM13.5 10C13.7761 10 14 9.77614 14 9.5C14 9.22386 13.7761 9 13.5 9C13.2239 9 13 9.22386 13 9.5C13 9.77614 13.2239 10 13.5 10ZM2 11.5C2 11.7761 1.77614 12 1.5 12C1.22386 12 1 11.7761 1 11.5C1 11.2239 1.22386 11 1.5 11C1.77614 11 2 11.2239 2 11.5ZM13.5 12C13.7761 12 14 11.7761 14 11.5C14 11.2239 13.7761 11 13.5 11C13.2239 11 13 11.2239 13 11.5C13 11.7761 13.2239 12 13.5 12ZM2 13.5C2 13.7761 1.77614 14 1.5 14C1.22386 14 1 13.7761 1 13.5C1 13.2239 1.22386 13 1.5 13C1.77614 13 2 13.2239 2 13.5ZM13.5 14C13.7761 14 14 13.7761 14 13.5C14 13.2239 13.7761 13 13.5 13C13.2239 13 13 13.2239 13 13.5C13 13.7761 13.2239 14 13.5 14Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n\nfunction SearchIcon() {\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      className=\"h-6 w-6\"\n      fill=\"none\"\n      viewBox=\"0 0 24 24\"\n      stroke=\"currentColor\"\n      strokeWidth={1.5}\n    >\n      <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n    </svg>\n  )\n}\n\nfunction SliderIcon() {\n  return (\n    <svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M10.3004 7.49991C10.3004 8.4943 9.49426 9.30041 8.49988 9.30041C7.50549 9.30041 6.69938 8.4943 6.69938 7.49991C6.69938 6.50553 7.50549 5.69942 8.49988 5.69942C9.49426 5.69942 10.3004 6.50553 10.3004 7.49991ZM11.205 8C10.9699 9.28029 9.84816 10.2504 8.49988 10.2504C7.1516 10.2504 6.0299 9.28029 5.79473 8H0.5C0.223858 8 0 7.77614 0 7.5C0 7.22386 0.223858 7 0.5 7H5.7947C6.0298 5.71962 7.15154 4.74942 8.49988 4.74942C9.84822 4.74942 10.97 5.71962 11.2051 7H14.5C14.7761 7 15 7.22386 15 7.5C15 7.77614 14.7761 8 14.5 8H11.205Z\"\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n      ></path>\n    </svg>\n  )\n}\n"
  },
  {
    "path": "website/components/cmdk/linear.tsx",
    "content": "import { Command } from 'cmdk'\n\nexport function LinearCMDK() {\n  return (\n    <div className=\"linear\">\n      <Command>\n        <div cmdk-linear-badge=\"\">Issue - FUN-343</div>\n        <Command.Input autoFocus placeholder=\"Type a command or search...\" />\n        <Command.List>\n          <Command.Empty>No results found.</Command.Empty>\n          {items.map(({ icon, label, shortcut }) => {\n            return (\n              <Command.Item key={label} value={label}>\n                {icon}\n                {label}\n                <div cmdk-linear-shortcuts=\"\">\n                  {shortcut.map((key) => {\n                    return <kbd key={key}>{key}</kbd>\n                  })}\n                </div>\n              </Command.Item>\n            )\n          })}\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nconst items = [\n  {\n    icon: <AssignToIcon />,\n    label: 'Assign to...',\n    shortcut: ['A'],\n  },\n  {\n    icon: <AssignToMeIcon />,\n    label: 'Assign to me',\n    shortcut: ['I'],\n  },\n  {\n    icon: <ChangeStatusIcon />,\n    label: 'Change status...',\n    shortcut: ['S'],\n  },\n  {\n    icon: <ChangePriorityIcon />,\n    label: 'Change priority...',\n    shortcut: ['P'],\n  },\n  {\n    icon: <ChangeLabelsIcon />,\n    label: 'Change labels...',\n    shortcut: ['L'],\n  },\n  {\n    icon: <RemoveLabelIcon />,\n    label: 'Remove label...',\n    shortcut: ['⇧', 'L'],\n  },\n  {\n    icon: <SetDueDateIcon />,\n    label: 'Set due date...',\n    shortcut: ['⇧', 'D'],\n  },\n]\n\nfunction AssignToIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n      <path d=\"M7 7a2.5 2.5 0 10.001-4.999A2.5 2.5 0 007 7zm0 1c-1.335 0-4 .893-4 2.667v.666c0 .367.225.667.5.667h2.049c.904-.909 2.417-1.911 4.727-2.009v-.72a.27.27 0 01.007-.063C9.397 8.404 7.898 8 7 8zm4.427 2.028a.266.266 0 01.286.032l2.163 1.723a.271.271 0 01.013.412l-2.163 1.97a.27.27 0 01-.452-.2v-.956c-3.328.133-5.282 1.508-5.287 1.535a.27.27 0 01-.266.227h-.022a.27.27 0 01-.249-.271c0-.046 1.549-3.328 5.824-3.509v-.72a.27.27 0 01.153-.243z\" />\n    </svg>\n  )\n}\n\nfunction AssignToMeIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n      <path d=\"M7.00003 7C8.38128 7 9.50003 5.88125 9.50003 4.5C9.50003 3.11875 8.38128 2 7.00003 2C5.61878 2 4.50003 3.11875 4.50003 4.5C4.50003 5.88125 5.61878 7 7.00003 7Z\" />\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M7.00005 8C5.66505 8 3.00006 8.89333 3.00006 10.6667V11.3333C3.00006 11.7 3.22506 12 3.50006 12H3.98973C4.01095 11.9415 4.04535 11.8873 4.09266 11.8425L7.21783 8.88444C7.28966 8.81658 7.38297 8.77917 7.4796 8.77949C7.69459 8.78018 7.86826 8.96356 7.86753 9.1891L7.86214 10.629C9.00553 10.5858 10.0366 10.4354 10.9441 10.231C10.5539 8.74706 8.22087 8 7.00005 8Z\"\n      />\n      <path d=\"M6.72511 14.718C6.80609 14.7834 6.91767 14.7955 7.01074 14.749C7.10407 14.7036 7.16321 14.6087 7.16295 14.5047L7.1605 13.7849C11.4352 13.5894 12.9723 10.3023 12.9722 10.2563C12.9722 10.1147 12.8634 9.9971 12.7225 9.98626L12.7009 9.98634C12.5685 9.98689 12.4561 10.0833 12.4351 10.2142C12.4303 10.2413 10.4816 11.623 7.15364 11.7666L7.1504 10.8116C7.14981 10.662 7.02829 10.5412 6.87896 10.5418C6.81184 10.5421 6.74721 10.5674 6.69765 10.6127L4.54129 12.5896C4.43117 12.6906 4.42367 12.862 4.52453 12.9723C4.53428 12.9829 4.54488 12.9928 4.55621 13.0018L6.72511 14.718Z\" />\n    </svg>\n  )\n}\n\nfunction ChangeStatusIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" viewBox=\"-1 -1 15 15\" fill=\"currentColor\">\n      <path d=\"M10.5714 7C10.5714 8.97245 8.97245 10.5714 7 10.5714L6.99975 3.42857C8.9722 3.42857 10.5714 5.02755 10.5714 7Z\" />\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M7 12.5C10.0376 12.5 12.5 10.0376 12.5 7C12.5 3.96243 10.0376 1.5 7 1.5C3.96243 1.5 1.5 3.96243 1.5 7C1.5 10.0376 3.96243 12.5 7 12.5ZM7 14C10.866 14 14 10.866 14 7C14 3.13401 10.866 0 7 0C3.13401 0 0 3.13401 0 7C0 10.866 3.13401 14 7 14Z\"\n      />\n    </svg>\n  )\n}\n\nfunction ChangePriorityIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n      <rect x=\"1\" y=\"8\" width=\"3\" height=\"6\" rx=\"1\"></rect>\n      <rect x=\"6\" y=\"5\" width=\"3\" height=\"9\" rx=\"1\"></rect>\n      <rect x=\"11\" y=\"2\" width=\"3\" height=\"12\" rx=\"1\"></rect>\n    </svg>\n  )\n}\n\nfunction ChangeLabelsIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M10.2105 4C10.6337 4 11.0126 4.18857 11.24 4.48L14 8L11.24 11.52C11.0126 11.8114 10.6337 12 10.2105 12L3.26316 11.9943C2.56842 11.9943 2 11.4857 2 10.8571V5.14286C2 4.51429 2.56842 4.00571 3.26316 4.00571L10.2105 4ZM11.125 9C11.6773 9 12.125 8.55228 12.125 8C12.125 7.44772 11.6773 7 11.125 7C10.5727 7 10.125 7.44772 10.125 8C10.125 8.55228 10.5727 9 11.125 9Z\"\n      />\n    </svg>\n  )\n}\n\nfunction RemoveLabelIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M10.2105 4C10.6337 4 11.0126 4.18857 11.24 4.48L14 8L11.24 11.52C11.0126 11.8114 10.6337 12 10.2105 12L3.26316 11.9943C2.56842 11.9943 2 11.4857 2 10.8571V5.14286C2 4.51429 2.56842 4.00571 3.26316 4.00571L10.2105 4ZM11.125 9C11.6773 9 12.125 8.55228 12.125 8C12.125 7.44772 11.6773 7 11.125 7C10.5727 7 10.125 7.44772 10.125 8C10.125 8.55228 10.5727 9 11.125 9Z\"\n      />\n    </svg>\n  )\n}\n\nfunction SetDueDateIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M15 5C15 2.79086 13.2091 1 11 1H5C2.79086 1 1 2.79086 1 5V11C1 13.2091 2.79086 15 5 15H6.25C6.66421 15 7 14.6642 7 14.25C7 13.8358 6.66421 13.5 6.25 13.5H5C3.61929 13.5 2.5 12.3807 2.5 11V6H13.5V6.25C13.5 6.66421 13.8358 7 14.25 7C14.6642 7 15 6.66421 15 6.25V5ZM11.5001 8C11.9143 8 12.2501 8.33579 12.2501 8.75V10.75L14.2501 10.75C14.6643 10.75 15.0001 11.0858 15.0001 11.5C15.0001 11.9142 14.6643 12.25 14.2501 12.25L12.2501 12.25V14.25C12.2501 14.6642 11.9143 15 11.5001 15C11.0859 15 10.7501 14.6642 10.7501 14.25V12.25H8.75C8.33579 12.25 8 11.9142 8 11.5C8 11.0858 8.33579 10.75 8.75 10.75L10.7501 10.75V8.75C10.7501 8.33579 11.0859 8 11.5001 8Z\"\n      />\n    </svg>\n  )\n}\n"
  },
  {
    "path": "website/components/cmdk/raycast.tsx",
    "content": "import React from 'react'\nimport { useTheme } from 'next-themes'\nimport * as Popover from '@radix-ui/react-popover'\nimport { Command } from 'cmdk'\nimport { Logo, LinearIcon, FigmaIcon, SlackIcon, YouTubeIcon, RaycastIcon } from 'components'\n\nexport function RaycastCMDK() {\n  const { resolvedTheme: theme } = useTheme()\n  const [value, setValue] = React.useState('linear')\n  const inputRef = React.useRef<HTMLInputElement | null>(null)\n  const listRef = React.useRef(null)\n\n  React.useEffect(() => {\n    inputRef?.current?.focus()\n  }, [])\n\n  return (\n    <div className=\"raycast\">\n      <Command value={value} onValueChange={(v) => setValue(v)}>\n        <div cmdk-raycast-top-shine=\"\" />\n        <Command.Input ref={inputRef} autoFocus placeholder=\"Search for apps and commands...\" />\n        <hr cmdk-raycast-loader=\"\" />\n        <Command.List ref={listRef}>\n          <Command.Empty>No results found.</Command.Empty>\n          <Command.Group heading=\"Suggestions\">\n            <Item value=\"Linear\" keywords={['issue', 'sprint']}>\n              <Logo>\n                <LinearIcon\n                  style={{\n                    width: 12,\n                    height: 12,\n                  }}\n                />\n              </Logo>\n              Linear\n            </Item>\n            <Item value=\"Figma\" keywords={['design', 'ui', 'ux']}>\n              <Logo>\n                <FigmaIcon />\n              </Logo>\n              Figma\n            </Item>\n            <Item value=\"Slack\" keywords={['chat', 'team', 'communication']}>\n              <Logo>\n                <SlackIcon />\n              </Logo>\n              Slack\n            </Item>\n            <Item value=\"YouTube\" keywords={['video', 'watch', 'stream']}>\n              <Logo>\n                <YouTubeIcon />\n              </Logo>\n              YouTube\n            </Item>\n            <Item value=\"Raycast\" keywords={['productivity', 'tools', 'apps']}>\n              <Logo>\n                <RaycastIcon />\n              </Logo>\n              Raycast\n            </Item>\n          </Command.Group>\n          <Command.Group heading=\"Commands\">\n            <Item isCommand value=\"Clipboard History\" keywords={['copy', 'paste', 'clipboard']}>\n              <Logo>\n                <ClipboardIcon />\n              </Logo>\n              Clipboard History\n            </Item>\n            <Item isCommand value=\"Import Extension\" keywords={['import', 'extension']}>\n              <HammerIcon />\n              Import Extension\n            </Item>\n            <Item isCommand value=\"Manage Extensions\" keywords={['manage', 'extension']}>\n              <HammerIcon />\n              Manage Extensions\n            </Item>\n          </Command.Group>\n        </Command.List>\n\n        <div cmdk-raycast-footer=\"\">\n          {theme === 'dark' ? <RaycastDarkIcon /> : <RaycastLightIcon />}\n\n          <button cmdk-raycast-open-trigger=\"\">\n            Open Application\n            <kbd>↵</kbd>\n          </button>\n\n          <hr />\n\n          <SubCommand listRef={listRef} selectedValue={value} inputRef={inputRef} />\n        </div>\n      </Command>\n    </div>\n  )\n}\n\nfunction Item({\n  children,\n  value,\n  keywords,\n  isCommand = false,\n}: {\n  children: React.ReactNode\n  value: string\n  keywords?: string[]\n  isCommand?: boolean\n}) {\n  return (\n    <Command.Item value={value} keywords={keywords} onSelect={() => {}}>\n      {children}\n      <span cmdk-raycast-meta=\"\">{isCommand ? 'Command' : 'Application'}</span>\n    </Command.Item>\n  )\n}\n\nfunction SubCommand({\n  inputRef,\n  listRef,\n  selectedValue,\n}: {\n  inputRef: React.RefObject<HTMLInputElement>\n  listRef: React.RefObject<HTMLElement>\n  selectedValue: string\n}) {\n  const [open, setOpen] = React.useState(false)\n\n  React.useEffect(() => {\n    function listener(e: KeyboardEvent) {\n      if (e.key === 'k' && e.metaKey) {\n        e.preventDefault()\n        setOpen((o) => !o)\n      }\n    }\n\n    document.addEventListener('keydown', listener)\n\n    return () => {\n      document.removeEventListener('keydown', listener)\n    }\n  }, [])\n\n  React.useEffect(() => {\n    const el = listRef.current\n\n    if (!el) return\n\n    if (open) {\n      el.style.overflow = 'hidden'\n    } else {\n      el.style.overflow = ''\n    }\n  }, [open, listRef])\n\n  return (\n    <Popover.Root open={open} onOpenChange={setOpen} modal>\n      <Popover.Trigger cmdk-raycast-subcommand-trigger=\"\" onClick={() => setOpen(true)} aria-expanded={open}>\n        Actions\n        <kbd>⌘</kbd>\n        <kbd>K</kbd>\n      </Popover.Trigger>\n      <Popover.Content\n        side=\"top\"\n        align=\"end\"\n        className=\"raycast-submenu\"\n        sideOffset={16}\n        alignOffset={0}\n        onCloseAutoFocus={(e) => {\n          e.preventDefault()\n          inputRef?.current?.focus()\n        }}\n      >\n        <Command>\n          <Command.List>\n            <Command.Group heading={selectedValue}>\n              <SubItem shortcut=\"↵\">\n                <WindowIcon />\n                Open Application\n              </SubItem>\n              <SubItem shortcut=\"⌘ ↵\">\n                <FinderIcon />\n                Show in Finder\n              </SubItem>\n              <SubItem shortcut=\"⌘ I\">\n                <FinderIcon />\n                Show Info in Finder\n              </SubItem>\n              <SubItem shortcut=\"⌘ ⇧ F\">\n                <StarIcon />\n                Add to Favorites\n              </SubItem>\n            </Command.Group>\n          </Command.List>\n          <Command.Input placeholder=\"Search for actions...\" />\n        </Command>\n      </Popover.Content>\n    </Popover.Root>\n  )\n}\n\nfunction SubItem({ children, shortcut }: { children: React.ReactNode; shortcut: string }) {\n  return (\n    <Command.Item>\n      {children}\n      <div cmdk-raycast-submenu-shortcuts=\"\">\n        {shortcut.split(' ').map((key) => {\n          return <kbd key={key}>{key}</kbd>\n        })}\n      </div>\n    </Command.Item>\n  )\n}\n\nfunction TerminalIcon() {\n  return (\n    <svg\n      width=\"24\"\n      height=\"24\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n    >\n      <polyline points=\"4 17 10 11 4 5\"></polyline>\n      <line x1=\"12\" y1=\"19\" x2=\"20\" y2=\"19\"></line>\n    </svg>\n  )\n}\n\nfunction RaycastLightIcon() {\n  return (\n    <svg width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M934.302 511.971L890.259 556.017L723.156 388.902V300.754L934.302 511.971ZM511.897 89.5373L467.854 133.583L634.957 300.698H723.099L511.897 89.5373ZM417.334 184.275L373.235 228.377L445.776 300.923H533.918L417.334 184.275ZM723.099 490.061V578.209L795.641 650.755L839.74 606.652L723.099 490.061ZM697.868 653.965L723.099 628.732H395.313V300.754L370.081 325.987L322.772 278.675L278.56 322.833L325.869 370.146L300.638 395.379V446.071L228.097 373.525L183.997 417.627L300.638 534.275V634.871L133.59 467.925L89.4912 512.027L511.897 934.461L555.996 890.359L388.892 723.244H489.875L606.516 839.892L650.615 795.79L578.074 723.244H628.762L653.994 698.011L701.303 745.323L745.402 701.221L697.868 653.965Z\"\n        fill=\"#FF6363\"\n      />\n    </svg>\n  )\n}\n\nfunction RaycastDarkIcon() {\n  return (\n    <svg width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M301.144 634.799V722.856L90 511.712L134.244 467.804L301.144 634.799ZM389.201 722.856H301.144L512.288 934L556.34 889.996L389.201 722.856ZM889.996 555.956L934 511.904L512.096 90L468.092 134.052L634.799 300.952H534.026L417.657 184.679L373.605 228.683L446.065 301.144H395.631V628.561H723.048V577.934L795.509 650.395L839.561 606.391L723.048 489.878V389.105L889.996 555.956ZM323.17 278.926L279.166 322.978L326.385 370.198L370.39 326.145L323.17 278.926ZM697.855 653.61L653.994 697.615L701.214 744.834L745.218 700.782L697.855 653.61ZM228.731 373.413L184.679 417.465L301.144 533.93V445.826L228.731 373.413ZM578.174 722.856H490.07L606.535 839.321L650.587 795.269L578.174 722.856Z\"\n        fill=\"#FF6363\"\n      />\n    </svg>\n  )\n}\n\nfunction WindowIcon() {\n  return (\n    <svg width=\"32\" height=\"32\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M14.25 4.75V3.75C14.25 2.64543 13.3546 1.75 12.25 1.75H3.75C2.64543 1.75 1.75 2.64543 1.75 3.75V4.75M14.25 4.75V12.25C14.25 13.3546 13.3546 14.25 12.25 14.25H3.75C2.64543 14.25 1.75 13.3546 1.75 12.25V4.75M14.25 4.75H1.75\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n    </svg>\n  )\n}\n\nfunction FinderIcon() {\n  return (\n    <svg width=\"32\" height=\"32\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M5 4.75V6.25M11 4.75V6.25M8.75 1.75H3.75C2.64543 1.75 1.75 2.64543 1.75 3.75V12.25C1.75 13.3546 2.64543 14.25 3.75 14.25H8.75M8.75 1.75H12.25C13.3546 1.75 14.25 2.64543 14.25 3.75V12.25C14.25 13.3546 13.3546 14.25 12.25 14.25H8.75M8.75 1.75L7.08831 7.1505C6.9202 7.69686 7.32873 8.25 7.90037 8.25C8.36961 8.25 8.75 8.63039 8.75 9.09963V14.25M5 10.3203C5 10.3203 5.95605 11.25 8 11.25C10.0439 11.25 11 10.3203 11 10.3203\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n    </svg>\n  )\n}\n\nfunction StarIcon() {\n  return (\n    <svg width=\"32\" height=\"32\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M7.43376 2.17103C7.60585 1.60966 8.39415 1.60966 8.56624 2.17103L9.61978 5.60769C9.69652 5.85802 9.92611 6.02873 10.186 6.02873H13.6562C14.2231 6.02873 14.4665 6.75397 14.016 7.10088L11.1582 9.3015C10.9608 9.45349 10.8784 9.71341 10.9518 9.95262L12.0311 13.4735C12.2015 14.0292 11.5636 14.4777 11.1051 14.1246L8.35978 12.0106C8.14737 11.847 7.85263 11.847 7.64022 12.0106L4.89491 14.1246C4.43638 14.4777 3.79852 14.0292 3.96889 13.4735L5.04824 9.95262C5.12157 9.71341 5.03915 9.45349 4.84178 9.3015L1.98404 7.10088C1.53355 6.75397 1.77692 6.02873 2.34382 6.02873H5.81398C6.07389 6.02873 6.30348 5.85802 6.38022 5.60769L7.43376 2.17103Z\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n    </svg>\n  )\n}\n\nfunction ClipboardIcon() {\n  return (\n    <div cmdk-raycast-clipboard-icon=\"\">\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path\n          d=\"M6.07512 2.75H4.75C3.64543 2.75 2.75 3.64543 2.75 4.75V12.25C2.75 13.3546 3.64543 14.25 4.75 14.25H11.25C12.3546 14.25 13.25 13.3546 13.25 12.25V4.75C13.25 3.64543 12.3546 2.75 11.25 2.75H9.92488M9.88579 3.02472L9.5934 4.04809C9.39014 4.75952 8.73989 5.25 8 5.25V5.25C7.26011 5.25 6.60986 4.75952 6.4066 4.04809L6.11421 3.02472C5.93169 2.38591 6.41135 1.75 7.07573 1.75H8.92427C9.58865 1.75 10.0683 2.3859 9.88579 3.02472Z\"\n          stroke=\"currentColor\"\n          strokeWidth=\"1.5\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n      </svg>\n    </div>\n  )\n}\n\nfunction HammerIcon() {\n  return (\n    <div cmdk-raycast-hammer-icon=\"\">\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path\n          d=\"M6.73762 6.19288L2.0488 11.2217C1.6504 11.649 1.6504 12.3418 2.0488 12.769L3.13083 13.9295C3.52923 14.3568 4.17515 14.3568 4.57355 13.9295L9.26238 8.90071M6.73762 6.19288L7.0983 5.80605C7.4967 5.37877 7.4967 4.686 7.0983 4.25872L6.01627 3.09822L6.37694 2.71139C7.57213 1.42954 9.50991 1.42954 10.7051 2.71139L13.9512 6.19288C14.3496 6.62017 14.3496 7.31293 13.9512 7.74021L12.8692 8.90071C12.4708 9.328 11.8248 9.328 11.4265 8.90071L11.0658 8.51388C10.6674 8.0866 10.0215 8.0866 9.62306 8.51388L9.26238 8.90071M6.73762 6.19288L9.26238 8.90071\"\n          stroke=\"currentColor\"\n          strokeWidth=\"1.5\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n      </svg>\n    </div>\n  )\n}\n"
  },
  {
    "path": "website/components/cmdk/vercel.tsx",
    "content": "import React from 'react'\nimport { Command } from 'cmdk'\n\nexport function VercelCMDK() {\n  const ref = React.useRef<HTMLDivElement | null>(null)\n  const [inputValue, setInputValue] = React.useState('')\n\n  const [pages, setPages] = React.useState<string[]>(['home'])\n  const activePage = pages[pages.length - 1]\n  const isHome = activePage === 'home'\n\n  const popPage = React.useCallback(() => {\n    setPages((pages) => {\n      const x = [...pages]\n      x.splice(-1, 1)\n      return x\n    })\n  }, [])\n\n  const onKeyDown = React.useCallback(\n    (e: KeyboardEvent) => {\n      if (isHome || inputValue.length) {\n        return\n      }\n\n      if (e.key === 'Backspace') {\n        e.preventDefault()\n        popPage()\n      }\n    },\n    [inputValue.length, isHome, popPage],\n  )\n\n  function bounce() {\n    if (ref.current) {\n      ref.current.style.transform = 'scale(0.96)'\n      setTimeout(() => {\n        if (ref.current) {\n          ref.current.style.transform = ''\n        }\n      }, 100)\n\n      setInputValue('')\n    }\n  }\n\n  return (\n    <div className=\"vercel\">\n      <Command\n        ref={ref}\n        onKeyDown={(e: React.KeyboardEvent) => {\n          if (e.key === 'Enter') {\n            bounce()\n          }\n\n          if (isHome || inputValue.length) {\n            return\n          }\n\n          if (e.key === 'Backspace') {\n            e.preventDefault()\n            popPage()\n            bounce()\n          }\n        }}\n      >\n        <div>\n          {pages.map((p) => (\n            <div key={p} cmdk-vercel-badge=\"\">\n              {p}\n            </div>\n          ))}\n        </div>\n        <Command.Input\n          autoFocus\n          placeholder=\"What do you need?\"\n          onValueChange={(value) => {\n            setInputValue(value)\n          }}\n        />\n        <Command.List>\n          <Command.Empty>No results found.</Command.Empty>\n          {activePage === 'home' && <Home searchProjects={() => setPages([...pages, 'projects'])} />}\n          {activePage === 'projects' && <Projects />}\n        </Command.List>\n      </Command>\n    </div>\n  )\n}\n\nfunction Home({ searchProjects }: { searchProjects: Function }) {\n  return (\n    <>\n      <Command.Group heading=\"Projects\">\n        <Item\n          shortcut=\"S P\"\n          onSelect={() => {\n            searchProjects()\n          }}\n        >\n          <ProjectsIcon />\n          Search Projects...\n        </Item>\n        <Item>\n          <PlusIcon />\n          Create New Project...\n        </Item>\n      </Command.Group>\n      <Command.Group heading=\"Teams\">\n        <Item shortcut=\"⇧ P\">\n          <TeamsIcon />\n          Search Teams...\n        </Item>\n        <Item>\n          <PlusIcon />\n          Create New Team...\n        </Item>\n      </Command.Group>\n      <Command.Group heading=\"Help\">\n        <Item shortcut=\"⇧ D\">\n          <DocsIcon />\n          Search Docs...\n        </Item>\n        <Item>\n          <FeedbackIcon />\n          Send Feedback...\n        </Item>\n        <Item>\n          <ContactIcon />\n          Contact Support\n        </Item>\n      </Command.Group>\n    </>\n  )\n}\n\nfunction Projects() {\n  return (\n    <>\n      <Item>Project 1</Item>\n      <Item>Project 2</Item>\n      <Item>Project 3</Item>\n      <Item>Project 4</Item>\n      <Item>Project 5</Item>\n      <Item>Project 6</Item>\n    </>\n  )\n}\n\nfunction Item({\n  children,\n  shortcut,\n  onSelect = () => {},\n}: {\n  children: React.ReactNode\n  shortcut?: string\n  onSelect?: (value: string) => void\n}) {\n  return (\n    <Command.Item onSelect={onSelect}>\n      {children}\n      {shortcut && (\n        <div cmdk-vercel-shortcuts=\"\">\n          {shortcut.split(' ').map((key) => {\n            return <kbd key={key}>{key}</kbd>\n          })}\n        </div>\n      )}\n    </Command.Item>\n  )\n}\n\nfunction ProjectsIcon() {\n  return (\n    <svg\n      fill=\"none\"\n      height=\"24\"\n      shapeRendering=\"geometricPrecision\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n    >\n      <path d=\"M3 3h7v7H3z\"></path>\n      <path d=\"M14 3h7v7h-7z\"></path>\n      <path d=\"M14 14h7v7h-7z\"></path>\n      <path d=\"M3 14h7v7H3z\"></path>\n    </svg>\n  )\n}\n\nfunction PlusIcon() {\n  return (\n    <svg\n      fill=\"none\"\n      height=\"24\"\n      shapeRendering=\"geometricPrecision\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n    >\n      <path d=\"M12 5v14\"></path>\n      <path d=\"M5 12h14\"></path>\n    </svg>\n  )\n}\n\nfunction TeamsIcon() {\n  return (\n    <svg\n      fill=\"none\"\n      height=\"24\"\n      shapeRendering=\"geometricPrecision\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n    >\n      <path d=\"M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2\"></path>\n      <circle cx=\"9\" cy=\"7\" r=\"4\"></circle>\n      <path d=\"M23 21v-2a4 4 0 00-3-3.87\"></path>\n      <path d=\"M16 3.13a4 4 0 010 7.75\"></path>\n    </svg>\n  )\n}\n\nfunction CopyIcon() {\n  return (\n    <svg\n      fill=\"none\"\n      height=\"24\"\n      shapeRendering=\"geometricPrecision\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n    >\n      <path d=\"M8 17.929H6c-1.105 0-2-.912-2-2.036V5.036C4 3.91 4.895 3 6 3h8c1.105 0 2 .911 2 2.036v1.866m-6 .17h8c1.105 0 2 .91 2 2.035v10.857C20 21.09 19.105 22 18 22h-8c-1.105 0-2-.911-2-2.036V9.107c0-1.124.895-2.036 2-2.036z\"></path>\n    </svg>\n  )\n}\n\nfunction DocsIcon() {\n  return (\n    <svg\n      fill=\"none\"\n      height=\"24\"\n      shapeRendering=\"geometricPrecision\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n    >\n      <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"></path>\n      <path d=\"M14 2v6h6\"></path>\n      <path d=\"M16 13H8\"></path>\n      <path d=\"M16 17H8\"></path>\n      <path d=\"M10 9H8\"></path>\n    </svg>\n  )\n}\n\nfunction FeedbackIcon() {\n  return (\n    <svg\n      fill=\"none\"\n      height=\"24\"\n      shapeRendering=\"geometricPrecision\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n    >\n      <path d=\"M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z\"></path>\n    </svg>\n  )\n}\n\nfunction ContactIcon() {\n  return (\n    <svg\n      fill=\"none\"\n      height=\"24\"\n      shapeRendering=\"geometricPrecision\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.5\"\n      viewBox=\"0 0 24 24\"\n      width=\"24\"\n    >\n      <path d=\"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z\"></path>\n      <path d=\"M22 6l-10 7L2 6\"></path>\n    </svg>\n  )\n}\n"
  },
  {
    "path": "website/components/code/code.module.scss",
    "content": ".root {\n  border-radius: 12px;\n  padding: 16px;\n  backdrop-filter: blur(10px);\n  border: 1px solid var(--gray6);\n  position: relative;\n  line-height: 16px;\n  background: var(--lowContrast);\n  white-space: pre-wrap;\n  box-shadow: rgb(0 0 0 / 10%) 0px 5px 30px -5px;\n\n  @media (prefers-color-scheme: dark) {\n    background: var(--grayA2);\n  }\n\n  button {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 32px;\n    height: 32px;\n    background: var(--grayA3);\n    border-radius: 8px;\n    position: absolute;\n    top: 12px;\n    right: 12px;\n    color: var(--gray11);\n    cursor: copy;\n    transition: color 150ms ease, background 150ms ease, transform 150ms ease;\n\n    &:hover {\n      color: var(--gray12);\n      background: var(--grayA4);\n    }\n\n    &:active {\n      color: var(--gray12);\n      background: var(--grayA5);\n      transform: scale(0.96);\n    }\n  }\n}\n\n.shine {\n  @media (prefers-color-scheme: dark) {\n    background: linear-gradient(\n      90deg,\n      rgba(56, 189, 248, 0),\n      var(--gray5) 20%,\n      var(--gray9) 67.19%,\n      rgba(236, 72, 153, 0)\n    );\n    height: 1px;\n    position: absolute;\n    top: -1px;\n    width: 97%;\n    z-index: -1;\n  }\n}\n\n@media (max-width: 640px) {\n  .root {\n    :global(.token-line) {\n      font-size: 11px !important;\n    }\n  }\n}\n"
  },
  {
    "path": "website/components/code/index.tsx",
    "content": "import React from 'react'\nimport copy from 'copy-to-clipboard'\nimport Highlight, { defaultProps } from 'prism-react-renderer'\nimport styles from './code.module.scss'\nimport { CopyIcon } from 'components/icons'\n\nconst theme = {\n  plain: {\n    color: 'var(--gray12)',\n    fontSize: 12,\n    fontFamily: 'Menlo, monospace',\n  },\n  styles: [\n    {\n      types: ['comment'],\n      style: {\n        color: 'var(--gray9)',\n      },\n    },\n    {\n      types: ['atrule', 'keyword', 'attr-name', 'selector'],\n      style: {\n        color: 'var(--gray10)',\n      },\n    },\n    {\n      types: ['punctuation', 'operator'],\n      style: {\n        color: 'var(--gray9)',\n      },\n    },\n    {\n      types: ['class-name', 'function', 'tag'],\n      style: {\n        color: 'var(--gray12)',\n      },\n    },\n  ],\n}\n\nexport function Code({ children }: { children: string }) {\n  return (\n    <Highlight {...defaultProps} theme={theme} code={children} language=\"jsx\">\n      {({ className, style, tokens, getLineProps, getTokenProps }) => (\n        <pre className={`${className} ${styles.root}`} style={style}>\n          <button\n            aria-label=\"Copy Code\"\n            onClick={() => {\n              copy(children)\n            }}\n          >\n            <CopyIcon />\n          </button>\n          <div className={styles.shine} />\n          {tokens.map((line, i) => (\n            <div key={i} {...getLineProps({ line, key: i })}>\n              {line.map((token, key) => (\n                <span key={i} {...getTokenProps({ token, key })} />\n              ))}\n            </div>\n          ))}\n        </pre>\n      )}\n    </Highlight>\n  )\n}\n"
  },
  {
    "path": "website/components/icons/icons.module.scss",
    "content": ".blurLogo {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  position: relative;\n  border-radius: 4px;\n  overflow: hidden;\n  box-shadow: inset 0 0 1px 1px rgba(0, 0, 0, 0.015);\n\n  .bg {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    position: absolute;\n    z-index: 1;\n    pointer-events: none;\n    user-select: none;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    transform: scale(1.5) translateZ(0);\n    filter: blur(12px) opacity(0.4) saturate(100%);\n    transition: filter 150ms ease;\n  }\n\n  .inner {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    object-fit: cover;\n    width: 100%;\n    height: 100%;\n    user-select: none;\n    pointer-events: none;\n    border-radius: inherit;\n    z-index: 2;\n\n    svg {\n      width: 14px;\n      height: 14px;\n      filter: drop-shadow(0 4px 4px rgba(0, 0, 0, 0.16));\n      transition: filter 150ms ease;\n    }\n  }\n}\n"
  },
  {
    "path": "website/components/icons/index.tsx",
    "content": "import styles from './icons.module.scss'\n\nexport function FigmaIcon() {\n  return (\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"48px\" height=\"48px\">\n      <path fill=\"#e64a19\" d=\"M26,17h-8c-3.866,0-7-3.134-7-7v0c0-3.866,3.134-7,7-7h8V17z\" />\n      <path fill=\"#7c4dff\" d=\"M25,31h-7c-3.866,0-7-3.134-7-7v0c0-3.866,3.134-7,7-7h7V31z\" />\n      <path fill=\"#66bb6a\" d=\"M18,45L18,45c-3.866,0-7-3.134-7-7v0c0-3.866,3.134-7,7-7h7v7C25,41.866,21.866,45,18,45z\" />\n      <path fill=\"#ff7043\" d=\"M32,17h-7V3h7c3.866,0,7,3.134,7,7v0C39,13.866,35.866,17,32,17z\" />\n      <circle cx=\"32\" cy=\"24\" r=\"7\" fill=\"#29b6f6\" />\n    </svg>\n  )\n}\n\nexport function RaycastIcon() {\n  return (\n    <svg width=\"28\" height=\"28\" viewBox=\"0 0 28 28\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M7 18.073V20.994L0 13.994L1.46 12.534L7 18.075V18.073ZM9.921 20.994H7L14 27.994L15.46 26.534L9.921 20.994V20.994ZM26.535 15.456L27.996 13.994L13.996 -0.00598145L12.538 1.46002L18.077 6.99802H14.73L10.864 3.14002L9.404 4.60002L11.809 7.00402H10.129V17.87H20.994V16.19L23.399 18.594L24.859 17.134L20.994 13.268V9.92102L26.534 15.456H26.535ZM7.73 6.27002L6.265 7.73202L7.833 9.29802L9.294 7.83802L7.73 6.27002ZM20.162 18.702L18.702 20.164L20.268 21.732L21.73 20.27L20.162 18.702V18.702ZM4.596 9.40402L3.134 10.866L7 14.732V11.809L4.596 9.40402ZM16.192 21H13.268L17.134 24.866L18.596 23.404L16.192 21Z\"\n        fill=\"#FF6363\"\n      />\n    </svg>\n  )\n}\n\nexport function YouTubeIcon() {\n  return (\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"48px\" height=\"48px\">\n      <path\n        fill=\"#FF3D00\"\n        d=\"M43.2,33.9c-0.4,2.1-2.1,3.7-4.2,4c-3.3,0.5-8.8,1.1-15,1.1c-6.1,0-11.6-0.6-15-1.1c-2.1-0.3-3.8-1.9-4.2-4C4.4,31.6,4,28.2,4,24c0-4.2,0.4-7.6,0.8-9.9c0.4-2.1,2.1-3.7,4.2-4C12.3,9.6,17.8,9,24,9c6.2,0,11.6,0.6,15,1.1c2.1,0.3,3.8,1.9,4.2,4c0.4,2.3,0.9,5.7,0.9,9.9C44,28.2,43.6,31.6,43.2,33.9z\"\n      />\n      <path fill=\"#FFF\" d=\"M20 31L20 17 32 24z\" />\n    </svg>\n  )\n}\n\nexport function SlackIcon() {\n  return (\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"48px\" height=\"48px\">\n      <path\n        fill=\"#33d375\"\n        d=\"M33,8c0-2.209-1.791-4-4-4s-4,1.791-4,4c0,1.254,0,9.741,0,11c0,2.209,1.791,4,4,4s4-1.791,4-4\tC33,17.741,33,9.254,33,8z\"\n      />\n      <path\n        fill=\"#33d375\"\n        d=\"M43,19c0,2.209-1.791,4-4,4c-1.195,0-4,0-4,0s0-2.986,0-4c0-2.209,1.791-4,4-4S43,16.791,43,19z\"\n      />\n      <path\n        fill=\"#40c4ff\"\n        d=\"M8,14c-2.209,0-4,1.791-4,4s1.791,4,4,4c1.254,0,9.741,0,11,0c2.209,0,4-1.791,4-4s-1.791-4-4-4\tC17.741,14,9.254,14,8,14z\"\n      />\n      <path\n        fill=\"#40c4ff\"\n        d=\"M19,4c2.209,0,4,1.791,4,4c0,1.195,0,4,0,4s-2.986,0-4,0c-2.209,0-4-1.791-4-4S16.791,4,19,4z\"\n      />\n      <path\n        fill=\"#e91e63\"\n        d=\"M14,39.006C14,41.212,15.791,43,18,43s4-1.788,4-3.994c0-1.252,0-9.727,0-10.984\tc0-2.206-1.791-3.994-4-3.994s-4,1.788-4,3.994C14,29.279,14,37.754,14,39.006z\"\n      />\n      <path\n        fill=\"#e91e63\"\n        d=\"M4,28.022c0-2.206,1.791-3.994,4-3.994c1.195,0,4,0,4,0s0,2.981,0,3.994c0,2.206-1.791,3.994-4,3.994\tS4,30.228,4,28.022z\"\n      />\n      <path\n        fill=\"#ffc107\"\n        d=\"M39,33c2.209,0,4-1.791,4-4s-1.791-4-4-4c-1.254,0-9.741,0-11,0c-2.209,0-4,1.791-4,4s1.791,4,4,4\tC29.258,33,37.746,33,39,33z\"\n      />\n      <path\n        fill=\"#ffc107\"\n        d=\"M28,43c-2.209,0-4-1.791-4-4c0-1.195,0-4,0-4s2.986,0,4,0c2.209,0,4,1.791,4,4S30.209,43,28,43z\"\n      />\n    </svg>\n  )\n}\n\nexport function VercelIcon() {\n  return (\n    <svg aria-label=\"Vercel Logo\" fill=\"var(--highContrast)\" height=\"26\" viewBox=\"0 0 75 65\">\n      <path d=\"M37.59.25l36.95 64H.64l36.95-64z\"></path>\n    </svg>\n  )\n}\n\nexport function LinearIcon({ style }: { style?: Object }) {\n  return (\n    <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\" fill=\"none\" style={style}>\n      <path\n        d=\"M0.403013 37.3991L26.6009 63.597C13.2225 61.3356 2.66442 50.7775 0.403013 37.3991Z\"\n        fill=\"#5E6AD2\"\n      ></path>\n      <path\n        d=\"M0 30.2868L33.7132 64C35.7182 63.8929 37.6742 63.6013 39.5645 63.142L0.85799 24.4355C0.398679 26.3259 0.10713 28.2818 0 30.2868Z\"\n        fill=\"#5E6AD2\"\n      ></path>\n      <path\n        d=\"M2.53593 19.4042L44.5958 61.4641C46.1277 60.8066 47.598 60.0331 48.9956 59.1546L4.84543 15.0044C3.96691 16.402 3.19339 17.8723 2.53593 19.4042Z\"\n        fill=\"#5E6AD2\"\n      ></path>\n      <path\n        d=\"M7.69501 11.1447C13.5677 4.32093 22.2677 0 31.9769 0C49.6628 0 64 14.3372 64 32.0231C64 41.7323 59.6791 50.4323 52.8553 56.305L7.69501 11.1447Z\"\n        fill=\"#5E6AD2\"\n      ></path>\n    </svg>\n  )\n}\n\nexport function Logo({ children, size = '20px' }: { children: React.ReactNode; size?: string }) {\n  return (\n    <div\n      className={styles.blurLogo}\n      style={{\n        width: size,\n        height: size,\n      }}\n    >\n      <div className={styles.bg} aria-hidden>\n        {children}\n      </div>\n      <div className={styles.inner}>{children}</div>\n    </div>\n  )\n}\n\nexport function CopyIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" strokeWidth=\"1.5\" viewBox=\"0 0 24 24\" fill=\"none\">\n      <path\n        d=\"M19.4 20H9.6C9.26863 20 9 19.7314 9 19.4V9.6C9 9.26863 9.26863 9 9.6 9H19.4C19.7314 9 20 9.26863 20 9.6V19.4C20 19.7314 19.7314 20 19.4 20Z\"\n        stroke=\"currentColor\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n      <path\n        d=\"M15 9V4.6C15 4.26863 14.7314 4 14.4 4H4.6C4.26863 4 4 4.26863 4 4.6V14.4C4 14.7314 4.26863 15 4.6 15H9\"\n        stroke=\"currentColor\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n    </svg>\n  )\n}\n\nexport function CopiedIcon() {\n  return (\n    <svg width=\"16\" height=\"16\" strokeWidth=\"1.5\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M5 13L9 17L19 7\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>\n  )\n}\n\nexport function GitHubIcon() {\n  return (\n    <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path\n        d=\"M7 0.175049C3.128 0.175049 0 3.30305 0 7.17505C0 10.259 2.013 12.885 4.79 13.825C5.14 13.891 5.272 13.672 5.272 13.497V12.316C3.325 12.731 2.909 11.375 2.909 11.375C2.581 10.565 2.122 10.347 2.122 10.347C1.488 9.90905 2.166 9.93105 2.166 9.93105C2.866 9.97505 3.237 10.653 3.237 10.653C3.872 11.725 4.878 11.419 5.272 11.243C5.338 10.784 5.512 10.478 5.709 10.303C4.156 10.128 2.516 9.51605 2.516 6.84705C2.516 6.08105 2.778 5.46905 3.237 4.96605C3.172 4.79105 2.931 4.06905 3.303 3.10605C3.303 3.10605 3.893 2.90905 5.228 3.82805C5.79831 3.67179 6.38668 3.5911 6.978 3.58805C7.568 3.58805 8.181 3.67505 8.728 3.82805C10.063 2.93105 10.653 3.10605 10.653 3.10605C11.025 4.06905 10.784 4.79105 10.719 4.96605C11.179 5.44605 11.441 6.08105 11.441 6.84605C11.441 9.53705 9.8 10.128 8.247 10.303C8.487 10.522 8.728 10.937 8.728 11.593V13.519C8.728 13.716 8.859 13.934 9.209 13.847C11.988 12.884 14 10.259 14 7.17505C14 3.30305 10.872 0.175049 7 0.175049V0.175049Z\"\n        fill=\"currentColor\"\n      />\n    </svg>\n  )\n}\n\nexport function FramerIcon() {\n  return (\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 24\">\n      <path\n        d=\"M 16 0 L 16 8 L 8 8 L 0 0 Z M 0 8 L 8 8 L 16 16 L 8 16 L 8 24 L 0 16 Z\"\n        fill=\"var(--highContrast)\"\n      ></path>\n    </svg>\n  )\n}\n"
  },
  {
    "path": "website/components/index.ts",
    "content": "export * from './cmdk/framer'\nexport * from './cmdk/linear'\nexport * from './cmdk/vercel'\nexport * from './cmdk/raycast'\nexport * from './icons'\nexport * from './code'\n"
  },
  {
    "path": "website/next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/basic-features/typescript for more information.\n"
  },
  {
    "path": "website/next.config.js",
    "content": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  reactStrictMode: true,\n  swcMinify: true,\n}\n\nmodule.exports = nextConfig\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"cmdk-website\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"pnpm -F 'cmdk-website^...' build && next build\",\n    \"start\": \"next start\",\n    \"lint\": \"eslint --ext .tsx\"\n  },\n  \"dependencies\": {\n    \"@radix-ui/react-popover\": \"^0.1.6\",\n    \"cmdk\": \"workspace:*\",\n    \"copy-to-clipboard\": \"^3.3.1\",\n    \"framer-motion\": \"^6.5.1\",\n    \"next\": \"13.5.1\",\n    \"next-seo\": \"^5.5.0\",\n    \"next-themes\": \"^0.2.0\",\n    \"prism-react-renderer\": \"^1.3.5\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\",\n    \"sass\": \"^1.53.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"18.0.4\",\n    \"@types/react\": \"18.0.15\",\n    \"@types/react-dom\": \"18.0.6\",\n    \"babel-eslint\": \"^10.1.0\",\n    \"eslint\": \"^8.19.0\",\n    \"eslint-config-next\": \"12.2.2\",\n    \"eslint-config-prettier\": \"^8.5.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"eslint-plugin-react\": \"^7.30.1\",\n    \"husky\": \"^8.0.1\",\n    \"lint-staged\": \"^13.0.3\",\n    \"typescript\": \"4.7.4\"\n  },\n  \"lint-staged\": {\n    \"*.{tsx},*.{ts},*.{mdx}\": [\n      \"eslint --fix\"\n    ]\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\"\n    }\n  }\n}\n"
  },
  {
    "path": "website/pages/_app.tsx",
    "content": "import 'styles/globals.scss'\n\nimport 'styles/cmdk/vercel.scss'\nimport 'styles/cmdk/linear.scss'\nimport 'styles/cmdk/raycast.scss'\nimport 'styles/cmdk/framer.scss'\n\nimport type { AppProps } from 'next/app'\nimport { ThemeProvider } from 'next-themes'\nimport { NextSeo } from 'next-seo'\nimport Head from 'next/head'\n\nconst title = '⌘K'\nconst description = 'Fast, composable, unstyled command menu for React'\nconst siteUrl = 'https://cmdk.paco.me'\n\nexport default function App({ Component, pageProps }: AppProps) {\n  return (\n    <>\n      <Head>\n        <link rel=\"shortcut icon\" href=\"/favicon.svg\" />\n        <meta name=\"twitter:card\" content=\"summary_large_image\" />\n      </Head>\n      <NextSeo\n        title={`${description} — ${title}`}\n        description={description}\n        openGraph={{\n          type: 'website',\n          url: siteUrl,\n          title,\n          description: description + '.',\n          images: [\n            {\n              url: `${siteUrl}/og.png`,\n              alt: title,\n            },\n          ],\n        }}\n      />\n      <ThemeProvider disableTransitionOnChange attribute=\"class\">\n        <Component {...pageProps} />\n      </ThemeProvider>\n    </>\n  )\n}\n"
  },
  {
    "path": "website/pages/_document.tsx",
    "content": "/* eslint-disable @next/next/no-sync-scripts */\nimport React from 'react'\nimport NextDocument, { Html, Head, Main, NextScript } from 'next/document'\n\nexport default class Document extends NextDocument {\n  render() {\n    return (\n      <Html lang=\"en\">\n        <Head>\n          <link rel=\"preload\" href=\"/inter-var-latin.woff2\" as=\"font\" type=\"font/woff2\" crossOrigin=\"anonymous\" />\n        </Head>\n        <body>\n          <Main />\n          <NextScript />\n        </body>\n      </Html>\n    )\n  }\n}\n"
  },
  {
    "path": "website/pages/index.tsx",
    "content": "import styles from 'styles/index.module.scss'\nimport React from 'react'\nimport { AnimatePresence, AnimateSharedLayout, motion, MotionProps, useInView } from 'framer-motion'\nimport {\n  FramerCMDK,\n  LinearCMDK,\n  LinearIcon,\n  VercelCMDK,\n  VercelIcon,\n  RaycastCMDK,\n  RaycastIcon,\n  CopyIcon,\n  FramerIcon,\n  GitHubIcon,\n  Code,\n  CopiedIcon,\n} from 'components'\nimport packageJSON from '../../cmdk/package.json'\n\ntype TTheme = {\n  theme: Themes\n  setTheme: Function\n}\n\ntype Themes = 'linear' | 'raycast' | 'vercel' | 'framer'\n\nconst ThemeContext = React.createContext<TTheme>({} as TTheme)\n\nexport default function Index() {\n  const [theme, setTheme] = React.useState<Themes>('raycast')\n\n  return (\n    <main className={styles.main}>\n      <div className={styles.content}>\n        <div className={styles.meta}>\n          <div className={styles.info}>\n            <VersionBadge />\n            <h1>⌘K</h1>\n            <p>Fast, composable, unstyled command menu for React.</p>\n          </div>\n\n          <div className={styles.buttons}>\n            <InstallButton />\n            <GitHubButton />\n          </div>\n        </div>\n\n        <AnimatePresence exitBeforeEnter initial={false}>\n          {theme === 'framer' && (\n            <CMDKWrapper key=\"framer\">\n              <FramerCMDK />\n            </CMDKWrapper>\n          )}\n          {theme === 'vercel' && (\n            <CMDKWrapper key=\"vercel\">\n              <VercelCMDK />\n            </CMDKWrapper>\n          )}\n          {theme === 'linear' && (\n            <CMDKWrapper key=\"linear\">\n              <LinearCMDK />\n            </CMDKWrapper>\n          )}\n          {theme === 'raycast' && (\n            <CMDKWrapper key=\"raycast\">\n              <RaycastCMDK />\n            </CMDKWrapper>\n          )}\n        </AnimatePresence>\n\n        <ThemeContext.Provider value={{ theme, setTheme }}>\n          <ThemeSwitcher />\n        </ThemeContext.Provider>\n\n        <div aria-hidden className={styles.line} />\n\n        <Codeblock />\n      </div>\n      <Footer />\n    </main>\n  )\n}\n\nfunction CMDKWrapper(props: MotionProps & { children: React.ReactNode }) {\n  return (\n    <motion.div\n      initial={{ opacity: 0, scale: 0.98 }}\n      animate={{ opacity: 1, scale: 1 }}\n      exit={{ opacity: 0, scale: 0.98 }}\n      transition={{ duration: 0.2 }}\n      style={{\n        height: 475,\n      }}\n      {...props}\n    />\n  )\n}\n\n//////////////////////////////////////////////////////////////////\n\nfunction InstallButton() {\n  const [copied, setCopied] = React.useState(false)\n\n  return (\n    <button\n      className={styles.installButton}\n      onClick={async () => {\n        try {\n          await navigator.clipboard.writeText(`npm install cmdk`)\n          setCopied(true)\n          setTimeout(() => {\n            setCopied(false)\n          }, 2000)\n        } catch (e) {}\n      }}\n    >\n      npm install cmdk\n      <span>{copied ? <CopiedIcon /> : <CopyIcon />}</span>\n    </button>\n  )\n}\n\nfunction GitHubButton() {\n  return (\n    <a\n      href=\"https://github.com/pacocoursey/cmdk\"\n      target=\"_blank\"\n      rel=\"noopener noreferrer\"\n      className={styles.githubButton}\n    >\n      <GitHubIcon />\n      pacocoursey/cmdk\n    </a>\n  )\n}\n\n//////////////////////////////////////////////////////////////////\n\nconst themes = [\n  {\n    icon: <RaycastIcon />,\n    key: 'raycast',\n  },\n  {\n    icon: <LinearIcon />,\n    key: 'linear',\n  },\n  {\n    icon: <VercelIcon />,\n    key: 'vercel',\n  },\n  {\n    icon: <FramerIcon />,\n    key: 'framer',\n  },\n]\n\nfunction ThemeSwitcher() {\n  const { theme, setTheme } = React.useContext(ThemeContext)\n  const ref = React.useRef<HTMLButtonElement | null>(null)\n  const [showArrowKeyHint, setShowArrowKeyHint] = React.useState(false)\n\n  React.useEffect(() => {\n    function listener(e: KeyboardEvent) {\n      const themeNames = themes.map((t) => t.key)\n\n      if (e.key === 'ArrowRight') {\n        const currentIndex = themeNames.indexOf(theme)\n        const nextIndex = currentIndex + 1\n        const nextItem = themeNames[nextIndex]\n\n        if (nextItem) {\n          setTheme(nextItem)\n        }\n      }\n\n      if (e.key === 'ArrowLeft') {\n        const currentIndex = themeNames.indexOf(theme)\n        const prevIndex = currentIndex - 1\n        const prevItem = themeNames[prevIndex]\n\n        if (prevItem) {\n          setTheme(prevItem)\n        }\n      }\n    }\n\n    document.addEventListener('keydown', listener)\n\n    return () => {\n      document.removeEventListener('keydown', listener)\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [theme])\n\n  return (\n    <div className={styles.switcher}>\n      <motion.span\n        className={styles.arrow}\n        initial={false}\n        animate={{\n          opacity: showArrowKeyHint ? 1 : 0,\n          x: showArrowKeyHint ? -24 : 0,\n        }}\n        style={{\n          left: 100,\n        }}\n      >\n        ←\n      </motion.span>\n      <AnimateSharedLayout>\n        {themes.map(({ key, icon }) => {\n          const isActive = theme === key\n          return (\n            <button\n              ref={ref}\n              key={key}\n              data-selected={isActive}\n              onClick={() => {\n                setTheme(key)\n                if (showArrowKeyHint === false) {\n                  setShowArrowKeyHint(true)\n                }\n              }}\n            >\n              {icon}\n              {key}\n              {isActive && (\n                <motion.div\n                  layoutId=\"activeTheme\"\n                  transition={{\n                    type: 'spring',\n                    stiffness: 250,\n                    damping: 27,\n                    mass: 1,\n                  }}\n                  className={styles.activeTheme}\n                />\n              )}\n            </button>\n          )\n        })}\n      </AnimateSharedLayout>\n      <motion.span\n        className={styles.arrow}\n        initial={false}\n        animate={{\n          opacity: showArrowKeyHint ? 1 : 0,\n          x: showArrowKeyHint ? 20 : 0,\n        }}\n        style={{\n          right: 100,\n        }}\n      >\n        →\n      </motion.span>\n    </div>\n  )\n}\n//////////////////////////////////////////////////////////////////\n\nfunction Codeblock() {\n  const code = `import { Command } from 'cmdk';\n\n<Command.Dialog open={open} onOpenChange={setOpen}>\n  <Command.Input />\n\n  <Command.List>\n    {loading && <Command.Loading>Hang on…</Command.Loading>}\n\n    <Command.Empty>No results found.</Command.Empty>\n\n    <Command.Group heading=\"Fruits\">\n      <Command.Item>Apple</Command.Item>\n      <Command.Item>Orange</Command.Item>\n      <Command.Separator />\n      <Command.Item>Pear</Command.Item>\n      <Command.Item>Blueberry</Command.Item>\n    </Command.Group>\n\n    <Command.Item>Fish</Command.Item>\n  </Command.List>\n</Command.Dialog>`\n\n  return (\n    <div className={styles.codeBlock}>\n      <div className={styles.line2} aria-hidden />\n      <div className={styles.line3} aria-hidden />\n      <Code>{code}</Code>\n    </div>\n  )\n}\n\n//////////////////////////////////////////////////////////////////\n\nfunction VersionBadge() {\n  return <span className={styles.versionBadge}>v{packageJSON.version}</span>\n}\n\nfunction Footer() {\n  const ref = React.useRef<HTMLElement | null>(null)\n  const isInView = useInView(ref, {\n    once: true,\n    margin: '100px',\n  })\n  return (\n    <footer ref={ref} className={styles.footer} data-animate={isInView}>\n      <div className={styles.footerText}>\n        Crafted by{' '}\n        <a href=\"https://paco.me\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <img src=\"/paco.png\" alt=\"Avatar of Paco\" />\n          Paco\n        </a>{' '}\n        and{' '}\n        <a href=\"https://rauno.me\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <img src=\"/rauno.jpeg\" alt=\"Avatar of Rauno\" />\n          Rauno\n        </a>\n      </div>\n      <RaunoSignature />\n      <PacoSignature />\n    </footer>\n  )\n}\n\nfunction RaunoSignature() {\n  return (\n    <motion.svg\n      initial={{ opacity: 1 }}\n      whileInView={{ opacity: 0 }}\n      transition={{ delay: 2.5 }}\n      viewport={{ once: true }}\n      className={styles.raunoSignature}\n      width=\"356\"\n      height=\"118\"\n      viewBox=\"0 0 356 118\"\n      fill=\"none\"\n    >\n      <path\n        d=\"M39.6522 10.8727C32.0622 19.9486 23.7402 27.7351 17.4485 37.93C14.1895 43.2106 10.8425 48.7619 8.15072 54.3365M2 4.56219C30.9703 4.28687 59.8154 4.46461 88.706 2M5.10832 31.8394C13.3342 30.3515 21.957 30.4518 30.2799 30.1261C32.4305 30.042 44.8189 31.0777 46.043 28.5427M35.5504 60.1056C40.7881 57.8276 45.1269 55.9145 45.2348 49.7269C45.2992 46.04 42.3852 43.6679 39.7347 41.6068C37.1441 39.5922 35.2035 40.7255 34.7931 43.7239C34.4752 46.0474 34.2899 48.3127 37.0257 48.7777C42.1989 49.6571 48.6039 49.4477 53.6739 48.0927C55.9963 47.472 58.0383 46.5469 59.7769 44.897C61.5598 43.2051 59.4798 48.3421 59.2622 48.8504C57.0455 54.0293 55.0028 57.9764 61.8826 60.0079C65.247 61.0013 68.6702 59.0371 71.8755 58.2384C74.4094 57.607 78.1527 57.4135 79.4538 54.7188C80.3093 52.9471 79.5946 45.3814 78.0185 44.19C77.8193 44.0395 70.1595 58.7844 70.5548 61.5199C71.083 65.1755 85.5921 60.8116 87.8354 59.9155C93.0005 57.8521 101.259 42.1787 98.0502 46.7216C96.0097 49.6102 94.8149 54.7237 94.0336 58.1224C93.9591 58.4465 92.9251 63.1692 94.3224 62.558C100.1 60.0307 107.906 58.9913 111.843 53.589C116.212 47.5929 116.624 39.2412 120.13 32.719C123.998 25.5256 110.938 47.1508 110.652 55.3129C110.53 58.8278 110.847 62.2658 113.478 64.8739C115.031 66.4132 118.704 68.7663 120.95 67.3511C122.633 66.2906 122.854 63.0236 123.332 61.285C123.533 60.558 124.804 54.7916 125.523 57.8018C127.423 65.7487 134.234 63.8099 139.205 59.3585C141.166 57.6021 143.163 55.3598 143.895 52.7674C144.073 52.137 144.083 50.0543 142.883 50.96C140.761 52.5616 132.552 63.5513 136.828 65.8799C140.973 68.1366 147.493 69.2386 151.211 66.0229C153.763 63.8167 155.807 60.4623 157.011 57.3295C157.374 56.3842 159.996 48.1819 158.697 47.5545C157.253 46.8572 157.109 52.813 157.414 53.5674C158.282 55.7108 161.296 55.7058 163.208 55.4606C164.958 55.2361 168.071 54.7284 169.248 53.2144C170.028 52.2114 170.241 55.5535 170.738 56.7227C172.225 60.2188 177.289 62.6928 181.044 61.096C183.988 59.8437 186.231 55.0676 189.15 54.6094C192.701 54.052 190.67 50.7455 188.287 49.8024C180.738 46.815 172.87 57.705 176.69 64.571C177.646 66.2894 181.226 63.8978 182.329 63.5067C188.555 61.2998 194.823 59.1513 199.465 54.2015C200.301 53.3106 200.377 52.9071 199.546 54.504C197.173 59.0586 195.315 63.8749 193.213 68.5549C190.335 74.9632 187.327 81.8528 182.771 87.2918C171.982 100.172 154.827 106.815 139.004 110.814C107.54 118.768 70.3986 118.508 39.9452 106.375C37.0775 105.233 32.6626 103.665 30.3512 101.309C28.0213 98.9348 36.0214 97.3532 39.3217 96.9357C56.758 94.7296 74.5289 94.2763 92.0549 93.4762C135.849 91.4768 179.752 90.2295 223.344 85.2523C252.079 81.9713 280.556 77.0898 308.262 68.6373C317.289 65.8833 330.847 60.7964 339.74 56.4402C358.309 47.3441 339.301 55.8458 353.656 47.521M100.748 33.252C100.877 36.5762 102.167 37.0453 102.123 33.916\"\n        stroke=\"currentColor\"\n        strokeWidth=\"3\"\n        strokeLinecap=\"round\"\n        pathLength={1}\n      />\n    </motion.svg>\n  )\n}\n\nfunction PacoSignature() {\n  return (\n    <motion.svg\n      className={styles.pacoSignature}\n      width=\"892\"\n      height=\"235\"\n      viewBox=\"0 0 892 235\"\n      fill=\"none\"\n      initial={{ opacity: 1 }}\n      whileInView={{ opacity: 0 }}\n      transition={{ delay: 2.5 }}\n      viewport={{ once: true }}\n    >\n      <path\n        d=\"M86.684 24.8853C84.684 64.5519 81.884 144.085 86.684 144.885M39.684 8.88526C68.3506 0.385261 131.984 -7.11474 157.184 30.8853C182.384 68.8853 96.3507 111.719 50.184 128.385C26.8506 138.885 -14.116 162.085 8.68398 170.885\"\n        stroke=\"currentColor\"\n        strokeWidth=\"9\"\n        pathLength={1}\n      />\n      <path\n        d=\"M325.184 46.8853C294.184 43.5519 231.684 60.3853 244.684 143.885C280.184 193.385 371.684 142.885 388.684 134.885C399.684 127.552 420.584 112.885 416.184 112.885C410.684 112.885 428.184 129.385 437.684 130.385C447.184 131.385 481.184 110.885 489.684 114.885C498.184 118.885 542.684 129.885 550.684 172.885C558.684 215.885 534.684 226.385 526.684 231.385C518.684 236.385 481.184 214.885 483.184 199.385C485.184 183.885 502.684 152.885 520.684 143.885C538.684 134.885 618.684 83.3853 762.684 83.3853C877.884 83.3853 894.351 80.7186 888.184 79.3853\"\n        stroke=\"currentColor\"\n        strokeWidth=\"9\"\n        pathLength={1}\n      />\n      <path\n        d=\"M143.988 132.079C142.168 132.664 140.426 133.273 138.785 134.307C137.602 135.052 136.639 136.008 135.799 137.117C135.239 137.856 134.695 138.701 134.743 139.671C134.853 141.857 138.728 140.36 139.712 139.916C141.396 139.157 142.992 138.066 144.34 136.808C144.939 136.249 145.832 135.423 145.673 134.488C145.427 133.044 141.601 133.881 140.843 134.019C139.375 134.287 137.534 134.645 137.388 136.418C137.251 138.081 139.708 137.088 140.469 136.738C140.847 136.565 144.28 134.356 143.343 133.705C142.07 132.819 140.471 134.865 139.691 135.619C139.27 136.026 137.078 137.59 138.577 138.061C139.847 138.46 141.551 137.108 142.437 136.392C142.594 136.265 143.818 135.405 143.658 135.075C143.455 134.656 142.071 134.774 141.749 134.808C140.582 134.932 139.512 135.552 138.55 136.184C138.184 136.424 137.281 136.915 137.654 137.144C137.914 137.302 138.113 137.435 138.401 137.549C139.178 137.856 140.088 137.628 140.832 137.255C142.185 136.579 143.389 135.45 144.457 134.382C144.666 134.173 145.14 133.692 145.14 133.374C145.14 133.019 144.968 132.525 144.612 132.367C143.862 132.033 143.442 132.242 142.719 132.58C142.217 132.814 141.792 133.137 141.397 133.518C140.401 134.48 139.261 135.281 138.273 136.259C137.694 136.832 136.936 137.472 136.561 138.22C136.275 138.794 136.605 139.184 137.239 139.031C138.012 138.844 138.778 138.695 139.558 138.551C140.026 138.465 140.57 138.301 140.725 137.837\"\n        stroke=\"currentColor\"\n        strokeWidth=\"9\"\n        strokeLinecap=\"round\"\n        pathLength={1}\n      />\n    </motion.svg>\n  )\n}\n"
  },
  {
    "path": "website/public/robots.txt",
    "content": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "website/styles/cmdk/framer.scss",
    "content": ".framer {\n  [cmdk-root] {\n    max-width: 640px;\n    width: 100%;\n    padding: 8px;\n    background: #ffffff;\n    border-radius: 16px;\n    overflow: hidden;\n    font-family: var(--font-sans);\n    border: 1px solid var(--gray6);\n    box-shadow: var(--cmdk-shadow);\n    outline: none;\n\n    .dark & {\n      background: var(--gray2);\n    }\n  }\n\n  [cmdk-framer-header] {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    height: 48px;\n    padding: 0 8px;\n    border-bottom: 1px solid var(--gray5);\n    margin-bottom: 12px;\n    padding-bottom: 8px;\n\n    svg {\n      width: 20px;\n      height: 20px;\n      color: var(--gray9);\n      transform: translateY(1px);\n    }\n  }\n\n  [cmdk-input] {\n    font-family: var(--font-sans);\n    border: none;\n    width: 100%;\n    font-size: 16px;\n    outline: none;\n    background: var(--bg);\n    color: var(--gray12);\n\n    &::placeholder {\n      color: var(--gray9);\n    }\n  }\n\n  [cmdk-item] {\n    content-visibility: auto;\n\n    cursor: pointer;\n    border-radius: 12px;\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    gap: 12px;\n    color: var(--gray12);\n    padding: 8px 8px;\n    margin-right: 8px;\n    font-weight: 500;\n    transition: all 150ms ease;\n    transition-property: none;\n\n    &[data-selected='true'] {\n      background: var(--blue9);\n      color: #ffffff;\n\n      [cmdk-framer-item-subtitle] {\n        color: #ffffff;\n      }\n    }\n\n    &[data-disabled='true'] {\n      color: var(--gray8);\n      cursor: not-allowed;\n    }\n\n    & + [cmdk-item] {\n      margin-top: 4px;\n    }\n\n    svg {\n      width: 16px;\n      height: 16px;\n      color: #ffffff;\n    }\n  }\n\n  [cmdk-framer-icon-wrapper] {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    min-width: 32px;\n    height: 32px;\n    background: orange;\n    border-radius: 8px;\n  }\n\n  [cmdk-framer-item-meta] {\n    display: flex;\n    flex-direction: column;\n    gap: 4px;\n  }\n\n  [cmdk-framer-item-subtitle] {\n    font-size: 12px;\n    font-weight: 400;\n    color: var(--gray11);\n  }\n\n  [cmdk-framer-items] {\n    min-height: 308px;\n    display: flex;\n  }\n\n  [cmdk-framer-left] {\n    width: 40%;\n  }\n\n  [cmdk-framer-separator] {\n    width: 1px;\n    border: 0;\n    margin-right: 8px;\n    background: var(--gray6);\n  }\n\n  [cmdk-framer-right] {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    border-radius: 8px;\n    margin-left: 8px;\n    width: 60%;\n\n    button {\n      width: 120px;\n      height: 40px;\n      background: var(--blue9);\n      border-radius: 6px;\n      font-weight: 500;\n      color: white;\n      font-size: 14px;\n    }\n\n    input[type='text'] {\n      height: 40px;\n      width: 160px;\n      border: 1px solid var(--gray6);\n      background: #ffffff;\n      border-radius: 6px;\n      padding: 0 8px;\n      font-size: 14px;\n      font-family: var(--font-sans);\n      box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.08);\n\n      &::placeholder {\n        color: var(--gray9);\n      }\n\n      @media (prefers-color-scheme: dark) {\n        background: var(--gray3);\n      }\n    }\n\n    [cmdk-framer-radio] {\n      display: flex;\n      align-items: center;\n      gap: 4px;\n      color: var(--gray12);\n      font-weight: 500;\n      font-size: 14px;\n      accent-color: var(--blue9);\n\n      input {\n        width: 20px;\n        height: 20px;\n      }\n    }\n\n    img {\n      width: 40px;\n      height: 40px;\n      border-radius: 9999px;\n      border: 1px solid var(--gray6);\n    }\n\n    [cmdk-framer-container] {\n      width: 100px;\n      height: 100px;\n      background: var(--blue9);\n      border-radius: 16px;\n    }\n\n    [cmdk-framer-badge] {\n      background: var(--blue3);\n      padding: 0 8px;\n      height: 28px;\n      font-size: 14px;\n      line-height: 28px;\n      color: var(--blue11);\n      border-radius: 9999px;\n      font-weight: 500;\n    }\n\n    [cmdk-framer-slider] {\n      height: 20px;\n      width: 200px;\n      background: linear-gradient(90deg, var(--blue9) 40%, var(--gray3) 0%);\n      border-radius: 9999px;\n\n      div {\n        width: 20px;\n        height: 20px;\n        background: #ffffff;\n        border-radius: 9999px;\n        box-shadow: 0 1px 3px -1px rgba(0, 0, 0, 0.32);\n        transform: translateX(70px);\n      }\n    }\n  }\n\n  [cmdk-list] {\n    overflow: auto;\n  }\n\n  [cmdk-separator] {\n    height: 1px;\n    width: 100%;\n    background: var(--gray5);\n    margin: 4px 0;\n  }\n\n  [cmdk-group-heading] {\n    user-select: none;\n    font-size: 12px;\n    color: var(--gray11);\n    padding: 0 8px;\n    display: flex;\n    align-items: center;\n    margin-bottom: 8px;\n  }\n\n  [cmdk-empty] {\n    font-size: 14px;\n    padding: 32px;\n    white-space: pre-wrap;\n    color: var(--gray11);\n  }\n}\n\n@media (max-width: 640px) {\n  .framer {\n    [cmdk-framer-icon-wrapper] {\n    }\n\n    [cmdk-framer-item-subtitle] {\n      display: none;\n    }\n  }\n}\n"
  },
  {
    "path": "website/styles/cmdk/linear.scss",
    "content": ".linear {\n  [cmdk-root] {\n    max-width: 640px;\n    width: 100%;\n    background: #ffffff;\n    border-radius: 8px;\n    overflow: hidden;\n    padding: 0;\n    font-family: var(--font-sans);\n    box-shadow: var(--cmdk-shadow);\n    outline: none;\n\n    .dark & {\n      background: linear-gradient(136.61deg, rgb(39, 40, 43) 13.72%, rgb(45, 46, 49) 74.3%);\n    }\n  }\n\n  [cmdk-linear-badge] {\n    height: 24px;\n    padding: 0 8px;\n    font-size: 12px;\n    color: var(--gray11);\n    background: var(--gray3);\n    border-radius: 4px;\n    width: fit-content;\n    display: flex;\n    align-items: center;\n    margin: 16px 16px 0;\n  }\n\n  [cmdk-linear-shortcuts] {\n    display: flex;\n    margin-left: auto;\n    gap: 8px;\n\n    kbd {\n      font-family: var(--font-sans);\n      font-size: 13px;\n      color: var(--gray11);\n    }\n  }\n\n  [cmdk-input] {\n    font-family: var(--font-sans);\n    border: none;\n    width: 100%;\n    font-size: 18px;\n    padding: 20px;\n    outline: none;\n    background: var(--bg);\n    color: var(--gray12);\n    border-bottom: 1px solid var(--gray6);\n    border-radius: 0;\n    caret-color: #6e5ed2;\n    margin: 0;\n\n    &::placeholder {\n      color: var(--gray9);\n    }\n  }\n\n  [cmdk-item] {\n    content-visibility: auto;\n\n    cursor: pointer;\n    height: 48px;\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    gap: 12px;\n    padding: 0 16px;\n    color: var(--gray12);\n    user-select: none;\n    will-change: background, color;\n    transition: all 150ms ease;\n    transition-property: none;\n    position: relative;\n\n    &[data-selected='true'] {\n      background: var(--gray3);\n\n      svg {\n        color: var(--gray12);\n      }\n\n      &:after {\n        content: '';\n        position: absolute;\n        left: 0;\n        z-index: 123;\n        width: 3px;\n        height: 100%;\n        background: #5f6ad2;\n      }\n    }\n\n    &[data-disabled='true'] {\n      color: var(--gray8);\n      cursor: not-allowed;\n    }\n\n    &:active {\n      transition-property: background;\n      background: var(--gray4);\n    }\n\n    & + [cmdk-item] {\n      margin-top: 4px;\n    }\n\n    svg {\n      width: 16px;\n      height: 16px;\n      color: var(--gray10);\n    }\n  }\n\n  [cmdk-list] {\n    height: min(300px, var(--cmdk-list-height));\n    max-height: 400px;\n    overflow: auto;\n    overscroll-behavior: contain;\n    transition: 100ms ease;\n    transition-property: height;\n  }\n\n  [cmdk-group-heading] {\n    user-select: none;\n    font-size: 12px;\n    color: var(--gray11);\n    padding: 0 8px;\n    display: flex;\n    align-items: center;\n  }\n\n  [cmdk-empty] {\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 64px;\n    white-space: pre-wrap;\n    color: var(--gray11);\n  }\n}\n"
  },
  {
    "path": "website/styles/cmdk/raycast.scss",
    "content": ".raycast {\n  [cmdk-root] {\n    max-width: 640px;\n    width: 100%;\n    background: var(--gray1);\n    border-radius: 12px;\n    padding: 8px 0;\n    font-family: var(--font-sans);\n    box-shadow: var(--cmdk-shadow);\n    border: 1px solid var(--gray6);\n    position: relative;\n    outline: none;\n\n    .dark & {\n      background: var(--gray2);\n      border: 0;\n\n      &:after {\n        content: '';\n        background: linear-gradient(\n          to right,\n          var(--gray6) 20%,\n          var(--gray6) 40%,\n          var(--gray10) 50%,\n          var(--gray10) 55%,\n          var(--gray6) 70%,\n          var(--gray6) 100%\n        );\n        z-index: -1;\n        position: absolute;\n        border-radius: 12px;\n        top: -1px;\n        left: -1px;\n        width: calc(100% + 2px);\n        height: calc(100% + 2px);\n        animation: shine 3s ease forwards 0.1s;\n        background-size: 200% auto;\n      }\n\n      &:before {\n        content: '';\n        z-index: -1;\n        position: absolute;\n        border-radius: 12px;\n        top: -1px;\n        left: -1px;\n        width: calc(100% + 2px);\n        height: calc(100% + 2px);\n        box-shadow: 0 0 0 1px transparent;\n        animation: border 1s linear forwards 0.5s;\n      }\n    }\n\n    kbd {\n      font-family: var(--font-sans);\n      background: var(--gray3);\n      color: var(--gray11);\n      height: 20px;\n      width: 20px;\n      border-radius: 4px;\n      padding: 0 4px;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n\n      &:first-of-type {\n        margin-left: 8px;\n      }\n    }\n  }\n\n  [cmdk-input] {\n    font-family: var(--font-sans);\n    border: none;\n    width: 100%;\n    font-size: 15px;\n    padding: 8px 16px;\n    outline: none;\n    background: var(--bg);\n    color: var(--gray12);\n\n    &::placeholder {\n      color: var(--gray9);\n    }\n  }\n\n  [cmdk-raycast-top-shine] {\n    .dark & {\n      background: linear-gradient(\n        90deg,\n        rgba(56, 189, 248, 0),\n        var(--gray5) 20%,\n        var(--gray9) 67.19%,\n        rgba(236, 72, 153, 0)\n      );\n      height: 1px;\n      position: absolute;\n      top: -1px;\n      width: 100%;\n      z-index: -1;\n      opacity: 0;\n      animation: showTopShine 0.1s ease forwards 0.2s;\n    }\n  }\n\n  [cmdk-raycast-loader] {\n    --loader-color: var(--gray9);\n    border: 0;\n    width: 100%;\n    left: 0;\n    height: 1px;\n    background: var(--gray6);\n    position: relative;\n    overflow: visible;\n    display: block;\n    margin-top: 12px;\n    margin-bottom: 12px;\n\n    &:after {\n      content: '';\n      width: 50%;\n      height: 1px;\n      position: absolute;\n      background: linear-gradient(90deg, transparent 0%, var(--loader-color) 50%, transparent 100%);\n      top: -1px;\n      opacity: 0;\n      animation-duration: 1.5s;\n      animation-delay: 1s;\n      animation-timing-function: ease;\n      animation-name: loading;\n    }\n  }\n\n  [cmdk-item] {\n    content-visibility: auto;\n\n    cursor: pointer;\n    height: 40px;\n    border-radius: 8px;\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    padding: 0 8px;\n    color: var(--gray12);\n    user-select: none;\n    will-change: background, color;\n    transition: all 150ms ease;\n\n    &[data-selected='true'] {\n      background: var(--gray4);\n      color: var(--gray12);\n    }\n\n    &[data-disabled='true'] {\n      color: var(--gray8);\n      cursor: not-allowed;\n    }\n\n    &:active {\n      transition-property: background;\n      background: var(--gray4);\n    }\n\n    &:first-child {\n      margin-top: 8px;\n    }\n\n    & + [cmdk-item] {\n      margin-top: 4px;\n    }\n\n    svg {\n      width: 18px;\n      height: 18px;\n    }\n  }\n\n  [cmdk-raycast-meta] {\n    margin-left: auto;\n    color: var(--gray11);\n    font-size: 13px;\n  }\n\n  [cmdk-list] {\n    padding: 0 8px;\n    height: 393px;\n    overflow: auto;\n    overscroll-behavior: contain;\n    scroll-padding-block-end: 40px;\n    transition: 100ms ease;\n    transition-property: height;\n    padding-bottom: 40px;\n  }\n\n  [cmdk-raycast-open-trigger],\n  [cmdk-raycast-subcommand-trigger] {\n    color: var(--gray11);\n    padding: 0px 4px 0px 8px;\n    border-radius: 6px;\n    font-weight: 500;\n    font-size: 12px;\n    height: 28px;\n    letter-spacing: -0.25px;\n  }\n\n  [cmdk-raycast-clipboard-icon],\n  [cmdk-raycast-hammer-icon] {\n    width: 20px;\n    height: 20px;\n    border-radius: 6px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    color: #ffffff;\n\n    svg {\n      width: 14px;\n      height: 14px;\n    }\n  }\n\n  [cmdk-raycast-clipboard-icon] {\n    background: linear-gradient(to bottom, #f55354, #eb4646);\n  }\n\n  [cmdk-raycast-hammer-icon] {\n    background: linear-gradient(to bottom, #6cb9a3, #2c6459);\n  }\n\n  [cmdk-raycast-open-trigger] {\n    display: flex;\n    align-items: center;\n    color: var(--gray12);\n  }\n\n  [cmdk-raycast-subcommand-trigger] {\n    display: flex;\n    align-items: center;\n    gap: 4px;\n    right: 8px;\n    bottom: 8px;\n\n    svg {\n      width: 14px;\n      height: 14px;\n    }\n\n    hr {\n      height: 100%;\n      background: var(--gray6);\n      border: 0;\n      width: 1px;\n    }\n\n    &[aria-expanded='true'],\n    &:hover {\n      background: var(--gray4);\n\n      kbd {\n        background: var(--gray7);\n      }\n    }\n  }\n\n  [cmdk-separator] {\n    height: 1px;\n    width: 100%;\n    background: var(--gray5);\n    margin: 4px 0;\n  }\n\n  *:not([hidden]) + [cmdk-group] {\n    margin-top: 8px;\n  }\n\n  [cmdk-group-heading] {\n    user-select: none;\n    font-size: 12px;\n    color: var(--gray11);\n    padding: 0 8px;\n    display: flex;\n    align-items: center;\n  }\n\n  [cmdk-raycast-footer] {\n    display: flex;\n    height: 40px;\n    align-items: center;\n    width: 100%;\n    position: absolute;\n    background: var(--gray1);\n    bottom: 0;\n    padding: 8px;\n    border-top: 1px solid var(--gray6);\n    border-radius: 0 0 12px 12px;\n\n    svg {\n      width: 20px;\n      height: 20px;\n      filter: grayscale(1);\n      margin-right: auto;\n    }\n\n    hr {\n      height: 12px;\n      width: 1px;\n      border: 0;\n      background: var(--gray6);\n      margin: 0 4px 0px 12px;\n    }\n\n    @media (prefers-color-scheme: dark) {\n      background: var(--gray2);\n    }\n  }\n\n  [cmdk-dialog] {\n    z-index: var(--layer-portal);\n    position: fixed;\n    left: 50%;\n    top: var(--page-top);\n    transform: translateX(-50%);\n\n    [cmdk] {\n      width: 640px;\n      transform-origin: center center;\n      animation: dialogIn var(--transition-fast) forwards;\n    }\n\n    &[data-state='closed'] [cmdk] {\n      animation: dialogOut var(--transition-fast) forwards;\n    }\n  }\n\n  [cmdk-empty] {\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 64px;\n    white-space: pre-wrap;\n    color: var(--gray11);\n  }\n}\n\n@keyframes loading {\n  0% {\n    opacity: 0;\n    transform: translateX(0);\n  }\n\n  50% {\n    opacity: 1;\n    transform: translateX(100%);\n  }\n\n  100% {\n    opacity: 0;\n    transform: translateX(0);\n  }\n}\n\n@keyframes shine {\n  to {\n    background-position: 200% center;\n    opacity: 0;\n  }\n}\n\n@keyframes border {\n  to {\n    box-shadow: 0 0 0 1px var(--gray6);\n  }\n}\n\n@keyframes showTopShine {\n  to {\n    opacity: 1;\n  }\n}\n\n.raycast-submenu {\n  [cmdk-root] {\n    display: flex;\n    flex-direction: column;\n    width: 320px;\n    border: 1px solid var(--gray6);\n    background: var(--gray2);\n    border-radius: 8px;\n  }\n\n  [cmdk-list] {\n    padding: 8px;\n    overflow: auto;\n    overscroll-behavior: contain;\n    transition: 100ms ease;\n    transition-property: height;\n  }\n\n  [cmdk-item] {\n    cursor: pointer;\n    height: 40px;\n    border-radius: 8px;\n    font-size: 13px;\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    padding: 0 8px;\n    color: var(--gray12);\n    user-select: none;\n    will-change: background, color;\n    transition: all 150ms ease;\n\n    &[aria-selected='true'] {\n      background: var(--gray5);\n      color: var(--gray12);\n\n      [cmdk-raycast-submenu-shortcuts] kbd {\n        background: var(--gray7);\n      }\n    }\n\n    &[aria-disabled='true'] {\n      color: var(--gray8);\n      cursor: not-allowed;\n    }\n\n    svg {\n      width: 16px;\n      height: 16px;\n    }\n\n    [cmdk-raycast-submenu-shortcuts] {\n      display: flex;\n      margin-left: auto;\n      gap: 2px;\n\n      kbd {\n        font-family: var(--font-sans);\n        background: var(--gray5);\n        color: var(--gray11);\n        height: 20px;\n        width: 20px;\n        border-radius: 4px;\n        padding: 0 4px;\n        font-size: 12px;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n\n        &:first-of-type {\n          margin-left: 8px;\n        }\n      }\n    }\n  }\n\n  [cmdk-group-heading] {\n    text-transform: capitalize;\n    font-size: 12px;\n    color: var(--gray11);\n    font-weight: 500;\n    margin-bottom: 8px;\n    margin-top: 8px;\n    margin-left: 4px;\n  }\n\n  [cmdk-input] {\n    padding: 12px;\n    font-family: var(--font-sans);\n    border: 0;\n    border-top: 1px solid var(--gray6);\n    font-size: 13px;\n    background: transparent;\n    margin-top: auto;\n    width: 100%;\n    outline: 0;\n    border-radius: 0;\n  }\n\n  animation-duration: 0.2s;\n  animation-timing-function: ease;\n  animation-fill-mode: forwards;\n  transform-origin: var(--radix-popover-content-transform-origin);\n\n  &[data-state='open'] {\n    animation-name: slideIn;\n  }\n\n  &[data-state='closed'] {\n    animation-name: slideOut;\n  }\n\n  [cmdk-empty] {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 64px;\n    white-space: pre-wrap;\n    font-size: 14px;\n    color: var(--gray11);\n  }\n}\n\n@keyframes slideIn {\n  0% {\n    opacity: 0;\n    transform: scale(0.96);\n  }\n\n  100% {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n\n@keyframes slideOut {\n  0% {\n    opacity: 1;\n    transform: scale(1);\n  }\n\n  100% {\n    opacity: 0;\n    transform: scale(0.96);\n  }\n}\n\n@media (max-width: 640px) {\n  .raycast {\n    [cmdk-input] {\n      font-size: 16px;\n    }\n  }\n}\n"
  },
  {
    "path": "website/styles/cmdk/vercel.scss",
    "content": ".vercel {\n  [cmdk-root] {\n    max-width: 640px;\n    width: 100%;\n    padding: 8px;\n    background: #ffffff;\n    border-radius: 12px;\n    overflow: hidden;\n    font-family: var(--font-sans);\n    border: 1px solid var(--gray6);\n    box-shadow: var(--cmdk-shadow);\n    transition: transform 100ms ease;\n    outline: none;\n\n    .dark & {\n      background: rgba(22, 22, 22, 0.7);\n    }\n  }\n\n  [cmdk-input] {\n    font-family: var(--font-sans);\n    border: none;\n    width: 100%;\n    font-size: 17px;\n    padding: 8px 8px 16px 8px;\n    outline: none;\n    background: var(--bg);\n    color: var(--gray12);\n    border-bottom: 1px solid var(--gray6);\n    margin-bottom: 16px;\n    border-radius: 0;\n\n    &::placeholder {\n      color: var(--gray9);\n    }\n  }\n\n  [cmdk-vercel-badge] {\n    height: 20px;\n    background: var(--grayA3);\n    display: inline-flex;\n    align-items: center;\n    padding: 0 8px;\n    font-size: 12px;\n    color: var(--grayA11);\n    border-radius: 4px;\n    margin: 4px 0 4px 4px;\n    user-select: none;\n    text-transform: capitalize;\n    font-weight: 500;\n  }\n\n  [cmdk-item] {\n    content-visibility: auto;\n\n    cursor: pointer;\n    height: 48px;\n    border-radius: 8px;\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    padding: 0 16px;\n    color: var(--gray11);\n    user-select: none;\n    will-change: background, color;\n    transition: all 150ms ease;\n    transition-property: none;\n\n    &[data-selected='true'] {\n      background: var(--grayA3);\n      color: var(--gray12);\n    }\n\n    &[data-disabled='true'] {\n      color: var(--gray8);\n      cursor: not-allowed;\n    }\n\n    &:active {\n      transition-property: background;\n      background: var(--gray4);\n    }\n\n    & + [cmdk-item] {\n      margin-top: 4px;\n    }\n\n    svg {\n      width: 18px;\n      height: 18px;\n    }\n  }\n\n  [cmdk-list] {\n    height: min(330px, calc(var(--cmdk-list-height)));\n    max-height: 400px;\n    overflow: auto;\n    overscroll-behavior: contain;\n    transition: 100ms ease;\n    transition-property: height;\n  }\n\n  [cmdk-vercel-shortcuts] {\n    display: flex;\n    margin-left: auto;\n    gap: 8px;\n\n    kbd {\n      font-family: var(--font-sans);\n      font-size: 12px;\n      min-width: 20px;\n      padding: 4px;\n      height: 20px;\n      border-radius: 4px;\n      color: var(--gray11);\n      background: var(--gray4);\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      text-transform: uppercase;\n    }\n  }\n\n  [cmdk-separator] {\n    height: 1px;\n    width: 100%;\n    background: var(--gray5);\n    margin: 4px 0;\n  }\n\n  *:not([hidden]) + [cmdk-group] {\n    margin-top: 8px;\n  }\n\n  [cmdk-group-heading] {\n    user-select: none;\n    font-size: 12px;\n    color: var(--gray11);\n    padding: 0 8px;\n    display: flex;\n    align-items: center;\n    margin-bottom: 8px;\n  }\n\n  [cmdk-empty] {\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 48px;\n    white-space: pre-wrap;\n    color: var(--gray11);\n  }\n}\n"
  },
  {
    "path": "website/styles/globals.scss",
    "content": "@font-face {\n  font-family: 'Inter';\n  font-style: normal;\n  font-weight: 100 900; // Range of weights supported\n  font-display: optional;\n  src: url(/inter-var-latin.woff2) format('woff2');\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC,\n    U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n\n::selection {\n  background: hotpink;\n  color: white;\n}\n\nhtml,\nbody {\n  padding: 0;\n  margin: 0;\n  font-family: var(--font-sans);\n}\n\nbody {\n  background: var(--app-bg);\n  overflow-x: hidden;\n}\n\nbutton {\n  background: none;\n  font-family: var(--font-sans);\n  padding: 0;\n  border: 0;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\np {\n  margin: 0;\n}\n\na {\n  color: inherit;\n  text-decoration: none;\n}\n\n*,\n*::after,\n*::before {\n  box-sizing: border-box;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n:root {\n  --font-sans: 'Inter', --apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans,\n    Droid Sans, Helvetica Neue, sans-serif;\n  --app-bg: var(--gray1);\n  --cmdk-shadow: 0 16px 70px rgb(0 0 0 / 20%);\n\n  --lowContrast: #ffffff;\n  --highContrast: #000000;\n\n  --gray1: hsl(0, 0%, 99%);\n  --gray2: hsl(0, 0%, 97.3%);\n  --gray3: hsl(0, 0%, 95.1%);\n  --gray4: hsl(0, 0%, 93%);\n  --gray5: hsl(0, 0%, 90.9%);\n  --gray6: hsl(0, 0%, 88.7%);\n  --gray7: hsl(0, 0%, 85.8%);\n  --gray8: hsl(0, 0%, 78%);\n  --gray9: hsl(0, 0%, 56.1%);\n  --gray10: hsl(0, 0%, 52.3%);\n  --gray11: hsl(0, 0%, 43.5%);\n  --gray12: hsl(0, 0%, 9%);\n\n  --grayA1: hsla(0, 0%, 0%, 0.012);\n  --grayA2: hsla(0, 0%, 0%, 0.027);\n  --grayA3: hsla(0, 0%, 0%, 0.047);\n  --grayA4: hsla(0, 0%, 0%, 0.071);\n  --grayA5: hsla(0, 0%, 0%, 0.09);\n  --grayA6: hsla(0, 0%, 0%, 0.114);\n  --grayA7: hsla(0, 0%, 0%, 0.141);\n  --grayA8: hsla(0, 0%, 0%, 0.22);\n  --grayA9: hsla(0, 0%, 0%, 0.439);\n  --grayA10: hsla(0, 0%, 0%, 0.478);\n  --grayA11: hsla(0, 0%, 0%, 0.565);\n  --grayA12: hsla(0, 0%, 0%, 0.91);\n\n  --blue1: hsl(206, 100%, 99.2%);\n  --blue2: hsl(210, 100%, 98%);\n  --blue3: hsl(209, 100%, 96.5%);\n  --blue4: hsl(210, 98.8%, 94%);\n  --blue5: hsl(209, 95%, 90.1%);\n  --blue6: hsl(209, 81.2%, 84.5%);\n  --blue7: hsl(208, 77.5%, 76.9%);\n  --blue8: hsl(206, 81.9%, 65.3%);\n  --blue9: hsl(206, 100%, 50%);\n  --blue10: hsl(208, 100%, 47.3%);\n  --blue11: hsl(211, 100%, 43.2%);\n  --blue12: hsl(211, 100%, 15%);\n}\n\n.dark {\n  --app-bg: var(--gray1);\n\n  --lowContrast: #000000;\n  --highContrast: #ffffff;\n\n  --gray1: hsl(0, 0%, 8.5%);\n  --gray2: hsl(0, 0%, 11%);\n  --gray3: hsl(0, 0%, 13.6%);\n  --gray4: hsl(0, 0%, 15.8%);\n  --gray5: hsl(0, 0%, 17.9%);\n  --gray6: hsl(0, 0%, 20.5%);\n  --gray7: hsl(0, 0%, 24.3%);\n  --gray8: hsl(0, 0%, 31.2%);\n  --gray9: hsl(0, 0%, 43.9%);\n  --gray10: hsl(0, 0%, 49.4%);\n  --gray11: hsl(0, 0%, 62.8%);\n  --gray12: hsl(0, 0%, 93%);\n\n  --grayA1: hsla(0, 0%, 100%, 0);\n  --grayA2: hsla(0, 0%, 100%, 0.026);\n  --grayA3: hsla(0, 0%, 100%, 0.056);\n  --grayA4: hsla(0, 0%, 100%, 0.077);\n  --grayA5: hsla(0, 0%, 100%, 0.103);\n  --grayA6: hsla(0, 0%, 100%, 0.129);\n  --grayA7: hsla(0, 0%, 100%, 0.172);\n  --grayA8: hsla(0, 0%, 100%, 0.249);\n  --grayA9: hsla(0, 0%, 100%, 0.386);\n  --grayA10: hsla(0, 0%, 100%, 0.446);\n  --grayA11: hsla(0, 0%, 100%, 0.592);\n  --grayA12: hsla(0, 0%, 100%, 0.923);\n\n  --blue1: hsl(212, 35%, 9.2%);\n  --blue2: hsl(216, 50%, 11.8%);\n  --blue3: hsl(214, 59.4%, 15.3%);\n  --blue4: hsl(214, 65.8%, 17.9%);\n  --blue5: hsl(213, 71.2%, 20.2%);\n  --blue6: hsl(212, 77.4%, 23.1%);\n  --blue7: hsl(211, 85.1%, 27.4%);\n  --blue8: hsl(211, 89.7%, 34.1%);\n  --blue9: hsl(206, 100%, 50%);\n  --blue10: hsl(209, 100%, 60.6%);\n  --blue11: hsl(210, 100%, 66.1%);\n  --blue12: hsl(206, 98%, 95.8%);\n}\n"
  },
  {
    "path": "website/styles/index.module.scss",
    "content": ".main {\n  width: 100vw;\n  min-height: 100vh;\n  position: relative;\n  display: flex;\n  justify-content: center;\n  padding: 120px 24px 160px 24px;\n\n  &:before {\n    background: radial-gradient(circle, rgba(2, 0, 36, 0) 0, var(--gray1) 100%);\n    position: absolute;\n    content: '';\n    z-index: 2;\n    width: 100%;\n    height: 100%;\n    top: 0;\n  }\n\n  &:after {\n    content: '';\n    background-image: url('/grid.svg');\n    z-index: -1;\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    opacity: 0.2;\n    filter: invert(1);\n\n    @media (prefers-color-scheme: dark) {\n      filter: unset;\n    }\n  }\n\n  h1 {\n    font-size: 32px;\n    color: var(--gray12);\n    font-weight: 600;\n    letter-spacing: -2px;\n    line-height: 40px;\n  }\n\n  p {\n    color: var(--gray11);\n    margin-top: 8px;\n    font-size: 16px;\n  }\n}\n\n.content {\n  height: fit-content;\n  position: relative;\n  z-index: 3;\n  width: 100%;\n  max-width: 640px;\n\n  &:after {\n    background-image: radial-gradient(at 27% 37%, hsla(215, 98%, 61%, 1) 0px, transparent 50%),\n      radial-gradient(at 97% 21%, hsla(256, 98%, 72%, 1) 0px, transparent 50%),\n      radial-gradient(at 52% 99%, hsla(354, 98%, 61%, 1) 0px, transparent 50%),\n      radial-gradient(at 10% 29%, hsla(133, 96%, 67%, 1) 0px, transparent 50%),\n      radial-gradient(at 97% 96%, hsla(38, 60%, 74%, 1) 0px, transparent 50%),\n      radial-gradient(at 33% 50%, hsla(222, 67%, 73%, 1) 0px, transparent 50%),\n      radial-gradient(at 79% 53%, hsla(343, 68%, 79%, 1) 0px, transparent 50%);\n    position: absolute;\n    content: '';\n    z-index: 2;\n    width: 100%;\n    height: 100%;\n    filter: blur(100px) saturate(150%);\n    z-index: -1;\n    top: 80px;\n    opacity: 0.2;\n    transform: translateZ(0);\n\n    @media (prefers-color-scheme: dark) {\n      opacity: 0.1;\n    }\n  }\n}\n\n.meta {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  margin-bottom: 48px;\n  flex-wrap: wrap;\n  gap: 16px;\n}\n\n.buttons {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-end;\n  gap: 12px;\n  transform: translateY(12px);\n}\n\n.githubButton,\n.installButton,\n.switcher button {\n  height: 40px;\n  color: var(--gray12);\n  border-radius: 9999px;\n  font-size: 14px;\n  transition-duration: 150ms;\n  transition-property: background, color, transform;\n  transition-timing-function: ease-in;\n  will-change: transform;\n}\n\n.githubButton {\n  width: 177px;\n  padding: 0 12px;\n  display: inline-flex;\n  align-items: center;\n  gap: 8px;\n  font-weight: 500;\n\n  &:hover {\n    background: var(--grayA3);\n  }\n\n  &:active {\n    background: var(--grayA5);\n    transform: scale(0.97);\n  }\n\n  &:focus-visible {\n    outline: 0;\n    outline: 2px solid var(--gray7);\n  }\n}\n\n.installButton {\n  background: var(--grayA3);\n  display: flex;\n  align-items: center;\n  gap: 16px;\n  padding: 0px 8px 0 16px;\n  cursor: copy;\n  font-weight: 500;\n\n  &:hover {\n    background: var(--grayA4);\n\n    span {\n      background: var(--grayA5);\n\n      svg {\n        color: var(--gray12);\n      }\n    }\n  }\n\n  &:focus-visible {\n    outline: 0;\n    outline: 2px solid var(--gray7);\n    outline-offset: 2px;\n  }\n\n  &:active {\n    background: var(--gray5);\n    transform: scale(0.97);\n  }\n\n  span {\n    width: 28px;\n    height: 28px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    margin-left: auto;\n    background: var(--grayA3);\n    border-radius: 9999px;\n    transition: background 150ms ease;\n\n    svg {\n      size: 16px;\n      color: var(--gray11);\n      transition: color 150ms ease;\n    }\n  }\n}\n\n.switcher {\n  display: grid;\n  grid-template-columns: repeat(4, 100px);\n  align-items: center;\n  justify-content: center;\n  gap: 4px;\n  margin-top: 48px;\n  position: relative;\n\n  button {\n    height: 32px;\n    line-height: 32px;\n    display: flex;\n    align-items: center;\n    margin: auto;\n    gap: 8px;\n    padding: 0 16px;\n    border-radius: 9999px;\n    color: var(--gray11);\n    font-size: 14px;\n    cursor: pointer;\n    user-select: none;\n    position: relative;\n    text-transform: capitalize;\n\n    &:hover {\n      color: var(--gray12);\n    }\n\n    &:active {\n      transform: scale(0.96);\n    }\n\n    &:focus-visible {\n      outline: 0;\n      outline: 2px solid var(--gray7);\n    }\n\n    svg {\n      width: 14px;\n      height: 14px;\n    }\n\n    &[data-selected='true'] {\n      color: var(--gray12);\n\n      &:hover .activeTheme {\n        background: var(--grayA6);\n      }\n\n      &:active {\n        transform: scale(0.96);\n\n        .activeTheme {\n          background: var(--grayA7);\n        }\n      }\n    }\n  }\n\n  .activeTheme {\n    background: var(--grayA5);\n    border-radius: 9999px;\n    height: 32px;\n    width: 100%;\n    top: 0;\n    position: absolute;\n    left: 0;\n  }\n\n  .arrow {\n    color: var(--gray11);\n    user-select: none;\n    position: absolute;\n  }\n}\n\n.header {\n  position: absolute;\n  left: 0;\n  top: -64px;\n  gap: 8px;\n  background: var(--gray3);\n  padding: 4px;\n  display: flex;\n  align-items: center;\n  border-radius: 9999px;\n\n  button {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 28px;\n    height: 28px;\n    padding: 4px;\n    border-radius: 9999px;\n    color: var(--gray11);\n\n    svg {\n      width: 16px;\n      height: 16px;\n    }\n\n    &[aria-selected='true'] {\n      background: #ffffff;\n      color: var(--gray12);\n      box-shadow: 0px 2px 5px -2px rgb(0 0 0 / 15%), 0 1px 3px -1px rgb(0 0 0 / 20%);\n    }\n  }\n}\n\n.versionBadge {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  color: var(--grayA11);\n  background: var(--grayA3);\n  padding: 4px 8px;\n  border-radius: 4px;\n  font-weight: 500;\n  font-size: 14px;\n  margin-bottom: 8px;\n\n  @media (prefers-color-scheme: dark) {\n    background: var(--grayA2);\n  }\n}\n\n.codeBlock {\n  margin-top: 72px;\n  position: relative;\n}\n\n.footer {\n  display: flex;\n  align-items: center;\n  gap: 4px;\n  width: fit-content;\n  margin: 32px auto;\n  bottom: 16px;\n  color: var(--gray11);\n  font-size: 13px;\n  z-index: 3;\n  position: absolute;\n  bottom: 0;\n\n  a {\n    display: inline-flex;\n    align-items: center;\n    gap: 4px;\n    color: var(--gray12);\n    font-weight: 500;\n    border-radius: 9999px;\n    padding: 4px;\n    margin: 0 -2px;\n    transition: background 150ms ease;\n\n    &:hover,\n    &:focus-visible {\n      background: var(--grayA4);\n      outline: 0;\n    }\n  }\n\n  img {\n    width: 20px;\n    height: 20px;\n    border: 1px solid var(--gray5);\n    border-radius: 9999px;\n  }\n}\n\n.line {\n  height: 20px;\n  width: 180px;\n  margin: 64px auto;\n  background-image: url('/line.svg');\n  filter: invert(1);\n  mask-image: linear-gradient(90deg, transparent, #fff 4rem, #fff calc(100% - 4rem), transparent);\n\n  @media (prefers-color-scheme: dark) {\n    filter: unset;\n  }\n}\n\n.line2 {\n  height: 1px;\n  width: 300px;\n  background: var(--gray7);\n  position: absolute;\n  top: 0;\n  mask-image: linear-gradient(90deg, transparent, #fff 4rem, #fff calc(100% - 4rem), transparent);\n}\n\n.line3 {\n  height: 300px;\n  width: calc(100% + 32px);\n  position: absolute;\n  top: -16px;\n  left: -16px;\n\n  border-radius: 16px 16px 0 0;\n  --size: 1px;\n  --gradient: linear-gradient(to top, var(--gray1), var(--gray7));\n\n  &::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    border-radius: inherit;\n    padding: var(--size);\n    background: linear-gradient(to top, var(--gray1), var(--gray7));\n    mask: linear-gradient(black, black) content-box, linear-gradient(black, black);\n    mask-composite: exclude;\n    transform: translateZ(0);\n\n    @media (prefers-color-scheme: dark) {\n      mask: none;\n      mask-composite: none;\n      opacity: 0.2;\n      backdrop-filter: blur(20px);\n    }\n  }\n}\n\n.raunoSignature,\n.pacoSignature {\n  position: absolute;\n  height: fit-content;\n  color: var(--gray11);\n  pointer-events: none;\n}\n\n.raunoSignature {\n  width: 120px;\n  stroke-dashoffset: 1;\n  stroke-dasharray: 1;\n  right: -48px;\n}\n\n.pacoSignature {\n  width: 120px;\n  stroke-dashoffset: 1;\n  stroke-dasharray: 1;\n  left: -8px;\n}\n\n.footerText {\n  display: flex;\n  display: flex;\n  align-items: center;\n  gap: 4px;\n  opacity: 0;\n}\n\n.footer[data-animate='true'] {\n  .raunoSignature path {\n    animation: drawRaunoSignature 1.5s ease forwards 0.5s;\n  }\n\n  .pacoSignature path {\n    animation: drawPacoSignature 0.8s linear forwards 0.5s;\n  }\n\n  .footerText {\n    animation: showFooter 1s linear forwards 3s;\n  }\n}\n\n@keyframes drawPacoSignature {\n  100% {\n    stroke-dashoffset: 0;\n  }\n}\n\n@keyframes drawRaunoSignature {\n  100% {\n    stroke-dashoffset: 0;\n  }\n}\n\n@keyframes showFooter {\n  100% {\n    opacity: 1;\n  }\n}\n\n@media (max-width: 640px) {\n  .main {\n    padding-top: 24px;\n    padding-bottom: 120px;\n  }\n\n  .switcher {\n    grid-template-columns: repeat(2, 100px);\n    gap: 16px;\n\n    .arrow {\n      display: none;\n    }\n  }\n}\n"
  },
  {
    "path": "website/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true,\n    \"baseUrl\": \".\"\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "website/vercel.json",
    "content": "{\n  \"headers\": [\n    {\n      \"source\": \"/inter-var-latin.woff2\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"public, max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n"
  }
]