{"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-selection.svelte.ts","../../src/svelte/components/TextSelection.svelte","../../src/svelte/components/MarqueeSelection.svelte","../../src/svelte/components/CopyToClipboard.svelte","../../src/svelte/index.ts","../../src/svelte/components/SelectionLayer.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { SelectionPlugin } from '@embedpdf/plugin-selection';\n\n/**\n * Hook to get the selection plugin's capability API.\n * This provides methods for controlling and listening to selection events.\n */\nexport const useSelectionCapability = () => useCapability<SelectionPlugin>(SelectionPlugin.id);\n\n/**\n * Hook to get the raw selection plugin instance.\n * Useful for accessing plugin-specific properties or methods not exposed in the capability.\n */\nexport const useSelectionPlugin = () => usePlugin<SelectionPlugin>(SelectionPlugin.id);\n","<script lang=\"ts\">\n  import type { Snippet } from 'svelte';\n  import type { Rect } from '@embedpdf/models';\n  import { Rotation } from '@embedpdf/models';\n  import { useDocumentState } from '@embedpdf/core/svelte';\n  import {\n    CounterRotate,\n    type MenuWrapperProps,\n    type SelectionMenuPlacement,\n  } from '@embedpdf/utils/svelte';\n  import { useSelectionPlugin } from '../hooks/use-selection.svelte';\n  import type {\n    SelectionSelectionMenuRenderFn,\n    SelectionSelectionMenuProps,\n    SelectionSelectionContext,\n  } from '../types';\n  import type { SelectionMenuPlacement as UtilsSelectionMenuPlacement } from '@embedpdf/plugin-selection';\n\n  interface TextSelectionProps {\n    /** Document ID */\n    documentId: string;\n    /** Index of the page this layer lives on */\n    pageIndex: number;\n    /** Scale of the page (optional, defaults to document scale) */\n    scale?: number;\n    /** Rotation of the page (optional, defaults to document rotation) */\n    rotation?: Rotation;\n    /** Background color for text selection highlights. Default: 'rgba(33,150,243)' */\n    background?: string;\n    /** Render function for selection menu (schema-driven approach) */\n    selectionMenu?: SelectionSelectionMenuRenderFn;\n    /** Snippet for custom selection menu (slot-based approach) */\n    selectionMenuSnippet?: Snippet<[SelectionSelectionMenuProps]>;\n  }\n\n  let {\n    documentId,\n    pageIndex,\n    scale: scaleOverride,\n    rotation: rotationOverride,\n    background = 'rgba(33,150,243)',\n    selectionMenu,\n    selectionMenuSnippet,\n  }: TextSelectionProps = $props();\n\n  const selectionPlugin = useSelectionPlugin();\n  const documentState = useDocumentState(() => documentId);\n\n  const page = $derived(documentState.current?.document?.pages?.[pageIndex]);\n\n  let rects = $state<Rect[]>([]);\n  let boundingRect = $state<Rect | null>(null);\n  let placement = $state<UtilsSelectionMenuPlacement | null>(null);\n\n  const actualScale = $derived(\n    scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n  );\n\n  const actualRotation = $derived.by(() => {\n    if (rotationOverride !== undefined) return rotationOverride;\n    // Combine page intrinsic rotation with document rotation\n    const pageRotation = page?.rotation ?? 0;\n    const docRotation = documentState.current?.rotation ?? 0;\n    return ((pageRotation + docRotation) % 4) as Rotation;\n  });\n\n  // Check if menu should render: placement is valid AND (render fn OR snippet exists)\n  const shouldRenderMenu = $derived(\n    Boolean(\n      placement &&\n      placement.pageIndex === pageIndex &&\n      placement.isVisible &&\n      (selectionMenu || selectionMenuSnippet),\n    ),\n  );\n\n  // Track selection rectangles on this page\n  $effect(() => {\n    if (!selectionPlugin.plugin || !documentId) {\n      rects = [];\n      boundingRect = null;\n      return;\n    }\n\n    return selectionPlugin.plugin.registerSelectionOnPage({\n      documentId,\n      pageIndex,\n      onRectsChange: ({ rects: newRects, boundingRect: newBoundingRect }) => {\n        rects = newRects;\n        boundingRect = newBoundingRect;\n      },\n    });\n  });\n\n  // Track menu placement for this document\n  $effect(() => {\n    if (!selectionPlugin.plugin || !documentId) {\n      placement = null;\n      return;\n    }\n\n    return selectionPlugin.plugin.onMenuPlacement(documentId, (newPlacement) => {\n      placement = newPlacement;\n    });\n  });\n\n  // --- Selection Menu Logic ---\n\n  // Build context object for selection menu\n  function buildContext(): SelectionSelectionContext {\n    return {\n      type: 'selection',\n      pageIndex,\n    };\n  }\n\n  // Build placement hints from plugin placement data\n  function buildMenuPlacement(): SelectionMenuPlacement {\n    return {\n      suggestTop: placement?.suggestTop ?? false,\n      spaceAbove: placement?.spaceAbove ?? 0,\n      spaceBelow: placement?.spaceBelow ?? 0,\n    };\n  }\n\n  // Build menu props\n  function buildMenuProps(\n    rect: Rect,\n    menuWrapperProps: MenuWrapperProps,\n  ): SelectionSelectionMenuProps {\n    return {\n      context: buildContext(),\n      selected: true, // Selection is always \"selected\" when visible\n      rect,\n      placement: buildMenuPlacement(),\n      menuWrapperProps,\n    };\n  }\n</script>\n\n{#if boundingRect}\n  <!-- Highlight layer -->\n  <div\n    style:position=\"absolute\"\n    style:left={`${boundingRect.origin.x * actualScale}px`}\n    style:top={`${boundingRect.origin.y * actualScale}px`}\n    style:width={`${boundingRect.size.width * actualScale}px`}\n    style:height={`${boundingRect.size.height * actualScale}px`}\n    style:mix-blend-mode=\"multiply\"\n    style:isolation=\"isolate\"\n    style:pointer-events=\"none\"\n  >\n    {#each rects as rect, i (i)}\n      <div\n        style:position=\"absolute\"\n        style:left={`${(rect.origin.x - boundingRect.origin.x) * actualScale}px`}\n        style:top={`${(rect.origin.y - boundingRect.origin.y) * actualScale}px`}\n        style:width={`${rect.size.width * actualScale}px`}\n        style:height={`${rect.size.height * actualScale}px`}\n        style:background\n        style:pointer-events=\"none\"\n      ></div>\n    {/each}\n  </div>\n\n  <!-- Selection menu (counter-rotated) -->\n  {#if shouldRenderMenu && placement}\n    <CounterRotate\n      rect={{\n        origin: {\n          x: placement.rect.origin.x * actualScale,\n          y: placement.rect.origin.y * actualScale,\n        },\n        size: {\n          width: placement.rect.size.width * actualScale,\n          height: placement.rect.size.height * actualScale,\n        },\n      }}\n      rotation={actualRotation}\n    >\n      {#snippet children({ rect, menuWrapperProps })}\n        {@const menuProps = buildMenuProps(rect, menuWrapperProps)}\n        {#if selectionMenu}\n          <!-- Priority 1: Render function (schema-driven) -->\n          {@const result = selectionMenu(menuProps)}\n          {#if result}\n            <result.component {...result.props} />\n          {/if}\n        {:else if selectionMenuSnippet}\n          <!-- Priority 2: Snippet (manual customization) -->\n          {@render selectionMenuSnippet(menuProps)}\n        {/if}\n      {/snippet}\n    </CounterRotate>\n  {/if}\n{/if}\n","<script lang=\"ts\">\n  import type { Rect } from '@embedpdf/models';\n  import { useDocumentState } from '@embedpdf/core/svelte';\n  import { useSelectionPlugin } from '../hooks';\n\n  interface MarqueeSelectionProps {\n    /** The ID of the document */\n    documentId: string;\n    /** Index of the page this layer lives on */\n    pageIndex: number;\n    /** Scale of the page (optional, defaults to document scale) */\n    scale?: number;\n    /** Optional CSS class applied to the marquee rectangle */\n    class?: string;\n    /** Fill/background color inside the marquee rectangle. Default: 'rgba(0,122,204,0.15)' */\n    background?: string;\n    /** Border color of the marquee rectangle. Default: 'rgba(0,122,204,0.8)' */\n    borderColor?: string;\n    /** Border style. Default: 'dashed' */\n    borderStyle?: 'solid' | 'dashed' | 'dotted';\n    /**\n     * @deprecated Use `borderColor` instead.\n     */\n    stroke?: string;\n    /**\n     * @deprecated Use `background` instead.\n     */\n    fill?: string;\n  }\n\n  let {\n    documentId,\n    pageIndex,\n    scale: scaleOverride,\n    class: propsClass,\n    background,\n    borderColor,\n    borderStyle = 'dashed',\n    stroke,\n    fill,\n  }: MarqueeSelectionProps = $props();\n\n  const selectionPlugin = useSelectionPlugin();\n  const documentState = useDocumentState(() => documentId);\n\n  // Resolve deprecated props: new CSS-standard props take precedence\n  const resolvedBorderColor = $derived(borderColor ?? stroke ?? 'rgba(0,122,204,0.8)');\n  const resolvedBackground = $derived(background ?? fill ?? 'rgba(0,122,204,0.15)');\n\n  let rect = $state<Rect | null>(null);\n\n  const actualScale = $derived(\n    scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n  );\n\n  $effect(() => {\n    rect = null;\n\n    if (!selectionPlugin.plugin) {\n      return;\n    }\n\n    return selectionPlugin.plugin.registerMarqueeOnPage({\n      documentId,\n      pageIndex,\n      scale: actualScale,\n      onRectChange: (newRect) => {\n        rect = newRect;\n      },\n    });\n  });\n</script>\n\n{#if rect}\n  <div\n    style:position=\"absolute\"\n    style:pointer-events=\"none\"\n    style:left={`${rect.origin.x * actualScale}px`}\n    style:top={`${rect.origin.y * actualScale}px`}\n    style:width={`${rect.size.width * actualScale}px`}\n    style:height={`${rect.size.height * actualScale}px`}\n    style:border={`1px ${borderStyle} ${resolvedBorderColor}`}\n    style:background={resolvedBackground}\n    style:box-sizing=\"border-box\"\n    style:z-index=\"1000\"\n    class={propsClass}\n  ></div>\n{/if}\n","<script lang=\"ts\">\n  import { useSelectionCapability } from '../hooks/use-selection.svelte';\n\n  const selectionCapability = useSelectionCapability();\n\n  $effect(() => {\n    if (!selectionCapability.provides) return;\n\n    return selectionCapability.provides.onCopyToClipboard(({ text }) => {\n      navigator.clipboard.writeText(text).catch((err) => {\n        console.error('Failed to copy text to clipboard:', err);\n      });\n    });\n  });\n</script>\n\n<!-- This component renders nothing to the DOM -->\n","import { createPluginPackage } from '@embedpdf/core';\nimport { SelectionPluginPackage as BaseSelectionPluginPackage } from '@embedpdf/plugin-selection';\n\nimport { CopyToClipboard } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from './types';\nexport * from '@embedpdf/plugin-selection';\n\nexport const SelectionPluginPackage = createPluginPackage(BaseSelectionPluginPackage)\n  .addUtility(CopyToClipboard)\n  .build();\n","<script lang=\"ts\">\n  import type { Snippet } from 'svelte';\n  import { Rotation } from '@embedpdf/models';\n  import type { TextSelectionStyle, MarqueeSelectionStyle } from '@embedpdf/plugin-selection';\n  import type { SelectionSelectionMenuRenderFn, SelectionSelectionMenuProps } from '../types';\n  import TextSelection from './TextSelection.svelte';\n  import MarqueeSelection from './MarqueeSelection.svelte';\n\n  interface SelectionLayerProps {\n    /** Document ID */\n    documentId: string;\n    /** Index of the page this layer lives on */\n    pageIndex: number;\n    /** Scale of the page (optional, defaults to document scale) */\n    scale?: number;\n    /** Rotation of the page (optional, defaults to document rotation) */\n    rotation?: Rotation;\n    /**\n     * @deprecated Use `textStyle.background` instead.\n     * Background color for selection rectangles.\n     */\n    background?: string;\n    /** Styling options for text selection highlights */\n    textStyle?: TextSelectionStyle;\n    /** Styling options for the marquee selection rectangle */\n    marqueeStyle?: MarqueeSelectionStyle;\n    /** Optional CSS class applied to the marquee rectangle */\n    marqueeClass?: string;\n    /** Render function for selection menu (schema-driven approach) */\n    selectionMenu?: SelectionSelectionMenuRenderFn;\n    /** Snippet for custom selection menu (slot-based approach) */\n    selectionMenuSnippet?: Snippet<[SelectionSelectionMenuProps]>;\n  }\n\n  let {\n    documentId,\n    pageIndex,\n    scale,\n    rotation,\n    background,\n    textStyle,\n    marqueeStyle,\n    marqueeClass,\n    selectionMenu,\n    selectionMenuSnippet,\n  }: SelectionLayerProps = $props();\n\n  const resolvedTextBackground = $derived(textStyle?.background ?? background);\n</script>\n\n<TextSelection\n  {documentId}\n  {pageIndex}\n  {scale}\n  {rotation}\n  background={resolvedTextBackground}\n  {selectionMenu}\n  {selectionMenuSnippet}\n/>\n<MarqueeSelection\n  {documentId}\n  {pageIndex}\n  {scale}\n  background={marqueeStyle?.background}\n  borderColor={marqueeStyle?.borderColor}\n  borderStyle={marqueeStyle?.borderStyle}\n  class={marqueeClass}\n/>\n"],"names":["useSelectionCapability","useCapability","SelectionPlugin","id","useSelectionPlugin","usePlugin","background","selectionPlugin","documentState","useDocumentState","$$props","documentId","page","_c","_b","_a","current","document","pages","pageIndex","rects","$","state","proxy","boundingRect","placement","actualScale","derived","scale","actualRotation","rotation","get","shouldRenderMenu","Boolean","isVisible","selectionMenu","selectionMenuSnippet","user_effect","plugin","registerSelectionOnPage","onRectsChange","newRects","newBoundingRect","set","onMenuPlacement","newPlacement","div","first_child","fragment_1","index","$$anchor","rect","div_1","root_2","styles_1","origin","x","y","width","size","height","children","$$arg0","menuProps","menuWrapperProps","context","type","selected","suggestTop","spaceAbove","spaceBelow","buildMenuProps","result","result_component","spread_props","props","consequent","CounterRotate","$$render","consequent_3","styles","left","top","consequent_4","borderStyle","resolvedBorderColor","resolvedBackground","registerMarqueeOnPage","onRectChange","newRect","root_1","clsx","class","border","selectionCapability","provides","onCopyToClipboard","text","navigator","clipboard","writeText","catch","err","console","error","SelectionPluginPackage","createPluginPackage","BaseSelectionPluginPackage","addUtility","CopyToClipboard","build","resolvedTextBackground","TextSelection","node","borderColor","MarqueeSelection","node_1"],"mappings":"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"}