@veltdev/plate-comments-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +59 -0
  2. package/cjs/index.js +2 -0
  3. package/cjs/index.js.map +1 -0
  4. package/cjs/types/adapters/host/doc.d.ts +69 -0
  5. package/cjs/types/adapters/host/marks.d.ts +51 -0
  6. package/cjs/types/adapters/host/storage.d.ts +36 -0
  7. package/cjs/types/adapters/velt.d.ts +50 -0
  8. package/cjs/types/constants/common.d.ts +62 -0
  9. package/cjs/types/core/ExtensionComponent.d.ts +13 -0
  10. package/cjs/types/core/extension.d.ts +50 -0
  11. package/cjs/types/core/registry.d.ts +52 -0
  12. package/cjs/types/core/state.d.ts +80 -0
  13. package/cjs/types/features/addComment.d.ts +63 -0
  14. package/cjs/types/features/commentRenderer.d.ts +46 -0
  15. package/cjs/types/features/renderComments.d.ts +73 -0
  16. package/cjs/types/features/updateContent.d.ts +20 -0
  17. package/cjs/types/index.d.ts +16 -0
  18. package/cjs/types/types/common.d.ts +54 -0
  19. package/cjs/types/types/host.d.ts +74 -0
  20. package/cjs/types/types/state.d.ts +28 -0
  21. package/cjs/types/types/velt.d.ts +23 -0
  22. package/cjs/types/utils/common.d.ts +80 -0
  23. package/cjs/types/utils/console.d.ts +10 -0
  24. package/cjs/types/utils/serializer.d.ts +20 -0
  25. package/esm/index.js +2 -0
  26. package/esm/index.js.map +1 -0
  27. package/esm/types/adapters/host/doc.d.ts +69 -0
  28. package/esm/types/adapters/host/marks.d.ts +51 -0
  29. package/esm/types/adapters/host/storage.d.ts +36 -0
  30. package/esm/types/adapters/velt.d.ts +50 -0
  31. package/esm/types/constants/common.d.ts +62 -0
  32. package/esm/types/core/ExtensionComponent.d.ts +13 -0
  33. package/esm/types/core/extension.d.ts +50 -0
  34. package/esm/types/core/registry.d.ts +52 -0
  35. package/esm/types/core/state.d.ts +80 -0
  36. package/esm/types/features/addComment.d.ts +63 -0
  37. package/esm/types/features/commentRenderer.d.ts +46 -0
  38. package/esm/types/features/renderComments.d.ts +73 -0
  39. package/esm/types/features/updateContent.d.ts +20 -0
  40. package/esm/types/index.d.ts +16 -0
  41. package/esm/types/types/common.d.ts +54 -0
  42. package/esm/types/types/host.d.ts +74 -0
  43. package/esm/types/types/state.d.ts +28 -0
  44. package/esm/types/types/velt.d.ts +23 -0
  45. package/esm/types/utils/common.d.ts +80 -0
  46. package/esm/types/utils/console.d.ts +10 -0
  47. package/esm/types/utils/serializer.d.ts +20 -0
  48. package/index.d.ts +291 -0
  49. package/package.json +28 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/constants/common.ts","../../src/utils/common.ts","../../src/utils/console.ts","../../src/adapters/host/doc.ts","../../src/core/ExtensionComponent.tsx","../../src/core/state.ts","../../src/core/registry.ts","../../src/adapters/host/marks.ts","../../node_modules/tslib/tslib.es6.js","../../src/adapters/velt.ts","../../src/features/updateContent.ts","../../src/core/extension.ts","../../src/adapters/host/storage.ts","../../src/features/addComment.ts","../../src/features/commentRenderer.ts","../../src/features/renderComments.ts","../../src/utils/serializer.ts"],"sourcesContent":["/**\n * Shared constants for Plate-Velt Comments integration\n *\n * This module contains all magic strings and configuration constants\n * used across the application.\n */\nexport const Constants = {\n /**\n * DOM attribute names used for editor identification and location tracking.\n */\n ATTRIBUTES: {\n EDITOR_ID: 'data-editor-id',\n LOCATION_ID: 'data-velt-location-id',\n ANNOTATION_ID: 'annotation-id',\n MULTI_THREAD_ANNOTATION_ID: 'multi-thread-annotation-id',\n },\n /**\n * Element types used in the editor's document model.\n */\n ELEMENT_TYPE: {\n VELT_COMMENT: 'veltComment',\n },\n /**\n * Mark/extension name constant.\n * Generic constant name, value is Plate-specific for this package.\n */\n MARK_NAME: 'veltComment',\n /**\n * Plugin key for Plate.js plugin system.\n */\n PLUGIN_KEY: 'veltComments',\n /**\n * Storage key constant.\n * Generic constant name, value is Plate-specific for this package.\n */\n STORAGE_KEY: 'plateVeltComments',\n /**\n * Default extension name for error messages.\n */\n DEFAULT_EXTENSION_NAME: 'VeltComments',\n /**\n * Default editor ID used when no editor ID is provided.\n * Uses '__default__' to avoid collision with user-provided values.\n */\n DEFAULT_EDITOR_ID: '__default__',\n /**\n * Terminal status type for resolved/closed comments.\n */\n STATUS_TERMINAL: 'terminal',\n /**\n * Log prefix for console messages.\n */\n LOG_PREFIX: 'PlateVeltComments: ',\n /**\n * Session storage key for debug mode.\n */\n DEBUG_MODE_KEY: 'debugMode',\n /**\n * Session storage key for forced debug mode.\n */\n FORCE_DEBUG_MODE_KEY: 'forceDebugMode',\n};\n","/**\n * Pure utility functions with zero side effects.\n * These functions contain algorithmic logic extracted from legacy code.\n *\n * IMPORTANT: This module MUST NOT import any external SDKs or have side effects.\n * All functions must be pure: input → output, deterministic, no mutations.\n */\n/**\n * Computes the KMP (Knuth-Morris-Pratt) failure function (LPS array).\n * This is used for efficient pattern matching in text search.\n *\n * @param pattern The pattern string to compute the failure function for\n * @returns Longest proper prefix array (LPS array)\n *\n * @example\n * ```typescript\n * const lps = computeKMPTable(\"abcabc\");\n * // Returns: [0, 0, 0, 1, 2, 3]\n * ```\n */\nexport const computeKMPTable = (pattern) => {\n if (!pattern || pattern.length === 0) {\n return [];\n }\n const lps = new Array(pattern.length).fill(0);\n let len = 0;\n let i = 1;\n while (i < pattern.length) {\n if (pattern[i] === pattern[len]) {\n len++;\n lps[i] = len;\n i++;\n }\n else {\n if (len !== 0) {\n len = lps[len - 1];\n }\n else {\n lps[i] = 0;\n i++;\n }\n }\n }\n return lps;\n};\n/**\n * Finds all occurrences of a pattern in text using the KMP algorithm.\n *\n * @param text The text to search in\n * @param pattern The pattern to search for\n * @param startPos Starting position offset (default: 0)\n * @param maxOccurrences Maximum number of occurrences to find (optional)\n * @returns Array of start positions (0-based indices in the text)\n *\n * @example\n * ```typescript\n * const positions = kmpSearch(\"abcabcabc\", \"abc\", 0, 2);\n * // Returns: [0, 3] (first 2 occurrences)\n * ```\n */\nexport const kmpSearch = (text, pattern, startPos = 0, maxOccurrences) => {\n const positions = [];\n if (!pattern || !text || pattern.length > text.length) {\n return positions;\n }\n const lps = computeKMPTable(pattern);\n let i = 0;\n let j = 0;\n while (i < text.length) {\n if (pattern[j] === text[i]) {\n i++;\n j++;\n }\n if (j === pattern.length) {\n positions.push(startPos + i - j);\n j = lps[j - 1];\n if (maxOccurrences && positions.length >= maxOccurrences) {\n break;\n }\n }\n else if (i < text.length && pattern[j] !== text[i]) {\n if (j !== 0) {\n j = lps[j - 1];\n }\n else {\n i++;\n }\n }\n }\n return positions;\n};\n/**\n * Maps text positions in a combined string back to document positions.\n * Used when searching across multiple text nodes that have been concatenated.\n *\n * @param textNodes Array of text nodes with their document positions\n * @param textPositions Positions in the combined text (from kmpSearch)\n * @param patternLength Length of the pattern being searched for\n * @returns Array of { from, to } ranges in document coordinates\n *\n * @example\n * ```typescript\n * const textNodes = [\n * { text: \"Hello \", pos: 0 },\n * { text: \"World\", pos: 6 }\n * ];\n * const positions = [0]; // Found at start of combined text\n * const ranges = mapTextPositionsToDocument(textNodes, positions, 5);\n * // Returns: [{ from: 0, to: 5 }]\n * ```\n */\nexport const mapTextPositionsToDocument = (textNodes, textPositions, patternLength) => {\n const ranges = [];\n for (const textPos of textPositions) {\n let currentPos = 0;\n let startNodeIndex = -1;\n let startOffset = 0;\n let endNodeIndex = -1;\n let endOffset = 0;\n // Find the start and end nodes for this match\n for (let i = 0; i < textNodes.length; i++) {\n const node = textNodes[i];\n const nodeLength = node.text.length;\n // Check if this node contains the start of the match\n if (startNodeIndex === -1 && textPos < currentPos + nodeLength) {\n startNodeIndex = i;\n startOffset = textPos - currentPos;\n }\n // Check if this node contains the end of the match\n if (endNodeIndex === -1 && textPos + patternLength <= currentPos + nodeLength) {\n endNodeIndex = i;\n endOffset = textPos + patternLength - currentPos;\n break;\n }\n currentPos += nodeLength;\n }\n // If we found both start and end nodes, create the range\n if (startNodeIndex !== -1 && endNodeIndex !== -1) {\n const startPos = textNodes[startNodeIndex].pos + startOffset;\n const endPos = textNodes[endNodeIndex].pos + endOffset;\n ranges.push({ from: startPos, to: endPos });\n }\n }\n return ranges;\n};\n/**\n * Compares two maps for equality.\n * Checks if both maps have the same size and identical key-value pairs.\n *\n * @param map1 First map to compare\n * @param map2 Second map to compare\n * @returns True if maps are equal, false otherwise\n *\n * @example\n * ```typescript\n * const map1 = new Map([['a', true], ['b', false]]);\n * const map2 = new Map([['a', true], ['b', false]]);\n * areMapsEqual(map1, map2); // Returns: true\n * ```\n */\nexport const areMapsEqual = (map1, map2) => {\n if (map1.size !== map2.size)\n return false;\n for (const [key, value] of Array.from(map1)) {\n if (map2.get(key) !== value)\n return false;\n }\n return true;\n};\n","import { Constants } from '@/constants/common';\nexport class Console {\n static showLogs() {\n try {\n return !!sessionStorage.getItem(Constants.DEBUG_MODE_KEY) || !!sessionStorage.getItem(Constants.FORCE_DEBUG_MODE_KEY);\n }\n catch (err) {\n Console.catch('Error in showLogs: ', err);\n return false;\n }\n }\n}\nConsole.log = Console.showLogs() ? console.log : () => { };\nConsole.warn = Console.showLogs() ? console.warn : () => { };\nConsole.error = Console.showLogs() ? console.error : () => { };\nConsole.debug = Console.showLogs() ? console.debug : () => { };\nConsole.info = Console.showLogs() ? console.info : () => { };\nConsole.logsEnabled = true;\n// to show error catched in try catch\nConsole.catch = (message, error) => {\n try {\n if (Console.logsEnabled) {\n if (error !== undefined) {\n console.warn(Constants.LOG_PREFIX, message, error);\n }\n else {\n console.warn(Constants.LOG_PREFIX, message);\n }\n }\n }\n catch (err) {\n // do nothing\n }\n};\n","/**\n * Host editor document operations adapter for Plate.js.\n * This is the ONLY place where editor-specific types may be imported.\n *\n * Responsibilities:\n * - Extract selection context from editor\n * - Find text occurrences in document\n * - Detect document changes for annotations\n * - Get editor ID from DOM\n *\n * Architectural Rules:\n * - MAY import editor-specific types (PlateEditor, etc.)\n * - MUST NOT import Velt SDK types\n * - Uses pure utilities from utils/common.ts where possible\n *\n * NOTE: This file uses Plate.js native utilities from @platejs/slate\n */\nimport { ElementApi, NodeApi, PathApi } from '@platejs/slate';\nimport { Editor as SlateEditor } from 'slate';\nimport { ReactEditor } from 'slate-react';\nimport { Constants } from '@/constants/common';\nimport { kmpSearch } from '@/utils/common';\nimport { Console } from '@/utils/console';\n/**\n * Gets editor ID from editor instance by traversing DOM.\n * Returns null if editor ID attribute not found.\n */\nexport const getEditorId = (editor) => {\n var _a, _b;\n try {\n // Get the DOM node representing the editor using ReactEditor.toDOMNode\n const domNode = ReactEditor.toDOMNode(editor, editor);\n if (domNode) {\n return ((_b = (_a = domNode === null || domNode === void 0 ? void 0 : domNode.closest(`[${Constants.ATTRIBUTES.EDITOR_ID}]`)) === null || _a === void 0 ? void 0 : _a.getAttribute(Constants.ATTRIBUTES.EDITOR_ID)) !== null && _b !== void 0 ? _b : null);\n }\n // No parent with data-editor-id found\n return null;\n }\n catch (error) {\n // Editor not mounted yet - this is expected during initial editor creation\n // Return null silently, the editorId will be resolved when editor is mounted\n // or a default will be used by the extension\n return null;\n }\n};\n/**\n * Gets current selection context from editor with full details.\n * Returns null if no selection or selection is collapsed.\n */\nexport const getCurrentSelectionContext = (editor) => {\n var _a, _b, _c;\n try {\n // Ensure there's a selection\n if (!editor.selection) {\n return null;\n }\n // Get selected text using Slate's Editor.string\n const text = SlateEditor.string(editor, editor.selection);\n if (!text) {\n return null;\n }\n // Calculate start and end positions using Slate's utilities\n const startPoint = SlateEditor.start(editor, editor.selection);\n const endPoint = SlateEditor.end(editor, editor.selection);\n const from = (_a = startPoint === null || startPoint === void 0 ? void 0 : startPoint.offset) !== null && _a !== void 0 ? _a : 0;\n const to = (_b = endPoint === null || endPoint === void 0 ? void 0 : endPoint.offset) !== null && _b !== void 0 ? _b : 0;\n // Find parent node with ID for targetTextNodeId\n const targetTextNode = findParentNodeWithId(editor);\n const targetTextNodeId = targetTextNode === null || targetTextNode === void 0 ? void 0 : targetTextNode.id;\n // Find location ID from DOM\n let locationId;\n if (targetTextNode) {\n locationId =\n ((_c = targetTextNode\n .closest(`[${Constants.ATTRIBUTES.LOCATION_ID}]`)) === null || _c === void 0 ? void 0 : _c.getAttribute(Constants.ATTRIBUTES.LOCATION_ID)) || undefined;\n }\n // Find occurrence index\n const occurrence = findOccurrenceIndex(editor, text, targetTextNodeId);\n return {\n text,\n from,\n to,\n occurrence,\n targetTextNodeId,\n locationId,\n };\n }\n catch (error) {\n Console.catch('[HostAdapter] Error getting selection context:', error);\n return null;\n }\n};\n/**\n * Finds occurrence index of selected text in the document.\n * Returns 1-based occurrence index, or 0 if not found.\n */\nexport const findOccurrenceIndex = (editor, text, targetTextNodeId) => {\n try {\n if (!text || !editor.selection) {\n return 0;\n }\n // If targetTextNodeId is provided, find occurrences within that node\n if (targetTextNodeId) {\n const targetElement = document.getElementById(targetTextNodeId);\n if (targetElement) {\n // Use DOM-based occurrence finding for scoped search\n const startOffset = editor.selection.anchor.offset;\n return findOccurrenceInDOM(targetElement, text, startOffset);\n }\n }\n // Find all matches in the document\n const allMatches = findAllMatches(editor, text);\n const selection = editor.selection;\n if (!selection || allMatches.length === 0) {\n return 0;\n }\n // Check if selection is forward or backward using Plate's PathApi\n const isBackward = PathApi.compare(selection.anchor.path, selection.focus.path) > 0 ||\n (PathApi.equals(selection.anchor.path, selection.focus.path) &&\n selection.anchor.offset > selection.focus.offset);\n // Find matching occurrence\n const matchIndex = allMatches.findIndex((match) => {\n if (isBackward) {\n return (PathApi.equals(match.anchor.path, selection.focus.path) &&\n PathApi.equals(match.focus.path, selection.anchor.path) &&\n match.anchor.offset === selection.focus.offset &&\n match.focus.offset === selection.anchor.offset);\n }\n else {\n return (PathApi.equals(match.anchor.path, selection.anchor.path) &&\n PathApi.equals(match.focus.path, selection.focus.path) &&\n match.anchor.offset === selection.anchor.offset &&\n match.focus.offset === selection.focus.offset);\n }\n });\n return matchIndex !== -1 ? matchIndex + 1 : 0;\n }\n catch (error) {\n Console.catch('[HostAdapter] Error finding occurrence index:', error);\n return 0;\n }\n};\n/**\n * Finds parent node with ID attribute for current selection.\n * Returns HTMLElement with ID, or null if not found.\n */\nexport const findParentNodeWithId = (editor) => {\n try {\n const { selection } = editor;\n if (!selection) {\n return null;\n }\n const { anchor } = selection;\n const node = NodeApi.get(editor, anchor.path);\n if (!node) {\n return null;\n }\n return findParentNodeWithIdFromNode(editor, node, anchor.path);\n }\n catch (error) {\n Console.catch('[HostAdapter] Error finding parent node with ID:', error);\n return null;\n }\n};\n/**\n * Helper: Finds parent node with ID from a given node.\n */\nconst findParentNodeWithIdFromNode = (editor, node, path, maxIterations = 100) => {\n try {\n let domNode = null;\n let editorDOM = null;\n try {\n // Convert Slate node to DOM node using ReactEditor.toDOMNode\n domNode = ReactEditor.toDOMNode(editor, node);\n }\n catch (err) {\n return null;\n }\n try {\n // Get the editor's DOM element\n editorDOM = ReactEditor.toDOMNode(editor, editor);\n }\n catch (err) {\n return null;\n }\n let currentNode = domNode;\n let iterationCount = 0;\n while (currentNode && currentNode !== document.body && iterationCount < maxIterations) {\n // Check if we're still within the editor's DOM\n if (!editorDOM || !editorDOM.contains(currentNode)) {\n return null;\n }\n // Check if current node has an ID\n if (currentNode.id) {\n return currentNode;\n }\n currentNode = currentNode.parentElement;\n iterationCount++;\n }\n return null;\n }\n catch (error) {\n Console.catch('[HostAdapter] Error finding parent node:', error);\n return null;\n }\n};\n/**\n * Helper: Finds all matches of text in the document using KMP algorithm.\n */\nconst findAllMatches = (editor, textToSearch, caseSensitive = true) => {\n try {\n const matches = [];\n if (!textToSearch) {\n return matches;\n }\n // Safely get text from a node\n const getText = (node) => {\n return typeof node === 'object' && node !== null && 'text' in node ? node.text : '';\n };\n // Check if a node is a text node\n const isTextNode = (node) => {\n return (typeof node === 'object' &&\n node !== null &&\n 'text' in node &&\n typeof node.text === 'string');\n };\n // Iterate through all text nodes in the document\n const searchInNode = (node, path) => {\n // Handle text nodes\n if (isTextNode(node)) {\n const text = getText(node);\n // Apply case sensitivity\n const searchText = caseSensitive ? textToSearch : textToSearch.toLowerCase();\n const nodeText = caseSensitive ? text : text.toLowerCase();\n // Use KMP algorithm to find all matches in the current text node\n const positions = kmpSearch(nodeText, searchText);\n // Create ranges for each match\n for (const index of positions) {\n const range = {\n anchor: { path, offset: index },\n focus: { path, offset: index + textToSearch.length },\n };\n matches.push(range);\n }\n }\n // Recursively search child nodes\n if ('children' in node && Array.isArray(node.children)) {\n node.children.forEach((child, index) => {\n searchInNode(child, [...path, index]);\n });\n }\n };\n // Start the search from the root of the document\n try {\n // Use NodeApi.nodes to iterate through nodes\n const nodeEntries = NodeApi.nodes(editor, { pass: () => true });\n const [initialNode] = Array.from(nodeEntries).slice(0, 1);\n if (initialNode) {\n searchInNode(initialNode[0], initialNode[1]);\n }\n }\n catch (error) {\n Console.catch('[HostAdapter] Error searching in document:', error);\n }\n return matches;\n }\n catch (error) {\n Console.catch('[HostAdapter] Error finding all matches:', error);\n return [];\n }\n};\n/**\n * Helper: Finds occurrence in DOM element using KMP algorithm (for scoped searches).\n */\nconst findOccurrenceInDOM = (element, searchText, startOffset, caseSensitive = true) => {\n try {\n if (!searchText) {\n return 0;\n }\n const fullText = element.textContent || '';\n const processedFullText = caseSensitive ? fullText : fullText.toLowerCase();\n const processedSearchText = caseSensitive ? searchText : searchText.toLowerCase();\n // Use KMP algorithm to find all occurrences\n const occurrences = kmpSearch(processedFullText, processedSearchText);\n if (occurrences.length === 0) {\n return 0;\n }\n // Calculate position (1-based)\n if (startOffset !== undefined) {\n const positionBeforeSelected = occurrences.filter((index) => index < startOffset).length + 1;\n return positionBeforeSelected;\n }\n return 1; // Default to first occurrence\n }\n catch (error) {\n Console.catch('[HostAdapter] Error finding occurrence in DOM:', error);\n return 0;\n }\n};\n/**\n * Detects document changes for annotations.\n * Compares current document state with stored annotation data.\n */\nexport const detectDocumentChanges = (editor, transaction, markType = Constants.MARK_NAME, getAnnotationData) => {\n const logPrefix = '[detectDocumentChanges]';\n const changes = new Map();\n try {\n // Collect all annotation nodes in the document using NodeApi\n const annotationNodes = Array.from(NodeApi.nodes(editor, {\n pass: ([node]) => {\n return (ElementApi.isElement(node) &&\n node.type === Constants.ELEMENT_TYPE.VELT_COMMENT &&\n 'annotationId' in node);\n },\n })).filter(([node]) => {\n return (ElementApi.isElement(node) &&\n node.type === Constants.ELEMENT_TYPE.VELT_COMMENT &&\n 'annotationId' in node);\n });\n for (const [node, path] of annotationNodes) {\n const veltNode = node;\n const annotationId = veltNode.annotationId;\n if (!annotationId) {\n Console.warn(`${logPrefix} Node missing annotationId, skipping`);\n continue;\n }\n // Get stored annotation data\n const storedData = getAnnotationData(annotationId);\n if (!storedData) {\n Console.warn(`${logPrefix} No stored data found for annotationId: ${annotationId}, skipping`);\n continue;\n }\n const originalText = storedData.originalText;\n const originalOccurrence = storedData.originalOccurrence;\n const originalTargetTextNodeId = storedData.targetTextNodeId || '';\n // Extract current text from node using NodeApi.string\n const currentText = NodeApi.string(node);\n if (!currentText) {\n Console.warn(`${logPrefix} Node has no text content, skipping`);\n continue;\n }\n // Find parent node with ID\n const currentTargetNode = findParentNodeWithIdFromNode(editor, node, path);\n const currentTargetNodeId = (currentTargetNode === null || currentTargetNode === void 0 ? void 0 : currentTargetNode.id) || '';\n // Calculate current occurrence\n const currentOccurrence = findOccurrenceForNode(editor, currentText, node, path, currentTargetNodeId);\n // Detect changes\n const textChanged = currentText !== originalText;\n const occurrenceChanged = currentOccurrence !== originalOccurrence;\n const targetTextNodeIdChanged = originalTargetTextNodeId !== currentTargetNodeId;\n if (textChanged || occurrenceChanged || targetTextNodeIdChanged) {\n const annotation = storedData.annotation;\n changes.set(annotationId, {\n annotationId,\n multiThreadAnnotationId: annotation.multiThreadAnnotationId,\n originalText,\n currentText,\n originalOccurrence,\n currentOccurrence,\n originalTargetTextNodeId,\n newTargetTextNodeId: currentTargetNodeId,\n annotation,\n contentChanged: textChanged,\n occurrenceChanged,\n targetTextNodeIdChanged,\n });\n }\n }\n }\n catch (error) {\n Console.catch('[HostAdapter] Error detecting document changes:', error);\n }\n return changes;\n};\n/**\n * Helper: Finds occurrence index for a given node and text.\n */\nconst findOccurrenceForNode = (editor, text, node, path, targetTextNodeId) => {\n try {\n if (!text) {\n return 0;\n }\n // Use NodeApi.string to get node text\n const nodeText = NodeApi.string(node);\n if (!nodeText || !nodeText.trim()) {\n return 0;\n }\n // Find all matches\n const allMatches = findAllMatches(editor, text);\n if (allMatches.length === 0) {\n return 0;\n }\n // Find which occurrence matches the node's path\n for (let i = 0; i < allMatches.length; i++) {\n const match = allMatches[i];\n const matchStart = SlateEditor.start(editor, match);\n if (!matchStart)\n continue;\n const matchPath = matchStart.path;\n const isEqual = PathApi.equals(matchPath, path);\n const isDescendant = PathApi.isAncestor(path, matchPath);\n if (isEqual || isDescendant) {\n return i + 1;\n }\n }\n return 0;\n }\n catch (error) {\n Console.catch('[HostAdapter] Error finding occurrence for node:', error);\n return 0;\n }\n};\n/**\n * Finds all text occurrences in the document.\n * Returns array of ranges matching the search text.\n */\nexport const findTextOccurrences = (editor, text, targetTextNodeId, occurrence) => {\n try {\n if (!text) {\n return [];\n }\n // Find all matches using editor traversal\n const ranges = findAllMatches(editor, text);\n // Convert ranges to OccurrenceMatch format using Slate's utilities\n const matches = ranges.map((range, index) => {\n var _a, _b;\n const startPoint = SlateEditor.start(editor, range);\n const endPoint = SlateEditor.end(editor, range);\n const start = (_a = startPoint === null || startPoint === void 0 ? void 0 : startPoint.offset) !== null && _a !== void 0 ? _a : 0;\n const end = (_b = endPoint === null || endPoint === void 0 ? void 0 : endPoint.offset) !== null && _b !== void 0 ? _b : 0;\n return {\n index: index + 1, // 1-based\n start,\n end,\n text,\n };\n });\n // Filter by occurrence if specified\n if (occurrence !== undefined && occurrence > 0) {\n const match = matches[occurrence - 1];\n return match ? [match] : [];\n }\n return matches;\n }\n catch (error) {\n Console.catch('[HostAdapter] Error finding text occurrences:', error);\n return [];\n }\n};\n/**\n * Ensures editor is set up (registered and document listeners configured).\n */\nexport const ensureEditorSetup = (editorId, editor) => {\n const logPrefix = '[ensureEditorSetup]';\n try {\n // Resolve editor ID if not provided\n let finalEditorId = editorId;\n if (!finalEditorId) {\n finalEditorId = getEditorId(editor) || Constants.DEFAULT_EDITOR_ID;\n }\n return { editorId: finalEditorId };\n }\n catch (error) {\n Console.warn(`${logPrefix} Error setting up editor:`, error);\n return { editorId: editorId || Constants.DEFAULT_EDITOR_ID };\n }\n};\n/**\n * Resets the editor selection by focusing the editor.\n */\nexport const resetEditorSelection = (editor) => {\n // For Plate, selection reset is typically handled by the editor itself\n};\n","/**\n * React component for rendering Velt comment elements in Plate editor.\n * This component renders the <velt-comment-text> custom element.\n *\n * Note: velt-comment-text is an inline element, so it should only contain text nodes\n * or other inline elements, never block elements like <p>.\n */\nimport React from 'react';\nimport { Constants } from '@/constants/common';\nexport const PlateVeltComment = (props) => {\n const { attributes, children, element } = props;\n const annotationId = element === null || element === void 0 ? void 0 : element.annotationId;\n // Use React.createElement to avoid TypeScript JSX type checking for custom web component\n // velt-comment-text is an inline element, so children should be inline content only\n return React.createElement('velt-comment-text', Object.assign({ [Constants.ATTRIBUTES.ANNOTATION_ID]: annotationId }, attributes), children);\n};\n","/**\n * Core state management module.\n *\n * Purpose: Single source of truth for annotation state per editor.\n * This module manages annotation data and selected annotations for each editor instance.\n *\n * Key responsibilities:\n * - Create and manage per-editor annotation state\n * - CRUD operations for annotations\n * - Track selected annotations\n * - Ensure state isolation between editor instances\n *\n * Dependencies: types/state.ts, types/common.ts\n */\nimport { Console } from '@/utils/console';\n/**\n * Per-editor state storage\n * Maps editorId -> AnnotationState\n */\nconst stateMap = new Map();\n/**\n * Creates a new annotation state for an editor instance.\n *\n * @param editorId Unique identifier for the editor\n * @returns New AnnotationState instance\n */\nexport const createAnnotationState = (editorId) => {\n const state = {\n annotations: new Map(),\n commentAnnotations: [], // Full CommentAnnotation[] with status for rendering\n selectedAnnotations: new Set(),\n editorId,\n };\n stateMap.set(editorId, state);\n return state;\n};\n/**\n * Gets the annotation state for an editor, creating it if it doesn't exist.\n *\n * @param editorId Unique identifier for the editor\n * @returns AnnotationState instance\n */\nconst getOrCreateState = (editorId) => {\n let state = stateMap.get(editorId);\n if (!state) {\n state = createAnnotationState(editorId);\n }\n return state;\n};\n/**\n * Updates annotations in state from Velt SDK data.\n * Converts CommentAnnotation[] to AnnotationData[] and stores them.\n *\n * @param editorId Unique identifier for the editor\n * @param annotations Array of CommentAnnotation from Velt SDK\n */\nexport const updateAnnotations = (editorId, annotations) => {\n try {\n const state = getOrCreateState(editorId);\n // Store full CommentAnnotation[] with status for rendering\n state.commentAnnotations = annotations;\n // Convert CommentAnnotation[] to AnnotationData[] for core logic\n const annotationDataMap = new Map();\n for (const annotation of annotations) {\n if (!(annotation === null || annotation === void 0 ? void 0 : annotation.annotationId)) {\n continue;\n }\n const annotationData = {\n annotationId: annotation.annotationId,\n multiThreadAnnotationId: annotation.multiThreadAnnotationId,\n context: annotation.context,\n // Position will be set when marks are applied\n };\n annotationDataMap.set(annotation.annotationId, annotationData);\n }\n // Update state\n state.annotations = annotationDataMap;\n }\n catch (error) {\n Console.catch('Error updating annotations:', error);\n }\n};\n/**\n * Retrieves a single annotation by ID.\n *\n * @param editorId Unique identifier for the editor\n * @param annotationId The annotation ID to retrieve\n * @returns AnnotationData or null if not found\n */\nexport const getAnnotation = (editorId, annotationId) => {\n try {\n const state = stateMap.get(editorId);\n if (!state) {\n return null;\n }\n return state.annotations.get(annotationId) || null;\n }\n catch (error) {\n Console.catch('Error getting annotation:', error);\n return null;\n }\n};\n/**\n * Removes an annotation from state.\n *\n * @param editorId Unique identifier for the editor\n * @param annotationId The annotation ID to remove\n */\nexport const removeAnnotation = (editorId, annotationId) => {\n try {\n const state = stateMap.get(editorId);\n if (!state) {\n return;\n }\n state.annotations.delete(annotationId);\n state.selectedAnnotations.delete(annotationId);\n }\n catch (error) {\n Console.catch('Error removing annotation:', error);\n }\n};\n/**\n * Gets the set of selected annotation IDs for an editor.\n *\n * @param editorId Unique identifier for the editor\n * @returns Set of selected annotation IDs\n */\nexport const getSelectedAnnotations = (editorId) => {\n try {\n const state = stateMap.get(editorId);\n if (!state) {\n return new Set();\n }\n return new Set(state.selectedAnnotations);\n }\n catch (error) {\n Console.catch('Error getting selected annotations:', error);\n return new Set();\n }\n};\n/**\n * Updates the set of selected annotation IDs for an editor.\n *\n * @param editorId Unique identifier for the editor\n * @param selectedIds Set of selected annotation IDs\n */\nexport const setSelectedAnnotations = (editorId, selectedIds) => {\n try {\n const state = getOrCreateState(editorId);\n state.selectedAnnotations = new Set(selectedIds);\n }\n catch (error) {\n Console.catch('Error setting selected annotations:', error);\n }\n};\n/**\n * Gets all annotations for an editor.\n *\n * @param editorId Unique identifier for the editor\n * @returns Map of annotation ID to AnnotationData\n */\nexport const getAllAnnotations = (editorId) => {\n try {\n const state = stateMap.get(editorId);\n if (!state) {\n return new Map();\n }\n return new Map(state.annotations);\n }\n catch (error) {\n Console.catch('Error getting all annotations:', error);\n return new Map();\n }\n};\n/**\n * Gets all comment annotations for an editor (with status field).\n *\n * @param editorId Unique identifier for the editor\n * @returns Array of CommentAnnotation with status field\n */\nexport const getCommentAnnotations = (editorId) => {\n try {\n const state = stateMap.get(editorId);\n if (!state) {\n return [];\n }\n return [...state.commentAnnotations];\n }\n catch (error) {\n Console.catch('Error getting comment annotations:', error);\n return [];\n }\n};\n/**\n * Clears all state for an editor (used during cleanup).\n *\n * @param editorId Unique identifier for the editor\n */\nexport const clearState = (editorId) => {\n stateMap.delete(editorId);\n};\n","/**\n * Core registry module.\n *\n * Purpose: Maintains a registry mapping editorId → editor context.\n * Replaces the singleton pattern from legacy Plugin class with a proper registry.\n *\n * Key responsibilities:\n * - Register editor instances with their configuration\n * - Retrieve editor contexts by ID\n * - Unregister editors when they're destroyed\n * - Extract editor IDs from editor instances\n *\n * Dependencies: types/common.ts, core/state.ts, adapters/host/doc.ts\n */\nimport { getEditorId } from '@/adapters/host/doc';\nimport { clearState, createAnnotationState } from '@/core/state';\nimport { Console } from '@/utils/console';\n/**\n * Registry mapping editorId -> EditorContext\n */\nconst registry = new Map();\n/**\n * Registers an editor instance in the registry.\n * Creates initial state for the editor.\n *\n * @param editorId Unique identifier for the editor\n * @param editor The editor instance\n * @param config Extension configuration options\n * @returns EditorContext for the registered editor\n */\nexport const registerEditor = (editorId, editor, config) => {\n // Ensure editorId is set\n const finalEditorId = editorId || 'default';\n // Create initial state for this editor\n createAnnotationState(finalEditorId);\n const context = {\n editorId: finalEditorId,\n editor,\n config: config || {},\n };\n registry.set(finalEditorId, context);\n return context;\n};\n/**\n * Retrieves the editor context for a given editor ID.\n *\n * @param editorId Unique identifier for the editor\n * @returns EditorContext or null if not found\n */\nexport const getEditorContext = (editorId) => {\n const context = registry.get(editorId);\n return context || null;\n};\n/**\n * Unregisters an editor from the registry and cleans up its state.\n *\n * @param editorId Unique identifier for the editor\n */\nexport const unregisterEditor = (editorId) => {\n registry.delete(editorId);\n clearState(editorId);\n};\n/**\n * Extracts the editor ID from an editor instance.\n * Checks editor storage first, then DOM attributes.\n *\n * @param editor The editor instance\n * @returns Editor ID or null if not found\n */\nexport const getEditorIdFromEditor = (editor) => {\n try {\n // Use the host adapter to extract editor ID\n // This avoids importing editor types here\n return getEditorId(editor);\n }\n catch (error) {\n Console.catch('Error extracting editor ID:', error);\n return null;\n }\n};\n/**\n * Gets all registered editor IDs.\n *\n * @returns Array of editor IDs\n */\nexport const getAllEditorIds = () => {\n return Array.from(registry.keys());\n};\n","/**\n * Host editor marks/nodes operations adapter for Plate.js.\n * This is the ONLY place where editor-specific mark/node operations may be implemented.\n *\n * Responsibilities:\n * - Apply comment marks/nodes to editor\n * - Remove comment marks/nodes from editor\n * - Update marks/nodes when document changes\n *\n * Architectural Rules:\n * - MAY import editor-specific types (PlateEditor, Element, Transforms, etc.)\n * - MUST NOT import Velt SDK types\n * - Handles editor-specific mark/node application logic\n *\n * NOTE: This file uses Plate.js native utilities from @platejs/slate\n */\nimport { ElementApi, NodeApi, TextApi } from '@platejs/slate';\nimport { ReactEditor } from 'slate-react';\nimport { Constants } from '@/constants/common';\nimport { Console } from '@/utils/console';\n/**\n * History editor type (if available from extension config).\n * Used to wrap operations without saving to history.\n * This is editor-specific and may vary, so we use unknown.\n */\nlet HistoryEditor = null;\n/**\n * Sets the history editor instance (called from extension).\n */\nexport const setHistoryEditor = (historyEditor) => {\n HistoryEditor = historyEditor;\n};\n/**\n * Gets the history editor instance.\n */\nexport const getHistoryEditor = () => {\n return HistoryEditor;\n};\n/**\n * Checks if a node is a Velt comment element.\n */\nconst isVeltCommentText = (element) => {\n return ElementApi.isElement(element) && element.type === Constants.ELEMENT_TYPE.VELT_COMMENT;\n};\n/**\n * Internal function that applies annotation mark/node to editor at specified range.\n * Wraps text range with comment element/node.\n */\nconst applyAnnotationMarkWithRange = (editor, annotationId, multiThreadAnnotationId, range) => {\n try {\n if (!range) {\n return false;\n }\n // Check if the range is already wrapped with a velt-comment-text element\n const nodesAtRange = Array.from(NodeApi.nodes(editor, {\n from: range.anchor.path,\n to: range.focus.path,\n pass: ([node]) => {\n if (!ElementApi.isElement(node)) {\n return false;\n }\n return isVeltCommentText(node);\n },\n })).filter(([node]) => ElementApi.isElement(node) && isVeltCommentText(node));\n if (nodesAtRange.length > 0) {\n return false;\n }\n // Wrap nodes with comment element using Plate's editor.tf.wrapNodes\n const wrapNodes = () => {\n editor.tf.wrapNodes({\n type: Constants.ELEMENT_TYPE.VELT_COMMENT,\n children: [],\n annotationId: annotationId,\n multiThreadAnnotationId: multiThreadAnnotationId,\n }, { at: range, split: true });\n };\n // Use history editor if available to wrap without saving to history\n if (HistoryEditor && typeof HistoryEditor.withoutSaving === 'function') {\n HistoryEditor.withoutSaving(editor, () => {\n wrapNodes();\n });\n }\n else {\n wrapNodes();\n }\n return true;\n }\n catch (error) {\n Console.catch('[HostAdapter] Error applying annotation mark:', error);\n return false;\n }\n};\n/**\n * Applies annotation mark/node by finding text occurrence and wrapping it.\n * This is the main entry point for applying marks.\n *\n * @param editor The editor instance (typed as unknown to avoid importing editor types in feature modules)\n * @param textToSearch The text to search for\n * @param occurrence The occurrence number (1-based)\n * @param annotationId The annotation ID to mark\n * @param multiThreadAnnotationId Optional multi-thread annotation ID\n * @param targetElementId Optional target element ID to scope the search\n * @returns True if mark was successfully applied, false otherwise\n */\nexport const applyAnnotationMarkByText = (editor, textToSearch, occurrence, annotationId, multiThreadAnnotationId, targetElementId) => {\n const logPrefix = '[applyAnnotationMarkByText]';\n try {\n if (!editor || !annotationId) {\n return false;\n }\n const plateEditor = editor;\n // Find target element\n let targetElement = null;\n if (targetElementId) {\n targetElement = document.getElementById(targetElementId);\n // Validate target element\n if (!targetElement) {\n Console.warn(`${logPrefix} Target element not found: ${targetElementId}`);\n return false;\n }\n // Ensure the element is part of the editor\n if (!isElementInEditor(plateEditor, targetElement)) {\n Console.warn(`${logPrefix} Target element not in editor: ${targetElementId}`);\n return false;\n }\n }\n else {\n // For Plate, we need to find the editor's DOM element differently\n try {\n // Try to get the editor element via the DOM using data-slate-editor attribute\n const editorElement = document.querySelector('[data-slate-editor=\"true\"]');\n if (editorElement) {\n targetElement = editorElement;\n }\n }\n catch (e) {\n Console.warn(`${logPrefix} Could not find editor DOM element`, e);\n }\n }\n if (!targetElement) {\n Console.warn(`${logPrefix} No target element found`);\n return false;\n }\n // Find the range for the specific text occurrence\n const range = findTextOccurrenceRange(plateEditor, textToSearch, occurrence, targetElement);\n if (!range) {\n Console.warn(`${logPrefix} Could not find text occurrence range for \"${textToSearch}\" occurrence ${occurrence}`);\n return false;\n }\n // Apply mark directly with range instead of converting to from/to\n const result = applyAnnotationMarkWithRange(plateEditor, annotationId, multiThreadAnnotationId, range);\n return result;\n }\n catch (error) {\n Console.catch(`${logPrefix} Error applying annotation mark by text:`, error);\n return false;\n }\n};\n/**\n * Removes annotation mark/node from editor by annotation ID.\n * Finds all nodes with matching annotationId and unwraps them.\n */\nexport const removeAnnotationMark = (editor, annotationId) => {\n const logPrefix = '[removeAnnotationMark]';\n try {\n if (!editor || !annotationId) {\n return false;\n }\n // Create an array to store paths of elements to remove\n const elementsToUnwrap = [];\n // Iterate through all nodes in the editor using NodeApi.descendants\n for (const [node, path] of NodeApi.descendants(editor)) {\n // Check if the node is a Velt comment element with matching annotationId\n if (ElementApi.isElement(node) &&\n isVeltCommentText(node) &&\n node.annotationId === annotationId) {\n elementsToUnwrap.push(path);\n }\n }\n if (elementsToUnwrap.length === 0) {\n return false;\n }\n // Unwrap elements in reverse order to avoid path shifting issues\n elementsToUnwrap.reverse().forEach((path) => {\n try {\n const unwrapNodes = () => {\n // Use Plate's editor.tf.unwrapNodes\n editor.tf.unwrapNodes({\n at: path,\n mode: 'lowest',\n });\n };\n // Use history editor if available\n if (HistoryEditor && typeof HistoryEditor.withoutSaving === 'function') {\n HistoryEditor.withoutSaving(editor, () => {\n unwrapNodes();\n });\n }\n else {\n unwrapNodes();\n }\n }\n catch (err) {\n Console.catch(`${logPrefix} Error unwrapping element at path ${path}:`, err);\n }\n });\n return true;\n }\n catch (error) {\n Console.catch(`${logPrefix} Error removing annotation mark:`, error);\n return false;\n }\n};\n/**\n * Updates marks/nodes based on document changes.\n * Removes old marks and applies new ones at updated positions.\n */\nexport const updateMarks = (editor, changes) => {\n try {\n for (const [annotationId] of changes) {\n // Remove old mark\n removeAnnotationMark(editor, annotationId);\n // TODO: Re-apply mark at new position if needed\n // This requires the full annotation data to rebuild the mark\n // For now, just remove - re-application will happen via renderComments\n }\n }\n catch (error) {\n Console.catch('[HostAdapter] Error updating marks:', error);\n }\n};\n/**\n * Helper: Checks if element is within editor DOM.\n */\nconst isElementInEditor = (editor, element) => {\n try {\n // Find editor element via DOM attribute instead of ReactEditor.toDOMNode\n const editorElement = document.querySelector('[data-slate-editor=\"true\"]');\n if (!editorElement) {\n return false;\n }\n return editorElement.contains(element);\n }\n catch (error) {\n Console.catch('[HostAdapter] Error checking element in editor:', error);\n return false;\n }\n};\n/**\n * Helper: Finds text occurrence range in editor.\n * Converts DOM element to Slate range for the specified occurrence.\n */\nconst findTextOccurrenceRange = (editor, textToSearch, occurrence, targetElement) => {\n const logPrefix = '[findTextOccurrenceRange]';\n try {\n let targetNode;\n let targetPath;\n // Check if target element is the editor element itself\n const isEditorElement = targetElement.hasAttribute('data-slate-editor');\n if (isEditorElement) {\n // For editor element, use the editor itself as the root and path []\n targetNode = editor;\n targetPath = [];\n }\n else {\n // Convert target element to Slate node using ReactEditor.toSlateNode\n const slateNode = ReactEditor.toSlateNode(editor, targetElement);\n if (!slateNode) {\n Console.warn(`${logPrefix} Could not convert target element to Slate node`);\n return null;\n }\n targetNode = slateNode;\n // Find path using editor's api\n const foundPath = editor.api.findPath(targetNode);\n if (!foundPath) {\n Console.warn(`${logPrefix} Could not find path for node`);\n return null;\n }\n targetPath = foundPath;\n }\n // Collect all text from the subtree\n const { fullText, textNodePositions } = collectSubtreeText(editor, targetNode, targetPath);\n // Find all matches in the full text\n const matches = [];\n let match;\n const regex = new RegExp(textToSearch.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g');\n while ((match = regex.exec(fullText)) !== null) {\n matches.push({ index: match.index });\n }\n // If we don't have enough occurrences, return null\n if (matches.length < occurrence) {\n Console.warn(`${logPrefix} Not enough occurrences: found ${matches.length}, need ${occurrence}`);\n return null;\n }\n // Get the specific match\n const targetMatch = matches[occurrence - 1];\n // Find which text nodes the match spans\n const matchStart = targetMatch.index;\n const matchEnd = matchStart + textToSearch.length;\n // Find the range that covers this match\n let anchorNodeInfo;\n let focusNodeInfo;\n for (const nodePosition of textNodePositions) {\n // Check for anchor (start of match)\n if (matchStart >= nodePosition.start && matchStart < nodePosition.end && !anchorNodeInfo) {\n anchorNodeInfo = nodePosition;\n }\n // Check for focus (end of match)\n if (matchEnd > nodePosition.start && matchEnd <= nodePosition.end && !focusNodeInfo) {\n focusNodeInfo = nodePosition;\n }\n // If we have both anchor and focus, we can create the range\n if (anchorNodeInfo && focusNodeInfo) {\n const range = {\n anchor: {\n path: anchorNodeInfo.path,\n offset: matchStart - anchorNodeInfo.start,\n },\n focus: {\n path: focusNodeInfo.path,\n offset: matchEnd - focusNodeInfo.start,\n },\n };\n return range;\n }\n }\n Console.warn(`${logPrefix} Could not find anchor/focus nodes for match`);\n return null;\n }\n catch (error) {\n Console.catch(`${logPrefix} Error finding text occurrence range:`, error);\n return null;\n }\n};\n/**\n * Helper: Collects subtree text and maps text node positions.\n */\nconst collectSubtreeText = (editor, node, path) => {\n const textNodePositions = [];\n let fullText = '';\n // Traverse nodes for text\n const traverseNodesForText = (currentNode, currentPath, textNodePositions, fullText) => {\n try {\n if (TextApi.isText(currentNode)) {\n const start = fullText.length;\n fullText += currentNode.text;\n const end = fullText.length;\n textNodePositions.push({\n node: currentNode,\n path: currentPath,\n start,\n end,\n });\n }\n else if (ElementApi.isElement(currentNode)) {\n // Traverse child nodes\n for (let i = 0; i < currentNode.children.length; i++) {\n const childPath = [...currentPath, i];\n fullText = traverseNodesForText(currentNode.children[i], childPath, textNodePositions, fullText);\n }\n }\n return fullText;\n }\n catch (error) {\n Console.catch('[HostAdapter] Error traversing nodes for text:', error);\n return fullText;\n }\n };\n // Special case for the root node (editor itself)\n if (path.length === 0) {\n // When path is [], we're at the editor root, so traverse all children\n for (let i = 0; i < editor.children.length; i++) {\n const childPath = [i];\n fullText = traverseNodesForText(editor.children[i], childPath, textNodePositions, fullText);\n }\n }\n else {\n // Normal case for non-root nodes\n fullText = traverseNodesForText(node, path, textNodePositions, fullText);\n }\n return { fullText, textNodePositions };\n};\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\r\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\r\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nvar ownKeys = function(o) {\r\n ownKeys = Object.getOwnPropertyNames || function (o) {\r\n var ar = [];\r\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\r\n return ar;\r\n };\r\n return ownKeys(o);\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose, inner;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n if (async) inner = dispose;\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n var r, s = 0;\r\n function next() {\r\n while (r = env.stack.pop()) {\r\n try {\r\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\r\n if (r.dispose) {\r\n var result = r.dispose.call(r.value);\r\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n else s |= 1;\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\r\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\r\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\r\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\r\n });\r\n }\r\n return path;\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __esDecorate: __esDecorate,\r\n __runInitializers: __runInitializers,\r\n __propKey: __propKey,\r\n __setFunctionName: __setFunctionName,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n __rewriteRelativeImportExtension: __rewriteRelativeImportExtension,\r\n};\r\n","/**\n * Velt SDK adapter.\n * This is the ONLY place where @veltdev/types may be imported or window.Velt accessed.\n *\n * Responsibilities:\n * - Wrap all Velt SDK calls with error handling\n * - Provide high-level async functions for SDK operations\n * - Manage singleton subscription pattern\n *\n * Architectural Rules:\n * - MAY import @veltdev/types\n * - MAY access window.Velt\n * - MUST wrap all SDK calls in try-catch\n * - MUST NOT import editor types\n */\nimport { __awaiter } from \"tslib\";\nimport { areMapsEqual } from '@/utils/common';\nimport { Console } from '@/utils/console';\n/**\n * Global state for singleton subscription pattern.\n */\nlet isSubscribed = false;\nlet selectedCommentsMap = new Map();\nconst subscribers = new Map();\n/**\n * Gets Velt comment element from SDK.\n * Returns null if SDK is not available.\n */\nexport const getCommentElement = () => {\n try {\n // Access window.Velt safely\n const velt = window.Velt;\n if (velt === null || velt === void 0 ? void 0 : velt.getCommentElement) {\n return velt.getCommentElement();\n }\n return null;\n }\n catch (error) {\n Console.catch('[VeltAdapter] Error getting comment element:', error);\n return null;\n }\n};\n/**\n * Adds a comment via Velt SDK.\n * Returns the created annotation, or null on failure.\n */\nexport const addVeltComment = (params) => __awaiter(void 0, void 0, void 0, function* () {\n try {\n const commentElement = getCommentElement();\n if (!commentElement) {\n return null;\n }\n const result = yield commentElement.addManualComment({\n context: params.context,\n location: params.location,\n });\n if (!result) {\n return null;\n }\n // Result should contain the annotation\n return {\n annotation: result,\n };\n }\n catch (error) {\n Console.catch('[VeltAdapter] Error adding comment:', error);\n return null;\n }\n});\n/**\n * Updates annotation context in Velt SDK.\n */\nexport const updateAnnotationContext = (annotationId, context) => {\n try {\n const commentElement = getCommentElement();\n if (!commentElement) {\n return;\n }\n commentElement.updateContext(annotationId, context);\n }\n catch (error) {\n Console.catch('[VeltAdapter] Error updating context:', error);\n }\n};\n/**\n * Sets up the singleton subscription to getSelectedComments.\n * This is separated out so it can be retried when commentElement becomes available.\n */\nconst setupSelectedCommentsSubscription = () => {\n const commentElement = getCommentElement();\n if (!(commentElement === null || commentElement === void 0 ? void 0 : commentElement.getSelectedComments)) {\n return false;\n }\n try {\n const observable = commentElement.getSelectedComments();\n if (!(observable === null || observable === void 0 ? void 0 : observable.subscribe)) {\n return false;\n }\n // Subscribe returns an RxJS Subscription object with an unsubscribe method\n const subscription = observable.subscribe((comments) => {\n const selectedMap = new Map();\n comments === null || comments === void 0 ? void 0 : comments.forEach((comment) => {\n if (comment === null || comment === void 0 ? void 0 : comment.annotationId) {\n selectedMap.set(comment.annotationId, true);\n }\n });\n // Skip update if maps are equal\n if (!areMapsEqual(selectedMap, selectedCommentsMap)) {\n selectedCommentsMap = selectedMap;\n // Convert Map to Set<string> for callback\n const selectedIds = new Set();\n for (const [annotationId] of selectedMap) {\n selectedIds.add(annotationId);\n }\n // Notify all subscribers with Set<string>\n subscribers.forEach((subscriber) => {\n if (typeof subscriber === 'function') {\n try {\n subscriber(selectedIds);\n }\n catch (error) {\n Console.catch('[VeltAdapter] Error in subscriber callback:', error);\n }\n }\n });\n }\n });\n // Check if subscription was successful by verifying the subscription object\n // has an unsubscribe method (RxJS Subscription pattern)\n if (subscription && typeof subscription.unsubscribe === 'function') {\n isSubscribed = true;\n return true;\n }\n }\n catch (error) {\n Console.catch('[VeltAdapter] Error setting up getSelectedComments subscription:', error);\n }\n return false;\n};\n/**\n * Subscribes to selected annotations from Velt SDK.\n * Uses singleton pattern to avoid multiple subscriptions.\n * Returns unsubscribe function.\n *\n * Callback receives Set<string> of selected annotation IDs.\n */\nexport const subscribeToSelectedAnnotations = (callback, editorId) => {\n try {\n // Register this editor's callback first\n subscribers.set(editorId, callback);\n // Try to set up singleton subscription if not already subscribed\n if (!isSubscribed) {\n setupSelectedCommentsSubscription();\n }\n // Return unsubscribe function\n return () => {\n subscribers.delete(editorId);\n };\n }\n catch (error) {\n Console.catch('[VeltAdapter] Error subscribing to selected annotations:', error);\n return () => {\n // No-op unsubscribe on error\n };\n }\n};\n/**\n * Attempts to set up the selected comments subscription if not already done.\n * This should be called when we know the Velt SDK is ready.\n * Returns true if subscription is now active.\n */\nexport const ensureSelectedCommentsSubscription = () => {\n if (isSubscribed) {\n return true;\n }\n return setupSelectedCommentsSubscription();\n};\n","/**\n * Update content feature module.\n *\n * Handles document content changes and updates annotation positions.\n * Called when text changes are detected in the editor.\n *\n * Dependencies:\n * - adapters/host/doc.ts (document operations)\n * - adapters/velt.ts (Velt SDK operations)\n * - core/state.ts (state management)\n */\nimport { detectDocumentChanges } from '@/adapters/host/doc';\nimport { updateMarks } from '@/adapters/host/marks';\nimport { updateAnnotationContext } from '@/adapters/velt';\nimport { Constants } from '@/constants/common';\nimport { getAnnotation } from '@/core/state';\nimport { Console } from '@/utils/console';\n/**\n * Handles content updates in the editor.\n * Detects changes to annotations and updates their positions/contexts.\n *\n * @param editorId The editor ID\n * @param editor The editor instance\n * @param transaction The transaction/operation that triggered the update\n */\nexport const handleContentUpdate = (editorId, editor, transaction) => {\n var _a;\n const logPrefix = '[handleContentUpdate]';\n try {\n // Step 1: Detect document changes using host adapter\n // This requires a function to get annotation data from state\n const getAnnotationData = (annotationId) => {\n var _a, _b, _c, _d, _e, _f;\n const annotation = getAnnotation(editorId, annotationId);\n if (!annotation) {\n return null;\n }\n const originalText = ((_b = (_a = annotation.context) === null || _a === void 0 ? void 0 : _a.textEditorConfig) === null || _b === void 0 ? void 0 : _b.text) || '';\n const originalOccurrence = ((_d = (_c = annotation.context) === null || _c === void 0 ? void 0 : _c.textEditorConfig) === null || _d === void 0 ? void 0 : _d.occurrence) || 1;\n const targetTextNodeId = ((_f = (_e = annotation.context) === null || _e === void 0 ? void 0 : _e.textEditorConfig) === null || _f === void 0 ? void 0 : _f.targetTextNodeId) || '';\n return {\n annotation: annotation,\n originalText,\n originalOccurrence,\n targetTextNodeId,\n };\n };\n const changes = detectDocumentChanges(editor, transaction, Constants.MARK_NAME, getAnnotationData);\n if (changes.size === 0) {\n return;\n }\n Console.log(`${logPrefix} Detected ${changes.size} annotation changes`);\n // Step 2: Process each change (matching Slate updateVeltComments logic)\n for (const [annotationId, change] of Array.from(changes.entries())) {\n const changeLogPrefix = `${logPrefix}[${annotationId}]`;\n const annotation = getAnnotation(editorId, annotationId);\n if (!annotation) {\n Console.warn(`${changeLogPrefix} Annotation not found in state, skipping`);\n continue;\n }\n // Step 3: Build updated context (matching Slate updateVeltComments logic)\n if (!((_a = annotation.context) === null || _a === void 0 ? void 0 : _a.textEditorConfig)) {\n Console.warn(`${changeLogPrefix} No textEditorConfig, skipping`);\n continue;\n }\n const textEditorConfig = JSON.parse(JSON.stringify(annotation.context.textEditorConfig));\n if (change.contentChanged) {\n Console.log(`${changeLogPrefix} Content changed: \"${textEditorConfig.text}\" -> \"${change.currentText}\"`);\n textEditorConfig.text = change.currentText;\n }\n if (change.occurrenceChanged) {\n Console.log(`${changeLogPrefix} Occurrence changed: ${textEditorConfig.occurrence} -> ${change.currentOccurrence}`);\n textEditorConfig.occurrence = change.currentOccurrence;\n }\n if (change.targetTextNodeIdChanged) {\n Console.log(`${changeLogPrefix} TargetTextNodeId changed: \"${textEditorConfig.targetTextNodeId}\" -> \"${change.newTargetTextNodeId}\"`);\n textEditorConfig.targetTextNodeId = change.newTargetTextNodeId;\n }\n const updatedContext = Object.assign(Object.assign({}, annotation.context), { textEditorConfig });\n // Step 4: Update Velt context\n Console.log(`${changeLogPrefix} Updating Velt context`);\n updateAnnotationContext(annotationId, updatedContext);\n }\n // Step 5: Update marks if needed\n updateMarks(editor, changes);\n }\n catch (error) {\n Console.catch(`${logPrefix} Error handling content update:`, error);\n }\n};\n","/**\n * Core extension module for Plate.js.\n * This module creates the Plate plugin that wires everything together.\n *\n * Responsibilities:\n * - Create plugin using Plate's createPlatePlugin\n * - Wire features into editor lifecycle hooks\n * - Register editor in registry\n * - Handle cleanup on editor destruction\n *\n * Architectural Rules:\n * - This module MAY import Plate types (it's the extension entry point)\n * - It delegates to features and adapters for actual work\n *\n * KEY DIFFERENCE FROM SLATE:\n * - Slate uses HOC pattern: withVeltComments(editor)\n * - Plate uses plugin pattern: createPlatePlugin({ key, node, handlers })\n */\nimport { createPlatePlugin } from '@platejs/core/react';\nimport { ElementApi } from '@platejs/slate';\nimport { getEditorId } from '@/adapters/host/doc';\nimport { Constants } from '@/constants/common';\nimport { PlateVeltComment } from '@/core/ExtensionComponent';\nimport { registerEditor } from '@/core/registry';\nimport { handleContentUpdate } from '@/features/updateContent';\n/**\n * Checks if an element is a Velt comment element.\n */\nconst isVeltCommentText = (element) => {\n return ElementApi.isElement(element) && element.type === Constants.ELEMENT_TYPE.VELT_COMMENT;\n};\n/**\n * Plugin key constant for accessing options\n */\nconst PLUGIN_KEY = Constants.PLUGIN_KEY;\n/**\n * VeltCommentsPlugin - Plate.js plugin for Velt Comments integration.\n *\n * This is the main entry point that enhances the editor with comment functionality.\n * It creates an inline element type for comment highlighting and sets up\n * change detection for updating comment positions.\n *\n * @example\n * ```typescript\n * import { usePlateEditor } from '@platejs/core/react';\n * import { VeltCommentsPlugin } from '@veltdev/plate-comments-react';\n *\n * const editor = usePlateEditor({\n * plugins: [VeltCommentsPlugin],\n * });\n *\n * // With configuration\n * const editor = usePlateEditor({\n * plugins: [\n * VeltCommentsPlugin.configure({\n * options: { editorId: 'my-editor' }\n * })\n * ],\n * });\n * ```\n */\nexport const VeltCommentsPlugin = createPlatePlugin({\n key: PLUGIN_KEY,\n // Define the veltComment element as inline (not void, so it can contain text)\n node: {\n isElement: true,\n isInline: true,\n type: Constants.ELEMENT_TYPE.VELT_COMMENT,\n },\n // Render the velt-comment-text element directly (bypasses PlateElement wrapper)\n render: {\n node: PlateVeltComment,\n },\n // Plugin options/configuration\n options: {\n editorId: undefined,\n persistVeltMarks: true,\n },\n // Event handlers - note: Plate's onChange handler receives different params than Slate\n handlers: {\n onChange: ({ editor, getOptions, }) => {\n var _a;\n // Only process text-related operations (insert_text and remove_text)\n const isTextChange = (_a = editor.operations) === null || _a === void 0 ? void 0 : _a.some((operation) => operation.type === 'insert_text' || operation.type === 'remove_text');\n if (isTextChange) {\n const options = getOptions();\n const editorId = options.editorId || getEditorId(editor) || Constants.DEFAULT_EDITOR_ID;\n handleContentUpdate(editorId, editor, undefined);\n }\n },\n },\n})\n // Override isInline to treat Velt comment elements as inline\n .overrideEditor(({ api: { isInline }, editor, getOptions, }) => {\n var _a;\n // Get plugin options and register editor\n const options = getOptions();\n const editorId = options.editorId || getEditorId(editor) || Constants.DEFAULT_EDITOR_ID;\n // Register editor in registry\n registerEditor(editorId, editor, {\n persistVeltMarks: (_a = options.persistVeltMarks) !== null && _a !== void 0 ? _a : true,\n editorId,\n });\n return {\n api: {\n isInline(element) {\n if (ElementApi.isElement(element) && isVeltCommentText(element)) {\n return true;\n }\n return isInline(element);\n },\n },\n };\n});\n","/**\n * Storage adapter for editor-specific storage access.\n *\n * Purpose: Abstracts away editor-specific storage patterns.\n * This allows the codebase to be more generic and reusable across different editor implementations.\n *\n * Key responsibilities:\n * - Get persistVeltMarks setting (for Plate, checks plugin options via registry)\n * - Determine if marks should be applied\n *\n * Dependencies:\n * - @platejs/core/react (ONLY place allowed to import PlateEditor for storage access)\n */\nimport { getEditorId } from '@/adapters/host/doc';\nimport { Constants } from '@/constants/common';\nimport { getEditorContext } from '@/core/registry';\nimport { Console } from '@/utils/console';\n/**\n * Gets persistVeltMarks setting from storage.\n * For Plate, checks the plugin config from registry.\n *\n * @param editor The editor instance\n * @param storageKey The storage key (unused for Plate, kept for API compatibility)\n * @returns persistVeltMarks boolean value (defaults to true)\n */\nexport const getPersistVeltMarks = (editor, storageKey = Constants.STORAGE_KEY) => {\n var _a;\n try {\n // Get editor ID first\n const editorId = getEditorId(editor);\n if (!editorId) {\n return true; // Default to true if editorId not found\n }\n // Get editor context from registry\n const context = getEditorContext(editorId);\n if (((_a = context === null || context === void 0 ? void 0 : context.config) === null || _a === void 0 ? void 0 : _a.persistVeltMarks) !== undefined) {\n return context.config.persistVeltMarks;\n }\n // Default to true if not configured\n return true;\n }\n catch (error) {\n Console.warn('[getPersistVeltMarks] Error checking persistVeltMarks, defaulting to true:', error);\n return true;\n }\n};\n/**\n * Determines if marks should be applied based on persistVeltMarks setting.\n * This is a unified adapter function that abstracts the mark application logic.\n *\n * @param editor The editor instance (typed as unknown to avoid importing editor types in feature modules)\n * @param storageKey The storage key (default: 'plateVeltComments')\n * @returns boolean indicating if marks should be applied\n *\n * @remarks\n * - For Plate: checks persistVeltMarks setting (apply if FALSE)\n * - Defaults to true if storage is unavailable\n */\nexport const shouldApplyMark = (editor, storageKey = Constants.STORAGE_KEY) => {\n try {\n const persistVeltMarks = getPersistVeltMarks(editor, storageKey);\n // Apply mark if persistVeltMarks is FALSE (matching legacy behavior)\n return persistVeltMarks === false;\n }\n catch (error) {\n Console.warn('[shouldApplyMark] Error checking persistVeltMarks, defaulting to true:', error);\n return true;\n }\n};\n","/**\n * Add comment feature module.\n *\n * Purpose: End-to-end add comment orchestration.\n * Orchestrates adapters and core to implement the add comment flow.\n *\n * Key responsibilities:\n * - Get Velt comment element\n * - Extract selection context from editor\n * - Create comment via Velt SDK\n * - Apply mark to editor document\n * - Update state with annotation data\n *\n * Dependencies:\n * - adapters/velt.ts (for Velt SDK calls)\n * - adapters/host/doc.ts (for selection extraction, editor setup, and selection reset)\n * - adapters/host/marks.ts (for mark application)\n * - adapters/host/storage.ts (for mark application configuration)\n * - core/state.ts (for state updates)\n * - types/common.ts (for CommentAnnotationContext)\n *\n * IMPORTANT: This module MUST NOT import editor or Velt types directly.\n * All SDK access goes through adapters.\n */\nimport { __awaiter } from \"tslib\";\nimport { ensureEditorSetup, getCurrentSelectionContext, resetEditorSelection } from '@/adapters/host/doc';\nimport { applyAnnotationMarkByText } from '@/adapters/host/marks';\nimport { shouldApplyMark } from '@/adapters/host/storage';\nimport { addVeltComment, getCommentElement } from '@/adapters/velt';\nimport { Constants } from '@/constants/common';\nimport { updateAnnotations } from '@/core/state';\nimport { Console } from '@/utils/console';\n/**\n * Adds a comment to the currently selected text in the editor.\n *\n * This is the main entry point for adding comments. It handles:\n * - Extracting selection context from the editor\n * - Creating the comment via Velt SDK\n * - Applying marks to the editor if configured\n * - Updating state with annotation data\n *\n * @param request - Object containing editorId (optional), editor, and context (optional)\n * @returns Promise that resolves when the comment is added (or fails silently)\n *\n * @example\n * ```typescript\n * // Simple usage\n * await addComment({ editor });\n *\n * // With editor ID\n * await addComment({ editorId: 'my-editor', editor });\n *\n * // With custom context\n * await addComment({\n * editorId: 'my-editor',\n * editor,\n * context: {\n * userId: 'user123',\n * metadata: { source: 'web-app' }\n * }\n * });\n * ```\n *\n * @remarks\n * - Requires text to be selected in the editor\n * - Requires Velt SDK to be available (window.Velt)\n * - Marks are only applied if persistVeltMarks is FALSE in plugin config (matching legacy behavior)\n * - Fails silently if Velt SDK is unavailable or selection is invalid\n */\nexport function addComment(_a) {\n return __awaiter(this, arguments, void 0, function* ({ editorId, editor, context: clientContext, }) {\n const logPrefix = '[addComment]';\n // Validate editor parameter\n if (!editor) {\n Console.catch(`${logPrefix} ERROR: No editor provided`);\n return;\n }\n try {\n // Step 1: Get Velt comment element\n const commentElement = getCommentElement();\n if (!commentElement) {\n Console.warn(`${logPrefix} Velt SDK not available, cannot add comment`);\n return;\n }\n // Step 2: Extract selection context from editor\n // Type assertion needed because editor type is generic (unknown) to avoid importing editor types\n const selectionContext = getCurrentSelectionContext(editor);\n if (!selectionContext) {\n Console.warn(`${logPrefix} No valid selection found, exiting`);\n return;\n }\n // Step 3: Ensure editor is set up (registered and document listeners configured)\n const { editorId: finalEditorId } = ensureEditorSetup(editorId, editor);\n // Step 4: Build context object for Velt SDK\n // Only include editorId in textEditorConfig if user explicitly provided it\n // (either directly or via editor storage/DOM). DEFAULT_EDITOR_ID means it was auto-generated,\n // so we omit it for backward compatibility with old data that has no editorId.\n const userProvidedEditorId = editorId !== undefined || finalEditorId !== Constants.DEFAULT_EDITOR_ID;\n const context = Object.assign(Object.assign({}, (clientContext && typeof clientContext === 'object' ? clientContext : {})), { textEditorConfig: Object.assign(Object.assign({ text: selectionContext.text, occurrence: selectionContext.occurrence }, (userProvidedEditorId && { editorId: finalEditorId })), { targetTextNodeId: selectionContext.targetTextNodeId }) });\n // Step 5: Build location object if locationId is available\n let location;\n if (selectionContext.locationId) {\n location = { id: selectionContext.locationId };\n }\n // 5.1 Short delay to prevent comment dialog from closing immediately\n // This improves user experience when interacting with comments\n yield new Promise((resolve) => setTimeout(resolve, 200));\n // Step 6: Add comment via Velt SDK (matching legacy behavior - mark applied in callback)\n const veltResult = yield addVeltComment({ context, location });\n if (!veltResult || !veltResult.annotation) {\n Console.warn(`${logPrefix} Failed to create comment via Velt SDK`);\n return;\n }\n const annotation = veltResult.annotation;\n // Step 7: Check if marks should be applied (matching legacy behavior)\n // This means: if persistVeltMarks is FALSE, apply the mark\n const shouldApplyMarkValue = shouldApplyMark(editor, Constants.STORAGE_KEY);\n // Step 8: Apply mark to editor if needed (matching legacy behavior)\n // Legacy applies mark in the .then() callback, but we've already awaited, so apply now\n // Use text + occurrence approach for correct mark positioning across all document structures\n if (shouldApplyMarkValue && annotation.annotationId) {\n applyAnnotationMarkByText(editor, selectionContext.text, selectionContext.occurrence, annotation.annotationId, annotation.multiThreadAnnotationId, selectionContext.targetTextNodeId);\n }\n // Step 9: Update state with new annotation\n if (annotation.annotationId) {\n updateAnnotations(finalEditorId, [annotation]);\n }\n else {\n Console.warn(`${logPrefix} No annotationId, skipping state update`);\n }\n // Step 10: Reset editor selection (matching legacy behavior)\n resetEditorSelection(editor);\n }\n catch (error) {\n Console.catch(`${logPrefix} Error adding comment:`, error);\n }\n });\n}\n","/**\n * Comment renderer module.\n *\n * Purpose: Handle filtering, comparison, and mark updates for comment annotations.\n * This module manages the rendering state and applies marks based on resolved/selected status.\n *\n * Key responsibilities:\n * - Filter annotations based on status (terminal/resolved) and selected state\n * - Compare previous vs current filtered annotations to detect removals\n * - Remove marks for annotations that should no longer be shown\n * - Re-apply marks for all filtered annotations\n *\n * Dependencies:\n * - core/state.ts (for reading annotations and selected state)\n * - adapters/host/doc.ts (for finding text occurrences)\n * - adapters/host/marks.ts (for applying/removing marks)\n * - types/velt.ts (for CommentAnnotation)\n *\n * IMPORTANT: This module MUST NOT import editor or Velt types directly.\n * All SDK access goes through adapters.\n */\nimport { applyAnnotationMarkByText, removeAnnotationMark } from '@/adapters/host/marks';\nimport { Constants } from '@/constants/common';\nimport { getCommentAnnotations, getSelectedAnnotations } from '@/core/state';\nimport { Console } from '@/utils/console';\nconst rendererStore = new Map();\n/**\n * Filters annotations based on status and selected state.\n * Excludes terminal/resolved comments unless they're selected.\n *\n * @param annotations Array of CommentAnnotation to filter\n * @param selectedIds Set of selected annotation IDs\n * @returns Filtered array of CommentAnnotation\n */\nconst filterAnnotations = (annotations, selectedIds) => {\n return annotations.filter((annotation) => {\n var _a;\n // Include if not terminal/resolved\n if (((_a = annotation === null || annotation === void 0 ? void 0 : annotation.status) === null || _a === void 0 ? void 0 : _a.type) !== Constants.STATUS_TERMINAL) {\n return true;\n }\n // Include terminal/resolved only if selected\n return selectedIds.has(annotation.annotationId);\n });\n};\n/**\n * Applies marks for filtered annotations.\n * Finds text occurrences and applies marks to the editor.\n *\n * @param editor The editor instance\n * @param filteredAnnotations Array of filtered CommentAnnotation to render\n */\nconst applyMarksForAnnotations = (editor, filteredAnnotations) => {\n var _a;\n for (const annotation of filteredAnnotations) {\n const textEditorConfig = (_a = annotation === null || annotation === void 0 ? void 0 : annotation.context) === null || _a === void 0 ? void 0 : _a.textEditorConfig;\n if (!(textEditorConfig === null || textEditorConfig === void 0 ? void 0 : textEditorConfig.text) || !annotation.annotationId) {\n continue;\n }\n const textToFind = textEditorConfig.text;\n const occurrence = textEditorConfig.occurrence || 1;\n const targetTextNodeId = textEditorConfig.targetTextNodeId;\n // Use applyAnnotationMarkByText which takes text and occurrence directly\n // This function handles finding the text and applying the mark internally\n applyAnnotationMarkByText(editor, textToFind, occurrence, annotation.annotationId, annotation.multiThreadAnnotationId, targetTextNodeId);\n }\n};\n/**\n * Updates comments for an editor by filtering, comparing, removing, and re-applying marks.\n * This is the core rendering logic that handles resolved comment filtering.\n *\n * @param editorId Unique identifier for the editor\n * @param editor The editor instance\n * @param annotations All CommentAnnotation from Velt SDK (with status)\n */\nexport const updateComments = (editorId, editor, annotations) => {\n var _a;\n const logPrefix = '[commentRenderer:updateComments]';\n try {\n // Store editor instance in renderer store\n const storeEntry = rendererStore.get(editorId);\n if (storeEntry) {\n storeEntry.editor = editor;\n }\n else {\n rendererStore.set(editorId, {\n editor,\n previousFilteredAnnotations: [],\n });\n }\n // Get selected annotations from state\n const selectedIds = getSelectedAnnotations(editorId);\n // Filter annotations based on status and selected state\n const filteredAnnotations = filterAnnotations(annotations, selectedIds);\n // Get previous filtered annotations for comparison\n const previousFilteredAnnotations = ((_a = rendererStore.get(editorId)) === null || _a === void 0 ? void 0 : _a.previousFilteredAnnotations) || [];\n // Create sets of annotation IDs for comparison\n const newAnnotationIds = new Set(filteredAnnotations.map((ann) => ann.annotationId).filter(Boolean));\n const previousAnnotationIds = new Set(previousFilteredAnnotations.map((ann) => ann.annotationId).filter(Boolean));\n // Find annotations that should be removed (were in previous, not in new)\n const removedAnnotationIds = Array.from(previousAnnotationIds).filter((id) => !newAnnotationIds.has(id));\n // Remove marks for removed annotations\n for (const annotationId of removedAnnotationIds) {\n if (annotationId) {\n removeAnnotationMark(editor, annotationId);\n }\n }\n // Update previous filtered annotations in renderer store\n const currentStoreEntry = rendererStore.get(editorId);\n if (currentStoreEntry) {\n currentStoreEntry.previousFilteredAnnotations = filteredAnnotations;\n }\n // Re-apply marks for all filtered annotations\n // This ensures newly selected resolved comments are highlighted\n applyMarksForAnnotations(editor, filteredAnnotations);\n }\n catch (error) {\n Console.catch(`${logPrefix} Error updating comments:`, error);\n }\n};\n/**\n * Updates comments when selected annotations change.\n * Re-reads annotations from state and triggers re-rendering.\n *\n * @param editorId Unique identifier for the editor\n * @param selectedIds Set of selected annotation IDs (already updated in state)\n */\nexport const updateSelection = (editorId, selectedIds) => {\n const logPrefix = '[commentRenderer:updateSelection]';\n try {\n // Get editor instance from renderer store\n const storeEntry = rendererStore.get(editorId);\n if (!storeEntry || !storeEntry.editor) {\n Console.warn(`${logPrefix} No editor found for editorId: ${editorId}`);\n return;\n }\n // Get all comment annotations from state (with status)\n const annotations = getCommentAnnotations(editorId);\n // Re-run updateComments with current annotations and new selection\n // This will filter, compare, remove, and re-apply marks\n updateComments(editorId, storeEntry.editor, annotations);\n }\n catch (error) {\n Console.catch(`${logPrefix} Error updating selection:`, error);\n }\n};\n/**\n * Cleans up renderer store for an editor.\n * Should be called when editor is destroyed.\n *\n * @param editorId Unique identifier for the editor\n */\nexport const cleanupRenderer = (editorId) => {\n rendererStore.delete(editorId);\n};\n","/**\n * Render comments feature module.\n *\n * Purpose: Public API entry point for rendering comment annotations.\n * Orchestrates state updates, subscriptions, and delegates to commentRenderer.\n *\n * Key responsibilities:\n * - Update state with new annotations\n * - Subscribe to selected annotations from Velt\n * - Delegate rendering logic to commentRenderer\n *\n * Dependencies:\n * - adapters/velt.ts (for Velt SDK subscription)\n * - adapters/host/doc.ts (for editor setup)\n * - core/state.ts (for state management)\n * - core/registry.ts (for editor ID extraction)\n * - features/commentRenderer.ts (for rendering logic)\n * - types/velt.ts (for CommentAnnotation)\n *\n * IMPORTANT: This module MUST NOT import editor or Velt types directly.\n * All SDK access goes through adapters.\n */\nimport { ensureEditorSetup } from '@/adapters/host/doc';\nimport { ensureSelectedCommentsSubscription, subscribeToSelectedAnnotations } from '@/adapters/velt';\nimport { Constants } from '@/constants/common';\nimport { setSelectedAnnotations, updateAnnotations } from '@/core/state';\nimport { cleanupRenderer, updateComments, updateSelection } from '@/features/commentRenderer';\nimport { Console } from '@/utils/console';\n/**\n * Subscription map to track subscriptions per editor\n */\nconst subscriptionMap = new Map();\n/**\n * Renders comment annotations as marks in the editor.\n *\n * This function renders comment annotations as visual marks in the editor.\n * It filters annotations for the specific editor and applies marks accordingly.\n *\n * @param request - Object containing editor, editorId (optional), and commentAnnotations (optional)\n *\n * @example\n * ```typescript\n * // Simple usage\n * renderComments({ editor });\n *\n * // With editor ID\n * renderComments({ editorId: 'my-editor', editor });\n *\n * // With annotations\n * renderComments({\n * editorId: 'my-editor',\n * editor,\n * commentAnnotations: [\n * {\n * annotationId: 'ann-123',\n * context: {\n * textEditorConfig: {\n * text: 'Hello world',\n * occurrence: 1,\n * editorId: 'my-editor'\n * }\n * }\n * }\n * ]\n * });\n * ```\n *\n * @remarks\n * - Only annotations with matching editorId are rendered\n * - Automatically subscribes to selected annotations changes\n * - Filters out terminal/resolved comments unless they're selected\n * - Removes marks when comments become resolved\n * - Re-applies marks when resolved comments are selected\n */\nexport const renderComments = ({ editor, editorId, commentAnnotations, }) => {\n const logPrefix = '[renderComments]';\n try {\n if (!editor) {\n Console.warn(`${logPrefix} No editor provided`);\n return;\n }\n // Validate commentAnnotations silently - skip if not available or not an array\n if (!commentAnnotations || !Array.isArray(commentAnnotations)) {\n commentAnnotations = [];\n }\n // Step 0: Ensure editor is set up (registered and document listeners configured)\n const { editorId: finalEditorId } = ensureEditorSetup(editorId, editor);\n // Deep clone annotations to avoid mutations\n const clonedAnnotations = JSON.parse(JSON.stringify(commentAnnotations));\n // Filter annotations for this specific editor\n // - If finalEditorId is DEFAULT_EDITOR_ID, match annotations without editorId OR with editorId === DEFAULT_EDITOR_ID\n // - Otherwise, match annotations with exact editorId match\n const editorAnnotations = clonedAnnotations.filter((annotation) => {\n var _a;\n if (!((_a = annotation === null || annotation === void 0 ? void 0 : annotation.context) === null || _a === void 0 ? void 0 : _a.textEditorConfig)) {\n return false;\n }\n const annotationEditorId = annotation.context.textEditorConfig.editorId;\n // Default editor matches: no editorId OR explicit DEFAULT_EDITOR_ID OR legacy 'default'\n if (finalEditorId === Constants.DEFAULT_EDITOR_ID) {\n return annotationEditorId === undefined ||\n annotationEditorId === Constants.DEFAULT_EDITOR_ID ||\n annotationEditorId === 'default'; // Backward compatibility\n }\n // For user-provided editorIds, require exact match\n return annotationEditorId === finalEditorId;\n });\n // Step 1: Update state with filtered annotations (stores both AnnotationData and CommentAnnotation[])\n updateAnnotations(finalEditorId, editorAnnotations);\n // Step 2: Set up subscription to selected annotations (singleton pattern)\n if (!subscriptionMap.has(finalEditorId)) {\n // Capture finalEditorId in const to ensure type safety in closure\n const editorIdForSubscription = finalEditorId;\n const unsubscribe = subscribeToSelectedAnnotations((selectedIds) => {\n // Update selected annotations in state\n setSelectedAnnotations(editorIdForSubscription, selectedIds);\n // Trigger re-rendering with new selection\n updateSelection(editorIdForSubscription, selectedIds);\n }, editorIdForSubscription);\n subscriptionMap.set(finalEditorId, unsubscribe);\n }\n // Step 2.5: Ensure the selected comments subscription is active\n // This retries the subscription if it failed earlier (e.g., commentElement wasn't ready)\n ensureSelectedCommentsSubscription();\n // Step 3: Delegate to commentRenderer to handle filtering, comparison, removal, and re-application\n updateComments(finalEditorId, editor, editorAnnotations);\n }\n catch (error) {\n Console.catch(`${logPrefix} Error rendering comments:`, error);\n }\n};\n/**\n * Cleans up subscriptions and renderer state for an editor.\n * Should be called when editor is destroyed.\n *\n * @param editorId Unique identifier for the editor\n */\nexport const cleanupRenderComments = (editorId) => {\n // Clean up subscription\n const unsubscribe = subscriptionMap.get(editorId);\n if (unsubscribe) {\n unsubscribe();\n subscriptionMap.delete(editorId);\n }\n // Clean up renderer store\n cleanupRenderer(editorId);\n};\n","/**\n * Serializer utilities for Plate editor content\n *\n * This module provides utilities for serializing Plate editor content,\n * particularly for removing comment nodes from serialized JSON.\n *\n * Use this when persisting editor content to remove Velt comment elements\n * while preserving the original text content.\n */\nimport { Constants } from '@/constants/common';\n/** Use the element's canonical type string */\nconst COMMENT_TYPE = Constants.ELEMENT_TYPE.VELT_COMMENT;\n/**\n * Export JSON without comment nodes.\n *\n * This function takes Plate editor content and removes all comment nodes,\n * unwrapping their children and merging adjacent text nodes with same formatting.\n *\n * @param content - Plate editor content (Descendant[])\n * @returns Serialized content without comment nodes\n */\nexport const exportJSONWithoutComments = (content) => {\n // 1) Strip comment nodes from the content\n const strippedContent = stripCommentsFromContent(content);\n // 2) Normalize adjacent text nodes created by unwrapping\n const normalizedContent = normalizeTextNodesInContent(strippedContent);\n return normalizedContent;\n};\n/* -------------------- internals (strictly typed) -------------------- */\nconst stripCommentsFromContent = (content) => {\n return stripFromChildrenArray(content);\n};\n/**\n * Flattens comment nodes inside a children array and recurses.\n */\nconst stripFromChildrenArray = (children) => {\n const out = [];\n for (const child of children) {\n if (isElementNode(child) && child.type === COMMENT_TYPE) {\n // Unwrap: push processed grandchildren directly\n const flattened = stripFromChildrenArray(child.children);\n out.push(...flattened);\n continue;\n }\n out.push(stripCommentsFromNode(child));\n }\n return out;\n};\nconst stripCommentsFromNode = (node) => {\n if (isElementNode(node)) {\n const nextChildren = stripFromChildrenArray(node.children);\n return Object.assign(Object.assign({}, node), { children: nextChildren });\n }\n return node;\n};\n/* -------------------- normalization (strictly typed) -------------------- */\nconst normalizeTextNodesInContent = (content) => {\n const normalizedKids = content.map(normalizeTextNodesInNode);\n return mergeAdjacentTextNodes(normalizedKids);\n};\nconst normalizeTextNodesInNode = (node) => {\n if (isElementNode(node)) {\n const normalizedKids = node.children.map(normalizeTextNodesInNode);\n return Object.assign(Object.assign({}, node), { children: mergeAdjacentTextNodes(normalizedKids) });\n }\n return node;\n};\nconst mergeAdjacentTextNodes = (children) => {\n var _a, _b;\n if (children.length < 2)\n return children;\n const merged = [];\n let i = 0;\n while (i < children.length) {\n const cur = children[i];\n if (isTextNode(cur)) {\n // Skip empty text nodes (artifacts from Slate's split operation)\n if (cur.text === '') {\n i++;\n continue;\n }\n let text = (_a = cur.text) !== null && _a !== void 0 ? _a : '';\n let j = i + 1;\n while (j < children.length) {\n const nxt = children[j];\n // Skip empty text nodes\n if (isTextNode(nxt) && nxt.text === '') {\n j++;\n continue;\n }\n if (isTextNode(nxt) && haveSameTextFormat(cur, nxt)) {\n text += (_b = nxt.text) !== null && _b !== void 0 ? _b : '';\n j++;\n }\n else {\n break;\n }\n }\n merged.push(Object.assign(Object.assign({}, cur), { text }));\n i = j;\n }\n else {\n merged.push(cur);\n i++;\n }\n }\n // Ensure at least one child for element nodes\n return merged.length > 0 ? merged : [{ text: '' }];\n};\n/* -------------------- type guards & equality -------------------- */\nconst isElementNode = (node) => {\n // Slate Element nodes always have a 'children' array and 'type' property\n return (Object.prototype.hasOwnProperty.call(node, 'children') &&\n Object.prototype.hasOwnProperty.call(node, 'type'));\n};\nconst isTextNode = (node) => {\n return Object.prototype.hasOwnProperty.call(node, 'text');\n};\nconst haveSameTextFormat = (a, b) => {\n return (a.bold === b.bold &&\n a.italic === b.italic &&\n a.underline === b.underline);\n};\n"],"names":["Constants","EDITOR_ID","LOCATION_ID","ANNOTATION_ID","MULTI_THREAD_ANNOTATION_ID","VELT_COMMENT","kmpSearch","text","pattern","startPos","maxOccurrences","positions","length","lps","Array","fill","len","i","computeKMPTable","j","push","Console","showLogs","sessionStorage","getItem","err","catch","log","console","warn","error","debug","info","logsEnabled","message","undefined","getEditorId","editor","_a","_b","domNode","ReactEditor","toDOMNode","closest","getAttribute","findOccurrenceIndex","targetTextNodeId","selection","targetElement","document","getElementById","startOffset","anchor","offset","findOccurrenceInDOM","allMatches","findAllMatches","isBackward","PathApi","compare","path","focus","equals","matchIndex","findIndex","match","findParentNodeWithId","node","NodeApi","get","findParentNodeWithIdFromNode","maxIterations","editorDOM","currentNode","iterationCount","body","contains","id","parentElement","textToSearch","caseSensitive","matches","getText","isTextNode","searchInNode","searchText","toLowerCase","nodeText","index","range","isArray","children","forEach","child","nodeEntries","nodes","pass","initialNode","from","slice","element","fullText","textContent","processedFullText","processedSearchText","occurrences","filter","findOccurrenceForNode","string","trim","matchStart","SlateEditor","start","matchPath","isEqual","isDescendant","isAncestor","ensureEditorSetup","editorId","finalEditorId","PlateVeltComment","props","attributes","annotationId","React","createElement","Object","assign","stateMap","Map","createAnnotationState","state","annotations","commentAnnotations","selectedAnnotations","Set","set","getOrCreateState","updateAnnotations","annotationDataMap","annotation","annotationData","multiThreadAnnotationId","context","getAnnotation","registry","isVeltCommentText","ElementApi","isElement","type","applyAnnotationMarkByText","occurrence","targetElementId","logPrefix","plateEditor","isElementInEditor","editorElement","querySelector","e","findTextOccurrenceRange","result","to","tf","wrapNodes","at","split","applyAnnotationMarkWithRange","removeAnnotationMark","elementsToUnwrap","descendants","reverse","unwrapNodes","mode","targetNode","targetPath","hasAttribute","slateNode","toSlateNode","foundPath","api","findPath","textNodePositions","collectSubtreeText","regex","RegExp","replace","exec","matchEnd","anchorNodeInfo","focusNodeInfo","nodePosition","end","traverseNodesForText","currentPath","TextApi","isText","childPath","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","rejected","done","then","apply","SuppressedError","isSubscribed","selectedCommentsMap","subscribers","getCommentElement","velt","window","Velt","updateAnnotationContext","commentElement","updateContext","setupSelectedCommentsSubscription","getSelectedComments","observable","subscribe","subscription","comments","selectedMap","comment","map1","map2","size","key","areMapsEqual","selectedIds","add","subscriber","unsubscribe","handleContentUpdate","transaction","getAnnotationData","_c","_d","_e","_f","originalText","textEditorConfig","originalOccurrence","changes","markType","annotationNodes","storedData","originalTargetTextNodeId","currentText","currentTargetNode","currentTargetNodeId","currentOccurrence","textChanged","occurrenceChanged","targetTextNodeIdChanged","newTargetTextNodeId","contentChanged","detectDocumentChanges","change","entries","changeLogPrefix","JSON","parse","stringify","updatedContext","updateMarks","VeltCommentsPlugin","createPlatePlugin","isInline","render","options","persistVeltMarks","handlers","onChange","getOptions","operations","some","operation","overrideEditor","config","registerEditor","getPersistVeltMarks","storageKey","getEditorContext","addComment","this","arguments","clientContext","params","selectionContext","startPoint","endPoint","targetTextNode","locationId","getCurrentSelectionContext","userProvidedEditorId","location","setTimeout","veltResult","addManualComment","shouldApplyMarkValue","shouldApplyMark","rendererStore","updateComments","storeEntry","previousFilteredAnnotations","getSelectedAnnotations","filteredAnnotations","status","has","filterAnnotations","newAnnotationIds","map","ann","Boolean","previousAnnotationIds","removedAnnotationIds","currentStoreEntry","textToFind","applyMarksForAnnotations","updateSelection","getCommentAnnotations","subscriptionMap","renderComments","editorAnnotations","annotationEditorId","editorIdForSubscription","callback","delete","subscribeToSelectedAnnotations","setSelectedAnnotations","cleanupRenderComments","cleanupRenderer","COMMENT_TYPE","exportJSONWithoutComments","content","strippedContent","stripCommentsFromContent","normalizeTextNodesInContent","stripFromChildrenArray","out","isElementNode","flattened","stripCommentsFromNode","nextChildren","normalizedKids","normalizeTextNodesInNode","mergeAdjacentTextNodes","merged","cur","nxt","haveSameTextFormat","prototype","hasOwnProperty","call","a","b","bold","italic","underline"],"mappings":"yOAMO,MAAMA,EAIG,CACRC,UAAW,iBACXC,YAAa,wBACbC,cAAe,gBACfC,2BAA4B,8BARvBJ,EAaK,CACVK,aAAc,eAdTL,EAoBE,cApBFA,EAwBG,eAxBHA,EA6BI,oBA7BJA,EAsCU,cAtCVA,EA0CQ,WA1CRA,EA8CG,sBA9CHA,EAkDO,YAlDPA,EAsDa,iBCAbM,EAAY,CAACC,EAAMC,EAASC,EAAW,EAAGC,KACnD,MAAMC,EAAY,GAClB,IAAKH,IAAYD,GAAQC,EAAQI,OAASL,EAAKK,OAC3C,OAAOD,EAEX,MAAME,EA7CqB,CAACL,IAC5B,IAAKA,GAA8B,IAAnBA,EAAQI,OACpB,MAAO,GAEX,MAAMC,EAAM,IAAIC,MAAMN,EAAQI,QAAQG,KAAK,GAC3C,IAAIC,EAAM,EACNC,EAAI,EACR,KAAOA,EAAIT,EAAQI,QACXJ,EAAQS,KAAOT,EAAQQ,IACvBA,IACAH,EAAII,GAAKD,EACTC,KAGY,IAARD,EACAA,EAAMH,EAAIG,EAAM,IAGhBH,EAAII,GAAK,EACTA,KAIZ,OAAOJ,GAsBKK,CAAgBV,GAC5B,IAAIS,EAAI,EACJE,EAAI,EACR,KAAOF,EAAIV,EAAKK,QAKZ,GAJIJ,EAAQW,KAAOZ,EAAKU,KACpBA,IACAE,KAEAA,IAAMX,EAAQI,QAGd,GAFAD,EAAUS,KAAKX,EAAWQ,EAAIE,GAC9BA,EAAIN,EAAIM,EAAI,GACRT,GAAkBC,EAAUC,QAAUF,EACtC,WAGCO,EAAIV,EAAKK,QAAUJ,EAAQW,KAAOZ,EAAKU,KAClC,IAANE,EACAA,EAAIN,EAAIM,EAAI,GAGZF,KAIZ,OAAON,GCxFJ,MAAMU,EACT,eAAOC,GACH,IACI,QAASC,eAAeC,QAAQxB,MAA+BuB,eAAeC,QAAQxB,EACzF,CACD,MAAOyB,GAEH,OADAJ,EAAQK,MAAM,sBAAuBD,IAC9B,CACV,CACJ,EAELJ,EAAQM,IAAMN,EAAQC,WAAaM,QAAQD,IAAM,OACjDN,EAAQQ,KAAOR,EAAQC,WAAaM,QAAQC,KAAO,OACnDR,EAAQS,MAAQT,EAAQC,WAAaM,QAAQE,MAAQ,OACrDT,EAAQU,MAAQV,EAAQC,WAAaM,QAAQG,MAAQ,OACrDV,EAAQW,KAAOX,EAAQC,WAAaM,QAAQI,KAAO,OACnDX,EAAQY,aAAc,EAEtBZ,EAAQK,MAAQ,CAACQ,EAASJ,KACtB,IACQT,EAAQY,mBACME,IAAVL,EACAF,QAAQC,KAAK7B,EAAsBkC,EAASJ,GAG5CF,QAAQC,KAAK7B,EAAsBkC,GAG9C,CACD,MAAOT,GAEN,GCLE,MAAMW,EAAeC,IACxB,IAAIC,EAAIC,EACR,IAEI,MAAMC,EAAUC,EAAYC,UAAUL,EAAQA,GAC9C,OAAIG,IACwN,QAA/MD,EAAyH,QAAnHD,EAAKE,aAAyC,EAASA,EAAQG,QAAQ,IAAI3C,EAAqBC,qBAAkC,IAAPqC,OAAgB,EAASA,EAAGM,aAAa5C,EAAqBC,kBAA+B,IAAPsC,GAAgBA,EAG7O,IACV,CACD,MAAOT,GAIH,OAAO,IACV,GAqDQe,EAAsB,CAACR,EAAQ9B,EAAMuC,KAC9C,IACI,IAAKvC,IAAS8B,EAAOU,UACjB,OAAO,EAGX,GAAID,EAAkB,CAClB,MAAME,EAAgBC,SAASC,eAAeJ,GAC9C,GAAIE,EAAe,CAEf,MAAMG,EAAcd,EAAOU,UAAUK,OAAOC,OAC5C,OAAOC,EAAoBN,EAAezC,EAAM4C,EACnD,CACJ,CAED,MAAMI,EAAaC,EAAenB,EAAQ9B,GACpCwC,EAAYV,EAAOU,UACzB,IAAKA,GAAmC,IAAtBQ,EAAW3C,OACzB,OAAO,EAGX,MAAM6C,EAAaC,EAAQC,QAAQZ,EAAUK,OAAOQ,KAAMb,EAAUc,MAAMD,MAAQ,GAC7EF,EAAQI,OAAOf,EAAUK,OAAOQ,KAAMb,EAAUc,MAAMD,OACnDb,EAAUK,OAAOC,OAASN,EAAUc,MAAMR,OAE5CU,EAAaR,EAAWS,UAAWC,GACjCR,EACQC,EAAQI,OAAOG,EAAMb,OAAOQ,KAAMb,EAAUc,MAAMD,OACtDF,EAAQI,OAAOG,EAAMJ,MAAMD,KAAMb,EAAUK,OAAOQ,OAClDK,EAAMb,OAAOC,SAAWN,EAAUc,MAAMR,QACxCY,EAAMJ,MAAMR,SAAWN,EAAUK,OAAOC,OAGpCK,EAAQI,OAAOG,EAAMb,OAAOQ,KAAMb,EAAUK,OAAOQ,OACvDF,EAAQI,OAAOG,EAAMJ,MAAMD,KAAMb,EAAUc,MAAMD,OACjDK,EAAMb,OAAOC,SAAWN,EAAUK,OAAOC,QACzCY,EAAMJ,MAAMR,SAAWN,EAAUc,MAAMR,QAGnD,OAAuB,IAAhBU,EAAoBA,EAAa,EAAI,CAC/C,CACD,MAAOjC,GAEH,OADAT,EAAQK,MAAM,gDAAiDI,GACxD,CACV,GAMQoC,EAAwB7B,IACjC,IACI,MAAMU,UAAEA,GAAcV,EACtB,IAAKU,EACD,OAAO,KAEX,MAAMK,OAAEA,GAAWL,EACboB,EAAOC,EAAQC,IAAIhC,EAAQe,EAAOQ,MACxC,OAAKO,EAGEG,EAA6BjC,EAAQ8B,EAAMf,EAAOQ,MAF9C,IAGd,CACD,MAAO9B,GAEH,OADAT,EAAQK,MAAM,mDAAoDI,GAC3D,IACV,GAKCwC,EAA+B,CAACjC,EAAQ8B,EAAMP,EAAMW,EAAgB,OACtE,IACI,IAAI/B,EAAU,KACVgC,EAAY,KAChB,IAEIhC,EAAUC,EAAYC,UAAUL,EAAQ8B,EAC3C,CACD,MAAO1C,GACH,OAAO,IACV,CACD,IAEI+C,EAAY/B,EAAYC,UAAUL,EAAQA,EAC7C,CACD,MAAOZ,GACH,OAAO,IACV,CACD,IAAIgD,EAAcjC,EACdkC,EAAiB,EACrB,KAAOD,GAAeA,IAAgBxB,SAAS0B,MAAQD,EAAiBH,GAAe,CAEnF,IAAKC,IAAcA,EAAUI,SAASH,GAClC,OAAO,KAGX,GAAIA,EAAYI,GACZ,OAAOJ,EAEXA,EAAcA,EAAYK,cAC1BJ,GACH,CACD,OAAO,IACV,CACD,MAAO5C,GAEH,OADAT,EAAQK,MAAM,2CAA4CI,GACnD,IACV,GAKC0B,EAAiB,CAACnB,EAAQ0C,EAAcC,GAAgB,KAC1D,IACI,MAAMC,EAAU,GAChB,IAAKF,EACD,OAAOE,EAGX,MAAMC,EAAWf,GACU,iBAATA,GAA8B,OAATA,GAAiB,SAAUA,EAAOA,EAAK5D,KAAO,GAG/E4E,EAAchB,GACQ,iBAATA,GACF,OAATA,GACA,SAAUA,GACW,iBAAdA,EAAK5D,KAGd6E,EAAe,CAACjB,EAAMP,KAExB,GAAIuB,EAAWhB,GAAO,CAClB,MAAM5D,EAAO2E,EAAQf,GAEfkB,EAAaL,EAAgBD,EAAeA,EAAaO,cACzDC,EAAWP,EAAgBzE,EAAOA,EAAK+E,cAEvC3E,EAAYL,EAAUiF,EAAUF,GAEtC,IAAK,MAAMG,KAAS7E,EAAW,CAC3B,MAAM8E,EAAQ,CACVrC,OAAQ,CAAEQ,OAAMP,OAAQmC,GACxB3B,MAAO,CAAED,OAAMP,OAAQmC,EAAQT,EAAanE,SAEhDqE,EAAQ7D,KAAKqE,EAChB,CACJ,CAEG,aAActB,GAAQrD,MAAM4E,QAAQvB,EAAKwB,WACzCxB,EAAKwB,SAASC,QAAQ,CAACC,EAAOL,KAC1BJ,EAAaS,EAAO,IAAIjC,EAAM4B,OAK1C,IAEI,MAAMM,EAAc1B,EAAQ2B,MAAM1D,EAAQ,CAAE2D,KAAM,KAAM,KACjDC,GAAenF,MAAMoF,KAAKJ,GAAaK,MAAM,EAAG,GACnDF,GACAb,EAAaa,EAAY,GAAIA,EAAY,GAEhD,CACD,MAAOnE,GACHT,EAAQK,MAAM,6CAA8CI,EAC/D,CACD,OAAOmD,CACV,CACD,MAAOnD,GAEH,OADAT,EAAQK,MAAM,2CAA4CI,GACnD,EACV,GAKCwB,EAAsB,CAAC8C,EAASf,EAAYlC,EAAa6B,GAAgB,KAC3E,IACI,IAAKK,EACD,OAAO,EAEX,MAAMgB,EAAWD,EAAQE,aAAe,GAClCC,EAAoBvB,EAAgBqB,EAAWA,EAASf,cACxDkB,EAAsBxB,EAAgBK,EAAaA,EAAWC,cAE9DmB,EAAcnG,EAAUiG,EAAmBC,GACjD,GAA2B,IAAvBC,EAAY7F,OACZ,OAAO,EAGX,QAAoBuB,IAAhBgB,EAA2B,CAE3B,OAD+BsD,EAAYC,OAAQlB,GAAUA,EAAQrC,GAAavC,OAAS,CAE9F,CACD,OAAO,CACV,CACD,MAAOkB,GAEH,OADAT,EAAQK,MAAM,iDAAkDI,GACzD,CACV,GAgFC6E,EAAwB,CAACtE,EAAQ9B,EAAM4D,EAAMP,EAAMd,KACrD,IACI,IAAKvC,EACD,OAAO,EAGX,MAAMgF,EAAWnB,EAAQwC,OAAOzC,GAChC,IAAKoB,IAAaA,EAASsB,OACvB,OAAO,EAGX,MAAMtD,EAAaC,EAAenB,EAAQ9B,GAC1C,GAA0B,IAAtBgD,EAAW3C,OACX,OAAO,EAGX,IAAK,IAAIK,EAAI,EAAGA,EAAIsC,EAAW3C,OAAQK,IAAK,CACxC,MAAMgD,EAAQV,EAAWtC,GACnB6F,EAAaC,EAAYC,MAAM3E,EAAQ4B,GAC7C,IAAK6C,EACD,SACJ,MAAMG,EAAYH,EAAWlD,KACvBsD,EAAUxD,EAAQI,OAAOmD,EAAWrD,GACpCuD,EAAezD,EAAQ0D,WAAWxD,EAAMqD,GAC9C,GAAIC,GAAWC,EACX,OAAOlG,EAAI,CAElB,CACD,OAAO,CACV,CACD,MAAOa,GAEH,OADAT,EAAQK,MAAM,mDAAoDI,GAC3D,CACV,GA0CQuF,EAAoB,CAACC,EAAUjF,KAExC,IAEI,IAAIkF,EAAgBD,EAIpB,OAHKC,IACDA,EAAgBnF,EAAYC,IAAWrC,GAEpC,CAAEsH,SAAUC,EACtB,CACD,MAAOzF,GAEH,OADAT,EAAQQ,KAAK,+CAAyCC,GAC/C,CAAEwF,SAAUA,GAAYtH,EAClC,GCxcQwH,EAAoBC,IAC7B,MAAMC,WAAEA,EAAU/B,SAAEA,EAAQS,QAAEA,GAAYqB,EACpCE,EAAevB,aAAyC,EAASA,EAAQuB,aAG/E,OAAOC,EAAMC,cAAc,oBAAqBC,OAAOC,OAAO,CAAE,CAAC/H,EAAqBG,eAAgBwH,GAAgBD,GAAa/B,ICKjIqC,EAAW,IAAIC,IAORC,EAAyBZ,IAClC,MAAMa,EAAQ,CACVC,YAAa,IAAIH,IACjBI,mBAAoB,GACpBC,oBAAqB,IAAIC,IACzBjB,YAGJ,OADAU,EAASQ,IAAIlB,EAAUa,GAChBA,GAQLM,EAAoBnB,IACtB,IAAIa,EAAQH,EAAS3D,IAAIiD,GAIzB,OAHKa,IACDA,EAAQD,EAAsBZ,IAE3Ba,GASEO,EAAoB,CAACpB,EAAUc,KACxC,IACI,MAAMD,EAAQM,EAAiBnB,GAE/Ba,EAAME,mBAAqBD,EAE3B,MAAMO,EAAoB,IAAIV,IAC9B,IAAK,MAAMW,KAAcR,EAAa,CAClC,KAAMQ,aAA+C,EAASA,EAAWjB,cACrE,SAEJ,MAAMkB,EAAiB,CACnBlB,aAAciB,EAAWjB,aACzBmB,wBAAyBF,EAAWE,wBACpCC,QAASH,EAAWG,SAGxBJ,EAAkBH,IAAII,EAAWjB,aAAckB,EAClD,CAEDV,EAAMC,YAAcO,CACvB,CACD,MAAO7G,GACHT,EAAQK,MAAM,8BAA+BI,EAChD,GASQkH,EAAgB,CAAC1B,EAAUK,KACpC,IACI,MAAMQ,EAAQH,EAAS3D,IAAIiD,GAC3B,OAAKa,GAGEA,EAAMC,YAAY/D,IAAIsD,IAFlB,IAGd,CACD,MAAO7F,GAEH,OADAT,EAAQK,MAAM,4BAA6BI,GACpC,IACV,GChFCmH,EAAW,IAAIhB,ICqBrB,MAAMiB,EAAqB9C,GAChB+C,EAAWC,UAAUhD,IAAYA,EAAQiD,OAASrJ,EAAuBK,aA8DvEiJ,EAA4B,CAACjH,EAAQ0C,EAAcwE,EAAY5B,EAAcmB,EAAyBU,KAC/G,MAAMC,EAAY,8BAClB,IACI,IAAKpH,IAAWsF,EACZ,OAAO,EAEX,MAAM+B,EAAcrH,EAEpB,IAAIW,EAAgB,KACpB,GAAIwG,EAAiB,CAGjB,GAFAxG,EAAgBC,SAASC,eAAesG,IAEnCxG,EAED,OADA3B,EAAQQ,KAAK,GAAG4H,+BAAuCD,MAChD,EAGX,IAAKG,EAAkBD,EAAa1G,GAEhC,OADA3B,EAAQQ,KAAK,GAAG4H,mCAA2CD,MACpD,CAEd,MAGG,IAEI,MAAMI,EAAgB3G,SAAS4G,cAAc,8BACzCD,IACA5G,EAAgB4G,EAEvB,CACD,MAAOE,GACHzI,EAAQQ,KAAK,GAAG4H,sCAA+CK,EAClE,CAEL,IAAK9G,EAED,OADA3B,EAAQQ,KAAK,GAAG4H,8BACT,EAGX,MAAMhE,EAAQsE,EAAwBL,EAAa3E,EAAcwE,EAAYvG,GAC7E,IAAKyC,EAED,OADApE,EAAQQ,KAAK,GAAG4H,+CAAuD1E,iBAA4BwE,MAC5F,EAGX,MAAMS,EAtGuB,EAAC3H,EAAQsF,EAAcmB,EAAyBrD,KACjF,IACI,QAAKA,MAIgB3E,MAAMoF,KAAK9B,EAAQ2B,MAAM1D,EAAQ,CAClD6D,KAAMT,EAAMrC,OAAOQ,KACnBqG,GAAIxE,EAAM5B,MAAMD,KAChBoC,KAAM,EAAE7B,OACCgF,EAAWC,UAAUjF,IAGnB+E,EAAkB/E,MAE7BuC,OAAO,EAAEvC,KAAUgF,EAAWC,UAAUjF,IAAS+E,EAAkB/E,IACtDvD,OAAS,KAKtByB,EAAO6H,GAAGC,UAAU,CAChBd,KAAMrJ,EAAuBK,aAC7BsF,SAAU,GACVgC,aAAcA,EACdmB,wBAAyBA,GAC1B,CAAEsB,GAAI3E,EAAO4E,OAAO,KAWpB,GACV,CACD,MAAOvI,GAEH,OADAT,EAAQK,MAAM,gDAAiDI,IACxD,CACV,GA4DkBwI,CAA6BZ,EAAa/B,EAAcmB,EAAyBrD,GAChG,OAAOuE,CACV,CACD,MAAOlI,GAEH,OADAT,EAAQK,MAAM,GAAG+H,4CAAqD3H,IAC/D,CACV,GAMQyI,EAAuB,CAAClI,EAAQsF,KACzC,MAAM8B,EAAY,yBAClB,IACI,IAAKpH,IAAWsF,EACZ,OAAO,EAGX,MAAM6C,EAAmB,GAEzB,IAAK,MAAOrG,EAAMP,KAASQ,EAAQqG,YAAYpI,GAEvC8G,EAAWC,UAAUjF,IACrB+E,EAAkB/E,IAClBA,EAAKwD,eAAiBA,GACtB6C,EAAiBpJ,KAAKwC,GAG9B,OAAgC,IAA5B4G,EAAiB5J,SAIrB4J,EAAiBE,UAAU9E,QAAShC,IAChC,IACwB,MAEhBvB,EAAO6H,GAAGS,YAAY,CAClBP,GAAIxG,EACJgH,KAAM,YAUVD,EAEP,CACD,MAAOlJ,GACHJ,EAAQK,MAAM,GAAG+H,sCAA8C7F,KAASnC,EAC3E,KAEE,EACV,CACD,MAAOK,GAEH,OADAT,EAAQK,MAAM,GAAG+H,oCAA6C3H,IACvD,CACV,GAuBC6H,EAAoB,CAACtH,EAAQ+D,KAC/B,IAEI,MAAMwD,EAAgB3G,SAAS4G,cAAc,8BAC7C,QAAKD,GAGEA,EAAchF,SAASwB,EACjC,CACD,MAAOtE,GAEH,OADAT,EAAQK,MAAM,kDAAmDI,IAC1D,CACV,GAMCiI,EAA0B,CAAC1H,EAAQ0C,EAAcwE,EAAYvG,KAC/D,MAAMyG,EAAY,4BAClB,IACI,IAAIoB,EACAC,EAGJ,GADwB9H,EAAc+H,aAAa,qBAG/CF,EAAaxI,EACbyI,EAAa,OAEZ,CAED,MAAME,EAAYvI,EAAYwI,YAAY5I,EAAQW,GAClD,IAAKgI,EAED,OADA3J,EAAQQ,KAAK,GAAG4H,oDACT,KAEXoB,EAAaG,EAEb,MAAME,EAAY7I,EAAO8I,IAAIC,SAASP,GACtC,IAAKK,EAED,OADA7J,EAAQQ,KAAK,GAAG4H,kCACT,KAEXqB,EAAaI,CAChB,CAED,MAAM7E,SAAEA,EAAQgF,kBAAEA,GAAsBC,EAAmBjJ,EAAQwI,EAAYC,GAEzE7F,EAAU,GAChB,IAAIhB,EACJ,MAAMsH,EAAQ,IAAIC,OAAOzG,EAAa0G,QAAQ,sBAAuB,QAAS,KAC9E,KAA0C,QAAlCxH,EAAQsH,EAAMG,KAAKrF,KACvBpB,EAAQ7D,KAAK,CAAEoE,MAAOvB,EAAMuB,QAGhC,GAAIP,EAAQrE,OAAS2I,EAEjB,OADAlI,EAAQQ,KAAK,GAAG4H,mCAA2CxE,EAAQrE,gBAAgB2I,KAC5E,KAGX,MAEMzC,EAFc7B,EAAQsE,EAAa,GAEV/D,MACzBmG,EAAW7E,EAAa/B,EAAanE,OAE3C,IAAIgL,EACAC,EACJ,IAAK,MAAMC,KAAgBT,EAUvB,GARIvE,GAAcgF,EAAa9E,OAASF,EAAagF,EAAaC,MAAQH,IACtEA,EAAiBE,GAGjBH,EAAWG,EAAa9E,OAAS2E,GAAYG,EAAaC,MAAQF,IAClEA,EAAgBC,GAGhBF,GAAkBC,EAAe,CAWjC,MAVc,CACVzI,OAAQ,CACJQ,KAAMgI,EAAehI,KACrBP,OAAQyD,EAAa8E,EAAe5E,OAExCnD,MAAO,CACHD,KAAMiI,EAAcjI,KACpBP,OAAQsI,EAAWE,EAAc7E,OAI5C,CAGL,OADA3F,EAAQQ,KAAK,GAAG4H,iDACT,IACV,CACD,MAAO3H,GAEH,OADAT,EAAQK,MAAM,GAAG+H,yCAAkD3H,GAC5D,IACV,GAKCwJ,EAAqB,CAACjJ,EAAQ8B,EAAMP,KACtC,MAAMyH,EAAoB,GAC1B,IAAIhF,EAAW,GAEf,MAAM2F,EAAuB,CAACvH,EAAawH,EAAaZ,EAAmBhF,KACvE,IACI,GAAI6F,EAAQC,OAAO1H,GAAc,CAC7B,MAAMuC,EAAQX,EAASzF,OAEjBmL,GADN1F,GAAY5B,EAAYlE,MACHK,OACrByK,EAAkBjK,KAAK,CACnB+C,KAAMM,EACNb,KAAMqI,EACNjF,QACA+E,OAEP,MACI,GAAI5C,EAAWC,UAAU3E,GAE1B,IAAK,IAAIxD,EAAI,EAAGA,EAAIwD,EAAYkB,SAAS/E,OAAQK,IAAK,CAClD,MAAMmL,EAAY,IAAIH,EAAahL,GACnCoF,EAAW2F,EAAqBvH,EAAYkB,SAAS1E,GAAImL,EAAWf,EAAmBhF,EAC1F,CAEL,OAAOA,CACV,CACD,MAAOvE,GAEH,OADAT,EAAQK,MAAM,iDAAkDI,GACzDuE,CACV,GAGL,GAAoB,IAAhBzC,EAAKhD,OAEL,IAAK,IAAIK,EAAI,EAAGA,EAAIoB,EAAOsD,SAAS/E,OAAQK,IAAK,CAC7C,MAAMmL,EAAY,CAACnL,GACnBoF,EAAW2F,EAAqB3J,EAAOsD,SAAS1E,GAAImL,EAAWf,EAAmBhF,EACrF,MAIDA,EAAW2F,EAAqB7H,EAAMP,EAAMyH,EAAmBhF,GAEnE,MAAO,CAAEA,WAAUgF,sBC1QhB,SAASgB,EAAUC,EAASC,EAAYC,EAAGC,GAE9C,OAAO,IAAKD,IAAMA,EAAIE,UAAU,SAAUC,EAASC,GAC/C,SAASC,EAAUC,GAAS,IAAMC,EAAKN,EAAUO,KAAKF,GAAQ,CAAG,MAAOhD,GAAK8C,EAAO9C,GAAO,CAC3F,SAASmD,EAASH,GAAS,IAAMC,EAAKN,EAAiB,MAAEK,GAAU,CAAC,MAAOhD,GAAK8C,EAAO9C,GAAO,CAC9F,SAASiD,EAAK/C,GAJlB,IAAe8C,EAIa9C,EAAOkD,KAAOP,EAAQ3C,EAAO8C,QAJ1CA,EAIyD9C,EAAO8C,MAJhDA,aAAiBN,EAAIM,EAAQ,IAAIN,EAAE,SAAUG,GAAWA,EAAQG,EAAO,IAIhBK,KAAKN,EAAWI,EAAY,CAC9GF,GAAMN,EAAYA,EAAUW,MAAMd,EAASC,GAAc,KAAKS,OACtE,EACA,CA8MkD,mBAApBK,iBAAiCA,gBCnT/D,IAAIC,GAAe,EACfC,EAAsB,IAAItF,IAC9B,MAAMuF,EAAc,IAAIvF,IAKXwF,EAAoB,KAC7B,IAEI,MAAMC,EAAOC,OAAOC,KACpB,OAAIF,aAAmC,EAASA,EAAKD,mBAC1CC,EAAKD,oBAET,IACV,CACD,MAAO3L,GAEH,OADAT,EAAQK,MAAM,+CAAgDI,GACvD,IACV,GAgCQ+L,EAA0B,CAAClG,EAAcoB,KAClD,IACI,MAAM+E,EAAiBL,IACvB,IAAKK,EACD,OAEJA,EAAeC,cAAcpG,EAAcoB,EAC9C,CACD,MAAOjH,GACHT,EAAQK,MAAM,wCAAyCI,EAC1D,GAMCkM,EAAoC,KACtC,MAAMF,EAAiBL,IACvB,KAAMK,aAAuD,EAASA,EAAeG,qBACjF,OAAO,EAEX,IACI,MAAMC,EAAaJ,EAAeG,sBAClC,KAAMC,aAA+C,EAASA,EAAWC,WACrE,OAAO,EAGX,MAAMC,EAAeF,EAAWC,UAAWE,IACvC,MAAMC,EAAc,IAAIrG,IAOxB,GANAoG,SAAoDA,EAASzI,QAAS2I,KAC9DA,aAAyC,EAASA,EAAQ5G,eAC1D2G,EAAY9F,IAAI+F,EAAQ5G,cAAc,MRyD9B,EAAC6G,EAAMC,KAC/B,GAAID,EAAKE,OAASD,EAAKC,KACnB,OAAO,EACX,IAAK,MAAOC,EAAK7B,KAAUhM,MAAMoF,KAAKsI,GAClC,GAAIC,EAAKpK,IAAIsK,KAAS7B,EAClB,OAAO,EAEf,OAAO,GQ5DM8B,CAAaN,EAAaf,GAAsB,CACjDA,EAAsBe,EAEtB,MAAMO,EAAc,IAAItG,IACxB,IAAK,MAAOZ,KAAiB2G,EACzBO,EAAYC,IAAInH,GAGpB6F,EAAY5H,QAASmJ,IACjB,GAA0B,mBAAfA,EACP,IACIA,EAAWF,EACd,CACD,MAAO/M,GACHT,EAAQK,MAAM,8CAA+CI,EAChE,GAGZ,IAIL,GAAIsM,GAAoD,mBAA7BA,EAAaY,YAEpC,OADA1B,GAAe,GACR,CAEd,CACD,MAAOxL,GACHT,EAAQK,MAAM,mEAAoEI,EACrF,CACD,OAAO,GChHEmN,EAAsB,CAAC3H,EAAUjF,EAAQ6M,KAClD,IAAI5M,EACJ,MAAMmH,EAAY,wBAClB,IAGI,MAAM0F,EAAqBxH,IACvB,IAAIrF,EAAIC,EAAI6M,EAAIC,EAAIC,EAAIC,EACxB,MAAM3G,EAAaI,EAAc1B,EAAUK,GAC3C,IAAKiB,EACD,OAAO,KAKX,MAAO,CACHA,WAAYA,EACZ4G,cALgH,QAA7FjN,EAAmC,QAA7BD,EAAKsG,EAAWG,eAA4B,IAAPzG,OAAgB,EAASA,EAAGmN,wBAAqC,IAAPlN,OAAgB,EAASA,EAAGhC,OAAS,GAM7JmP,oBALsH,QAA7FL,EAAmC,QAA7BD,EAAKxG,EAAWG,eAA4B,IAAPqG,OAAgB,EAASA,EAAGK,wBAAqC,IAAPJ,OAAgB,EAASA,EAAG9F,aAAe,EAMzKzG,kBALoH,QAA7FyM,EAAmC,QAA7BD,EAAK1G,EAAWG,eAA4B,IAAPuG,OAAgB,EAASA,EAAGG,wBAAqC,IAAPF,OAAgB,EAASA,EAAGzM,mBAAqB,KAQ/K6M,EPgQuB,EAACtN,EAAQ6M,EAAaU,EAAW5P,EAAqBmP,KACvF,MAAM1F,EAAY,0BACZkG,EAAU,IAAI1H,IACpB,IAEI,MAAM4H,EAAkB/O,MAAMoF,KAAK9B,EAAQ2B,MAAM1D,EAAQ,CACrD2D,KAAM,EAAE7B,KACIgF,EAAWC,UAAUjF,IACzBA,EAAKkF,OAASrJ,EAAuBK,cACrC,iBAAkB8D,KAE1BuC,OAAO,EAAEvC,KACDgF,EAAWC,UAAUjF,IACzBA,EAAKkF,OAASrJ,EAAuBK,cACrC,iBAAkB8D,GAE1B,IAAK,MAAOA,EAAMP,KAASiM,EAAiB,CACxC,MACMlI,EADWxD,EACawD,aAC9B,IAAKA,EAAc,CACftG,EAAQQ,KAAK,GAAG4H,yCAChB,QACH,CAED,MAAMqG,EAAaX,EAAkBxH,GACrC,IAAKmI,EAAY,CACbzO,EAAQQ,KAAK,GAAG4H,4CAAoD9B,eACpE,QACH,CACD,MAAM6H,EAAeM,EAAWN,aAC1BE,EAAqBI,EAAWJ,mBAChCK,EAA2BD,EAAWhN,kBAAoB,GAE1DkN,EAAc5L,EAAQwC,OAAOzC,GACnC,IAAK6L,EAAa,CACd3O,EAAQQ,KAAK,GAAG4H,wCAChB,QACH,CAED,MAAMwG,EAAoB3L,EAA6BjC,EAAQ8B,EAAMP,GAC/DsM,GAAuBD,aAA6D,EAASA,EAAkBpL,KAAO,GAEtHsL,EAAoBxJ,EAAsBtE,EAAQ2N,EAAa7L,EAAMP,EAAMsM,GAE3EE,EAAcJ,IAAgBR,EAC9Ba,EAAoBF,IAAsBT,EAC1CY,EAA0BP,IAA6BG,EAC7D,GAAIE,GAAeC,GAAqBC,EAAyB,CAC7D,MAAM1H,EAAakH,EAAWlH,WAC9B+G,EAAQnH,IAAIb,EAAc,CACtBA,eACAmB,wBAAyBF,EAAWE,wBACpC0G,eACAQ,cACAN,qBACAS,oBACAJ,2BACAQ,oBAAqBL,EACrBtH,aACA4H,eAAgBJ,EAChBC,oBACAC,2BAEP,CACJ,CACJ,CACD,MAAOxO,GACHT,EAAQK,MAAM,kDAAmDI,EACpE,CACD,OAAO6N,GOrUac,CAAsBpO,EAAQ6M,EAAalP,EAAqBmP,GAChF,GAAqB,IAAjBQ,EAAQjB,KACR,OAEJrN,EAAQM,IAAI,GAAG8H,cAAsBkG,EAAQjB,2BAE7C,IAAK,MAAO/G,EAAc+I,KAAW5P,MAAMoF,KAAKyJ,EAAQgB,WAAY,CAChE,MAAMC,EAAkB,GAAGnH,KAAa9B,KAClCiB,EAAaI,EAAc1B,EAAUK,GAC3C,IAAKiB,EAAY,CACbvH,EAAQQ,KAAK,GAAG+O,6CAChB,QACH,CAED,KAAoC,QAA7BtO,EAAKsG,EAAWG,eAA4B,IAAPzG,OAAgB,EAASA,EAAGmN,kBAAmB,CACvFpO,EAAQQ,KAAK,GAAG+O,mCAChB,QACH,CACD,MAAMnB,EAAmBoB,KAAKC,MAAMD,KAAKE,UAAUnI,EAAWG,QAAQ0G,mBAClEiB,EAAOF,iBACPnP,EAAQM,IAAI,GAAGiP,uBAAqCnB,EAAiBlP,aAAamQ,EAAOV,gBACzFP,EAAiBlP,KAAOmQ,EAAOV,aAE/BU,EAAOL,oBACPhP,EAAQM,IAAI,GAAGiP,yBAAuCnB,EAAiBlG,iBAAiBmH,EAAOP,qBAC/FV,EAAiBlG,WAAamH,EAAOP,mBAErCO,EAAOJ,0BACPjP,EAAQM,IAAI,GAAGiP,gCAA8CnB,EAAiB3M,yBAAyB4N,EAAOH,wBAC9Gd,EAAiB3M,iBAAmB4N,EAAOH,qBAE/C,MAAMS,EAAiBlJ,OAAOC,OAAOD,OAAOC,OAAO,GAAIa,EAAWG,SAAU,CAAE0G,qBAE9EpO,EAAQM,IAAI,GAAGiP,2BACf/C,EAAwBlG,EAAcqJ,EACzC,CHuIkB,EAAC3O,EAAQsN,KAChC,IACI,IAAK,MAAOhI,KAAiBgI,EAEzBpF,EAAqBlI,EAAQsF,EAKpC,CACD,MAAO7F,GACHT,EAAQK,MAAM,sCAAuCI,EACxD,GGjJGmP,CAAY5O,EAAQsN,EACvB,CACD,MAAO7N,GACHT,EAAQK,MAAM,GAAG+H,mCAA4C3H,EAChE,GC3BQoP,EAAqBC,EAAkB,CAChDxC,IA5Be3O,EA8BfmE,KAAM,CACFiF,WAAW,EACXgI,UAAU,EACV/H,KAAMrJ,EAAuBK,cAGjCgR,OAAQ,CACJlN,KAAMqD,GAGV8J,QAAS,CACLhK,cAAUnF,EACVoP,kBAAkB,GAGtBC,SAAU,CACNC,SAAU,EAAGpP,SAAQqP,iBACjB,IAAIpP,EAGJ,GADkD,QAA5BA,EAAKD,EAAOsP,kBAA+B,IAAPrP,OAAgB,EAASA,EAAGsP,KAAMC,GAAiC,gBAAnBA,EAAUxI,MAA6C,gBAAnBwI,EAAUxI,MACtI,CACd,MACM/B,EADUoK,IACSpK,UAAYlF,EAAYC,IAAWrC,EAC5DiP,EAAoB3H,EAAUjF,EACjC,MAKRyP,eAAe,EAAG3G,KAAOiG,YAAY/O,SAAQqP,iBAC9C,IAAIpP,EAEJ,MAAMgP,EAAUI,IACVpK,EAAWgK,EAAQhK,UAAYlF,EAAYC,IAAWrC,EAM5D,MLzE0B,EAACsH,EAAUjF,EAAQ0P,KAE7C,MAAMxK,EAAgBD,GAAY,UAElCY,EAAsBX,GACtB,MAAMwB,EAAU,CACZzB,SAAUC,EACVlF,SACA0P,OAAQA,GAAU,CAAE,GAExB9I,EAAST,IAAIjB,EAAewB,IK2D5BiJ,CAAe1K,EAAUjF,EAAQ,CAC7BkP,iBAAsD,QAAnCjP,EAAKgP,EAAQC,wBAAqC,IAAPjP,GAAgBA,EAC9EgF,aAEG,CACH6D,IAAK,CACDiG,SAAShL,MACD+C,EAAWC,UAAUhD,KA9Ef,CAACA,GAChB+C,EAAWC,UAAUhD,IAAYA,EAAQiD,OAASrJ,EAAuBK,aA6E/B6I,CAAkB9C,KAGhDgL,EAAShL,OCpFnB6L,EAAsB,CAAC5P,EAAQ6P,EAAalS,KACrD,IAAIsC,EACJ,IAEI,MAAMgF,EAAWlF,EAAYC,GAC7B,IAAKiF,EACD,OAAO,EAGX,MAAMyB,ENekB,CAACzB,GACb2B,EAAS5E,IAAIiD,IACX,KMjBE6K,CAAiB7K,GACjC,YAA2InF,KAA1D,QAA3EG,EAAKyG,aAAyC,EAASA,EAAQgJ,cAA2B,IAAPzP,OAAgB,EAASA,EAAGiP,mBAC1GxI,EAAQgJ,OAAOR,gBAI7B,CACD,MAAOzP,GAEH,OADAT,EAAQQ,KAAK,6EAA8EC,IACpF,CACV,GCyBE,SAASsQ,EAAW9P,GACvB,OAAO+J,EAAUgG,KAAMC,eAAW,EAAQ,WAAWhL,SAAEA,EAAQjF,OAAEA,EAAQ0G,QAASwJ,IAC9E,MAAM9I,EAAY,eJzBI,IAAC+I,EI2BvB,GAAKnQ,EAIL,IAGI,IADuBoL,IAGnB,YADApM,EAAQQ,KAAK,GAAG4H,gDAKpB,MAAMgJ,EVrCwB,CAACpQ,IACvC,IAAIC,EAAIC,EAAI6M,EACZ,IAEI,IAAK/M,EAAOU,UACR,OAAO,KAGX,MAAMxC,EAAOwG,EAAYH,OAAOvE,EAAQA,EAAOU,WAC/C,IAAKxC,EACD,OAAO,KAGX,MAAMmS,EAAa3L,EAAYC,MAAM3E,EAAQA,EAAOU,WAC9C4P,EAAW5L,EAAYgF,IAAI1J,EAAQA,EAAOU,WAC1CmD,EAA4F,QAApF5D,EAAKoQ,aAA+C,EAASA,EAAWrP,cAA2B,IAAPf,EAAgBA,EAAK,EACzH2H,EAAoF,QAA9E1H,EAAKoQ,aAA2C,EAASA,EAAStP,cAA2B,IAAPd,EAAgBA,EAAK,EAEjHqQ,EAAiB1O,EAAqB7B,GACtCS,EAAmB8P,aAAuD,EAASA,EAAe/N,GAExG,IAAIgO,EAQJ,OAPID,IACAC,GAE+D,QADzDzD,EAAKwD,EACFjQ,QAAQ,IAAI3C,EAAqBE,uBAAoC,IAAPkP,OAAgB,EAASA,EAAGxM,aAAa5C,EAAqBE,oBAAiBiC,GAInJ,CACH5B,OACA2F,OACA+D,KACAV,WALe1G,EAAoBR,EAAQ9B,EAAMuC,GAMjDA,mBACA+P,aAEP,CACD,MAAO/Q,GAEH,OADAT,EAAQK,MAAM,iDAAkDI,GACzD,IACV,GUJgCgR,CAA2BzQ,GACpD,IAAKoQ,EAED,YADApR,EAAQQ,KAAK,GAAG4H,uCAIpB,MAAQnC,SAAUC,GAAkBF,EAAkBC,EAAUjF,GAK1D0Q,OAAoC5Q,IAAbmF,GAA0BC,IAAkBvH,EACnE+I,EAAUjB,OAAOC,OAAOD,OAAOC,OAAO,CAAE,EAAGwK,GAA0C,iBAAlBA,EAA6BA,EAAgB,IAAM,CAAE9C,iBAAkB3H,OAAOC,OAAOD,OAAOC,OAAO,CAAExH,KAAMkS,EAAiBlS,KAAMgJ,WAAYkJ,EAAiBlJ,YAAewJ,GAAwB,CAAEzL,SAAUC,IAAmB,CAAEzE,iBAAkB2P,EAAiB3P,qBAEnV,IAAIkQ,EACAP,EAAiBI,aACjBG,EAAW,CAAEnO,GAAI4N,EAAiBI,mBAIhC,IAAInG,QAASC,GAAYsG,WAAWtG,EAAS,MAEnD,MAAMuG,QJ9DaV,EI8DqB,CAAEzJ,UAASiK,YJ9DrB3G,OAAU,OAAQ,OAAQ,EAAQ,YACxE,IACI,MAAMyB,EAAiBL,IACvB,IAAKK,EACD,OAAO,KAEX,MAAM9D,QAAe8D,EAAeqF,iBAAiB,CACjDpK,QAASyJ,EAAOzJ,QAChBiK,SAAUR,EAAOQ,WAErB,OAAKhJ,EAIE,CACHpB,WAAYoB,GAJL,IAMd,CACD,MAAOlI,GAEH,OADAT,EAAQK,MAAM,sCAAuCI,GAC9C,IACV,CACL,IIyCY,IAAKoR,IAAeA,EAAWtK,WAE3B,YADAvH,EAAQQ,KAAK,GAAG4H,2CAGpB,MAAMb,EAAasK,EAAWtK,WAGxBwK,ED1Da,EAAC/Q,EAAQ6P,EAAalS,KACjD,IAGI,OAA4B,IAFHiS,EAAoB5P,EAAQ6P,EAGxD,CACD,MAAOpQ,GAEH,OADAT,EAAQQ,KAAK,yEAA0EC,IAChF,CACV,GCiDoCuR,CAAgBhR,EAAQrC,GAIjDoT,GAAwBxK,EAAWjB,cACnC2B,EAA0BjH,EAAQoQ,EAAiBlS,KAAMkS,EAAiBlJ,WAAYX,EAAWjB,aAAciB,EAAWE,wBAAyB2J,EAAiB3P,kBAGpK8F,EAAWjB,aACXe,EAAkBnB,EAAe,CAACqB,IAGlCvH,EAAQQ,KAAK,GAAG4H,2CAIvB,CACD,MAAO3H,GACHT,EAAQK,MAAM,GAAG+H,0BAAmC3H,EACvD,MA7DGT,EAAQK,MAAM,GAAG+H,8BA8D7B,EACA,CChHA,MAAM6J,EAAgB,IAAIrL,IAkDbsL,EAAiB,CAACjM,EAAUjF,EAAQ+F,KAC7C,IAAI9F,EAEJ,IAEI,MAAMkR,EAAaF,EAAcjP,IAAIiD,GACjCkM,EACAA,EAAWnR,OAASA,EAGpBiR,EAAc9K,IAAIlB,EAAU,CACxBjF,SACAoR,4BAA6B,KAIrC,MAAM5E,EToCwB,CAACvH,IACnC,IACI,MAAMa,EAAQH,EAAS3D,IAAIiD,GAC3B,OAAKa,EAGE,IAAII,IAAIJ,EAAMG,qBAFV,IAAIC,GAGlB,CACD,MAAOzG,GAEH,OADAT,EAAQK,MAAM,sCAAuCI,GAC9C,IAAIyG,GACd,GS/CuBmL,CAAuBpM,GAErCqM,EA3DY,EAACvL,EAAayG,IAC7BzG,EAAY1B,OAAQkC,IACvB,IAAItG,EAEJ,OAA0F,QAApFA,EAAKsG,aAA+C,EAASA,EAAWgL,cAA2B,IAAPtR,OAAgB,EAASA,EAAG+G,QAAUrJ,GAIjI6O,EAAYgF,IAAIjL,EAAWjB,gBAmDNmM,CAAkB1L,EAAayG,GAErD4E,GAAsE,QAAtCnR,EAAKgR,EAAcjP,IAAIiD,UAA8B,IAAPhF,OAAgB,EAASA,EAAGmR,8BAAgC,GAE1IM,EAAmB,IAAIxL,IAAIoL,EAAoBK,IAAKC,GAAQA,EAAItM,cAAcjB,OAAOwN,UACrFC,EAAwB,IAAI5L,IAAIkL,EAA4BO,IAAKC,GAAQA,EAAItM,cAAcjB,OAAOwN,UAElGE,EAAuBtT,MAAMoF,KAAKiO,GAAuBzN,OAAQ7B,IAAQkP,EAAiBF,IAAIhP,IAEpG,IAAK,MAAM8C,KAAgByM,EACnBzM,GACA4C,EAAqBlI,EAAQsF,GAIrC,MAAM0M,EAAoBf,EAAcjP,IAAIiD,GACxC+M,IACAA,EAAkBZ,4BAA8BE,GA1D3B,EAACtR,EAAQsR,KACtC,IAAIrR,EACJ,IAAK,MAAMsG,KAAc+K,EAAqB,CAC1C,MAAMlE,EAAyG,QAArFnN,EAAKsG,aAA+C,EAASA,EAAWG,eAA4B,IAAPzG,OAAgB,EAASA,EAAGmN,iBACnJ,KAAMA,aAA2D,EAASA,EAAiBlP,QAAUqI,EAAWjB,aAC5G,SAEJ,MAAM2M,EAAa7E,EAAiBlP,KAC9BgJ,EAAakG,EAAiBlG,YAAc,EAC5CzG,EAAmB2M,EAAiB3M,iBAG1CwG,EAA0BjH,EAAQiS,EAAY/K,EAAYX,EAAWjB,aAAciB,EAAWE,wBAAyBhG,EAC1H,GAiDGyR,CAAyBlS,EAAQsR,EACpC,CACD,MAAO7R,GACHT,EAAQK,MAAM,4DAAyCI,EAC1D,GASQ0S,GAAkB,CAAClN,EAAUuH,KACtC,MAAMpF,EAAY,oCAClB,IAEI,MAAM+J,EAAaF,EAAcjP,IAAIiD,GACrC,IAAKkM,IAAeA,EAAWnR,OAE3B,YADAhB,EAAQQ,KAAK,GAAG4H,mCAA2CnC,KAI/D,MAAMc,ET2CuB,CAACd,IAClC,IACI,MAAMa,EAAQH,EAAS3D,IAAIiD,GAC3B,OAAKa,EAGE,IAAIA,EAAME,oBAFN,EAGd,CACD,MAAOvG,GAEH,OADAT,EAAQK,MAAM,qCAAsCI,GAC7C,EACV,GStDuB2S,CAAsBnN,GAG1CiM,EAAejM,EAAUkM,EAAWnR,OAAQ+F,EAC/C,CACD,MAAOtG,GACHT,EAAQK,MAAM,GAAG+H,8BAAuC3H,EAC3D,GCjHC4S,GAAkB,IAAIzM,IA2Cf0M,GAAiB,EAAGtS,SAAQiF,WAAUe,yBAC/C,MAAMoB,EAAY,mBAClB,IACI,IAAKpH,EAED,YADAhB,EAAQQ,KAAK,GAAG4H,wBAIfpB,GAAuBvH,MAAM4E,QAAQ2C,KACtCA,EAAqB,IAGzB,MAAQf,SAAUC,GAAkBF,EAAkBC,EAAUjF,GAM1DuS,EAJoB/D,KAAKC,MAAMD,KAAKE,UAAU1I,IAIR3B,OAAQkC,IAChD,IAAItG,EACJ,KAA4F,QAArFA,EAAKsG,aAA+C,EAASA,EAAWG,eAA4B,IAAPzG,OAAgB,EAASA,EAAGmN,kBAC5H,OAAO,EAEX,MAAMoF,EAAqBjM,EAAWG,QAAQ0G,iBAAiBnI,SAE/D,OAAIC,IAAkBvH,OACYmC,IAAvB0S,GACHA,IAAuB7U,GACA,YAAvB6U,EAGDA,IAAuBtN,IAKlC,GAFAmB,EAAkBnB,EAAeqN,IAE5BF,GAAgBb,IAAItM,GAAgB,CAErC,MAAMuN,EAA0BvN,EAC1ByH,ENiC4B,EAAC+F,EAAUzN,KACrD,IAQI,OANAkG,EAAYhF,IAAIlB,EAAUyN,GAErBzH,GACDU,IAGG,KACHR,EAAYwH,OAAO1N,GAE1B,CACD,MAAOxF,GAEH,OADAT,EAAQK,MAAM,2DAA4DI,GACnE,MAGV,GMnD2BmT,CAAgCpG,IViC1B,EAACvH,EAAUuH,KAC7C,IACkBpG,EAAiBnB,GACzBgB,oBAAsB,IAAIC,IAAIsG,EACvC,CACD,MAAO/M,GACHT,EAAQK,MAAM,sCAAuCI,EACxD,GUtCWoT,CAAuBJ,EAAyBjG,GAEhD2F,GAAgBM,IACjBA,GACHJ,GAAgBlM,IAAIjB,EAAeyH,EACtC,CNoDD1B,GAGGU,IMlDHuF,EAAehM,EAAelF,EAAQuS,EACzC,CACD,MAAO9S,GACHT,EAAQK,MAAM,GAAG+H,8BAAuC3H,EAC3D,GAQQqT,GAAyB7N,IAElC,MAAM0H,EAAc0F,GAAgBrQ,IAAIiD,GACpC0H,IACAA,IACA0F,GAAgBM,OAAO1N,IDUA,CAACA,IAC5BgM,EAAc0B,OAAO1N,ICRrB8N,CAAgB9N,ICtId+N,GAAerV,EAAuBK,aAU/BiV,GAA6BC,IAEtC,MAAMC,EAAkBC,GAAyBF,GAGjD,OAD0BG,GAA4BF,IAIpDC,GAA4BF,GACvBI,GAAuBJ,GAK5BI,GAA0BhQ,IAC5B,MAAMiQ,EAAM,GACZ,IAAK,MAAM/P,KAASF,EAAU,CAC1B,GAAIkQ,GAAchQ,IAAUA,EAAMwD,OAASgM,GAAc,CAErD,MAAMS,EAAYH,GAAuB9P,EAAMF,UAC/CiQ,EAAIxU,QAAQ0U,GACZ,QACH,CACDF,EAAIxU,KAAK2U,GAAsBlQ,GAClC,CACD,OAAO+P,GAELG,GAAyB5R,IAC3B,GAAI0R,GAAc1R,GAAO,CACrB,MAAM6R,EAAeL,GAAuBxR,EAAKwB,UACjD,OAAOmC,OAAOC,OAAOD,OAAOC,OAAO,CAAA,EAAI5D,GAAO,CAAEwB,SAAUqQ,GAC7D,CACD,OAAO7R,GAGLuR,GAA+BH,IACjC,MAAMU,EAAiBV,EAAQvB,IAAIkC,IACnC,OAAOC,GAAuBF,IAE5BC,GAA4B/R,IAC9B,GAAI0R,GAAc1R,GAAO,CACrB,MAAM8R,EAAiB9R,EAAKwB,SAASqO,IAAIkC,IACzC,OAAOpO,OAAOC,OAAOD,OAAOC,OAAO,CAAE,EAAE5D,GAAO,CAAEwB,SAAUwQ,GAAuBF,IACpF,CACD,OAAO9R,GAELgS,GAA0BxQ,IAC5B,IAAIrD,EAAIC,EACR,GAAIoD,EAAS/E,OAAS,EAClB,OAAO+E,EACX,MAAMyQ,EAAS,GACf,IAAInV,EAAI,EACR,KAAOA,EAAI0E,EAAS/E,QAAQ,CACxB,MAAMyV,EAAM1Q,EAAS1E,GACrB,GAAIkE,GAAWkR,GAAM,CAEjB,GAAiB,KAAbA,EAAI9V,KAAa,CACjBU,IACA,QACH,CACD,IAAIV,EAA2B,QAAnB+B,EAAK+T,EAAI9V,YAAyB,IAAP+B,EAAgBA,EAAK,GACxDnB,EAAIF,EAAI,EACZ,KAAOE,EAAIwE,EAAS/E,QAAQ,CACxB,MAAM0V,EAAM3Q,EAASxE,GAErB,GAAIgE,GAAWmR,IAAqB,KAAbA,EAAI/V,KACvBY,QADJ,CAIA,IAAIgE,GAAWmR,KAAQC,GAAmBF,EAAKC,GAK3C,MAJA/V,GAA4B,QAAnBgC,EAAK+T,EAAI/V,YAAyB,IAAPgC,EAAgBA,EAAK,GACzDpB,GAHH,CAQJ,CACDiV,EAAOhV,KAAK0G,OAAOC,OAAOD,OAAOC,OAAO,CAAE,EAAEsO,GAAM,CAAE9V,UACpDU,EAAIE,CACP,MAEGiV,EAAOhV,KAAKiV,GACZpV,GAEP,CAED,OAAOmV,EAAOxV,OAAS,EAAIwV,EAAS,CAAC,CAAE7V,KAAM,MAG3CsV,GAAiB1R,GAEX2D,OAAO0O,UAAUC,eAAeC,KAAKvS,EAAM,aAC/C2D,OAAO0O,UAAUC,eAAeC,KAAKvS,EAAM,QAE7CgB,GAAchB,GACT2D,OAAO0O,UAAUC,eAAeC,KAAKvS,EAAM,QAEhDoS,GAAqB,CAACI,EAAGC,IACnBD,EAAEE,OAASD,EAAEC,MACjBF,EAAEG,SAAWF,EAAEE,QACfH,EAAEI,YAAcH,EAAEG","x_google_ignoreList":[8]}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Host editor document operations adapter for Plate.js.
3
+ * This is the ONLY place where editor-specific types may be imported.
4
+ *
5
+ * Responsibilities:
6
+ * - Extract selection context from editor
7
+ * - Find text occurrences in document
8
+ * - Detect document changes for annotations
9
+ * - Get editor ID from DOM
10
+ *
11
+ * Architectural Rules:
12
+ * - MAY import editor-specific types (PlateEditor, etc.)
13
+ * - MUST NOT import Velt SDK types
14
+ * - Uses pure utilities from utils/common.ts where possible
15
+ *
16
+ * NOTE: This file uses Plate.js native utilities from @platejs/slate
17
+ */
18
+ import type { PlateEditor } from '@platejs/core/react';
19
+ import type { AnnotationChange, OccurrenceMatch, SelectionContext } from '@/types/host';
20
+ /**
21
+ * Gets editor ID from editor instance by traversing DOM.
22
+ * Returns null if editor ID attribute not found.
23
+ */
24
+ export declare const getEditorId: (editor: PlateEditor) => string | null;
25
+ /**
26
+ * Gets current selection context from editor with full details.
27
+ * Returns null if no selection or selection is collapsed.
28
+ */
29
+ export declare const getCurrentSelectionContext: (editor: PlateEditor) => SelectionContext | null;
30
+ /**
31
+ * Finds occurrence index of selected text in the document.
32
+ * Returns 1-based occurrence index, or 0 if not found.
33
+ */
34
+ export declare const findOccurrenceIndex: (editor: PlateEditor, text: string, targetTextNodeId?: string) => number;
35
+ /**
36
+ * Finds parent node with ID attribute for current selection.
37
+ * Returns HTMLElement with ID, or null if not found.
38
+ */
39
+ export declare const findParentNodeWithId: (editor: PlateEditor) => HTMLElement | null;
40
+ /**
41
+ * Function type for getting annotation data.
42
+ */
43
+ type GetAnnotationDataFn = (id: string) => {
44
+ annotation: unknown;
45
+ originalText: string;
46
+ originalOccurrence: number;
47
+ targetTextNodeId: string;
48
+ } | null;
49
+ /**
50
+ * Detects document changes for annotations.
51
+ * Compares current document state with stored annotation data.
52
+ */
53
+ export declare const detectDocumentChanges: (editor: PlateEditor, transaction: unknown, markType: string | undefined, getAnnotationData: GetAnnotationDataFn) => Map<string, AnnotationChange>;
54
+ /**
55
+ * Finds all text occurrences in the document.
56
+ * Returns array of ranges matching the search text.
57
+ */
58
+ export declare const findTextOccurrences: (editor: PlateEditor, text: string, targetTextNodeId?: string, occurrence?: number) => OccurrenceMatch[];
59
+ /**
60
+ * Ensures editor is set up (registered and document listeners configured).
61
+ */
62
+ export declare const ensureEditorSetup: (editorId: string | undefined, editor: unknown) => {
63
+ editorId: string;
64
+ };
65
+ /**
66
+ * Resets the editor selection by focusing the editor.
67
+ */
68
+ export declare const resetEditorSelection: (editor: unknown) => void;
69
+ export {};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Host editor marks/nodes operations adapter for Plate.js.
3
+ * This is the ONLY place where editor-specific mark/node operations may be implemented.
4
+ *
5
+ * Responsibilities:
6
+ * - Apply comment marks/nodes to editor
7
+ * - Remove comment marks/nodes from editor
8
+ * - Update marks/nodes when document changes
9
+ *
10
+ * Architectural Rules:
11
+ * - MAY import editor-specific types (PlateEditor, Element, Transforms, etc.)
12
+ * - MUST NOT import Velt SDK types
13
+ * - Handles editor-specific mark/node application logic
14
+ *
15
+ * NOTE: This file uses Plate.js native utilities from @platejs/slate
16
+ */
17
+ import type { PlateEditor } from '@platejs/core/react';
18
+ import type { AnnotationChange } from '@/types/host';
19
+ /**
20
+ * Sets the history editor instance (called from extension).
21
+ */
22
+ export declare const setHistoryEditor: (historyEditor: unknown) => void;
23
+ /**
24
+ * Gets the history editor instance.
25
+ */
26
+ export declare const getHistoryEditor: () => {
27
+ withoutSaving?: (editor: PlateEditor, fn: () => void) => void;
28
+ } | null;
29
+ /**
30
+ * Applies annotation mark/node by finding text occurrence and wrapping it.
31
+ * This is the main entry point for applying marks.
32
+ *
33
+ * @param editor The editor instance (typed as unknown to avoid importing editor types in feature modules)
34
+ * @param textToSearch The text to search for
35
+ * @param occurrence The occurrence number (1-based)
36
+ * @param annotationId The annotation ID to mark
37
+ * @param multiThreadAnnotationId Optional multi-thread annotation ID
38
+ * @param targetElementId Optional target element ID to scope the search
39
+ * @returns True if mark was successfully applied, false otherwise
40
+ */
41
+ export declare const applyAnnotationMarkByText: (editor: unknown, textToSearch: string, occurrence: number, annotationId: string, multiThreadAnnotationId: string | undefined, targetElementId?: string) => boolean;
42
+ /**
43
+ * Removes annotation mark/node from editor by annotation ID.
44
+ * Finds all nodes with matching annotationId and unwraps them.
45
+ */
46
+ export declare const removeAnnotationMark: (editor: PlateEditor, annotationId: string) => boolean;
47
+ /**
48
+ * Updates marks/nodes based on document changes.
49
+ * Removes old marks and applies new ones at updated positions.
50
+ */
51
+ export declare const updateMarks: (editor: PlateEditor, changes: Map<string, AnnotationChange>) => void;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Storage adapter for editor-specific storage access.
3
+ *
4
+ * Purpose: Abstracts away editor-specific storage patterns.
5
+ * This allows the codebase to be more generic and reusable across different editor implementations.
6
+ *
7
+ * Key responsibilities:
8
+ * - Get persistVeltMarks setting (for Plate, checks plugin options via registry)
9
+ * - Determine if marks should be applied
10
+ *
11
+ * Dependencies:
12
+ * - @platejs/core/react (ONLY place allowed to import PlateEditor for storage access)
13
+ */
14
+ import type { PlateEditor } from '@platejs/core/react';
15
+ /**
16
+ * Gets persistVeltMarks setting from storage.
17
+ * For Plate, checks the plugin config from registry.
18
+ *
19
+ * @param editor The editor instance
20
+ * @param storageKey The storage key (unused for Plate, kept for API compatibility)
21
+ * @returns persistVeltMarks boolean value (defaults to true)
22
+ */
23
+ export declare const getPersistVeltMarks: (editor: PlateEditor, storageKey?: string) => boolean;
24
+ /**
25
+ * Determines if marks should be applied based on persistVeltMarks setting.
26
+ * This is a unified adapter function that abstracts the mark application logic.
27
+ *
28
+ * @param editor The editor instance (typed as unknown to avoid importing editor types in feature modules)
29
+ * @param storageKey The storage key (default: 'plateVeltComments')
30
+ * @returns boolean indicating if marks should be applied
31
+ *
32
+ * @remarks
33
+ * - For Plate: checks persistVeltMarks setting (apply if FALSE)
34
+ * - Defaults to true if storage is unavailable
35
+ */
36
+ export declare const shouldApplyMark: (editor: unknown, storageKey?: string) => boolean;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Velt SDK adapter.
3
+ * This is the ONLY place where @veltdev/types may be imported or window.Velt accessed.
4
+ *
5
+ * Responsibilities:
6
+ * - Wrap all Velt SDK calls with error handling
7
+ * - Provide high-level async functions for SDK operations
8
+ * - Manage singleton subscription pattern
9
+ *
10
+ * Architectural Rules:
11
+ * - MAY import @veltdev/types
12
+ * - MAY access window.Velt
13
+ * - MUST wrap all SDK calls in try-catch
14
+ * - MUST NOT import editor types
15
+ */
16
+ import type { CommentAnnotationContext } from '@/types/common';
17
+ import type { CommentAnnotation, CommentElement, Location, UnsubscribeFn } from '@/types/velt';
18
+ /**
19
+ * Gets Velt comment element from SDK.
20
+ * Returns null if SDK is not available.
21
+ */
22
+ export declare const getCommentElement: () => CommentElement | null;
23
+ /**
24
+ * Adds a comment via Velt SDK.
25
+ * Returns the created annotation, or null on failure.
26
+ */
27
+ export declare const addVeltComment: (params: {
28
+ context: CommentAnnotationContext;
29
+ location?: Location;
30
+ }) => Promise<{
31
+ annotation: CommentAnnotation;
32
+ } | null>;
33
+ /**
34
+ * Updates annotation context in Velt SDK.
35
+ */
36
+ export declare const updateAnnotationContext: (annotationId: string, context: CommentAnnotationContext) => void;
37
+ /**
38
+ * Subscribes to selected annotations from Velt SDK.
39
+ * Uses singleton pattern to avoid multiple subscriptions.
40
+ * Returns unsubscribe function.
41
+ *
42
+ * Callback receives Set<string> of selected annotation IDs.
43
+ */
44
+ export declare const subscribeToSelectedAnnotations: (callback: (selectedIds: Set<string>) => void, editorId: string) => UnsubscribeFn;
45
+ /**
46
+ * Attempts to set up the selected comments subscription if not already done.
47
+ * This should be called when we know the Velt SDK is ready.
48
+ * Returns true if subscription is now active.
49
+ */
50
+ export declare const ensureSelectedCommentsSubscription: () => boolean;