{
  "name": "svelte-ui-inline-menu",
  "title": "svelte-ui-inline-menu",
  "type": "registry:component",
  "description": "",
  "registryDependencies": [
    "https://unpkg.com/prosekit-registry/dist/r/svelte-ui-button.json"
  ],
  "dependencies": [
    "@egoist/tailwindcss-icons",
    "@iconify-json/lucide",
    "prosekit@^0.22.0"
  ],
  "files": [
    {
      "path": "registry/src/svelte/ui/inline-menu/index.ts",
      "type": "registry:component",
      "target": "components/editor/ui/inline-menu/index.ts",
      "content": "export { default as InlineMenu } from './inline-menu.svelte'\n"
    },
    {
      "path": "registry/src/svelte/ui/inline-menu/inline-menu.svelte",
      "type": "registry:component",
      "target": "components/editor/ui/inline-menu/inline-menu.svelte",
      "content": "<script lang=\"ts\">\nimport 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/svelte'\nimport { InlinePopoverPopup, InlinePopoverPositioner, InlinePopoverRoot } from 'prosekit/svelte/inline-popover'\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.$from\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\nconst editor = useEditor<BasicExtension>()\nconst items = useEditorDerivedValue(getInlineMenuItems)\n\nlet linkMenuOpen = $state(false)\nfunction toggleLinkMenuOpen() {\n  linkMenuOpen = !linkMenuOpen\n}\n\nfunction handleLinkUpdate(href?: string) {\n  if (href) {\n    $editor.commands.addLink({ href })\n  } else {\n    $editor.commands.removeLink()\n  }\n\n  linkMenuOpen = false\n  $editor.focus()\n}\n</script>\n\n<InlinePopoverRoot\n  onOpenChange={(event) => {\n    if (!event.detail) linkMenuOpen = false\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      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      {#if $items.bold}\n        <Button\n          pressed={$items.bold.isActive}\n          disabled={!$items.bold.canExec}\n          onClick={$items.bold.command}\n          tooltip=\"Bold\"\n        >\n          <div class=\"i-lucide-bold size-5 block\"></div>\n        </Button>\n      {/if}\n      {#if $items.italic}\n        <Button\n          pressed={$items.italic.isActive}\n          disabled={!$items.italic.canExec}\n          onClick={$items.italic.command}\n          tooltip=\"Italic\"\n        >\n          <div class=\"i-lucide-italic size-5 block\"></div>\n        </Button>\n      {/if}\n      {#if $items.underline}\n        <Button\n          pressed={$items.underline.isActive}\n          disabled={!$items.underline.canExec}\n          onClick={$items.underline.command}\n          tooltip=\"Underline\"\n        >\n          <div class=\"i-lucide-underline size-5 block\"></div>\n        </Button>\n      {/if}\n      {#if $items.strike}\n        <Button\n          pressed={$items.strike.isActive}\n          disabled={!$items.strike.canExec}\n          onClick={$items.strike.command}\n          tooltip=\"Strikethrough\"\n        >\n          <div class=\"i-lucide-strikethrough size-5 block\"></div>\n        </Button>\n      {/if}\n      {#if $items.code}\n        <Button\n          pressed={$items.code.isActive}\n          disabled={!$items.code.canExec}\n          onClick={$items.code.command}\n          tooltip=\"Code\"\n        >\n          <div class=\"i-lucide-code size-5 block\"></div>\n        </Button>\n      {/if}\n      {#if $items.link?.canExec && $items.link}\n        <Button\n          pressed={$items.link.isActive}\n          onClick={() => {\n            $items.link!.command()\n            toggleLinkMenuOpen()\n          }}\n          tooltip=\"Link\"\n        >\n          <div class=\"i-lucide-link size-5 block\"></div>\n        </Button>\n      {/if}\n    </InlinePopoverPopup>\n  </InlinePopoverPositioner>\n</InlinePopoverRoot>\n\n<InlinePopoverRoot\n  defaultOpen={false}\n  open={linkMenuOpen}\n  onOpenChange={(event) => {\n    linkMenuOpen = event.detail\n  }}\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      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      {#if linkMenuOpen && $items.link}\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={$items.link.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      {/if}\n      {#if $items.link?.isActive}\n        <button\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          onclick={() => handleLinkUpdate()}\n          onmousedown={(e) => e.preventDefault()}\n        >\n          Remove link\n        </button>\n      {/if}\n    </InlinePopoverPopup>\n  </InlinePopoverPositioner>\n</InlinePopoverRoot>\n"
    }
  ],
  "meta": {
    "hasIcons": true,
    "hidden": false,
    "story": "",
    "framework": "svelte",
    "accumulatedFiles": [
      "registry/src/svelte/ui/button/button.svelte",
      "registry/src/svelte/ui/button/index.ts",
      "registry/src/svelte/ui/inline-menu/index.ts",
      "registry/src/svelte/ui/inline-menu/inline-menu.svelte"
    ],
    "internalDependencies": [
      "svelte-ui-button"
    ]
  },
  "css": {
    "@plugin @egoist/tailwindcss-icons": {}
  },
  "$schema": "https://ui.shadcn.com/schema/registry-item.json"
}
