{"version":3,"file":"index.cjs","sources":["../../src/vue/hooks/use-search.ts","../../src/vue/components/search-layer.vue"],"sourcesContent":["import { ref, watch, computed, toValue, type MaybeRefOrGetter, Ref, ComputedRef } from 'vue';\nimport { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport {\n  SearchPlugin,\n  SearchDocumentState,\n  SearchScope,\n  initialSearchDocumentState,\n} from '@embedpdf/plugin-search';\n\nexport const useSearchPlugin = () => usePlugin<SearchPlugin>(SearchPlugin.id);\nexport const useSearchCapability = () => useCapability<SearchPlugin>(SearchPlugin.id);\n\n/**\n * Hook for search state for a specific document\n * @param documentId Document ID (can be ref, computed, getter, or plain value)\n */\nexport const useSearch = (\n  documentId: MaybeRefOrGetter<string>,\n): {\n  state: Ref<SearchDocumentState>;\n  provides: ComputedRef<SearchScope | null>;\n} => {\n  const { provides } = useSearchCapability();\n  const searchState = ref<SearchDocumentState>(initialSearchDocumentState);\n\n  watch(\n    [provides, () => toValue(documentId)],\n    ([providesValue, docId], _, onCleanup) => {\n      if (!providesValue) {\n        searchState.value = initialSearchDocumentState;\n        return;\n      }\n\n      const scope = providesValue.forDocument(docId);\n\n      // Set initial state\n      searchState.value = scope.getState();\n\n      // Subscribe to changes\n      const unsubscribe = scope.onStateChange((state) => {\n        searchState.value = state;\n      });\n\n      onCleanup(unsubscribe);\n    },\n    { immediate: true },\n  );\n\n  const scopedProvides = computed(() => {\n    const docId = toValue(documentId);\n    return provides.value?.forDocument(docId) ?? null;\n  });\n\n  return {\n    state: searchState,\n    provides: scopedProvides,\n  };\n};\n","<script setup lang=\"ts\">\nimport { ref, watch, computed } from 'vue';\nimport { useDocumentState } from '@embedpdf/core/vue';\nimport type { SearchResultState } from '@embedpdf/plugin-search';\nimport { useSearchCapability } from '../hooks/use-search';\n\ninterface SearchLayerProps {\n  documentId: string;\n  pageIndex: number;\n  scale?: number;\n  highlightColor?: string;\n  activeHighlightColor?: string;\n}\n\nconst props = withDefaults(defineProps<SearchLayerProps>(), {\n  highlightColor: '#FFFF00',\n  activeHighlightColor: '#FFBF00',\n});\n\nconst { provides: searchProvides } = useSearchCapability();\nconst documentState = useDocumentState(() => props.documentId);\nconst searchResultState = ref<SearchResultState | null>(null);\n\nconst scope = computed(() => searchProvides.value?.forDocument(props.documentId) ?? null);\n\nconst actualScale = computed(() => {\n  if (props.scale !== undefined) return props.scale;\n  return documentState.value?.scale ?? 1;\n});\n\nwatch(\n  scope,\n  (scopeValue, _, onCleanup) => {\n    if (!scopeValue) {\n      searchResultState.value = null;\n      return;\n    }\n\n    // Set initial state\n    const currentState = scopeValue.getState();\n    searchResultState.value = {\n      results: currentState.results,\n      activeResultIndex: currentState.activeResultIndex,\n      showAllResults: currentState.showAllResults,\n      active: currentState.active,\n    };\n\n    // Subscribe to changes\n    const unsubscribe = scopeValue.onSearchResultStateChange((state) => {\n      searchResultState.value = state;\n    });\n\n    onCleanup(unsubscribe);\n  },\n  { immediate: true },\n);\n\n// Filter results for current page while preserving original indices\nconst pageResults = computed(() => {\n  if (!searchResultState.value) return [];\n\n  return searchResultState.value.results\n    .map((result, originalIndex) => ({ result, originalIndex }))\n    .filter(({ result }) => result.pageIndex === props.pageIndex);\n});\n\n// Decide which results to show\nconst resultsToShow = computed(() => {\n  if (!searchResultState.value) return [];\n\n  return pageResults.value.filter(\n    ({ originalIndex }) =>\n      searchResultState.value!.showAllResults ||\n      originalIndex === searchResultState.value!.activeResultIndex,\n  );\n});\n</script>\n\n<template>\n  <div\n    v-if=\"searchResultState && searchResultState.active\"\n    :style=\"{\n      pointerEvents: 'none',\n    }\"\n    v-bind=\"$attrs\"\n  >\n    <template v-for=\"({ result, originalIndex }, idx) in resultsToShow\" :key=\"`result-${idx}`\">\n      <div\n        v-for=\"(rect, rectIdx) in result.rects\"\n        :key=\"`rect-${idx}-${rectIdx}`\"\n        :style=\"{\n          position: 'absolute',\n          top: `${rect.origin.y * actualScale}px`,\n          left: `${rect.origin.x * actualScale}px`,\n          width: `${rect.size.width * actualScale}px`,\n          height: `${rect.size.height * actualScale}px`,\n          backgroundColor:\n            originalIndex === searchResultState.activeResultIndex\n              ? activeHighlightColor\n              : highlightColor,\n          mixBlendMode: 'multiply',\n          transform: 'scale(1.02)',\n          transformOrigin: 'center',\n          transition: 'opacity .3s ease-in-out',\n          opacity: 1,\n        }\"\n      />\n    </template>\n  </div>\n</template>\n"],"names":["useSearchCapability","useCapability","SearchPlugin","id","props","__props","provides","searchProvides","documentState","useDocumentState","documentId","searchResultState","ref","scope","computed","_a","value","forDocument","actualScale","scale","watch","scopeValue","_","onCleanup","currentState","getState","results","activeResultIndex","showAllResults","active","onSearchResultStateChange","state","immediate","pageResults","map","result","originalIndex","filter","pageIndex","resultsToShow","_openBlock","_createElementBlock","_mergeProps","style","$attrs","_Fragment","idx","rects","rect","rectIdx","key","_normalizeStyle","top","origin","y","left","x","width","size","height","activeHighlightColor","highlightColor","searchState","initialSearchDocumentState","toValue","providesValue","docId","onStateChange","scopedProvides","usePlugin"],"mappings":"4KAUaA,EAAsB,IAAMC,gBAA4BC,EAAAA,aAAaC,gLCIlF,MAAMC,EAAQC,GAKNC,SAAUC,GAAmBP,IAC/BQ,EAAgBC,EAAAA,iBAAiB,IAAML,EAAMM,YAC7CC,EAAoBC,EAAAA,IAA8B,MAElDC,EAAQC,WAAS,WAAM,OAAA,OAAAC,EAAAR,EAAeS,YAAf,EAAAD,EAAsBE,YAAYb,EAAMM,cAAe,OAE9EQ,EAAcJ,EAAAA,SAAS,WAC3B,YAAoB,IAAhBV,EAAMe,MAA4Bf,EAAMe,OACrC,OAAAJ,EAAAP,EAAcQ,YAAd,EAAAD,EAAqBI,QAAS,IAGvCC,EAAAA,MACEP,EACA,CAACQ,EAAYC,EAAGC,KACd,IAAKF,EAEH,YADAV,EAAkBK,MAAQ,MAK5B,MAAMQ,EAAeH,EAAWI,WAChCd,EAAkBK,MAAQ,CACxBU,QAASF,EAAaE,QACtBC,kBAAmBH,EAAaG,kBAChCC,eAAgBJ,EAAaI,eAC7BC,OAAQL,EAAaK,QAQvBN,EAJoBF,EAAWS,0BAA2BC,IACxDpB,EAAkBK,MAAQe,MAK9B,CAAEC,WAAW,IAIf,MAAMC,EAAcnB,EAAAA,SAAS,IACtBH,EAAkBK,MAEhBL,EAAkBK,MAAMU,QAC5BQ,IAAI,CAACC,EAAQC,KAAA,CAAqBD,SAAQC,mBAC1CC,OAAO,EAAGF,YAAaA,EAAOG,YAAclC,EAAMkC,WAJhB,IAQjCC,EAAgBzB,EAAAA,SAAS,IACxBH,EAAkBK,MAEhBiB,EAAYjB,MAAMqB,OACvB,EAAGD,mBACDzB,EAAkBK,MAAOY,gBACzBQ,IAAkBzB,EAAkBK,MAAOW,mBALV,iBAY7BhB,EAAAK,OAAqBL,EAAAK,MAAkBa,QAD/CW,EAAAA,YAAAC,EAAAA,mBA6BM,MA7BNC,aA6BM,OA3BHC,MAAO,wBAGAC,EAAAA,QAAM,EAEdJ,EAAAA,WAAA,GAAAC,qBAqBWI,EAAAA,2BArB0CN,EAAAvB,MAAa,EAA9CmB,SAAQC,iBAAiBU,kEAAuCA,OAClFN,EAAAA,WAAA,GAAAC,EAAAA,mBAmBEI,6BAlB0BV,EAAOY,MAAK,CAA9BC,EAAMC,mBADhBR,EAAAA,mBAmBE,MAAA,CAjBCS,IAAG,QAAUJ,KAAOG,IACpBN,MAAKQ,EAAAA,eAAA,qBAAsDC,IAAAJ,EAAKK,OAAOC,EAAIpC,EAAAF,MAAhB,KAAoDuC,KAAAP,EAAKK,OAAOG,EAAItC,EAAAF,MAAhB,KAAqDyC,MAAAT,EAAKU,KAAKD,MAAQvC,EAAAF,MAAlB,KAAwD2C,OAAAX,EAAKU,KAAKC,OAASzC,EAAAF,MAAnB,qBAA2EoB,IAAkBzB,EAAAK,MAAkBW,kBAAkCtB,EAAAuD,qBAAqCvD,EAAAwD,oPDzEzZnD,IAKA,MAAMJ,SAAEA,GAAaN,IACf8D,EAAclD,EAAAA,IAAyBmD,8BAE7C3C,EAAAA,MACE,CAACd,EAAU,IAAM0D,UAAQtD,IACzB,EAAEuD,EAAeC,GAAQ5C,EAAGC,KAC1B,IAAK0C,EAEH,YADAH,EAAY9C,MAAQ+C,EAAAA,4BAItB,MAAMlD,EAAQoD,EAAchD,YAAYiD,GAGxCJ,EAAY9C,MAAQH,EAAMY,WAO1BF,EAJoBV,EAAMsD,cAAepC,IACvC+B,EAAY9C,MAAQe,MAKxB,CAAEC,WAAW,IAGf,MAAMoC,EAAiBtD,EAAAA,SAAS,WAC9B,MAAMoD,EAAQF,EAAAA,QAAQtD,GACtB,OAAO,OAAAK,EAAAT,EAASU,YAAT,EAAAD,EAAgBE,YAAYiD,KAAU,OAG/C,MAAO,CACLnC,MAAO+B,EACPxD,SAAU8D,0DA9CiB,IAAMC,YAAwBnE,EAAAA,aAAaC"}