{
  "name": "solid-ui-inline-menu",
  "title": "solid-ui-inline-menu",
  "type": "registry:component",
  "description": "",
  "registryDependencies": [
    "https://unpkg.com/prosekit-registry/dist/r/solid-ui-button.json"
  ],
  "dependencies": [
    "@egoist/tailwindcss-icons",
    "@iconify-json/lucide",
    "prosekit@^0.22.0"
  ],
  "files": [
    {
      "path": "registry/src/solid/ui/inline-menu/index.ts",
      "type": "registry:component",
      "target": "components/editor/ui/inline-menu/index.ts",
      "content": "export { default as InlineMenu } from './inline-menu.tsx'\n"
    },
    {
      "path": "registry/src/solid/ui/inline-menu/inline-menu.tsx",
      "type": "registry:component",
      "target": "components/editor/ui/inline-menu/inline-menu.tsx",
      "content": "import type { BasicExtension } from 'prosekit/basic'\nimport type { Editor } from 'prosekit/core'\nimport type { LinkAttrs } from 'prosekit/extensions/link'\nimport type { EditorState } from 'prosekit/pm/state'\nimport { useEditor, useEditorDerivedValue } from 'prosekit/solid'\nimport { InlinePopoverPopup, InlinePopoverPositioner, InlinePopoverRoot } from 'prosekit/solid/inline-popover'\nimport { createSignal, Show, type JSX } from 'solid-js'\n\nimport { Button } from '../button/index.ts'\n\nfunction getInlineMenuItems(editor: Editor<BasicExtension>) {\n  return {\n    bold: editor.commands.toggleBold\n      ? {\n        isActive: editor.marks.bold.isActive(),\n        canExec: editor.commands.toggleBold.canExec(),\n        command: () => editor.commands.toggleBold(),\n      }\n      : undefined,\n    italic: editor.commands.toggleItalic\n      ? {\n        isActive: editor.marks.italic.isActive(),\n        canExec: editor.commands.toggleItalic.canExec(),\n        command: () => editor.commands.toggleItalic(),\n      }\n      : undefined,\n    underline: editor.commands.toggleUnderline\n      ? {\n        isActive: editor.marks.underline.isActive(),\n        canExec: editor.commands.toggleUnderline.canExec(),\n        command: () => editor.commands.toggleUnderline(),\n      }\n      : undefined,\n    strike: editor.commands.toggleStrike\n      ? {\n        isActive: editor.marks.strike.isActive(),\n        canExec: editor.commands.toggleStrike.canExec(),\n        command: () => editor.commands.toggleStrike(),\n      }\n      : undefined,\n    code: editor.commands.toggleCode\n      ? {\n        isActive: editor.marks.code.isActive(),\n        canExec: editor.commands.toggleCode.canExec(),\n        command: () => editor.commands.toggleCode(),\n      }\n      : undefined,\n    link: editor.commands.addLink\n      ? {\n        isActive: editor.marks.link.isActive(),\n        canExec: editor.commands.addLink.canExec({ href: '' }),\n        command: () => editor.commands.expandLink(),\n        currentLink: getCurrentLink(editor.state) || '',\n      }\n      : undefined,\n  }\n}\n\nfunction getCurrentLink(state: EditorState): string | undefined {\n  const { $from } = state.selection\n  const marks = $from.marksAcross($from)\n  if (!marks) {\n    return\n  }\n  for (const mark of marks) {\n    if (mark.type.name === 'link') {\n      return (mark.attrs as LinkAttrs).href\n    }\n  }\n}\n\nexport default function InlineMenu(): JSX.Element {\n  const editor = useEditor<BasicExtension>()\n  const items = useEditorDerivedValue(getInlineMenuItems)\n\n  const [linkMenuOpen, setLinkMenuOpen] = createSignal(false)\n  const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open)\n\n  const handleLinkUpdate = (href?: string) => {\n    if (href) {\n      editor().commands.addLink({ href })\n    } else {\n      editor().commands.removeLink()\n    }\n\n    setLinkMenuOpen(false)\n    editor().focus()\n  }\n\n  return (\n    <>\n      <InlinePopoverRoot\n        onOpenChange={(event) => {\n          if (!event.detail) {\n            setLinkMenuOpen(false)\n          }\n        }}\n      >\n        <InlinePopoverPositioner class=\"block overflow-visible w-min h-min z-50 ease-out transition-transform duration-100 motion-reduce:transition-none\">\n          <InlinePopoverPopup\n            attr:data-testid=\"inline-menu-main\"\n            class=\"box-border origin-(--transform-origin) transition-[opacity,scale] transition-discrete motion-reduce:transition-none data-[state=closed]:duration-150 data-[state=closed]:opacity-0 starting:opacity-0 data-[state=closed]:scale-95 starting:scale-95 duration-40 border border-gray-200 dark:border-gray-800 shadow-lg bg-[canvas] relative flex min-w-32 space-x-1 overflow-auto whitespace-nowrap rounded-lg p-1\"\n          >\n            <Show when={items().bold}>\n              {(item) => (\n                <Button\n                  pressed={item().isActive}\n                  disabled={!item().canExec}\n                  onClick={item().command}\n                  tooltip=\"Bold\"\n                >\n                  <div class=\"i-lucide-bold size-5 block\"></div>\n                </Button>\n              )}\n            </Show>\n            <Show when={items().italic}>\n              {(item) => (\n                <Button\n                  pressed={item().isActive}\n                  disabled={!item().canExec}\n                  onClick={item().command}\n                  tooltip=\"Italic\"\n                >\n                  <div class=\"i-lucide-italic size-5 block\"></div>\n                </Button>\n              )}\n            </Show>\n            <Show when={items().underline}>\n              {(item) => (\n                <Button\n                  pressed={item().isActive}\n                  disabled={!item().canExec}\n                  onClick={item().command}\n                  tooltip=\"Underline\"\n                >\n                  <div class=\"i-lucide-underline size-5 block\"></div>\n                </Button>\n              )}\n            </Show>\n            <Show when={items().strike}>\n              {(item) => (\n                <Button\n                  pressed={item().isActive}\n                  disabled={!item().canExec}\n                  onClick={item().command}\n                  tooltip=\"Strikethrough\"\n                >\n                  <div class=\"i-lucide-strikethrough size-5 block\"></div>\n                </Button>\n              )}\n            </Show>\n            <Show when={items().code}>\n              {(item) => (\n                <Button\n                  pressed={item().isActive}\n                  disabled={!item().canExec}\n                  onClick={item().command}\n                  tooltip=\"Code\"\n                >\n                  <div class=\"i-lucide-code size-5 block\"></div>\n                </Button>\n              )}\n            </Show>\n            <Show when={items().link?.canExec && items().link}>\n              {(item) => (\n                <Button\n                  pressed={item().isActive}\n                  onClick={() => {\n                    item().command()\n                    toggleLinkMenuOpen()\n                  }}\n                  tooltip=\"Link\"\n                >\n                  <div class=\"i-lucide-link size-5 block\"></div>\n                </Button>\n              )}\n            </Show>\n          </InlinePopoverPopup>\n        </InlinePopoverPositioner>\n      </InlinePopoverRoot>\n\n      <Show when={items().link}>\n        {(item) => (\n          <InlinePopoverRoot\n            defaultOpen={false}\n            open={linkMenuOpen()}\n            onOpenChange={(event) => setLinkMenuOpen(event.detail)}\n          >\n            <InlinePopoverPositioner placement=\"bottom\" class=\"block overflow-visible w-min h-min z-50 ease-out transition-transform duration-100 motion-reduce:transition-none\">\n              <InlinePopoverPopup\n                attr:data-testid=\"inline-menu-link\"\n                class=\"box-border origin-(--transform-origin) transition-[opacity,scale] transition-discrete motion-reduce:transition-none data-[state=closed]:duration-150 data-[state=closed]:opacity-0 starting:opacity-0 data-[state=closed]:scale-95 starting:scale-95 duration-40 border border-gray-200 dark:border-gray-800 shadow-lg bg-[canvas] relative flex flex-col w-xs rounded-lg p-4 gap-y-2 items-stretch\"\n              >\n                <Show when={linkMenuOpen()}>\n                  <form\n                    onSubmit={(event) => {\n                      event.preventDefault()\n                      const target = event.target as HTMLFormElement | null\n                      const href = target?.querySelector('input')?.value?.trim()\n                      handleLinkUpdate(href)\n                    }}\n                  >\n                    <input\n                      placeholder=\"Paste the link...\"\n                      value={item().currentLink || ''}\n                      class=\"flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50\"\n                    />\n                  </form>\n                </Show>\n                <Show when={item().isActive}>\n                  <button\n                    onClick={() => handleLinkUpdate()}\n                    onMouseDown={(event) => event.preventDefault()}\n                    class=\"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white dark:ring-offset-gray-950 transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border-0 bg-gray-900 dark:bg-gray-50 text-gray-50 dark:text-gray-900 hover:bg-gray-900/90 dark:hover:bg-gray-50/90 h-9 px-3\"\n                  >\n                    Remove link\n                  </button>\n                </Show>\n              </InlinePopoverPopup>\n            </InlinePopoverPositioner>\n          </InlinePopoverRoot>\n        )}\n      </Show>\n    </>\n  )\n}\n"
    }
  ],
  "meta": {
    "hasIcons": true,
    "hidden": false,
    "story": "",
    "framework": "solid",
    "accumulatedFiles": [
      "registry/src/solid/ui/button/button.tsx",
      "registry/src/solid/ui/button/index.ts",
      "registry/src/solid/ui/inline-menu/index.ts",
      "registry/src/solid/ui/inline-menu/inline-menu.tsx"
    ],
    "internalDependencies": [
      "solid-ui-button"
    ]
  },
  "css": {
    "@plugin @egoist/tailwindcss-icons": {}
  },
  "$schema": "https://ui.shadcn.com/schema/registry-item.json"
}
