@hienlh/ppm 0.13.50 → 0.13.51

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 (132) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +1 -1
  4. package/dist/web/assets/ai-settings-section-AuV6Lzz2.js +1 -2
  5. package/dist/web/assets/api-client-DIhJ5qVW.js +1 -2
  6. package/dist/web/assets/api-settings-C3T95dWg.js +1 -2
  7. package/dist/web/assets/arrow-up-Rcw6_KKu.js +1 -2
  8. package/dist/web/assets/{audio-preview-CILFIsuu.js → audio-preview-BQWWkcm0.js} +1 -2
  9. package/dist/web/assets/{chat-tab-DBYwH_Aa.js → chat-tab-B-QMa-uT.js} +5 -6
  10. package/dist/web/assets/chevron-right-DnHIvvcy.js +1 -2
  11. package/dist/web/assets/code-DGBecc50.js +1 -2
  12. package/dist/web/assets/{code-editor-MXnkYRLp.js → code-editor-DChspYxh.js} +3 -4
  13. package/dist/web/assets/{conflict-editor-C6wH5wV6.js → conflict-editor-C1dZ8tsU.js} +2 -3
  14. package/dist/web/assets/createLucideIcon-BjHrJDVb.js +1 -2
  15. package/dist/web/assets/csv-parser-Dly5nqE1.js +1 -2
  16. package/dist/web/assets/csv-preview-B3Dyhgho.js +1 -2
  17. package/dist/web/assets/data-grid-overlay-editor-C1UUm7Ob.js +1 -2
  18. package/dist/web/assets/data-grid-types-D2cHE8hx.js +1 -2
  19. package/dist/web/assets/database-DOWH9-Vv.js +1 -2
  20. package/dist/web/assets/{database-viewer-BjUruZLv.js → database-viewer-2KW73oEG.js} +1 -2
  21. package/dist/web/assets/{diff-viewer-B_nU7bQi.js → diff-viewer-BMla30lw.js} +2 -3
  22. package/dist/web/assets/dist-BoIkGNC8.js +1 -2
  23. package/dist/web/assets/dist-DVk8T0R5.js +1 -2
  24. package/dist/web/assets/esm-DCbn6xno.js +1 -2
  25. package/dist/web/assets/{extension-webview-B56ZfvoD.js → extension-webview-DpaCcCXq.js} +2 -3
  26. package/dist/web/assets/file-exclamation-point-BwzaQ50n.js +1 -2
  27. package/dist/web/assets/file-store-DOxcU_7s.js +1 -2
  28. package/dist/web/assets/{glide-data-grid-D-qQqqp7.js → glide-data-grid-D08bJMrD.js} +2 -3
  29. package/dist/web/assets/globe-B4Ilypbs.js +1 -2
  30. package/dist/web/assets/{image-preview-Dc6AiqYX.js → image-preview-DVQkHkSo.js} +1 -2
  31. package/dist/web/assets/{index-8_rE2Q1-.js → index-U7GK_3ED.js} +3 -4
  32. package/dist/web/assets/input-_LFQwhzd.js +1 -2
  33. package/dist/web/assets/katex-C10ndCVt.js +1 -2
  34. package/dist/web/assets/keybindings-store-B9gpby19.js +1 -0
  35. package/dist/web/assets/lib-C2D8j3K3.js +1 -2
  36. package/dist/web/assets/{markdown-renderer-CNQ8I0Dk.js → markdown-renderer-B4_rx1aO.js} +2 -3
  37. package/dist/web/assets/notification-store-7WlicqzJ.js +1 -0
  38. package/dist/web/assets/number-overlay-editor-CyEqxXcg.js +1 -2
  39. package/dist/web/assets/panel-store-C8wwxBpn.js +1 -2
  40. package/dist/web/assets/{pdf-preview-zs9QdgDp.js → pdf-preview-D16LLBdq.js} +1 -2
  41. package/dist/web/assets/{port-forwarding-tab-sArYx1nt.js → port-forwarding-tab-CoKoquJZ.js} +1 -2
  42. package/dist/web/assets/{postgres-viewer-khk7N7cd.js → postgres-viewer-B45DfArf.js} +2 -3
  43. package/dist/web/assets/react-DMIOAtcX.js +1 -2
  44. package/dist/web/assets/refresh-cw-BjrAbUJe.js +1 -2
  45. package/dist/web/assets/scroll-area-BDi_FNzr.js +1 -2
  46. package/dist/web/assets/search-tM8K5zWU.js +1 -2
  47. package/dist/web/assets/settings-store-8FpQDjEA.js +1 -2
  48. package/dist/web/assets/{settings-tab-CGWhVzQm.js → settings-tab-Dc8TBxJQ.js} +1 -1
  49. package/dist/web/assets/sparkles-CulWHe4c.js +1 -2
  50. package/dist/web/assets/{sql-query-editor-B5Ndypxp.js → sql-query-editor-DMk0nmOO.js} +2 -3
  51. package/dist/web/assets/{sqlite-viewer-BkpONSGa.js → sqlite-viewer-G81XimpL.js} +1 -2
  52. package/dist/web/assets/tab-store-CNas5Ny8.js +1 -2
  53. package/dist/web/assets/table-BzjWcs87.js +1 -2
  54. package/dist/web/assets/{terminal-tab-BgMCsdeN.js → terminal-tab-rslAfxoV.js} +2 -3
  55. package/dist/web/assets/text-wrap-DJz9Bgpa.js +1 -2
  56. package/dist/web/assets/use-blob-url-DB4nNruT.js +1 -2
  57. package/dist/web/assets/use-monaco-theme-DEI-tJAh.js +1 -2
  58. package/dist/web/assets/utils-CQux7CsO.js +1 -2
  59. package/dist/web/assets/vendor-markdown-0Mxgxy0L.js +1 -2
  60. package/dist/web/assets/vendor-mermaid-D2KKkqNs.js +1 -2
  61. package/dist/web/assets/vendor-ui-UXCWAcmi.js +1 -2
  62. package/dist/web/assets/vendor-xterm-D1P36hcr.js +1 -2
  63. package/dist/web/assets/{video-preview-w8ZAy8av.js → video-preview-vjw8RpLK.js} +1 -2
  64. package/dist/web/assets/x-BPReZWnP.js +1 -2
  65. package/dist/web/index.html +1 -1
  66. package/dist/web/sw.js +1 -2
  67. package/package.json +1 -1
  68. package/src/web/components/chat/chat-tab.tsx +6 -4
  69. package/src/web/components/layout/tab-pool.tsx +1 -1
  70. package/src/web/hooks/use-chat.ts +7 -6
  71. package/vite.config.ts +1 -1
  72. package/dist/web/assets/ai-settings-section-AuV6Lzz2.js.map +0 -1
  73. package/dist/web/assets/api-client-DIhJ5qVW.js.map +0 -1
  74. package/dist/web/assets/api-settings-C3T95dWg.js.map +0 -1
  75. package/dist/web/assets/arrow-up-Rcw6_KKu.js.map +0 -1
  76. package/dist/web/assets/audio-preview-CILFIsuu.js.map +0 -1
  77. package/dist/web/assets/chat-tab-DBYwH_Aa.js.map +0 -1
  78. package/dist/web/assets/chevron-right-DnHIvvcy.js.map +0 -1
  79. package/dist/web/assets/code-DGBecc50.js.map +0 -1
  80. package/dist/web/assets/code-editor-MXnkYRLp.js.map +0 -1
  81. package/dist/web/assets/conflict-editor-C6wH5wV6.js.map +0 -1
  82. package/dist/web/assets/createLucideIcon-BjHrJDVb.js.map +0 -1
  83. package/dist/web/assets/csv-parser-Dly5nqE1.js.map +0 -1
  84. package/dist/web/assets/csv-preview-B3Dyhgho.js.map +0 -1
  85. package/dist/web/assets/data-grid-overlay-editor-C1UUm7Ob.js.map +0 -1
  86. package/dist/web/assets/data-grid-types-D2cHE8hx.js.map +0 -1
  87. package/dist/web/assets/database-DOWH9-Vv.js.map +0 -1
  88. package/dist/web/assets/database-viewer-BjUruZLv.js.map +0 -1
  89. package/dist/web/assets/diff-viewer-B_nU7bQi.js.map +0 -1
  90. package/dist/web/assets/dist-BoIkGNC8.js.map +0 -1
  91. package/dist/web/assets/dist-DVk8T0R5.js.map +0 -1
  92. package/dist/web/assets/esm-DCbn6xno.js.map +0 -1
  93. package/dist/web/assets/extension-webview-B56ZfvoD.js.map +0 -1
  94. package/dist/web/assets/file-exclamation-point-BwzaQ50n.js.map +0 -1
  95. package/dist/web/assets/file-store-DOxcU_7s.js.map +0 -1
  96. package/dist/web/assets/glide-data-grid-D-qQqqp7.js.map +0 -1
  97. package/dist/web/assets/globe-B4Ilypbs.js.map +0 -1
  98. package/dist/web/assets/image-preview-Dc6AiqYX.js.map +0 -1
  99. package/dist/web/assets/index-8_rE2Q1-.js.map +0 -1
  100. package/dist/web/assets/input-_LFQwhzd.js.map +0 -1
  101. package/dist/web/assets/katex-C10ndCVt.js.map +0 -1
  102. package/dist/web/assets/keybindings-store-COJD5O6M.js +0 -1
  103. package/dist/web/assets/lib-C2D8j3K3.js.map +0 -1
  104. package/dist/web/assets/markdown-renderer-CNQ8I0Dk.js.map +0 -1
  105. package/dist/web/assets/notification-store-BiZaLXop.js +0 -1
  106. package/dist/web/assets/number-overlay-editor-CyEqxXcg.js.map +0 -1
  107. package/dist/web/assets/panel-store-C8wwxBpn.js.map +0 -1
  108. package/dist/web/assets/pdf-preview-zs9QdgDp.js.map +0 -1
  109. package/dist/web/assets/port-forwarding-tab-sArYx1nt.js.map +0 -1
  110. package/dist/web/assets/postgres-viewer-khk7N7cd.js.map +0 -1
  111. package/dist/web/assets/react-DMIOAtcX.js.map +0 -1
  112. package/dist/web/assets/refresh-cw-BjrAbUJe.js.map +0 -1
  113. package/dist/web/assets/scroll-area-BDi_FNzr.js.map +0 -1
  114. package/dist/web/assets/search-tM8K5zWU.js.map +0 -1
  115. package/dist/web/assets/settings-store-8FpQDjEA.js.map +0 -1
  116. package/dist/web/assets/sparkles-CulWHe4c.js.map +0 -1
  117. package/dist/web/assets/sql-query-editor-B5Ndypxp.js.map +0 -1
  118. package/dist/web/assets/sqlite-viewer-BkpONSGa.js.map +0 -1
  119. package/dist/web/assets/tab-store-CNas5Ny8.js.map +0 -1
  120. package/dist/web/assets/table-BzjWcs87.js.map +0 -1
  121. package/dist/web/assets/terminal-tab-BgMCsdeN.js.map +0 -1
  122. package/dist/web/assets/text-wrap-DJz9Bgpa.js.map +0 -1
  123. package/dist/web/assets/use-blob-url-DB4nNruT.js.map +0 -1
  124. package/dist/web/assets/use-monaco-theme-DEI-tJAh.js.map +0 -1
  125. package/dist/web/assets/utils-CQux7CsO.js.map +0 -1
  126. package/dist/web/assets/vendor-markdown-0Mxgxy0L.js.map +0 -1
  127. package/dist/web/assets/vendor-mermaid-D2KKkqNs.js.map +0 -1
  128. package/dist/web/assets/vendor-ui-UXCWAcmi.js.map +0 -1
  129. package/dist/web/assets/vendor-xterm-D1P36hcr.js.map +0 -1
  130. package/dist/web/assets/video-preview-w8ZAy8av.js.map +0 -1
  131. package/dist/web/assets/x-BPReZWnP.js.map +0 -1
  132. package/dist/web/sw.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"chevron-right-DnHIvvcy.js","names":[],"sources":["../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/icons/chevron-right.js"],"sourcesContent":["/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [[\"path\", { d: \"m9 18 6-6-6-6\", key: \"mthhwq\" }]];\nconst ChevronRight = createLucideIcon(\"chevron-right\", __iconNode);\n\nexport { __iconNode, ChevronRight as default };\n//# sourceMappingURL=chevron-right.js.map\n"],"x_google_ignoreList":[0],"mappings":"mDAUA,IAAM,EAAe,EAAiB,gBADnB,CAAC,CAAC,OAAQ,CAAE,EAAG,gBAAiB,IAAK,SAAU,CAAC,CAAC,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"code-DGBecc50.js","names":[],"sources":["../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/icons/code.js"],"sourcesContent":["/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"m16 18 6-6-6-6\", key: \"eg8j8\" }],\n [\"path\", { d: \"m8 6-6 6 6 6\", key: \"ppft3o\" }]\n];\nconst Code = createLucideIcon(\"code\", __iconNode);\n\nexport { __iconNode, Code as default };\n//# sourceMappingURL=code.js.map\n"],"x_google_ignoreList":[0],"mappings":"mDAaA,IAAM,EAAO,EAAiB,OAJX,CACjB,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAS,CAAC,CAC/C,CAAC,OAAQ,CAAE,EAAG,eAAgB,IAAK,SAAU,CAAC,CAC/C,CACgD"}
@@ -1 +0,0 @@
1
- {"version":3,"mappings":"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","names":[],"ignoreList":[0],"sources":["../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/icons/redo-2.js","../../../src/web/components/editor/editor-breadcrumb.tsx","../../../src/web/components/editor/editor-toolbar.tsx","../../../src/web/components/editor/save-as-dialog.tsx","../../../src/web/components/editor/editor-mobile-toolbar.tsx","../../../src/web/components/editor/code-editor.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"m15 14 5-5-5-5\", key: \"12vg1m\" }],\n [\"path\", { d: \"M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13\", key: \"6uklza\" }]\n];\nconst Redo2 = createLucideIcon(\"redo-2\", __iconNode);\n\nexport { __iconNode, Redo2 as default };\n//# sourceMappingURL=redo-2.js.map\n","import { useMemo, useRef, useEffect } from \"react\";\nimport { ChevronRight, Folder, File, FileCode, FileJson, FileText, FileType } from \"lucide-react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n} from \"@/components/ui/dropdown-menu\";\nimport { useFileStore, type FileNode } from \"@/stores/file-store\";\nimport { useShallow } from \"zustand/react/shallow\";\nimport { useTabStore } from \"@/stores/tab-store\";\nimport { useProjectStore } from \"@/stores/project-store\";\nimport { basename } from \"@/lib/utils\";\n\nconst ICON_MAP: Record<string, React.ComponentType<{ className?: string }>> = {\n ts: FileCode, tsx: FileCode, js: FileCode, jsx: FileCode,\n py: FileCode, rs: FileCode, go: FileCode, html: FileCode,\n css: FileCode, scss: FileCode,\n json: FileJson,\n md: FileText, txt: FileText,\n yaml: FileType, yml: FileType,\n};\n\nfunction getIcon(name: string, isDir: boolean) {\n if (isDir) return Folder;\n const ext = name.split(\".\").pop()?.toLowerCase() ?? \"\";\n return ICON_MAP[ext] ?? File;\n}\n\ninterface BreadcrumbSegment {\n name: string;\n fullPath: string;\n node: FileNode | null;\n siblings: FileNode[];\n /** Folder path whose children are the siblings (empty string = root) */\n parentPath: string;\n}\n\nfunction walkTree(tree: FileNode[], segments: string[]): BreadcrumbSegment[] {\n const result: BreadcrumbSegment[] = [];\n let current: FileNode[] = tree;\n let parentPath = \"\";\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]!;\n const fullPath = segments.slice(0, i + 1).join(\"/\");\n const match = current.find((n) => n.name === seg);\n result.push({\n name: seg,\n fullPath,\n node: match ?? null,\n siblings: current,\n parentPath,\n });\n if (match?.children) {\n parentPath = match.path;\n current = match.children;\n } else {\n // Remaining segments — parent children not loaded yet\n for (let j = i + 1; j < segments.length; j++) {\n result.push({\n name: segments[j]!,\n fullPath: segments.slice(0, j + 1).join(\"/\"),\n node: null,\n siblings: [],\n parentPath: segments.slice(0, j).join(\"/\"),\n });\n }\n break;\n }\n }\n return result;\n}\n\nfunction sortNodes(nodes: FileNode[]): FileNode[] {\n return [...nodes].sort((a, b) => {\n if (a.type !== b.type) return a.type === \"directory\" ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n}\n\ninterface EditorBreadcrumbProps {\n filePath: string;\n projectName: string;\n tabId: string;\n className?: string;\n}\n\nexport function EditorBreadcrumb({ filePath, projectName, tabId, className }: EditorBreadcrumbProps) {\n const tree = useFileStore((s) => s.tree);\n const { updateTab, openTab } = useTabStore(useShallow((s) => ({ updateTab: s.updateTab, openTab: s.openTab })));\n const projectPath = useProjectStore((s) => s.projects.find((p) => p.name === projectName)?.path ?? \"\");\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Strip project root prefix so segments align with the relative-path file tree\n const { prefixParts, relativePath } = useMemo(() => {\n const norm = filePath.startsWith(\"/\") ? filePath.slice(1) : filePath;\n const normRoot = projectPath.startsWith(\"/\") ? projectPath.slice(1) : projectPath;\n if (normRoot && norm.startsWith(normRoot + \"/\")) {\n const rel = norm.slice(normRoot.length + 1);\n return { prefixParts: normRoot.split(\"/\"), relativePath: rel };\n }\n return { prefixParts: [] as string[], relativePath: norm };\n }, [filePath, projectPath]);\n\n const segments = useMemo(\n () => walkTree(tree, relativePath.split(\"/\").filter(Boolean)),\n [tree, relativePath],\n );\n\n // Auto-scroll to rightmost segment\n useEffect(() => {\n if (scrollRef.current) {\n scrollRef.current.scrollLeft = scrollRef.current.scrollWidth;\n }\n }, [segments]);\n\n function handleFileClick(path: string, e: React.MouseEvent) {\n const name = basename(path);\n if (e.metaKey || e.ctrlKey) {\n openTab({ type: \"editor\", title: name, metadata: { filePath: path, projectName }, projectId: projectName, closable: true });\n } else {\n updateTab(tabId, { title: name, metadata: { filePath: path, projectName } });\n }\n }\n\n return (\n <div ref={scrollRef} className={className}>\n {prefixParts.map((part, i) => (\n <div key={`prefix-${i}`} className=\"flex items-center shrink-0\">\n {i > 0 && <ChevronRight className=\"size-3 text-muted-foreground shrink-0 mx-0.5\" />}\n <span className=\"text-xs text-muted-foreground px-1 py-0.5\">{part}</span>\n </div>\n ))}\n {segments.map((seg, i) => (\n <div key={seg.fullPath} className=\"flex items-center shrink-0\">\n {(i > 0 || prefixParts.length > 0) && <ChevronRight className=\"size-3 text-muted-foreground shrink-0 mx-0.5\" />}\n <SegmentDropdown\n segment={seg}\n isLast={i === segments.length - 1}\n projectName={projectName}\n onFileClick={handleFileClick}\n />\n </div>\n ))}\n </div>\n );\n}\n\ninterface SegmentDropdownProps {\n segment: BreadcrumbSegment;\n isLast: boolean;\n projectName: string;\n onFileClick: (path: string, e: React.MouseEvent) => void;\n}\n\nfunction SegmentDropdown({ segment, isLast, projectName, onFileClick }: SegmentDropdownProps) {\n const loadChildren = useFileStore((s) => s.loadChildren);\n const loadedPaths = useFileStore((s) => s.loadedPaths);\n const sorted = useMemo(() => sortNodes(segment.siblings), [segment.siblings]);\n const isLoaded = loadedPaths.has(segment.parentPath);\n\n function handleOpenChange(open: boolean) {\n if (open && !isLoaded) {\n loadChildren(projectName, segment.parentPath);\n }\n }\n\n return (\n <DropdownMenu onOpenChange={handleOpenChange}>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={`text-xs px-1 py-0.5 rounded hover:bg-muted transition-colors truncate max-w-[120px] ${\n isLast ? \"text-foreground font-medium\" : \"text-muted-foreground\"\n }`}\n >\n {segment.name}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"max-h-[300px] p-1\">\n {sorted.length === 0 ? (\n <DropdownMenuItem disabled className=\"text-xs text-muted-foreground\">\n Loading…\n </DropdownMenuItem>\n ) : (\n sorted.map((node) => (\n <NodeMenuItem\n key={node.path}\n node={node}\n projectName={projectName}\n activePath={segment.fullPath}\n onFileClick={onFileClick}\n />\n ))\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\ninterface NodeMenuItemProps {\n node: FileNode;\n projectName: string;\n activePath: string;\n onFileClick: (path: string, e: React.MouseEvent) => void;\n}\n\nfunction NodeMenuItem({ node, projectName, activePath, onFileClick }: NodeMenuItemProps) {\n const Icon = getIcon(node.name, node.type === \"directory\");\n const isActive = node.path === activePath;\n const loadChildren = useFileStore((s) => s.loadChildren);\n const loadedPaths = useFileStore((s) => s.loadedPaths);\n\n if (node.type === \"directory\") {\n const children = node.children ?? [];\n const isLoaded = loadedPaths.has(node.path);\n\n function handleSubOpen(open: boolean) {\n if (open && !isLoaded) {\n loadChildren(projectName, node.path);\n }\n }\n\n return (\n <DropdownMenuSub onOpenChange={handleSubOpen}>\n <DropdownMenuSubTrigger className={`text-xs gap-1.5 ${isActive ? \"bg-muted\" : \"\"}`}>\n <Icon className=\"size-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{node.name}</span>\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"max-h-[300px] overflow-y-auto p-1\">\n {children.length === 0 ? (\n <DropdownMenuItem disabled className=\"text-xs text-muted-foreground\">\n Loading…\n </DropdownMenuItem>\n ) : (\n sortNodes(children).map((child) => (\n <NodeMenuItem\n key={child.path}\n node={child}\n projectName={projectName}\n activePath={activePath}\n onFileClick={onFileClick}\n />\n ))\n )}\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n );\n }\n\n return (\n <DropdownMenuItem\n className={`text-xs gap-1.5 cursor-pointer ${isActive ? \"bg-muted\" : \"\"}`}\n onSelect={(e) => {\n // onSelect doesn't give MouseEvent, use click handler for Ctrl detection\n }}\n onClick={(e) => {\n onFileClick(node.path, e);\n }}\n >\n <Icon className=\"size-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{node.name}</span>\n </DropdownMenuItem>\n );\n}\n","import { Code, Eye, WrapText, Table, Download } from \"lucide-react\";\nimport { downloadFile } from \"@/lib/file-download\";\n\ninterface EditorToolbarProps {\n ext: string;\n mdMode?: \"edit\" | \"preview\";\n onMdModeChange?: (mode: \"edit\" | \"preview\") => void;\n csvMode?: \"table\" | \"raw\";\n onCsvModeChange?: (mode: \"table\" | \"raw\") => void;\n wordWrap: boolean;\n onToggleWordWrap: () => void;\n filePath?: string;\n projectName?: string;\n className?: string;\n}\n\nfunction ToolbarButton({\n active,\n onClick,\n icon: Icon,\n label,\n}: {\n active: boolean;\n onClick: () => void;\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={`flex items-center gap-1 px-2 py-1 rounded text-xs transition-colors ${\n active ? \"bg-muted text-foreground\" : \"text-muted-foreground hover:text-foreground\"\n }`}\n >\n <Icon className=\"size-3\" />\n <span className=\"hidden sm:inline\">{label}</span>\n </button>\n );\n}\n\nexport function EditorToolbar({\n ext,\n mdMode,\n onMdModeChange,\n csvMode,\n onCsvModeChange,\n wordWrap,\n onToggleWordWrap,\n filePath,\n projectName,\n className,\n}: EditorToolbarProps) {\n const isMarkdown = ext === \"md\" || ext === \"mdx\";\n const isCsv = ext === \"csv\";\n\n return (\n <div className={className}>\n {isMarkdown && onMdModeChange && (\n <>\n <ToolbarButton active={mdMode === \"edit\"} onClick={() => onMdModeChange(\"edit\")} icon={Code} label=\"Edit\" />\n <ToolbarButton active={mdMode === \"preview\"} onClick={() => onMdModeChange(\"preview\")} icon={Eye} label=\"Preview\" />\n </>\n )}\n {isCsv && onCsvModeChange && (\n <>\n <ToolbarButton active={csvMode === \"table\"} onClick={() => onCsvModeChange(\"table\")} icon={Table} label=\"Table\" />\n <ToolbarButton active={csvMode === \"raw\"} onClick={() => onCsvModeChange(\"raw\")} icon={Code} label=\"Raw\" />\n </>\n )}\n <ToolbarButton\n active={wordWrap}\n onClick={onToggleWordWrap}\n icon={WrapText}\n label=\"Wrap\"\n />\n {filePath && projectName && (\n <ToolbarButton\n active={false}\n onClick={() => downloadFile(projectName, filePath)}\n icon={Download}\n label=\"Download\"\n />\n )}\n </div>\n );\n}\n","import { useState, useCallback } from \"react\";\nimport {\n Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter,\n} from \"@/components/ui/dialog\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { FileBrowserPicker } from \"@/components/ui/file-browser-picker\";\nimport { useProjectStore } from \"@/stores/project-store\";\n\ninterface SaveAsDialogProps {\n open: boolean;\n defaultName: string;\n content: string;\n onSave: (fullPath: string, content: string) => void;\n onCancel: () => void;\n}\n\nexport function SaveAsDialog({ open, defaultName, content, onSave, onCancel }: SaveAsDialogProps) {\n const [filename, setFilename] = useState(defaultName);\n const [showPicker, setShowPicker] = useState(false);\n const [error, setError] = useState(\"\");\n const activeProject = useProjectStore((s) => s.activeProject);\n\n const validateAndProceed = useCallback(() => {\n const trimmed = filename.trim();\n if (!trimmed) { setError(\"Filename cannot be empty\"); return; }\n if (/[/\\\\]/.test(trimmed)) { setError(\"Filename cannot contain / or \\\\\"); return; }\n setError(\"\");\n setShowPicker(true);\n }, [filename]);\n\n const handleFolderSelect = useCallback((dirPath: string) => {\n const sep = dirPath.includes(\"\\\\\") ? \"\\\\\" : \"/\";\n const fullPath = dirPath.endsWith(sep) ? `${dirPath}${filename.trim()}` : `${dirPath}${sep}${filename.trim()}`;\n onSave(fullPath, content);\n }, [filename, content, onSave]);\n\n if (showPicker) {\n return (\n <FileBrowserPicker\n open\n mode=\"folder\"\n root={activeProject?.path}\n title={`Save \"${filename.trim()}\" to...`}\n onSelect={handleFolderSelect}\n onCancel={() => setShowPicker(false)}\n />\n );\n }\n\n return (\n <Dialog open={open} onOpenChange={(v) => { if (!v) onCancel(); }}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>Save As</DialogTitle>\n </DialogHeader>\n <div className=\"flex flex-col gap-2 py-2\">\n <label className=\"text-sm text-muted-foreground\">Filename</label>\n <Input\n value={filename}\n onChange={(e) => { setFilename(e.target.value); setError(\"\"); }}\n onKeyDown={(e) => { if (e.key === \"Enter\") validateAndProceed(); }}\n placeholder=\"e.g. my-file.ts\"\n autoFocus\n />\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n <DialogFooter>\n <Button variant=\"outline\" onClick={onCancel}>Cancel</Button>\n <Button onClick={validateAndProceed}>Choose Folder...</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { ClipboardPaste, Undo2, Redo2, X } from \"lucide-react\";\nimport type * as MonacoType from \"monaco-editor\";\n\n/** Clipboard API requires secure context (HTTPS / localhost) */\nconst isSecureContext = typeof window !== \"undefined\" && window.isSecureContext;\n\n/** Symbols commonly needed when coding on mobile — ordered by frequency */\nconst SYMBOL_KEYS = [\n \"(\", \")\", \"{\", \"}\", \"[\", \"]\",\n \"<\", \">\", \";\", \":\", \"=\",\n '\"', \"'\", \"`\", \"/\", \"\\\\\", \"_\", \"#\",\n];\n\nconst btnBase =\n \"px-2 py-1.5 rounded text-xs min-w-[36px] min-h-[32px] bg-surface-elevated text-text-primary active:bg-primary active:text-primary-foreground transition-colors select-none\";\nconst btnSymbol =\n \"px-3 py-1.5 rounded text-xs font-mono min-w-[36px] min-h-[32px] bg-surface-elevated text-text-primary active:bg-primary active:text-primary-foreground transition-colors select-none\";\nconst divider = \"w-px h-5 bg-border mx-0.5 shrink-0\";\n\ninterface EditorMobileToolbarProps {\n editorRef: React.RefObject<MonacoType.editor.IStandaloneCodeEditor | null>;\n readOnly?: boolean;\n}\n\nexport function EditorMobileToolbar({ editorRef, readOnly }: EditorMobileToolbarProps) {\n const getEditor = useCallback(() => editorRef.current, [editorRef]);\n\n /** Insert text at cursor position in Monaco */\n const insertText = useCallback((text: string) => {\n const editor = getEditor();\n if (!editor) return;\n editor.focus();\n const selection = editor.getSelection();\n if (selection) {\n editor.executeEdits(\"mobile-toolbar\", [{ range: selection, text }]);\n }\n }, [getEditor]);\n\n // --- Paste: two strategies based on secure context ---\n const [pasteMode, setPasteMode] = useState(false);\n const pasteRef = useRef<HTMLTextAreaElement | null>(null);\n\n // HTTPS: use Clipboard API directly (single tap)\n const handleClipboardPaste = useCallback(async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) insertText(text);\n } catch { /* permission denied */ }\n }, [insertText]);\n\n // HTTP fallback: show textarea for native long-press paste\n const openPasteMode = useCallback(() => {\n setPasteMode(true);\n requestAnimationFrame(() => pasteRef.current?.focus());\n }, []);\n\n const handleNativePaste = useCallback((e: React.ClipboardEvent<HTMLTextAreaElement>) => {\n e.preventDefault();\n const text = e.clipboardData.getData(\"text/plain\");\n if (!text) return;\n setPasteMode(false);\n insertText(text);\n }, [insertText]);\n\n const handleUndo = useCallback(() => {\n const editor = getEditor();\n if (!editor) return;\n editor.focus();\n editor.trigger(\"mobile-toolbar\", \"undo\", null);\n }, [getEditor]);\n\n const handleRedo = useCallback(() => {\n const editor = getEditor();\n if (!editor) return;\n editor.focus();\n editor.trigger(\"mobile-toolbar\", \"redo\", null);\n }, [getEditor]);\n\n const handleTab = useCallback(() => {\n const editor = getEditor();\n if (!editor) return;\n editor.focus();\n editor.trigger(\"mobile-toolbar\", \"tab\", null);\n }, [getEditor]);\n\n if (readOnly) return null;\n\n return (\n <div className=\"shrink-0 border-t border-border bg-surface\">\n {/* HTTP-only: textarea for native paste via long-press */}\n {!isSecureContext && pasteMode && (\n <div className=\"flex items-center gap-2 px-2 py-1.5 border-b border-border bg-muted/50\">\n <textarea\n ref={pasteRef}\n onPaste={handleNativePaste}\n placeholder=\"Long-press here → Paste\"\n className=\"flex-1 h-8 rounded border border-border bg-background text-foreground text-xs px-2 py-1.5 resize-none focus:outline-none focus:ring-1 focus:ring-primary\"\n />\n <button\n type=\"button\"\n onClick={() => setPasteMode(false)}\n className=\"p-1.5 rounded text-muted-foreground active:bg-muted transition-colors\"\n >\n <X size={14} />\n </button>\n </div>\n )}\n\n {/* Toolbar buttons */}\n <div className=\"flex items-center gap-1 px-2 py-1.5 overflow-x-auto\">\n {/* Paste: Clipboard API on HTTPS, textarea fallback on HTTP */}\n <button\n type=\"button\"\n onClick={isSecureContext ? handleClipboardPaste : openPasteMode}\n className={btnBase}\n title=\"Paste\"\n >\n <ClipboardPaste size={14} />\n </button>\n <button type=\"button\" onClick={handleUndo} className={btnBase} title=\"Undo\">\n <Undo2 size={14} />\n </button>\n <button type=\"button\" onClick={handleRedo} className={btnBase} title=\"Redo\">\n <Redo2 size={14} />\n </button>\n\n <div className={divider} />\n\n <button type=\"button\" onClick={handleTab} className={btnSymbol}>\n Tab\n </button>\n\n <div className={divider} />\n\n {SYMBOL_KEYS.map((key) => (\n <button key={key} type=\"button\" onClick={() => insertText(key)} className={btnSymbol}>\n {key}\n </button>\n ))}\n </div>\n </div>\n );\n}\n","import { useEffect, useState, useCallback, useRef, useMemo, memo, lazy, Suspense } from \"react\";\nimport Editor, { type OnMount } from \"@monaco-editor/react\";\nimport type * as MonacoType from \"monaco-editor\";\nimport { api, projectUrl } from \"@/lib/api-client\";\nimport { useShallow } from \"zustand/react/shallow\";\nimport { useTabStore } from \"@/stores/tab-store\";\nimport { usePanelStore } from \"@/stores/panel-store\";\nimport { useSettingsStore } from \"@/stores/settings-store\";\nimport { basename } from \"@/lib/utils\";\nimport { useMonacoTheme } from \"@/lib/use-monaco-theme\";\nimport { Loader2, FileWarning, Play, Database, ExternalLink, X, GripHorizontal } from \"lucide-react\";\nimport { EditorBreadcrumb } from \"./editor-breadcrumb\";\nimport { EditorToolbar } from \"./editor-toolbar\";\nimport { SaveAsDialog } from \"./save-as-dialog\";\nimport { EditorMobileToolbar } from \"./editor-mobile-toolbar\";\nimport { createSqlCompletionProvider, clearCompletionCache, type SchemaInfo } from \"../database/sql-completion-provider\";\nimport { useConnections, type Connection } from \"../database/use-connections\";\nimport { GlideDataGrid } from \"../database/glide-data-grid\";\nimport type { GridColumnSchema } from \"../database/glide-grid-types\";\nimport type { DbQueryResult } from \"../database/use-database\";\n\nconst MarkdownRenderer = lazy(() =>\n import(\"@/components/shared/markdown-renderer\").then((m) => ({ default: m.MarkdownRenderer }))\n);\nconst CsvPreview = lazy(() => import(\"./csv-preview\").then((m) => ({ default: m.CsvPreview })));\nconst ImagePreview = lazy(() => import(\"./image-preview\").then((m) => ({ default: m.ImagePreview })));\nconst PdfPreview = lazy(() => import(\"./pdf-preview\").then((m) => ({ default: m.PdfPreview })));\nconst VideoPreview = lazy(() => import(\"./video-preview\").then((m) => ({ default: m.VideoPreview })));\nconst AudioPreview = lazy(() => import(\"./audio-preview\").then((m) => ({ default: m.AudioPreview })));\n\n/** Image extensions renderable inline */\nconst IMAGE_EXTS = new Set([\"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"svg\", \"ico\"]);\n/** Video extensions playable inline */\nconst VIDEO_EXTS = new Set([\"mp4\", \"webm\", \"mov\", \"ogg\", \"avi\", \"mkv\"]);\n/** Audio extensions playable inline */\nconst AUDIO_EXTS = new Set([\"mp3\", \"wav\", \"flac\", \"aac\", \"m4a\", \"wma\"]);\n/** SQLite extensions — redirect to sqlite viewer */\nconst SQLITE_EXTS = new Set([\"db\", \"sqlite\", \"sqlite3\"]);\n\nfunction getFileExt(filename: string): string {\n return filename.split(\".\").pop()?.toLowerCase() ?? \"\";\n}\n\nfunction getMonacoLanguage(filename: string): string {\n const ext = getFileExt(filename);\n const map: Record<string, string> = {\n js: \"javascript\", jsx: \"javascript\",\n ts: \"typescript\", tsx: \"typescript\",\n py: \"python\", html: \"html\",\n css: \"css\", scss: \"scss\",\n json: \"json\", md: \"markdown\", mdx: \"markdown\",\n yaml: \"yaml\", yml: \"yaml\",\n sh: \"shell\", bash: \"shell\",\n sql: \"sql\",\n };\n return map[ext] ?? \"plaintext\";\n}\n\ninterface CodeEditorProps {\n metadata?: Record<string, unknown>;\n tabId?: string;\n}\n\nexport const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEditorProps) {\n const filePath = metadata?.filePath as string | undefined;\n const projectName = metadata?.projectName as string | undefined;\n // Inline content mode: read-only Monaco with pre-loaded content (e.g. cell viewer)\n const inlineContent = metadata?.inlineContent as string | undefined;\n const inlineLanguage = metadata?.inlineLanguage as string | undefined;\n const [content, setContent] = useState<string | null>(inlineContent ?? null);\n const [encoding, setEncoding] = useState<string>(\"utf-8\");\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [unsaved, setUnsaved] = useState(false);\n const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const latestContentRef = useRef<string>(\"\");\n const editorRef = useRef<MonacoType.editor.IStandaloneCodeEditor | null>(null);\n const { tabs, updateTab } = useTabStore(useShallow((s) => ({ tabs: s.tabs, updateTab: s.updateTab })));\n const { wordWrap, toggleWordWrap } = useSettingsStore(useShallow((s) => ({ wordWrap: s.wordWrap, toggleWordWrap: s.toggleWordWrap })));\n const monacoTheme = useMonacoTheme();\n\n const isUntitled = metadata?.isUntitled === true;\n const savedContent = metadata?.unsavedContent as string | undefined;\n const [showSaveAs, setShowSaveAs] = useState(false);\n\n const ownTab = tabs.find((t) => t.id === tabId);\n const ext = filePath ? getFileExt(filePath) : \"\";\n const isImage = IMAGE_EXTS.has(ext);\n const isPdf = ext === \"pdf\";\n const isVideo = VIDEO_EXTS.has(ext);\n const isAudio = AUDIO_EXTS.has(ext);\n const isSqlite = SQLITE_EXTS.has(ext);\n const isMarkdown = ext === \"md\" || ext === \"mdx\";\n const isCsv = ext === \"csv\";\n const isSql = ext === \"sql\";\n const [mdMode, setMdMode] = useState<\"edit\" | \"preview\">(\"preview\");\n const [csvMode, setCsvMode] = useState<\"table\" | \"raw\">(\"table\");\n\n // SQL file: connection picker + autocomplete + run in DB viewer\n const { connections, cachedTables, refreshTables } = useConnections();\n const [sqlConnId, setSqlConnId] = useState<number | null>(() => {\n if (!isSql || !filePath) return null;\n const stored = localStorage.getItem(`ppm:sql-conn:${filePath}`);\n return stored ? Number(stored) : null;\n });\n const monacoInstanceRef = useRef<typeof MonacoType | null>(null);\n const completionDisposable = useRef<MonacoType.IDisposable | null>(null);\n\n const selectedSqlConn = useMemo(() => connections.find((c) => c.id === sqlConnId) ?? null, [connections, sqlConnId]);\n\n // Beautify for inline content (must be before early returns to maintain hook order)\n const canBeautifyInline = inlineContent != null && (inlineLanguage === \"json\" || inlineLanguage === \"xml\");\n const [isBeautified, setIsBeautified] = useState(false);\n const handleBeautifyInline = useCallback(() => {\n if (!inlineContent) return;\n if (isBeautified) {\n setContent(inlineContent);\n setIsBeautified(false);\n } else {\n const trimmed = inlineContent.trimStart();\n if (inlineLanguage === \"json\") {\n try { setContent(JSON.stringify(JSON.parse(trimmed), null, 2)); setIsBeautified(true); } catch { /* not valid */ }\n } else if (inlineLanguage === \"xml\") {\n let indent = 0;\n const formatted = trimmed.replace(/(>)(<)(\\/*)/g, \"$1\\n$2$3\")\n .split(\"\\n\")\n .map((line) => {\n const l = line.trim();\n if (l.startsWith(\"</\")) indent = Math.max(0, indent - 1);\n const padded = \" \".repeat(indent) + l;\n if (l.startsWith(\"<\") && !l.startsWith(\"</\") && !l.endsWith(\"/>\") && !l.includes(\"</\")) indent++;\n return padded;\n })\n .join(\"\\n\");\n setContent(formatted);\n setIsBeautified(true);\n }\n }\n }, [inlineContent, inlineLanguage, isBeautified]);\n\n // Persist selected connection per file\n const handleSqlConnChange = useCallback((connId: number) => {\n setSqlConnId(connId);\n if (filePath) localStorage.setItem(`ppm:sql-conn:${filePath}`, String(connId));\n // Refresh tables for autocomplete\n refreshTables(connId).catch(() => {});\n }, [filePath, refreshTables]);\n\n // Build SchemaInfo for .sql file autocomplete\n const sqlSchemaInfo = useMemo<SchemaInfo | undefined>(() => {\n if (!isSql || !sqlConnId) return undefined;\n const tables = (cachedTables.get(sqlConnId) ?? []).map((t) => ({ name: t.tableName, schema: t.schemaName }));\n if (tables.length === 0) return undefined;\n return {\n tables,\n getColumns: async (table: string, schema?: string) => {\n return api.get<{ name: string; type: string }[]>(\n `/api/db/connections/${sqlConnId}/schema?table=${encodeURIComponent(table)}${schema ? `&schema=${encodeURIComponent(schema)}` : \"\"}`,\n );\n },\n };\n }, [isSql, sqlConnId, cachedTables]);\n\n // Register/dispose completion provider when connection changes\n useEffect(() => {\n if (!monacoInstanceRef.current || !sqlSchemaInfo) return;\n completionDisposable.current?.dispose();\n clearCompletionCache();\n completionDisposable.current = monacoInstanceRef.current.languages.registerCompletionItemProvider(\n \"sql\",\n createSqlCompletionProvider(monacoInstanceRef.current, sqlSchemaInfo),\n );\n return () => { completionDisposable.current?.dispose(); };\n }, [sqlSchemaInfo]);\n\n // Run SQL inline — execute query and show results in bottom panel\n const openTab = useTabStore((s) => s.openTab);\n const [sqlResult, setSqlResult] = useState<DbQueryResult | null>(null);\n const [sqlError, setSqlError] = useState<string | null>(null);\n const [sqlLoading, setSqlLoading] = useState(false);\n const [sqlResultSql, setSqlResultSql] = useState<string>(\"\");\n const runSqlInViewer = useCallback(async (sqlText: string) => {\n if (!selectedSqlConn) return;\n setSqlLoading(true);\n setSqlError(null);\n setSqlResultSql(sqlText);\n try {\n const result = await api.post<DbQueryResult>(`/api/db/connections/${selectedSqlConn.id}/query`, { sql: sqlText });\n setSqlResult(result);\n } catch (e) {\n setSqlError((e as Error).message);\n setSqlResult(null);\n } finally {\n setSqlLoading(false);\n }\n }, [selectedSqlConn]);\n const openSqlResultInTab = useCallback(() => {\n if (!selectedSqlConn || !sqlResultSql) return;\n openTab({\n type: \"database\",\n title: `${selectedSqlConn.name} · Query`,\n projectId: null,\n closable: true,\n metadata: { connectionId: selectedSqlConn.id, connectionName: selectedSqlConn.name, dbType: selectedSqlConn.type, initialSql: sqlResultSql },\n });\n }, [selectedSqlConn, openTab, sqlResultSql]);\n\n const handleRunInDbViewer = useCallback(() => {\n if (!editorRef.current || !selectedSqlConn) return;\n const editor = editorRef.current;\n const selection = editor.getSelection();\n const sqlText = selection && !selection.isEmpty()\n ? editor.getModel()?.getValueInRange(selection) ?? editor.getValue()\n : editor.getValue();\n runSqlInViewer(sqlText);\n }, [selectedSqlConn, runSqlInViewer]);\n\n // Touch device detection for mobile toolbar\n const isMobile = typeof window !== \"undefined\" && \"ontouchstart\" in window;\n\n // Track visual viewport so toolbar stays above mobile keyboard\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [mobileHeight, setMobileHeight] = useState<number | null>(null);\n useEffect(() => {\n if (!isMobile) return;\n const vv = window.visualViewport;\n if (!vv) return;\n const handle = () => {\n const el = containerRef.current;\n if (!el) return;\n // Calculate available height = viewport height - element's top offset from viewport\n const top = el.getBoundingClientRect().top;\n setMobileHeight(vv.height - Math.max(0, top));\n };\n vv.addEventListener(\"resize\", handle);\n vv.addEventListener(\"scroll\", handle);\n return () => {\n vv.removeEventListener(\"resize\", handle);\n vv.removeEventListener(\"scroll\", handle);\n };\n }, [isMobile]);\n\n // CodeLens: inline Run buttons between SQL statements\n const codeLensDisposable = useRef<MonacoType.IDisposable[]>([]);\n const runSqlRef = useRef(runSqlInViewer);\n runSqlRef.current = runSqlInViewer;\n\n // Cleanup CodeLens providers on unmount to prevent duplicate \"Run\" buttons\n useEffect(() => {\n return () => {\n codeLensDisposable.current.forEach((d) => d.dispose());\n codeLensDisposable.current = [];\n };\n }, []);\n\n // Redirect .db files to sqlite viewer by changing tab type\n useEffect(() => {\n if (isSqlite && tabId) updateTab(tabId, { type: \"sqlite\" });\n }, [isSqlite, tabId, updateTab]);\n\n // Detect external (absolute) file path — not relative to project\n const isExternalFile = filePath ? /^(\\/|[A-Za-z]:[/\\\\])/.test(filePath) : false;\n\n // Load file content\n useEffect(() => {\n if (inlineContent != null) { setLoading(false); return; }\n if (isUntitled) {\n setContent(savedContent ?? \"\");\n latestContentRef.current = savedContent ?? \"\";\n setLoading(false);\n if (savedContent) setUnsaved(true);\n return;\n }\n if (!filePath) return;\n if (!isExternalFile && !projectName) return;\n if (isImage || isPdf || isVideo || isAudio) { setLoading(false); return; }\n\n setLoading(true);\n setError(null);\n\n const readUrl = isExternalFile\n ? `/api/fs/read?path=${encodeURIComponent(filePath)}`\n : `${projectUrl(projectName!)}/files/read?path=${encodeURIComponent(filePath)}`;\n\n api\n .get<{ content: string; encoding?: string }>(readUrl)\n .then((data) => {\n setContent(data.content);\n if (data.encoding) setEncoding(data.encoding);\n latestContentRef.current = data.content;\n setLoading(false);\n })\n .catch((err) => {\n setError(err instanceof Error ? err.message : \"Failed to load file\");\n setLoading(false);\n });\n\n return () => { if (saveTimerRef.current) clearTimeout(saveTimerRef.current); };\n }, [filePath, projectName, isImage, isPdf, isExternalFile, isUntitled]);\n\n // Real-time reload: listen for file:changed WS events, re-fetch if editor is clean\n const unsavedRef = useRef(unsaved);\n unsavedRef.current = unsaved;\n useEffect(() => {\n if (!filePath || !projectName || inlineContent != null || isUntitled) return;\n const handler = (e: Event) => {\n const detail = (e as CustomEvent).detail;\n if (detail.projectName !== projectName || detail.path !== filePath) return;\n if (unsavedRef.current) return; // don't overwrite unsaved changes\n const readUrl = isExternalFile\n ? `/api/fs/read?path=${encodeURIComponent(filePath)}`\n : `${projectUrl(projectName)}/files/read?path=${encodeURIComponent(filePath)}`;\n api.get<{ content: string; encoding?: string }>(readUrl).then((data) => {\n if (data.content === latestContentRef.current) return; // skip if unchanged (e.g. self-save)\n setContent(data.content);\n latestContentRef.current = data.content;\n if (data.encoding) setEncoding(data.encoding);\n }).catch(() => {});\n };\n window.addEventListener(\"file:changed\", handler);\n return () => window.removeEventListener(\"file:changed\", handler);\n }, [filePath, projectName, isExternalFile, inlineContent, isUntitled]);\n\n // Update tab title unsaved indicator (skip for inline content — title set by caller)\n useEffect(() => {\n if (!ownTab || inlineContent != null) return;\n const baseName = isUntitled\n ? `Untitled-${metadata?.untitledNumber ?? 1}`\n : (filePath ? basename(filePath) : \"Untitled\");\n const newTitle = unsaved ? `${baseName} \\u25CF` : baseName;\n if (ownTab.title !== newTitle) updateTab(ownTab.id, { title: newTitle });\n }, [unsaved]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const saveFile = useCallback(\n async (text: string) => {\n if (!filePath) return;\n if (!isExternalFile && !projectName) return;\n try {\n if (isExternalFile) {\n await api.put(\"/api/fs/write\", { path: filePath, content: text });\n } else {\n await api.put(`${projectUrl(projectName!)}/files/write`, { path: filePath, content: text });\n }\n setUnsaved(false);\n } catch { /* Silent — unsaved indicator persists */ }\n },\n [filePath, projectName, isExternalFile],\n );\n\n function handleChange(value: string | undefined) {\n const val = value ?? \"\";\n setContent(val);\n latestContentRef.current = val;\n setUnsaved(true);\n if (saveTimerRef.current) clearTimeout(saveTimerRef.current);\n if (isUntitled) {\n // Persist to metadata for localStorage survival\n saveTimerRef.current = setTimeout(() => {\n if (tabId) updateTab(tabId, { metadata: { ...metadata, unsavedContent: latestContentRef.current } });\n }, 2000);\n } else {\n saveTimerRef.current = setTimeout(() => saveFile(latestContentRef.current), 1000);\n }\n }\n\n // Save As completion — transitions untitled → saved file\n const handleSaveAs = useCallback(async (targetPath: string, savedText: string) => {\n try {\n // Clear any pending metadata persistence timer to prevent race condition\n if (saveTimerRef.current) clearTimeout(saveTimerRef.current);\n await api.put(\"/api/fs/write\", { path: targetPath, content: savedText });\n if (tabId) {\n // Close old untitled tab and open as proper file tab\n const { closeTab, openTab } = usePanelStore.getState();\n closeTab(tabId);\n openTab({\n type: \"editor\",\n title: basename(targetPath),\n projectId: null,\n metadata: { filePath: targetPath },\n closable: true,\n });\n }\n setUnsaved(false);\n setShowSaveAs(false);\n } catch { /* silent — user can retry */ }\n }, [tabId]);\n\n // Jump to line when metadata.lineNumber is set (e.g. from search panel)\n const lineNumber = metadata?.lineNumber as number | undefined;\n const handleEditorMount: OnMount = useCallback((editor, monaco) => {\n editorRef.current = editor;\n monacoInstanceRef.current = monaco;\n if (lineNumber && lineNumber > 0) {\n setTimeout(() => {\n editor.revealLineInCenter(lineNumber);\n editor.setPosition({ lineNumber, column: 1 });\n editor.focus();\n }, 100);\n }\n // Ctrl+S → Save As for untitled tabs\n if (isUntitled) {\n editor.addCommand(\n monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS,\n () => setShowSaveAs(true),\n );\n }\n editor.addCommand(\n monaco.KeyMod.Alt | monaco.KeyCode.KeyZ,\n () => useSettingsStore.getState().toggleWordWrap(),\n );\n monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true, noSyntaxValidation: true, noSuggestionDiagnostics: true,\n });\n monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true, noSyntaxValidation: true, noSuggestionDiagnostics: true,\n });\n // Register SQL completion if schema available\n if (sqlSchemaInfo) {\n completionDisposable.current?.dispose();\n completionDisposable.current = monaco.languages.registerCompletionItemProvider(\n \"sql\", createSqlCompletionProvider(monaco, sqlSchemaInfo),\n );\n }\n\n // Register CodeLens for inline Run buttons on .sql files (scoped to this editor's model)\n if (isSql) {\n codeLensDisposable.current.forEach((d) => d.dispose());\n codeLensDisposable.current = [];\n\n const thisModel = editor.getModel();\n const cmdId = editor.addCommand(0, (_accessor: unknown, sql: string) => {\n if (sql) runSqlRef.current(sql);\n });\n\n if (cmdId && thisModel) {\n const provider = monaco.languages.registerCodeLensProvider(\"sql\", {\n provideCodeLenses: (model: MonacoType.editor.ITextModel) => {\n // Only provide lenses for THIS editor's model, not all SQL models\n if (model !== thisModel) return { lenses: [], dispose: () => {} };\n\n const lenses: MonacoType.languages.CodeLens[] = [];\n const text = model.getValue();\n const lines = text.split(\"\\n\");\n let stmtStartLine = -1;\n let stmtLines: string[] = [];\n let dollarBlock = false; // Track DO $$ ... $$ blocks\n\n const addLens = (line: number, stmt: string) => {\n const trimmed = stmt.trim();\n if (!trimmed || trimmed.startsWith(\"--\")) return;\n lenses.push({\n range: { startLineNumber: line, startColumn: 1, endLineNumber: line, endColumn: 1 },\n command: { id: cmdId, title: \"\\u25B7 Run\", arguments: [trimmed] },\n });\n };\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (stmtStartLine === -1) {\n if (!trimmed || trimmed.startsWith(\"--\")) continue;\n stmtStartLine = i + 1;\n stmtLines = [];\n }\n stmtLines.push(lines[i]!);\n\n // Detect $$ dollar-quoted block start/end\n const dollarMatches = (trimmed.match(/\\$\\$/g) || []).length;\n if (dollarMatches % 2 === 1) dollarBlock = !dollarBlock;\n\n // Only split on ; when NOT inside a $$ block\n if (!dollarBlock && trimmed.endsWith(\";\")) {\n addLens(stmtStartLine, stmtLines.join(\"\\n\"));\n stmtStartLine = -1;\n stmtLines = [];\n }\n }\n if (stmtStartLine > 0 && stmtLines.join(\"\").trim()) {\n addLens(stmtStartLine, stmtLines.join(\"\\n\"));\n }\n return { lenses, dispose: () => {} };\n },\n });\n codeLensDisposable.current.push(provider);\n }\n }\n }, [sqlSchemaInfo]); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (!inlineContent && !isUntitled && (!filePath || (!isExternalFile && !projectName))) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n No file selected.\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full gap-2 text-text-secondary\">\n <Loader2 className=\"size-5 animate-spin\" />\n <span className=\"text-sm\">Loading file...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full text-error text-sm\">{error}</div>\n );\n }\n\n if (isImage) return <Suspense fallback={<LoadingSpinner />}><ImagePreview filePath={filePath!} projectName={projectName!} /></Suspense>;\n if (isPdf) return <Suspense fallback={<LoadingSpinner />}><PdfPreview filePath={filePath!} projectName={projectName!} /></Suspense>;\n if (isVideo) return <Suspense fallback={<LoadingSpinner />}><VideoPreview filePath={filePath!} projectName={projectName!} /></Suspense>;\n if (isAudio) return <Suspense fallback={<LoadingSpinner />}><AudioPreview filePath={filePath!} projectName={projectName!} /></Suspense>;\n\n if (encoding === \"base64\") {\n return (\n <div className=\"flex flex-col items-center justify-center h-full gap-3 text-text-secondary\">\n <FileWarning className=\"size-10 text-text-subtle\" />\n <p className=\"text-sm\">This file is a binary format and cannot be displayed.</p>\n <p className=\"text-xs text-text-subtle\">{filePath}</p>\n </div>\n );\n }\n\n /** SQL connection picker bar (shared between breadcrumb and standalone) */\n const sqlPickerBar = isSql ? (\n <div className=\"shrink-0 flex items-center gap-1 px-2 border-l border-border\">\n <Database className=\"size-3 text-muted-foreground\" />\n <select\n value={sqlConnId ?? \"\"}\n onChange={(e) => { const v = Number(e.target.value); if (v) handleSqlConnChange(v); }}\n className=\"h-5 text-[10px] bg-transparent border border-border rounded px-1 text-foreground outline-none max-w-[140px]\"\n title=\"Select connection for autocomplete\"\n >\n <option value=\"\">Connection…</option>\n {connections.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}\n </select>\n <button\n type=\"button\"\n onClick={handleRunInDbViewer}\n disabled={!selectedSqlConn}\n className=\"p-0.5 rounded text-muted-foreground hover:text-primary disabled:opacity-30 transition-colors\"\n title=\"Run SQL\"\n >\n <Play className=\"size-3.5\" />\n </button>\n </div>\n ) : null;\n\n return (\n <div\n ref={containerRef}\n className=\"flex flex-col h-full w-full overflow-hidden\"\n style={mobileHeight ? { height: `${mobileHeight}px`, maxHeight: `${mobileHeight}px` } : undefined}\n >\n {/* Inline content toolbar (cell viewer mode) */}\n {inlineContent != null && canBeautifyInline && (\n <div className=\"flex items-center h-7 border-b border-border bg-background shrink-0 px-2 gap-2\">\n <button type=\"button\" onClick={handleBeautifyInline}\n className=\"text-[10px] px-2 py-0.5 rounded border border-border hover:bg-muted transition-colors text-foreground\">\n {isBeautified ? \"Raw\" : \"Beautify\"}\n </button>\n </div>\n )}\n {/* Breadcrumb + Toolbar bar — desktop only */}\n {filePath && projectName && tabId && (\n <div className=\"hidden md:flex items-center h-7 border-b border-border bg-background shrink-0\">\n <EditorBreadcrumb\n filePath={filePath}\n projectName={projectName}\n tabId={tabId}\n className=\"flex items-center flex-1 min-w-0 overflow-x-auto scrollbar-none px-2 gap-0.5\"\n />\n {sqlPickerBar}\n <EditorToolbar\n ext={ext}\n mdMode={mdMode}\n onMdModeChange={setMdMode}\n csvMode={csvMode}\n onCsvModeChange={setCsvMode}\n wordWrap={wordWrap}\n onToggleWordWrap={toggleWordWrap}\n filePath={filePath}\n projectName={projectName}\n className=\"shrink-0 flex items-center gap-1 px-2\"\n />\n </div>\n )}\n\n {/* Standalone SQL toolbar for external files (no breadcrumb available) */}\n {isSql && (!projectName || !tabId) && (\n <div className=\"hidden md:flex items-center h-7 border-b border-border bg-background shrink-0 px-2\">\n <span className=\"text-xs text-muted-foreground truncate flex-1\">{filePath ? basename(filePath) : \"SQL\"}</span>\n {sqlPickerBar}\n </div>\n )}\n\n {/* Content area */}\n {isCsv && csvMode === \"table\" ? (\n <Suspense fallback={<div className=\"flex items-center justify-center h-full\"><Loader2 className=\"size-5 animate-spin text-text-subtle\" /></div>}>\n <CsvPreview content={content ?? \"\"} onContentChange={handleChange} wordWrap={wordWrap} />\n </Suspense>\n ) : isMarkdown && mdMode === \"preview\" ? (\n <MarkdownPreview content={content ?? \"\"} />\n ) : (\n <div className=\"flex-1 overflow-hidden min-h-0\">\n <Editor\n height=\"100%\"\n language={inlineLanguage ?? getMonacoLanguage(filePath ?? \"\")}\n value={content ?? \"\"}\n onChange={inlineContent != null ? undefined : handleChange}\n onMount={handleEditorMount}\n theme={monacoTheme}\n options={{\n fontSize: 13,\n fontFamily: \"Menlo, Monaco, Consolas, monospace\",\n wordWrap: wordWrap ? \"on\" : \"off\",\n minimap: { enabled: false },\n scrollBeyondLastLine: false,\n automaticLayout: true,\n lineNumbers: \"on\",\n folding: true,\n bracketPairColorization: { enabled: true },\n readOnly: inlineContent != null,\n }}\n loading={<Loader2 className=\"size-5 animate-spin text-text-subtle\" />}\n />\n </div>\n )}\n\n {/* Inline SQL result panel */}\n {isSql && (sqlResult || sqlError || sqlLoading) && (\n <SqlResultPanel\n result={sqlResult} error={sqlError} loading={sqlLoading}\n connName={selectedSqlConn?.name}\n onClose={() => { setSqlResult(null); setSqlError(null); setSqlLoading(false); }}\n onOpenInTab={openSqlResultInTab}\n />\n )}\n\n {/* Mobile toolbar — bottom, like terminal */}\n {isMobile && <EditorMobileToolbar editorRef={editorRef} readOnly={inlineContent != null} />}\n\n {/* Save As dialog for untitled tabs */}\n {showSaveAs && (\n <SaveAsDialog\n open={showSaveAs}\n defaultName={`Untitled-${metadata?.untitledNumber ?? 1}`}\n content={latestContentRef.current}\n onSave={handleSaveAs}\n onCancel={() => setShowSaveAs(false)}\n />\n )}\n </div>\n );\n});\n\nconst NOOP = () => {};\n\n/** Inline SQL result panel — shows query results below the editor */\nfunction SqlResultPanel({ result, error, loading, connName, onClose, onOpenInTab }: {\n result: DbQueryResult | null;\n error: string | null;\n loading: boolean;\n connName?: string;\n onClose: () => void;\n onOpenInTab: () => void;\n}) {\n const tableData = useMemo(() => (\n result?.changeType === \"select\" && result.rows.length > 0\n ? { columns: result.columns, rows: result.rows, total: result.rows.length, limit: result.rows.length }\n : null\n ), [result]);\n\n const querySchema = useMemo<GridColumnSchema[]>(() => (\n (result?.columns ?? []).map((c) => ({ name: c, type: \"text\", nullable: true, pk: false, defaultValue: null }))\n ), [result?.columns]);\n\n const [panelHeight, setPanelHeight] = useState(250);\n const handleDrag = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n const startY = e.clientY;\n const startH = panelHeight;\n const onMove = (ev: MouseEvent) => setPanelHeight(Math.max(80, startH + (startY - ev.clientY)));\n const onUp = () => { document.removeEventListener(\"mousemove\", onMove); document.removeEventListener(\"mouseup\", onUp); };\n document.addEventListener(\"mousemove\", onMove);\n document.addEventListener(\"mouseup\", onUp);\n }, [panelHeight]);\n\n return (\n <div className=\"shrink-0 border-t border-border flex flex-col\" style={{ height: panelHeight }}>\n {/* Resize handle */}\n <div onMouseDown={handleDrag}\n className=\"shrink-0 h-1.5 cursor-row-resize bg-border/50 hover:bg-primary/30 flex items-center justify-center transition-colors\">\n <GripHorizontal className=\"size-3 text-muted-foreground/50\" />\n </div>\n {/* Title bar */}\n <div className=\"flex items-center gap-2 px-2 py-1 bg-muted/50 border-b border-border shrink-0\">\n <Database className=\"size-3 text-muted-foreground\" />\n <span className=\"text-xs font-medium text-foreground truncate flex-1\">\n {connName ? `${connName} · Results` : \"Query Results\"}\n {result?.executionTimeMs != null && <span className=\"text-muted-foreground ml-1.5 font-normal\">{result.executionTimeMs}ms</span>}\n </span>\n <button type=\"button\" onClick={onOpenInTab} title=\"Open in DB Viewer tab\"\n className=\"flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] text-muted-foreground hover:text-foreground hover:bg-muted transition-colors\">\n <ExternalLink className=\"size-3\" />\n <span className=\"hidden sm:inline\">Open in Tab</span>\n </button>\n <button type=\"button\" onClick={onClose} title=\"Close results\"\n className=\"p-0.5 rounded text-muted-foreground hover:text-foreground transition-colors\">\n <X className=\"size-3\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-hidden min-h-0\">\n {loading && (\n <div className=\"flex items-center justify-center h-full\">\n <Loader2 className=\"size-4 animate-spin text-muted-foreground\" />\n </div>\n )}\n {error && <div className=\"px-3 py-2 text-xs text-destructive bg-destructive/5\">{error}</div>}\n {result?.changeType === \"modify\" && (\n <div className=\"px-3 py-2 text-xs text-green-500\">\n {result.rowsAffected} row(s) affected\n </div>\n )}\n {tableData && (\n <GlideDataGrid\n columns={tableData.columns} rows={tableData.rows} total={tableData.total} limit={tableData.limit}\n schema={querySchema} loading={false}\n page={1} onPageChange={NOOP} onCellUpdate={NOOP}\n orderBy={null} orderDir=\"ASC\" onToggleSort={NOOP}\n connectionName={connName}\n />\n )}\n {result?.changeType === \"select\" && result.rows.length === 0 && (\n <div className=\"px-3 py-2 text-xs text-muted-foreground\">No results</div>\n )}\n </div>\n </div>\n );\n}\n\nfunction LoadingSpinner() {\n return <div className=\"flex items-center justify-center h-full\"><Loader2 className=\"size-5 animate-spin text-text-subtle\" /></div>;\n}\n\nfunction MarkdownPreview({ content }: { content: string }) {\n return (\n <Suspense fallback={<div className=\"animate-pulse h-4 bg-muted rounded m-4\" />}>\n <MarkdownRenderer content={content} className=\"flex-1 overflow-auto p-4\" />\n </Suspense>\n );\n}\n\n"],"file":"code-editor-MXnkYRLp.js"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"conflict-editor-C6wH5wV6.js","names":[],"sources":["../../../src/web/components/editor/conflict-editor.tsx"],"sourcesContent":["import { useEffect, useState, useRef, useCallback } from \"react\";\nimport Editor, { type OnMount } from \"@monaco-editor/react\";\nimport type * as MonacoType from \"monaco-editor\";\nimport { api, projectUrl } from \"@/lib/api-client\";\nimport { useShallow } from \"zustand/react/shallow\";\nimport { useSettingsStore } from \"@/stores/settings-store\";\nimport { useMonacoTheme } from \"@/lib/use-monaco-theme\";\nimport { Loader2 } from \"lucide-react\";\n\nfunction getMonacoLanguage(filename: string): string {\n const ext = filename.split(\".\").pop()?.toLowerCase() ?? \"\";\n const map: Record<string, string> = {\n js: \"javascript\", jsx: \"javascript\",\n ts: \"typescript\", tsx: \"typescript\",\n py: \"python\", html: \"html\",\n css: \"css\", scss: \"scss\",\n json: \"json\", md: \"markdown\", mdx: \"markdown\",\n yaml: \"yaml\", yml: \"yaml\",\n sh: \"shell\", bash: \"shell\",\n go: \"go\", rs: \"rust\", java: \"java\",\n rb: \"ruby\", php: \"php\", swift: \"swift\",\n sql: \"sql\", xml: \"xml\", toml: \"toml\",\n };\n return map[ext] ?? \"plaintext\";\n}\n\ninterface ConflictRegion {\n id: number;\n startLine: number; // 1-indexed, line of <<<<<<< marker\n separatorLine: number; // line of =======\n endLine: number; // line of >>>>>>> marker\n currentContent: string;\n incomingContent: string;\n currentLabel: string;\n incomingLabel: string;\n}\n\nfunction parseConflicts(content: string): ConflictRegion[] {\n const lines = content.split(\"\\n\");\n const regions: ConflictRegion[] = [];\n let i = 0;\n let id = 0;\n\n while (i < lines.length) {\n const line = lines[i]!;\n if (line.startsWith(\"<<<<<<<\")) {\n const startLine = i;\n const currentLabel = line.substring(7).trim();\n const currentLines: string[] = [];\n i++;\n\n while (i < lines.length && !lines[i]!.startsWith(\"=======\")) {\n currentLines.push(lines[i]!);\n i++;\n }\n if (i >= lines.length) break;\n\n const separatorLine = i;\n const incomingLines: string[] = [];\n i++;\n\n while (i < lines.length && !lines[i]!.startsWith(\">>>>>>>\")) {\n incomingLines.push(lines[i]!);\n i++;\n }\n if (i >= lines.length) break;\n\n const incomingLabel = lines[i]!.substring(7).trim();\n\n regions.push({\n id: id++,\n startLine: startLine + 1,\n separatorLine: separatorLine + 1,\n endLine: i + 1,\n currentContent: currentLines.join(\"\\n\"),\n incomingContent: incomingLines.join(\"\\n\"),\n currentLabel,\n incomingLabel,\n });\n }\n i++;\n }\n return regions;\n}\n\ninterface ConflictEditorProps {\n metadata?: Record<string, unknown>;\n tabId?: string;\n}\n\nexport function ConflictEditor({ metadata }: ConflictEditorProps) {\n const filePath = metadata?.filePath as string | undefined;\n const projectName = metadata?.projectName as string | undefined;\n\n const [content, setContent] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [conflictCount, setConflictCount] = useState(0);\n const editorRef = useRef<MonacoType.editor.IStandaloneCodeEditor | null>(null);\n const monacoRef = useRef<typeof MonacoType | null>(null);\n const widgetsRef = useRef<MonacoType.editor.IContentWidget[]>([]);\n const decorationsRef = useRef<MonacoType.editor.IEditorDecorationsCollection | null>(null);\n\n const { wordWrap } = useSettingsStore(useShallow((s) => ({ wordWrap: s.wordWrap })));\n const monacoTheme = useMonacoTheme();\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [containerHeight, setContainerHeight] = useState<number | undefined>();\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const ro = new ResizeObserver(([entry]) => {\n if (entry) setContainerHeight(Math.floor(entry.contentRect.height));\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n // Load file content\n useEffect(() => {\n if (!filePath || !projectName) return;\n setLoading(true);\n api\n .get<{ content: string }>(`${projectUrl(projectName)}/files/read?path=${encodeURIComponent(filePath)}`)\n .then((data) => {\n setContent(data.content);\n setLoading(false);\n })\n .catch((e: Error) => {\n setError(e.message || \"Failed to load file\");\n setLoading(false);\n });\n }, [filePath, projectName]);\n\n const refreshConflicts = useCallback(() => {\n const editor = editorRef.current;\n const monaco = monacoRef.current;\n if (!editor || !monaco) return;\n\n const value = editor.getModel()?.getValue() || \"\";\n const regions = parseConflicts(value);\n setConflictCount(regions.length);\n\n // Clear old widgets\n for (const w of widgetsRef.current) {\n editor.removeContentWidget(w);\n }\n widgetsRef.current = [];\n\n // Clear old decorations\n if (decorationsRef.current) {\n decorationsRef.current.clear();\n }\n\n if (regions.length === 0) return;\n\n // Apply decorations\n const decos: MonacoType.editor.IModelDeltaDecoration[] = [];\n for (const region of regions) {\n // Marker lines\n decos.push({\n range: new monaco.Range(region.startLine, 1, region.startLine, 1),\n options: { isWholeLine: true, className: \"conflict-marker-line\", glyphMarginClassName: \"conflict-glyph-current\" },\n });\n decos.push({\n range: new monaco.Range(region.separatorLine, 1, region.separatorLine, 1),\n options: { isWholeLine: true, className: \"conflict-marker-line\" },\n });\n decos.push({\n range: new monaco.Range(region.endLine, 1, region.endLine, 1),\n options: { isWholeLine: true, className: \"conflict-marker-line\", glyphMarginClassName: \"conflict-glyph-incoming\" },\n });\n // Current content (green)\n if (region.separatorLine - region.startLine > 1) {\n decos.push({\n range: new monaco.Range(region.startLine + 1, 1, region.separatorLine - 1, 1),\n options: { isWholeLine: true, className: \"conflict-current-content\" },\n });\n }\n // Incoming content (blue)\n if (region.endLine - region.separatorLine > 1) {\n decos.push({\n range: new monaco.Range(region.separatorLine + 1, 1, region.endLine - 1, 1),\n options: { isWholeLine: true, className: \"conflict-incoming-content\" },\n });\n }\n }\n\n decorationsRef.current = editor.createDecorationsCollection(decos);\n\n // Add accept widgets above each conflict\n for (const region of regions) {\n const widgetId = `conflict-widget-${region.id}`;\n\n const domNode = document.createElement(\"div\");\n domNode.className = \"conflict-actions\";\n domNode.innerHTML =\n `<span class=\"conflict-label\">Current Change (${escHtml(region.currentLabel || \"HEAD\")})</span>` +\n `<button class=\"conflict-btn conflict-btn-current\" data-action=\"current\">Accept Current</button>` +\n `<button class=\"conflict-btn conflict-btn-incoming\" data-action=\"incoming\">Accept Incoming</button>` +\n `<button class=\"conflict-btn conflict-btn-both\" data-action=\"both\">Accept Both</button>`;\n\n domNode.addEventListener(\"click\", (e) => {\n const btn = (e.target as HTMLElement).closest(\"[data-action]\");\n if (!btn) return;\n const action = btn.getAttribute(\"data-action\") as \"current\" | \"incoming\" | \"both\";\n acceptConflict(region.id, action);\n });\n\n const widget: MonacoType.editor.IContentWidget = {\n getId: () => widgetId,\n getDomNode: () => domNode,\n getPosition: () => ({\n position: { lineNumber: region.startLine, column: 1 },\n preference: [monaco.editor.ContentWidgetPositionPreference.ABOVE],\n }),\n };\n editor.addContentWidget(widget);\n widgetsRef.current.push(widget);\n }\n }, []);\n\n const acceptConflict = useCallback(\n (regionId: number, action: \"current\" | \"incoming\" | \"both\") => {\n const editor = editorRef.current;\n const monaco = monacoRef.current;\n if (!editor || !monaco) return;\n\n const model = editor.getModel();\n if (!model) return;\n\n const value = model.getValue();\n const regions = parseConflicts(value);\n const region = regions.find((r) => r.id === regionId);\n if (!region) return;\n\n let replacement: string;\n switch (action) {\n case \"current\":\n replacement = region.currentContent;\n break;\n case \"incoming\":\n replacement = region.incomingContent;\n break;\n case \"both\":\n replacement = region.currentContent + \"\\n\" + region.incomingContent;\n break;\n }\n\n const range = new monaco.Range(region.startLine, 1, region.endLine + 1, 1);\n model.pushEditOperations(\n [],\n [{ range, text: replacement + \"\\n\" }],\n () => null,\n );\n\n // Save and refresh\n saveFile(model.getValue());\n // Small delay to let the model update before refreshing decorations\n setTimeout(() => refreshConflicts(), 50);\n },\n [refreshConflicts],\n );\n\n const saveFile = useCallback(\n async (newContent: string) => {\n if (!filePath || !projectName) return;\n try {\n await api.put<{ written: boolean }>(`${projectUrl(projectName)}/files/write`, {\n path: filePath,\n content: newContent,\n });\n } catch (e) {\n console.error(\"[conflict-editor] save failed:\", e);\n }\n },\n [filePath, projectName],\n );\n\n const handleMount: OnMount = (editor, monaco) => {\n editorRef.current = editor;\n monacoRef.current = monaco;\n\n // Inject conflict editor styles (idempotent)\n const doc = editor.getDomNode()?.ownerDocument ?? document;\n if (!doc.getElementById(\"conflict-editor-styles\")) {\n const styleEl = doc.createElement(\"style\");\n styleEl.id = \"conflict-editor-styles\";\n styleEl.textContent = `\n .conflict-current-content { background: rgba(34, 197, 94, 0.1) !important; }\n .conflict-incoming-content { background: rgba(59, 130, 246, 0.1) !important; }\n .conflict-marker-line { background: rgba(100, 100, 100, 0.15) !important; font-style: italic; }\n .conflict-glyph-current { background: #22c55e !important; }\n .conflict-glyph-incoming { background: #3b82f6 !important; }\n .conflict-actions { display: flex; gap: 8px; align-items: center; padding: 2px 0; font-size: 12px; font-family: system-ui; }\n .conflict-label { color: #22c55e; font-weight: 600; margin-right: 8px; }\n .conflict-btn { padding: 1px 8px; border-radius: 3px; border: none; cursor: pointer; font-size: 11px; opacity: 0.9; }\n .conflict-btn:hover { opacity: 1; }\n .conflict-btn-current { color: #22c55e; background: rgba(34, 197, 94, 0.15); }\n .conflict-btn-incoming { color: #3b82f6; background: rgba(59, 130, 246, 0.15); }\n .conflict-btn-both { color: #a855f7; background: rgba(168, 85, 247, 0.15); }\n `;\n doc.head?.appendChild(styleEl);\n }\n\n refreshConflicts();\n };\n\n const fileName = filePath?.split(/[\\\\/]/).pop() ?? \"unknown\";\n const language = getMonacoLanguage(fileName);\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <Loader2 className=\"size-6 animate-spin text-primary\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full text-destructive\">\n {error}\n </div>\n );\n }\n\n return (\n <div className=\"h-full w-full flex flex-col\">\n <div className=\"flex items-center gap-2 px-3 py-1.5 text-xs border-b border-border bg-muted/50 flex-shrink-0\">\n <span className=\"font-medium\">{fileName}</span>\n <span className=\"text-muted-foreground\">—</span>\n {conflictCount > 0 ? (\n <span className=\"text-destructive font-medium\">\n {conflictCount} conflict{conflictCount !== 1 ? \"s\" : \"\"} remaining\n </span>\n ) : (\n <span className=\"text-green-500 font-medium\">All conflicts resolved</span>\n )}\n </div>\n <div ref={containerRef} className=\"flex-1 min-h-0\">\n {content !== null && containerHeight && (\n <Editor\n height={containerHeight}\n language={language}\n value={content}\n onMount={handleMount}\n theme={monacoTheme}\n options={{\n fontSize: 13,\n fontFamily: \"Menlo, Monaco, Consolas, monospace\",\n wordWrap: wordWrap ? \"on\" : \"off\",\n glyphMargin: true,\n readOnly: false,\n automaticLayout: true,\n scrollBeyondLastLine: false,\n minimap: { enabled: false },\n }}\n />\n )}\n </div>\n </div>\n );\n}\n\nfunction escHtml(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"createLucideIcon-BjHrJDVb.js","names":[],"sources":["../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js","../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.js","../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.js","../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.js","../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/defaultAttributes.js","../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.js","../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/Icon.js","../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/createLucideIcon.js"],"sourcesContent":["/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\n\nexport { mergeClasses };\n//# sourceMappingURL=mergeClasses.js.map\n","/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n\nexport { toKebabCase };\n//# sourceMappingURL=toKebabCase.js.map\n","/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\n\nexport { toCamelCase };\n//# sourceMappingURL=toCamelCase.js.map\n","/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { toCamelCase } from './toCamelCase.js';\n\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\n\nexport { toPascalCase };\n//# sourceMappingURL=toPascalCase.js.map\n","/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst hasA11yProp = (props) => {\n for (const prop in props) {\n if (prop.startsWith(\"aria-\") || prop === \"role\" || prop === \"title\") {\n return true;\n }\n }\n return false;\n};\n\nexport { hasA11yProp };\n//# sourceMappingURL=hasA11yProp.js.map\n","/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.js';\nimport { hasA11yProp } from './shared/src/utils/hasA11yProp.js';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.js';\n\nconst Icon = forwardRef(\n ({\n color = \"currentColor\",\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = \"\",\n children,\n iconNode,\n ...rest\n }, ref) => createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n className: mergeClasses(\"lucide\", className),\n ...!children && !hasA11yProp(rest) && { \"aria-hidden\": \"true\" },\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n )\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses } from './shared/src/utils/mergeClasses.js';\nimport { toKebabCase } from './shared/src/utils/toKebabCase.js';\nimport { toPascalCase } from './shared/src/utils/toPascalCase.js';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(\n `lucide-${toKebabCase(toPascalCase(iconName))}`,\n `lucide-${iconName}`,\n className\n ),\n ...props\n })\n );\n Component.displayName = toPascalCase(iconName);\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n"],"x_google_ignoreList":[0,1,2,3,4,5,6,7],"mappings":"qGAOA,IAAM,GAAgB,GAAG,IAAY,EAAQ,QAAQ,EAAW,EAAO,IAC9D,EAAQ,GAAc,EAAU,MAAM,GAAK,IAAM,EAAM,QAAQ,EAAU,GAAK,EACrF,CAAC,KAAK,IAAI,CAAC,MAAM,CCFb,EAAe,GAAW,EAAO,QAAQ,qBAAsB,QAAQ,CAAC,aAAa,CCArF,EAAe,GAAW,EAAO,QACrC,yBACC,EAAO,EAAI,IAAO,EAAK,EAAG,aAAa,CAAG,EAAG,aAAa,CAC5D,CCDK,EAAgB,GAAW,CAC/B,IAAM,EAAY,EAAY,EAAO,CACrC,OAAO,EAAU,OAAO,EAAE,CAAC,aAAa,CAAG,EAAU,MAAM,EAAE,ECJ3D,EAAoB,CACtB,MAAO,6BACP,MAAO,GACP,OAAQ,GACR,QAAS,YACT,KAAM,OACN,OAAQ,eACR,YAAa,EACb,cAAe,QACf,eAAgB,QACjB,CCVK,EAAe,GAAU,CAC7B,IAAK,IAAM,KAAQ,EACjB,GAAI,EAAK,WAAW,QAAQ,EAAI,IAAS,QAAU,IAAS,QAC1D,MAAO,GAGX,MAAO,aCDH,GAAA,EAAA,EAAA,aACH,CACC,QAAQ,eACR,OAAO,GACP,cAAc,EACd,sBACA,YAAY,GACZ,WACA,WACA,GAAG,GACF,KAAA,EAAA,EAAA,eACD,MACA,CACE,MACA,GAAG,EACH,MAAO,EACP,OAAQ,EACR,OAAQ,EACR,YAAa,EAAsB,OAAO,EAAY,CAAG,GAAK,OAAO,EAAK,CAAG,EAC7E,UAAW,EAAa,SAAU,EAAU,CAC5C,GAAG,CAAC,GAAY,CAAC,EAAY,EAAK,EAAI,CAAE,cAAe,OAAQ,CAC/D,GAAG,EACJ,CACD,CACE,GAAG,EAAS,KAAK,CAAC,EAAK,MAAA,EAAA,EAAA,eAAyB,EAAK,EAAM,CAAC,CAC5D,GAAG,MAAM,QAAQ,EAAS,CAAG,EAAW,CAAC,EAAS,CACnD,CACF,CACF,CC3BK,GAAoB,EAAU,IAAa,CAC/C,IAAM,GAAA,EAAA,EAAA,aACH,CAAE,YAAW,GAAG,GAAS,KAAA,EAAA,EAAA,eAAsB,EAAM,CACpD,MACA,WACA,UAAW,EACT,UAAU,EAAY,EAAa,EAAS,CAAC,GAC7C,UAAU,IACV,EACD,CACD,GAAG,EACJ,CAAC,CACH,CAED,MADA,GAAU,YAAc,EAAa,EAAS,CACvC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"csv-parser-Dly5nqE1.js","names":[],"sources":["../../../node_modules/.bun/lucide-react@0.577.0+b1ab299f0a400331/node_modules/lucide-react/dist/esm/icons/arrow-down.js","../../../src/web/lib/csv-parser.ts"],"sourcesContent":["/**\n * @license lucide-react v0.577.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }],\n [\"path\", { d: \"m19 12-7 7-7-7\", key: \"1idqje\" }]\n];\nconst ArrowDown = createLucideIcon(\"arrow-down\", __iconNode);\n\nexport { __iconNode, ArrowDown as default };\n//# sourceMappingURL=arrow-down.js.map\n","/** Simple state-machine CSV parser handling quoted fields, embedded commas, newlines */\n\nconst enum State {\n FIELD_START,\n UNQUOTED,\n QUOTED,\n QUOTE_IN_QUOTED,\n}\n\nexport interface CsvData {\n headers: string[];\n rows: string[][];\n}\n\nexport function parseCsv(content: string): CsvData {\n const rows: string[][] = [];\n let row: string[] = [];\n let field = \"\";\n let state: State = State.FIELD_START;\n\n for (let i = 0; i < content.length; i++) {\n const ch = content[i]!;\n\n switch (state) {\n case State.FIELD_START:\n if (ch === '\"') {\n state = State.QUOTED;\n } else if (ch === \",\") {\n row.push(field);\n field = \"\";\n } else if (ch === \"\\r\") {\n // skip \\r, handle \\n next\n } else if (ch === \"\\n\") {\n row.push(field);\n field = \"\";\n rows.push(row);\n row = [];\n } else {\n field += ch;\n state = State.UNQUOTED;\n }\n break;\n\n case State.UNQUOTED:\n if (ch === \",\") {\n row.push(field);\n field = \"\";\n state = State.FIELD_START;\n } else if (ch === \"\\r\") {\n // skip\n } else if (ch === \"\\n\") {\n row.push(field);\n field = \"\";\n rows.push(row);\n row = [];\n state = State.FIELD_START;\n } else {\n field += ch;\n }\n break;\n\n case State.QUOTED:\n if (ch === '\"') {\n state = State.QUOTE_IN_QUOTED;\n } else {\n field += ch;\n }\n break;\n\n case State.QUOTE_IN_QUOTED:\n if (ch === '\"') {\n // Escaped quote \"\"\n field += '\"';\n state = State.QUOTED;\n } else if (ch === \",\") {\n row.push(field);\n field = \"\";\n state = State.FIELD_START;\n } else if (ch === \"\\r\") {\n // skip\n } else if (ch === \"\\n\") {\n row.push(field);\n field = \"\";\n rows.push(row);\n row = [];\n state = State.FIELD_START;\n } else {\n // Malformed — treat closing quote as literal\n field += ch;\n state = State.UNQUOTED;\n }\n break;\n }\n }\n\n // Flush last field/row\n if (field || row.length > 0) {\n row.push(field);\n rows.push(row);\n }\n\n if (rows.length === 0) return { headers: [], rows: [] };\n\n const headers = rows[0]!;\n const dataRows = rows.slice(1);\n\n // Normalize column count — pad short rows, truncate long ones\n const colCount = headers.length;\n for (let i = 0; i < dataRows.length; i++) {\n const r = dataRows[i]!;\n if (r.length < colCount) {\n while (r.length < colCount) r.push(\"\");\n } else if (r.length > colCount) {\n dataRows[i] = r.slice(0, colCount);\n }\n }\n\n return { headers, rows: dataRows };\n}\n\nexport function serializeCsv(headers: string[], rows: string[][]): string {\n const escape = (val: string): string => {\n if (val.includes(\",\") || val.includes('\"') || val.includes(\"\\n\")) {\n return `\"${val.replace(/\"/g, '\"\"')}\"`;\n }\n return val;\n };\n\n const lines = [headers.map(escape).join(\",\")];\n for (const row of rows) {\n lines.push(row.map(escape).join(\",\"));\n }\n return lines.join(\"\\n\");\n}\n"],"x_google_ignoreList":[0],"mappings":"mDAaA,IAAM,EAAY,EAAiB,aAJhB,CACjB,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,SAAU,CAAC,CAC1C,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,SAAU,CAAC,CACjD,CAC2D,CCXjD,EAAX,SAAA,EAAA,OACE,GAAA,EAAA,YAAA,GAAA,cACA,EAAA,EAAA,SAAA,GAAA,WACA,EAAA,EAAA,OAAA,GAAA,SACA,EAAA,EAAA,gBAAA,GAAA,qBAJS,GAAA,EAAA,CAKV,CAOD,SAAgB,EAAS,EAA0B,CACjD,IAAM,EAAmB,EAAE,CACvB,EAAgB,EAAE,CAClB,EAAQ,GACR,EAAe,EAAM,YAEzB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAAK,CACvC,IAAM,EAAK,EAAQ,GAEnB,OAAQ,EAAR,CACE,KAAK,EAAM,YACL,IAAO,IACT,EAAQ,EAAM,OACL,IAAO,KAChB,EAAI,KAAK,EAAM,CACf,EAAQ,IACC,IAAO,OAEP,IAAO;GAChB,EAAI,KAAK,EAAM,CACf,EAAQ,GACR,EAAK,KAAK,EAAI,CACd,EAAM,EAAE,GAER,GAAS,EACT,EAAQ,EAAM,WAEhB,MAEF,KAAK,EAAM,SACL,IAAO,KACT,EAAI,KAAK,EAAM,CACf,EAAQ,GACR,EAAQ,EAAM,aACL,IAAO,OAEP,IAAO;GAChB,EAAI,KAAK,EAAM,CACf,EAAQ,GACR,EAAK,KAAK,EAAI,CACd,EAAM,EAAE,CACR,EAAQ,EAAM,aAEd,GAAS,GAEX,MAEF,KAAK,EAAM,OACL,IAAO,IACT,EAAQ,EAAM,gBAEd,GAAS,EAEX,MAEF,KAAK,EAAM,gBACL,IAAO,KAET,GAAS,IACT,EAAQ,EAAM,QACL,IAAO,KAChB,EAAI,KAAK,EAAM,CACf,EAAQ,GACR,EAAQ,EAAM,aACL,IAAO,OAEP,IAAO;GAChB,EAAI,KAAK,EAAM,CACf,EAAQ,GACR,EAAK,KAAK,EAAI,CACd,EAAM,EAAE,CACR,EAAQ,EAAM,cAGd,GAAS,EACT,EAAQ,EAAM,WAEhB,OAUN,IALI,GAAS,EAAI,OAAS,KACxB,EAAI,KAAK,EAAM,CACf,EAAK,KAAK,EAAI,EAGZ,EAAK,SAAW,EAAG,MAAO,CAAE,QAAS,EAAE,CAAE,KAAM,EAAE,CAAE,CAEvD,IAAM,EAAU,EAAK,GACf,EAAW,EAAK,MAAM,EAAE,CAGxB,EAAW,EAAQ,OACzB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAS,OAAQ,IAAK,CACxC,IAAM,EAAI,EAAS,GACnB,GAAI,EAAE,OAAS,EACb,KAAO,EAAE,OAAS,GAAU,EAAE,KAAK,GAAG,MAC7B,EAAE,OAAS,IACpB,EAAS,GAAK,EAAE,MAAM,EAAG,EAAS,EAItC,MAAO,CAAE,UAAS,KAAM,EAAU,CAGpC,SAAgB,EAAa,EAAmB,EAA0B,CACxE,IAAM,EAAU,GACV,EAAI,SAAS,IAAI,EAAI,EAAI,SAAS,IAAI,EAAI,EAAI,SAAS;EAAK,CACvD,IAAI,EAAI,QAAQ,KAAM,KAAK,CAAC,GAE9B,EAGH,EAAQ,CAAC,EAAQ,IAAI,EAAO,CAAC,KAAK,IAAI,CAAC,CAC7C,IAAK,IAAM,KAAO,EAChB,EAAM,KAAK,EAAI,IAAI,EAAO,CAAC,KAAK,IAAI,CAAC,CAEvC,OAAO,EAAM,KAAK;EAAK"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"csv-preview-B3Dyhgho.js","names":[],"sources":["../../../node_modules/.bun/@tanstack+virtual-core@3.13.23/node_modules/@tanstack/virtual-core/dist/esm/utils.js","../../../node_modules/.bun/@tanstack+virtual-core@3.13.23/node_modules/@tanstack/virtual-core/dist/esm/index.js","../../../node_modules/.bun/@tanstack+react-virtual@3.13.23+bf16f8eded5e12ee/node_modules/@tanstack/react-virtual/dist/esm/index.js","../../../src/web/components/editor/csv-preview.tsx"],"sourcesContent":["function memo(getDeps, fn, opts) {\n let deps = opts.initialDeps ?? [];\n let result;\n let isInitial = true;\n function memoizedFunction() {\n var _a, _b, _c;\n let depTime;\n if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();\n const newDeps = getDeps();\n const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);\n if (!depsChanged) {\n return result;\n }\n deps = newDeps;\n let resultTime;\n if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now();\n result = fn(...newDeps);\n if (opts.key && ((_c = opts.debug) == null ? void 0 : _c.call(opts))) {\n const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;\n const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;\n const resultFpsPercentage = resultEndTime / 16;\n const pad = (str, num) => {\n str = String(str);\n while (str.length < num) {\n str = \" \" + str;\n }\n return str;\n };\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120)\n )}deg 100% 31%);`,\n opts == null ? void 0 : opts.key\n );\n }\n if ((opts == null ? void 0 : opts.onChange) && !(isInitial && opts.skipInitialOnChange)) {\n opts.onChange(result);\n }\n isInitial = false;\n return result;\n }\n memoizedFunction.updateDeps = (newDeps) => {\n deps = newDeps;\n };\n return memoizedFunction;\n}\nfunction notUndefined(value, msg) {\n if (value === void 0) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : \"\"}`);\n } else {\n return value;\n }\n}\nconst approxEqual = (a, b) => Math.abs(a - b) < 1.01;\nconst debounce = (targetWindow, fn, ms) => {\n let timeoutId;\n return function(...args) {\n targetWindow.clearTimeout(timeoutId);\n timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);\n };\n};\nexport {\n approxEqual,\n debounce,\n memo,\n notUndefined\n};\n//# sourceMappingURL=utils.js.map\n","import { debounce, memo, notUndefined, approxEqual } from \"./utils.js\";\nconst getRect = (element) => {\n const { offsetWidth, offsetHeight } = element;\n return { width: offsetWidth, height: offsetHeight };\n};\nconst defaultKeyExtractor = (index) => index;\nconst defaultRangeExtractor = (range) => {\n const start = Math.max(range.startIndex - range.overscan, 0);\n const end = Math.min(range.endIndex + range.overscan, range.count - 1);\n const arr = [];\n for (let i = start; i <= end; i++) {\n arr.push(i);\n }\n return arr;\n};\nconst observeElementRect = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const targetWindow = instance.targetWindow;\n if (!targetWindow) {\n return;\n }\n const handler = (rect) => {\n const { width, height } = rect;\n cb({ width: Math.round(width), height: Math.round(height) });\n };\n handler(getRect(element));\n if (!targetWindow.ResizeObserver) {\n return () => {\n };\n }\n const observer = new targetWindow.ResizeObserver((entries) => {\n const run = () => {\n const entry = entries[0];\n if (entry == null ? void 0 : entry.borderBoxSize) {\n const box = entry.borderBoxSize[0];\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize });\n return;\n }\n }\n handler(getRect(element));\n };\n instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();\n });\n observer.observe(element, { box: \"border-box\" });\n return () => {\n observer.unobserve(element);\n };\n};\nconst addEventListenerOptions = {\n passive: true\n};\nconst observeWindowRect = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight });\n };\n handler();\n element.addEventListener(\"resize\", handler, addEventListenerOptions);\n return () => {\n element.removeEventListener(\"resize\", handler);\n };\n};\nconst supportsScrollend = typeof window == \"undefined\" ? true : \"onscrollend\" in window;\nconst observeElementOffset = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const targetWindow = instance.targetWindow;\n if (!targetWindow) {\n return;\n }\n let offset = 0;\n const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : debounce(\n targetWindow,\n () => {\n cb(offset, false);\n },\n instance.options.isScrollingResetDelay\n );\n const createHandler = (isScrolling) => () => {\n const { horizontal, isRtl } = instance.options;\n offset = horizontal ? element[\"scrollLeft\"] * (isRtl && -1 || 1) : element[\"scrollTop\"];\n fallback();\n cb(offset, isScrolling);\n };\n const handler = createHandler(true);\n const endHandler = createHandler(false);\n element.addEventListener(\"scroll\", handler, addEventListenerOptions);\n const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;\n if (registerScrollendEvent) {\n element.addEventListener(\"scrollend\", endHandler, addEventListenerOptions);\n }\n return () => {\n element.removeEventListener(\"scroll\", handler);\n if (registerScrollendEvent) {\n element.removeEventListener(\"scrollend\", endHandler);\n }\n };\n};\nconst observeWindowOffset = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const targetWindow = instance.targetWindow;\n if (!targetWindow) {\n return;\n }\n let offset = 0;\n const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : debounce(\n targetWindow,\n () => {\n cb(offset, false);\n },\n instance.options.isScrollingResetDelay\n );\n const createHandler = (isScrolling) => () => {\n offset = element[instance.options.horizontal ? \"scrollX\" : \"scrollY\"];\n fallback();\n cb(offset, isScrolling);\n };\n const handler = createHandler(true);\n const endHandler = createHandler(false);\n element.addEventListener(\"scroll\", handler, addEventListenerOptions);\n const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;\n if (registerScrollendEvent) {\n element.addEventListener(\"scrollend\", endHandler, addEventListenerOptions);\n }\n return () => {\n element.removeEventListener(\"scroll\", handler);\n if (registerScrollendEvent) {\n element.removeEventListener(\"scrollend\", endHandler);\n }\n };\n};\nconst measureElement = (element, entry, instance) => {\n if (entry == null ? void 0 : entry.borderBoxSize) {\n const box = entry.borderBoxSize[0];\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? \"inlineSize\" : \"blockSize\"]\n );\n return size;\n }\n }\n return element[instance.options.horizontal ? \"offsetWidth\" : \"offsetHeight\"];\n};\nconst windowScroll = (offset, {\n adjustments = 0,\n behavior\n}, instance) => {\n var _a, _b;\n const toOffset = offset + adjustments;\n (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {\n [instance.options.horizontal ? \"left\" : \"top\"]: toOffset,\n behavior\n });\n};\nconst elementScroll = (offset, {\n adjustments = 0,\n behavior\n}, instance) => {\n var _a, _b;\n const toOffset = offset + adjustments;\n (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {\n [instance.options.horizontal ? \"left\" : \"top\"]: toOffset,\n behavior\n });\n};\nclass Virtualizer {\n constructor(opts) {\n this.unsubs = [];\n this.scrollElement = null;\n this.targetWindow = null;\n this.isScrolling = false;\n this.scrollState = null;\n this.measurementsCache = [];\n this.itemSizeCache = /* @__PURE__ */ new Map();\n this.laneAssignments = /* @__PURE__ */ new Map();\n this.pendingMeasuredCacheIndexes = [];\n this.prevLanes = void 0;\n this.lanesChangedFlag = false;\n this.lanesSettling = false;\n this.scrollRect = null;\n this.scrollOffset = null;\n this.scrollDirection = null;\n this.scrollAdjustments = 0;\n this.elementsCache = /* @__PURE__ */ new Map();\n this.now = () => {\n var _a, _b, _c;\n return ((_c = (_b = (_a = this.targetWindow) == null ? void 0 : _a.performance) == null ? void 0 : _b.now) == null ? void 0 : _c.call(_b)) ?? Date.now();\n };\n this.observer = /* @__PURE__ */ (() => {\n let _ro = null;\n const get = () => {\n if (_ro) {\n return _ro;\n }\n if (!this.targetWindow || !this.targetWindow.ResizeObserver) {\n return null;\n }\n return _ro = new this.targetWindow.ResizeObserver((entries) => {\n entries.forEach((entry) => {\n const run = () => {\n const node = entry.target;\n const index = this.indexFromElement(node);\n if (!node.isConnected) {\n this.observer.unobserve(node);\n return;\n }\n if (this.shouldMeasureDuringScroll(index)) {\n this.resizeItem(\n index,\n this.options.measureElement(node, entry, this)\n );\n }\n };\n this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();\n });\n });\n };\n return {\n disconnect: () => {\n var _a;\n (_a = get()) == null ? void 0 : _a.disconnect();\n _ro = null;\n },\n observe: (target) => {\n var _a;\n return (_a = get()) == null ? void 0 : _a.observe(target, { box: \"border-box\" });\n },\n unobserve: (target) => {\n var _a;\n return (_a = get()) == null ? void 0 : _a.unobserve(target);\n }\n };\n })();\n this.range = null;\n this.setOptions = (opts2) => {\n Object.entries(opts2).forEach(([key, value]) => {\n if (typeof value === \"undefined\") delete opts2[key];\n });\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {\n },\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n gap: 0,\n indexAttribute: \"data-index\",\n initialMeasurementsCache: [],\n lanes: 1,\n isScrollingResetDelay: 150,\n enabled: true,\n isRtl: false,\n useScrollendEvent: false,\n useAnimationFrameWithResizeObserver: false,\n ...opts2\n };\n };\n this.notify = (sync) => {\n var _a, _b;\n (_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, sync);\n };\n this.maybeNotify = memo(\n () => {\n this.calculateRange();\n return [\n this.isScrolling,\n this.range ? this.range.startIndex : null,\n this.range ? this.range.endIndex : null\n ];\n },\n (isScrolling) => {\n this.notify(isScrolling);\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"maybeNotify\",\n debug: () => this.options.debug,\n initialDeps: [\n this.isScrolling,\n this.range ? this.range.startIndex : null,\n this.range ? this.range.endIndex : null\n ]\n }\n );\n this.cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d());\n this.unsubs = [];\n this.observer.disconnect();\n if (this.rafId != null && this.targetWindow) {\n this.targetWindow.cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.scrollState = null;\n this.scrollElement = null;\n this.targetWindow = null;\n };\n this._didMount = () => {\n return () => {\n this.cleanup();\n };\n };\n this._willUpdate = () => {\n var _a;\n const scrollElement = this.options.enabled ? this.options.getScrollElement() : null;\n if (this.scrollElement !== scrollElement) {\n this.cleanup();\n if (!scrollElement) {\n this.maybeNotify();\n return;\n }\n this.scrollElement = scrollElement;\n if (this.scrollElement && \"ownerDocument\" in this.scrollElement) {\n this.targetWindow = this.scrollElement.ownerDocument.defaultView;\n } else {\n this.targetWindow = ((_a = this.scrollElement) == null ? void 0 : _a.window) ?? null;\n }\n this.elementsCache.forEach((cached) => {\n this.observer.observe(cached);\n });\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect;\n this.maybeNotify();\n })\n );\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset, isScrolling) => {\n this.scrollAdjustments = 0;\n this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? \"forward\" : \"backward\" : null;\n this.scrollOffset = offset;\n this.isScrolling = isScrolling;\n if (this.scrollState) {\n this.scheduleScrollReconcile();\n }\n this.maybeNotify();\n })\n );\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: void 0,\n behavior: void 0\n });\n }\n };\n this.rafId = null;\n this.getSize = () => {\n if (!this.options.enabled) {\n this.scrollRect = null;\n return 0;\n }\n this.scrollRect = this.scrollRect ?? this.options.initialRect;\n return this.scrollRect[this.options.horizontal ? \"width\" : \"height\"];\n };\n this.getScrollOffset = () => {\n if (!this.options.enabled) {\n this.scrollOffset = null;\n return 0;\n }\n this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset === \"function\" ? this.options.initialOffset() : this.options.initialOffset);\n return this.scrollOffset;\n };\n this.getFurthestMeasurement = (measurements, index) => {\n const furthestMeasurementsFound = /* @__PURE__ */ new Map();\n const furthestMeasurements = /* @__PURE__ */ new Map();\n for (let m = index - 1; m >= 0; m--) {\n const measurement = measurements[m];\n if (furthestMeasurementsFound.has(measurement.lane)) {\n continue;\n }\n const previousFurthestMeasurement = furthestMeasurements.get(\n measurement.lane\n );\n if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) {\n furthestMeasurements.set(measurement.lane, measurement);\n } else if (measurement.end < previousFurthestMeasurement.end) {\n furthestMeasurementsFound.set(measurement.lane, true);\n }\n if (furthestMeasurementsFound.size === this.options.lanes) {\n break;\n }\n }\n return furthestMeasurements.size === this.options.lanes ? Array.from(furthestMeasurements.values()).sort((a, b) => {\n if (a.end === b.end) {\n return a.index - b.index;\n }\n return a.end - b.end;\n })[0] : void 0;\n };\n this.getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.options.enabled,\n this.options.lanes\n ],\n (count, paddingStart, scrollMargin, getItemKey, enabled, lanes) => {\n const lanesChanged = this.prevLanes !== void 0 && this.prevLanes !== lanes;\n if (lanesChanged) {\n this.lanesChangedFlag = true;\n }\n this.prevLanes = lanes;\n this.pendingMeasuredCacheIndexes = [];\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n enabled,\n lanes\n };\n },\n {\n key: false\n }\n );\n this.getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n ({ count, paddingStart, scrollMargin, getItemKey, enabled, lanes }, itemSizeCache) => {\n if (!enabled) {\n this.measurementsCache = [];\n this.itemSizeCache.clear();\n this.laneAssignments.clear();\n return [];\n }\n if (this.laneAssignments.size > count) {\n for (const index of this.laneAssignments.keys()) {\n if (index >= count) {\n this.laneAssignments.delete(index);\n }\n }\n }\n if (this.lanesChangedFlag) {\n this.lanesChangedFlag = false;\n this.lanesSettling = true;\n this.measurementsCache = [];\n this.itemSizeCache.clear();\n this.laneAssignments.clear();\n this.pendingMeasuredCacheIndexes = [];\n }\n if (this.measurementsCache.length === 0 && !this.lanesSettling) {\n this.measurementsCache = this.options.initialMeasurementsCache;\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size);\n });\n }\n const min = this.lanesSettling ? 0 : this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;\n this.pendingMeasuredCacheIndexes = [];\n if (this.lanesSettling && this.measurementsCache.length === count) {\n this.lanesSettling = false;\n }\n const measurements = this.measurementsCache.slice(0, min);\n const laneLastIndex = new Array(lanes).fill(\n void 0\n );\n for (let m = 0; m < min; m++) {\n const item = measurements[m];\n if (item) {\n laneLastIndex[item.lane] = m;\n }\n }\n for (let i = min; i < count; i++) {\n const key = getItemKey(i);\n const cachedLane = this.laneAssignments.get(i);\n let lane;\n let start;\n if (cachedLane !== void 0 && this.options.lanes > 1) {\n lane = cachedLane;\n const prevIndex = laneLastIndex[lane];\n const prevInLane = prevIndex !== void 0 ? measurements[prevIndex] : void 0;\n start = prevInLane ? prevInLane.end + this.options.gap : paddingStart + scrollMargin;\n } else {\n const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i);\n start = furthestMeasurement ? furthestMeasurement.end + this.options.gap : paddingStart + scrollMargin;\n lane = furthestMeasurement ? furthestMeasurement.lane : i % this.options.lanes;\n if (this.options.lanes > 1) {\n this.laneAssignments.set(i, lane);\n }\n }\n const measuredSize = itemSizeCache.get(key);\n const size = typeof measuredSize === \"number\" ? measuredSize : this.options.estimateSize(i);\n const end = start + size;\n measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane\n };\n laneLastIndex[lane] = i;\n }\n this.measurementsCache = measurements;\n return measurements;\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"getMeasurements\",\n debug: () => this.options.debug\n }\n );\n this.calculateRange = memo(\n () => [\n this.getMeasurements(),\n this.getSize(),\n this.getScrollOffset(),\n this.options.lanes\n ],\n (measurements, outerSize, scrollOffset, lanes) => {\n return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes\n }) : null;\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"calculateRange\",\n debug: () => this.options.debug\n }\n );\n this.getVirtualIndexes = memo(\n () => {\n let startIndex = null;\n let endIndex = null;\n const range = this.calculateRange();\n if (range) {\n startIndex = range.startIndex;\n endIndex = range.endIndex;\n }\n this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);\n return [\n this.options.rangeExtractor,\n this.options.overscan,\n this.options.count,\n startIndex,\n endIndex\n ];\n },\n (rangeExtractor, overscan, count, startIndex, endIndex) => {\n return startIndex === null || endIndex === null ? [] : rangeExtractor({\n startIndex,\n endIndex,\n overscan,\n count\n });\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"getVirtualIndexes\",\n debug: () => this.options.debug\n }\n );\n this.indexFromElement = (node) => {\n const attributeName = this.options.indexAttribute;\n const indexStr = node.getAttribute(attributeName);\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`\n );\n return -1;\n }\n return parseInt(indexStr, 10);\n };\n this.shouldMeasureDuringScroll = (index) => {\n var _a;\n if (!this.scrollState || this.scrollState.behavior !== \"smooth\") {\n return true;\n }\n const scrollIndex = this.scrollState.index ?? ((_a = this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)) == null ? void 0 : _a.index);\n if (scrollIndex !== void 0 && this.range) {\n const bufferSize = Math.max(\n this.options.overscan,\n Math.ceil((this.range.endIndex - this.range.startIndex) / 2)\n );\n const minIndex = Math.max(0, scrollIndex - bufferSize);\n const maxIndex = Math.min(\n this.options.count - 1,\n scrollIndex + bufferSize\n );\n return index >= minIndex && index <= maxIndex;\n }\n return true;\n };\n this.measureElement = (node) => {\n if (!node) {\n this.elementsCache.forEach((cached, key2) => {\n if (!cached.isConnected) {\n this.observer.unobserve(cached);\n this.elementsCache.delete(key2);\n }\n });\n return;\n }\n const index = this.indexFromElement(node);\n const key = this.options.getItemKey(index);\n const prevNode = this.elementsCache.get(key);\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode);\n }\n this.observer.observe(node);\n this.elementsCache.set(key, node);\n }\n if ((!this.isScrolling || this.scrollState) && this.shouldMeasureDuringScroll(index)) {\n this.resizeItem(index, this.options.measureElement(node, void 0, this));\n }\n };\n this.resizeItem = (index, size) => {\n var _a;\n const item = this.measurementsCache[index];\n if (!item) return;\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size;\n const delta = size - itemSize;\n if (delta !== 0) {\n if (((_a = this.scrollState) == null ? void 0 : _a.behavior) !== \"smooth\" && (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments)) {\n if (process.env.NODE_ENV !== \"production\" && this.options.debug) {\n console.info(\"correction\", delta);\n }\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: this.scrollAdjustments += delta,\n behavior: void 0\n });\n }\n this.pendingMeasuredCacheIndexes.push(item.index);\n this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size));\n this.notify(false);\n }\n };\n this.getVirtualItems = memo(\n () => [this.getVirtualIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems = [];\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k];\n const measurement = measurements[i];\n virtualItems.push(measurement);\n }\n return virtualItems;\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"getVirtualItems\",\n debug: () => this.options.debug\n }\n );\n this.getVirtualItemForOffset = (offset) => {\n const measurements = this.getMeasurements();\n if (measurements.length === 0) {\n return void 0;\n }\n return notUndefined(\n measurements[findNearestBinarySearch(\n 0,\n measurements.length - 1,\n (index) => notUndefined(measurements[index]).start,\n offset\n )]\n );\n };\n this.getMaxScrollOffset = () => {\n if (!this.scrollElement) return 0;\n if (\"scrollHeight\" in this.scrollElement) {\n return this.options.horizontal ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth : this.scrollElement.scrollHeight - this.scrollElement.clientHeight;\n } else {\n const doc = this.scrollElement.document.documentElement;\n return this.options.horizontal ? doc.scrollWidth - this.scrollElement.innerWidth : doc.scrollHeight - this.scrollElement.innerHeight;\n }\n };\n this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {\n if (!this.scrollElement) return 0;\n const size = this.getSize();\n const scrollOffset = this.getScrollOffset();\n if (align === \"auto\") {\n align = toOffset >= scrollOffset + size ? \"end\" : \"start\";\n }\n if (align === \"center\") {\n toOffset += (itemSize - size) / 2;\n } else if (align === \"end\") {\n toOffset -= size;\n }\n const maxOffset = this.getMaxScrollOffset();\n return Math.max(Math.min(maxOffset, toOffset), 0);\n };\n this.getOffsetForIndex = (index, align = \"auto\") => {\n index = Math.max(0, Math.min(index, this.options.count - 1));\n const size = this.getSize();\n const scrollOffset = this.getScrollOffset();\n const item = this.measurementsCache[index];\n if (!item) return;\n if (align === \"auto\") {\n if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {\n align = \"end\";\n } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {\n align = \"start\";\n } else {\n return [scrollOffset, align];\n }\n }\n if (align === \"end\" && index === this.options.count - 1) {\n return [this.getMaxScrollOffset(), align];\n }\n const toOffset = align === \"end\" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;\n return [\n this.getOffsetForAlignment(toOffset, align, item.size),\n align\n ];\n };\n this.scrollToOffset = (toOffset, { align = \"start\", behavior = \"auto\" } = {}) => {\n const offset = this.getOffsetForAlignment(toOffset, align);\n const now = this.now();\n this.scrollState = {\n index: null,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0\n };\n this._scrollToOffset(offset, { adjustments: void 0, behavior });\n this.scheduleScrollReconcile();\n };\n this.scrollToIndex = (index, {\n align: initialAlign = \"auto\",\n behavior = \"auto\"\n } = {}) => {\n index = Math.max(0, Math.min(index, this.options.count - 1));\n const offsetInfo = this.getOffsetForIndex(index, initialAlign);\n if (!offsetInfo) {\n return;\n }\n const [offset, align] = offsetInfo;\n const now = this.now();\n this.scrollState = {\n index,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0\n };\n this._scrollToOffset(offset, { adjustments: void 0, behavior });\n this.scheduleScrollReconcile();\n };\n this.scrollBy = (delta, { behavior = \"auto\" } = {}) => {\n const offset = this.getScrollOffset() + delta;\n const now = this.now();\n this.scrollState = {\n index: null,\n align: \"start\",\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0\n };\n this._scrollToOffset(offset, { adjustments: void 0, behavior });\n this.scheduleScrollReconcile();\n };\n this.getTotalSize = () => {\n var _a;\n const measurements = this.getMeasurements();\n let end;\n if (measurements.length === 0) {\n end = this.options.paddingStart;\n } else if (this.options.lanes === 1) {\n end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;\n } else {\n const endByLane = Array(this.options.lanes).fill(null);\n let endIndex = measurements.length - 1;\n while (endIndex >= 0 && endByLane.some((val) => val === null)) {\n const item = measurements[endIndex];\n if (endByLane[item.lane] === null) {\n endByLane[item.lane] = item.end;\n }\n endIndex--;\n }\n end = Math.max(...endByLane.filter((val) => val !== null));\n }\n return Math.max(\n end - this.options.scrollMargin + this.options.paddingEnd,\n 0\n );\n };\n this._scrollToOffset = (offset, {\n adjustments,\n behavior\n }) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this);\n };\n this.measure = () => {\n this.itemSizeCache = /* @__PURE__ */ new Map();\n this.laneAssignments = /* @__PURE__ */ new Map();\n this.notify(false);\n };\n this.setOptions(opts);\n }\n scheduleScrollReconcile() {\n if (!this.targetWindow) {\n this.scrollState = null;\n return;\n }\n if (this.rafId != null) return;\n this.rafId = this.targetWindow.requestAnimationFrame(() => {\n this.rafId = null;\n this.reconcileScroll();\n });\n }\n reconcileScroll() {\n if (!this.scrollState) return;\n const el = this.scrollElement;\n if (!el) return;\n const MAX_RECONCILE_MS = 5e3;\n if (this.now() - this.scrollState.startedAt > MAX_RECONCILE_MS) {\n this.scrollState = null;\n return;\n }\n const offsetInfo = this.scrollState.index != null ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align) : void 0;\n const targetOffset = offsetInfo ? offsetInfo[0] : this.scrollState.lastTargetOffset;\n const STABLE_FRAMES = 1;\n const targetChanged = targetOffset !== this.scrollState.lastTargetOffset;\n if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {\n this.scrollState.stableFrames++;\n if (this.scrollState.stableFrames >= STABLE_FRAMES) {\n this.scrollState = null;\n return;\n }\n } else {\n this.scrollState.stableFrames = 0;\n if (targetChanged) {\n this.scrollState.lastTargetOffset = targetOffset;\n this.scrollState.behavior = \"auto\";\n this._scrollToOffset(targetOffset, {\n adjustments: void 0,\n behavior: \"auto\"\n });\n }\n }\n this.scheduleScrollReconcile();\n }\n}\nconst findNearestBinarySearch = (low, high, getCurrentValue, value) => {\n while (low <= high) {\n const middle = (low + high) / 2 | 0;\n const currentValue = getCurrentValue(middle);\n if (currentValue < value) {\n low = middle + 1;\n } else if (currentValue > value) {\n high = middle - 1;\n } else {\n return middle;\n }\n }\n if (low > 0) {\n return low - 1;\n } else {\n return 0;\n }\n};\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes\n}) {\n const lastIndex = measurements.length - 1;\n const getOffset = (index) => measurements[index].start;\n if (measurements.length <= lanes) {\n return {\n startIndex: 0,\n endIndex: lastIndex\n };\n }\n let startIndex = findNearestBinarySearch(\n 0,\n lastIndex,\n getOffset,\n scrollOffset\n );\n let endIndex = startIndex;\n if (lanes === 1) {\n while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {\n endIndex++;\n }\n } else if (lanes > 1) {\n const endPerLane = Array(lanes).fill(0);\n while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {\n const item = measurements[endIndex];\n endPerLane[item.lane] = item.end;\n endIndex++;\n }\n const startPerLane = Array(lanes).fill(scrollOffset + outerSize);\n while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {\n const item = measurements[startIndex];\n startPerLane[item.lane] = item.start;\n startIndex--;\n }\n startIndex = Math.max(0, startIndex - startIndex % lanes);\n endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));\n }\n return { startIndex, endIndex };\n}\nexport {\n Virtualizer,\n approxEqual,\n debounce,\n defaultKeyExtractor,\n defaultRangeExtractor,\n elementScroll,\n measureElement,\n memo,\n notUndefined,\n observeElementOffset,\n observeElementRect,\n observeWindowOffset,\n observeWindowRect,\n windowScroll\n};\n//# sourceMappingURL=index.js.map\n","import * as React from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { Virtualizer, elementScroll, observeElementOffset, observeElementRect, windowScroll, observeWindowOffset, observeWindowRect } from \"@tanstack/virtual-core\";\nexport * from \"@tanstack/virtual-core\";\nconst useIsomorphicLayoutEffect = typeof document !== \"undefined\" ? React.useLayoutEffect : React.useEffect;\nfunction useVirtualizerBase({\n useFlushSync = true,\n ...options\n}) {\n const rerender = React.useReducer(() => ({}), {})[1];\n const resolvedOptions = {\n ...options,\n onChange: (instance2, sync) => {\n var _a;\n if (useFlushSync && sync) {\n flushSync(rerender);\n } else {\n rerender();\n }\n (_a = options.onChange) == null ? void 0 : _a.call(options, instance2, sync);\n }\n };\n const [instance] = React.useState(\n () => new Virtualizer(resolvedOptions)\n );\n instance.setOptions(resolvedOptions);\n useIsomorphicLayoutEffect(() => {\n return instance._didMount();\n }, []);\n useIsomorphicLayoutEffect(() => {\n return instance._willUpdate();\n });\n return instance;\n}\nfunction useVirtualizer(options) {\n return useVirtualizerBase({\n observeElementRect,\n observeElementOffset,\n scrollToFn: elementScroll,\n ...options\n });\n}\nfunction useWindowVirtualizer(options) {\n return useVirtualizerBase({\n getScrollElement: () => typeof document !== \"undefined\" ? window : null,\n observeElementRect: observeWindowRect,\n observeElementOffset: observeWindowOffset,\n scrollToFn: windowScroll,\n initialOffset: () => typeof document !== \"undefined\" ? window.scrollY : 0,\n ...options\n });\n}\nexport {\n useVirtualizer,\n useWindowVirtualizer\n};\n//# sourceMappingURL=index.js.map\n","import { useState, useMemo, useRef, useCallback, useEffect } from \"react\";\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n flexRender,\n type ColumnDef,\n type SortingState,\n} from \"@tanstack/react-table\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport { parseCsv, serializeCsv } from \"@/lib/csv-parser\";\nimport { ArrowUp, ArrowDown } from \"lucide-react\";\n\ninterface CsvPreviewProps {\n content: string;\n onContentChange: (csv: string) => void;\n wordWrap?: boolean;\n}\n\nexport function CsvPreview({ content, onContentChange, wordWrap }: CsvPreviewProps) {\n const parsed = useMemo(() => parseCsv(content), [content]);\n const [rows, setRows] = useState<string[][]>(() => parsed.rows);\n const [sorting, setSorting] = useState<SortingState>([]);\n const scrollRef = useRef<HTMLDivElement>(null);\n const internalEditRef = useRef(false);\n\n // Sync when content changes externally (e.g. file reload) — skip if we triggered it\n useEffect(() => {\n if (internalEditRef.current) {\n internalEditRef.current = false;\n return;\n }\n setRows(parsed.rows);\n }, [parsed.rows]);\n\n const headers = parsed.headers;\n\n const updateCell = useCallback(\n (rowIndex: number, colIndex: number, value: string) => {\n setRows((prev) => {\n const next = prev.map((r, i) => (i === rowIndex ? [...r] : r));\n next[rowIndex]![colIndex] = value;\n internalEditRef.current = true;\n onContentChange(serializeCsv(headers, next));\n return next;\n });\n },\n [headers, onContentChange],\n );\n\n const columns = useMemo<ColumnDef<string[], string>[]>(\n () =>\n headers.map((h, i) => ({\n id: `col-${i}`,\n header: h || `Column ${i + 1}`,\n accessorFn: (row: string[]) => row[i] ?? \"\",\n cell: ({ row, getValue }) => (\n <CsvCell\n value={getValue()}\n onSave={(v) => updateCell(row.index, i, v)}\n wordWrap={wordWrap}\n />\n ),\n size: 150,\n minSize: 80,\n })),\n [headers, updateCell, wordWrap],\n );\n\n const table = useReactTable({\n data: rows,\n columns,\n state: { sorting },\n onSortingChange: setSorting,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n enableColumnResizing: true,\n columnResizeMode: \"onChange\",\n });\n\n const { rows: tableRows } = table.getRowModel();\n\n const virtualizer = useVirtualizer({\n count: tableRows.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => 32,\n overscan: 20,\n });\n\n if (headers.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full text-muted-foreground text-sm\">\n Empty CSV file\n </div>\n );\n }\n\n return (\n <div ref={scrollRef} className=\"flex-1 overflow-auto\">\n <table className=\"w-full text-xs font-mono border-collapse\">\n <thead className=\"sticky top-0 bg-background z-10 border-b border-border block\">\n {table.getHeaderGroups().map((hg) => (\n <tr key={hg.id} className=\"flex w-full\">\n {hg.headers.map((header) => (\n <th\n key={header.id}\n className=\"relative text-left px-2 py-1.5 font-medium text-muted-foreground select-none cursor-pointer hover:bg-muted/50 border-r border-border last:border-r-0\"\n style={{ width: header.getSize(), minWidth: header.getSize() }}\n onClick={header.column.getToggleSortingHandler()}\n >\n <div className=\"flex items-center gap-1\">\n <span className=\"truncate\">\n {flexRender(header.column.columnDef.header, header.getContext())}\n </span>\n {header.column.getIsSorted() === \"asc\" && <ArrowUp className=\"size-3 shrink-0\" />}\n {header.column.getIsSorted() === \"desc\" && <ArrowDown className=\"size-3 shrink-0\" />}\n </div>\n {/* Resize handle */}\n <div\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute right-0 top-0 h-full w-1 cursor-col-resize hover:bg-primary/50 active:bg-primary\"\n />\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody style={{ height: virtualizer.getTotalSize(), position: \"relative\", display: \"block\" }}>\n {virtualizer.getVirtualItems().map((vRow) => {\n const row = tableRows[vRow.index]!;\n return (\n <tr\n key={row.id}\n data-index={vRow.index}\n ref={(node) => virtualizer.measureElement(node)}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${vRow.start}px)`,\n display: \"flex\",\n }}\n >\n {row.getVisibleCells().map((cell) => (\n <td\n key={cell.id}\n className={`px-2 py-1 border-b border-border/50 border-r border-r-border/30 last:border-r-0 ${wordWrap ? \"whitespace-pre-wrap break-words\" : \"truncate\"}`}\n style={{ width: cell.column.getSize(), minWidth: cell.column.getSize() }}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n\nfunction CsvCell({ value, onSave, wordWrap }: { value: string; onSave: (v: string) => void; wordWrap?: boolean }) {\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(value);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-resize textarea to fit content\n const autoResize = useCallback((el: HTMLTextAreaElement | null) => {\n if (!el) return;\n el.style.height = \"auto\";\n el.style.height = `${el.scrollHeight}px`;\n }, []);\n\n useEffect(() => {\n if (editing && textareaRef.current) {\n textareaRef.current.focus();\n autoResize(textareaRef.current);\n }\n }, [editing, autoResize]);\n\n if (!editing) {\n return (\n <span\n className={`block cursor-text ${wordWrap ? \"whitespace-pre-wrap break-words\" : \"truncate\"}`}\n onClick={() => {\n setDraft(value);\n setEditing(true);\n }}\n >\n {value || \"\\u00A0\"}\n </span>\n );\n }\n\n const isMultiline = draft.includes(\"\\n\");\n\n return (\n <textarea\n ref={textareaRef}\n className=\"w-full bg-transparent outline-none border border-primary/50 rounded text-xs font-mono resize-none p-0.5\"\n style={{ minHeight: isMultiline ? 48 : 20 }}\n rows={1}\n value={draft}\n onChange={(e) => {\n setDraft(e.target.value);\n autoResize(e.target);\n }}\n onBlur={() => {\n setEditing(false);\n if (draft !== value) onSave(draft);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n // Enter = save, Shift+Enter = newline\n e.preventDefault();\n setEditing(false);\n if (draft !== value) onSave(draft);\n } else if (e.key === \"Escape\") {\n setEditing(false);\n setDraft(value);\n }\n }}\n />\n );\n}\n"],"x_google_ignoreList":[0,1,2],"mappings":"mVAAA,SAAA,EAAA,EAAA,EAAA,EAAA,mDAOI,EAAA,KAAA,EAAA,OAAA,KAAA,EAAA,GAAA,EAAA,KAAA,KAAA,YAGA,GAAA,EAAA,EAAA,SAAA,EAAA,QAAA,EAAA,MAAA,EAAA,IAAA,EAAA,KAAA,EAAA,EAAA,OAAA,EAGA,EAAA,QAIA,GAFA,EAAA,KAAA,EAAA,OAAA,KAAA,EAAA,GAAA,EAAA,KAAA,KAAA,EACA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,KAAA,EAAA,OAAA,KAAA,EAAA,CAAA,gGAMI,IADA,EAAA,OAAA,EAAA,CACA,EAAA,OAAA,GAAA,EAAA,IAAA,EAGA,OAAA,GAEF,QAAA,KAAA,OAAA,EAAA,EAAA,EAAA,CAAA,IAAA,EAAA,EAAA,EAAA,CAAA,KAAA;;;qFAgBF,OAJA,GAAA,UAAA,EAAA,GAAA,EAAA,sBAAA,EAAA,SAAA,EAAA,CAGA,EAAA,GACA,EAKF,MAHA,GAAA,WAAA,GAAA,CACE,EAAA,GAEF,EAEF,SAAA,EAAA,EAAA,EAAA,CACE,GAAA,IAAA,IAAA,GAAA,MAAA,MAAA,uBAAA,EAAA,KAAA,IAAA,KAAA,UAMF,IAAA,GAAA,EAAA,IAAA,KAAA,IAAA,EAAA,EAAA,CAAA,KACA,GAAA,EAAA,EAAA,IAAA,OAEE,OAAA,SAAA,GAAA,EAAA,CACE,EAAA,aAAA,EAAA,CACA,EAAA,EAAA,eAAA,EAAA,MAAA,KAAA,EAAA,CAAA,EAAA,GC9DE,EAAW,GAAY,CAC3B,GAAM,CAAE,cAAa,gBAAiB,EACtC,MAAO,CAAE,MAAO,EAAa,OAAQ,EAAc,EAE/C,EAAuB,GAAU,EACjC,EAAyB,GAAU,CACvC,IAAM,EAAQ,KAAK,IAAI,EAAM,WAAa,EAAM,SAAU,EAAE,CACtD,EAAM,KAAK,IAAI,EAAM,SAAW,EAAM,SAAU,EAAM,MAAQ,EAAE,CAChE,EAAM,EAAE,CACd,IAAK,IAAI,EAAI,EAAO,GAAK,EAAK,IAC5B,EAAI,KAAK,EAAE,CAEb,OAAO,GAEH,GAAsB,EAAU,IAAO,CAC3C,IAAM,EAAU,EAAS,cACzB,GAAI,CAAC,EACH,OAEF,IAAM,EAAe,EAAS,aAC9B,GAAI,CAAC,EACH,OAEF,IAAM,EAAW,GAAS,CACxB,GAAM,CAAE,QAAO,UAAW,EAC1B,EAAG,CAAE,MAAO,KAAK,MAAM,EAAM,CAAE,OAAQ,KAAK,MAAM,EAAO,CAAE,CAAC,EAG9D,GADA,EAAQ,EAAQ,EAAQ,CAAC,CACrB,CAAC,EAAa,eAChB,UAAa,GAGf,IAAM,EAAW,IAAI,EAAa,eAAgB,GAAY,CAC5D,IAAM,MAAY,CAChB,IAAM,EAAQ,EAAQ,GACtB,GAAI,GAA+B,cAAe,CAChD,IAAM,EAAM,EAAM,cAAc,GAChC,GAAI,EAAK,CACP,EAAQ,CAAE,MAAO,EAAI,WAAY,OAAQ,EAAI,UAAW,CAAC,CACzD,QAGJ,EAAQ,EAAQ,EAAQ,CAAC,EAE3B,EAAS,QAAQ,oCAAsC,sBAAsB,EAAI,CAAG,GAAK,EACzF,CAEF,OADA,EAAS,QAAQ,EAAS,CAAE,IAAK,aAAc,CAAC,KACnC,CACX,EAAS,UAAU,EAAQ,GAGzB,EAA0B,CAC9B,QAAS,GACV,CAeK,EAAoB,OAAO,OAAU,IAAc,GAAO,gBAAiB,OAC3E,GAAwB,EAAU,IAAO,CAC7C,IAAM,EAAU,EAAS,cACzB,GAAI,CAAC,EACH,OAEF,IAAM,EAAe,EAAS,aAC9B,GAAI,CAAC,EACH,OAEF,IAAI,EAAS,EACP,EAAW,EAAS,QAAQ,mBAAqB,MAA0B,IAAK,GAAI,EACxF,MACM,CACJ,EAAG,EAAQ,GAAM,EAEnB,EAAS,QAAQ,sBAClB,CACK,EAAiB,OAAsB,CAC3C,GAAM,CAAE,aAAY,SAAU,EAAS,QACvC,EAAS,EAAa,EAAQ,YAAiB,GAAS,IAAM,GAAK,EAAQ,UAC3E,GAAU,CACV,EAAG,EAAQ,EAAY,EAEnB,EAAU,EAAc,GAAK,CAC7B,EAAa,EAAc,GAAM,CACvC,EAAQ,iBAAiB,SAAU,EAAS,EAAwB,CACpE,IAAM,EAAyB,EAAS,QAAQ,mBAAqB,EAIrE,OAHI,GACF,EAAQ,iBAAiB,YAAa,EAAY,EAAwB,KAE/D,CACX,EAAQ,oBAAoB,SAAU,EAAQ,CAC1C,GACF,EAAQ,oBAAoB,YAAa,EAAW,GAwCpD,GAAkB,EAAS,EAAO,IAAa,CACnD,GAAI,GAA+B,cAAe,CAChD,IAAM,EAAM,EAAM,cAAc,GAChC,GAAI,EAIF,OAHa,KAAK,MAChB,EAAI,EAAS,QAAQ,WAAa,aAAe,aAClD,CAIL,OAAO,EAAQ,EAAS,QAAQ,WAAa,cAAgB,iBAazD,GAAiB,EAAQ,CAC7B,cAAc,EACd,YACC,IAAa,CACd,IAAI,EAAI,EACR,IAAM,EAAW,EAAS,GACzB,GAAM,EAAK,EAAS,gBAAqC,WAAa,MAAgB,EAAG,KAAK,EAAI,EAChG,EAAS,QAAQ,WAAa,OAAS,OAAQ,EAChD,WACD,CAAC,EAEE,EAAN,KAAkB,CAChB,YAAY,EAAM,CAChB,KAAK,OAAS,EAAE,CAChB,KAAK,cAAgB,KACrB,KAAK,aAAe,KACpB,KAAK,YAAc,GACnB,KAAK,YAAc,KACnB,KAAK,kBAAoB,EAAE,CAC3B,KAAK,cAAgC,IAAI,IACzC,KAAK,gBAAkC,IAAI,IAC3C,KAAK,4BAA8B,EAAE,CACrC,KAAK,UAAY,IAAK,GACtB,KAAK,iBAAmB,GACxB,KAAK,cAAgB,GACrB,KAAK,WAAa,KAClB,KAAK,aAAe,KACpB,KAAK,gBAAkB,KACvB,KAAK,kBAAoB,EACzB,KAAK,cAAgC,IAAI,IACzC,KAAK,QAAY,CACf,IAAQ,EACR,QAAe,EAAW,KAAK,cAAoC,cAAmC,MAA2B,KAAK,EAAG,EAAK,KAAK,KAAK,EAE1J,KAAK,cAAkC,CACrC,IAAI,EAAM,KACJ,MACA,IAGA,CAAC,KAAK,cAAgB,CAAC,KAAK,aAAa,eACpC,KAEF,EAAM,IAAI,KAAK,aAAa,eAAgB,GAAY,CAC7D,EAAQ,QAAS,GAAU,CACzB,IAAM,MAAY,CAChB,IAAM,EAAO,EAAM,OACb,EAAQ,KAAK,iBAAiB,EAAK,CACzC,GAAI,CAAC,EAAK,YAAa,CACrB,KAAK,SAAS,UAAU,EAAK,CAC7B,OAEE,KAAK,0BAA0B,EAAM,EACvC,KAAK,WACH,EACA,KAAK,QAAQ,eAAe,EAAM,EAAO,KAAK,CAC/C,EAGL,KAAK,QAAQ,oCAAsC,sBAAsB,EAAI,CAAG,GAAK,EACrF,EACF,EAEJ,MAAO,CACL,eAAkB,CAChB,IAAI,GACH,EAAK,GAAK,GAAK,MAAgB,EAAG,YAAY,CAC/C,EAAM,MAER,QAAU,GAEK,GAAK,EAAwB,QAAQ,EAAQ,CAAE,IAAK,aAAc,CAAC,CAElF,UAAY,GAEG,GAAK,EAAwB,UAAU,EAAO,CAE9D,IACC,CACJ,KAAK,MAAQ,KACb,KAAK,WAAc,GAAU,CAC3B,OAAO,QAAQ,EAAM,CAAC,SAAS,CAAC,EAAK,KAAW,CACnC,IAAU,QAAa,OAAO,EAAM,IAC/C,CACF,KAAK,QAAU,CACb,MAAO,GACP,cAAe,EACf,SAAU,EACV,aAAc,EACd,WAAY,EACZ,mBAAoB,EACpB,iBAAkB,EAClB,WAAY,GACZ,WAAY,EACZ,eAAgB,EAChB,aAAgB,GAEhB,iBACA,YAAa,CAAE,MAAO,EAAG,OAAQ,EAAG,CACpC,aAAc,EACd,IAAK,EACL,eAAgB,aAChB,yBAA0B,EAAE,CAC5B,MAAO,EACP,sBAAuB,IACvB,QAAS,GACT,MAAO,GACP,kBAAmB,GACnB,oCAAqC,GACrC,GAAG,EACJ,EAEH,KAAK,OAAU,GAAS,CACtB,IAAI,EAAI,GACP,GAAM,EAAK,KAAK,SAAS,WAAa,MAAgB,EAAG,KAAK,EAAI,KAAM,EAAK,EAEhF,KAAK,YAAc,OAEf,KAAK,gBAAgB,CACd,CACL,KAAK,YACL,KAAK,MAAQ,KAAK,MAAM,WAAa,KACrC,KAAK,MAAQ,KAAK,MAAM,SAAW,KACpC,EAEF,GAAgB,CACf,KAAK,OAAO,EAAY,EAE1B,CACE,IAAK,GACL,UAAa,KAAK,QAAQ,MAC1B,YAAa,CACX,KAAK,YACL,KAAK,MAAQ,KAAK,MAAM,WAAa,KACrC,KAAK,MAAQ,KAAK,MAAM,SAAW,KACpC,CACF,CACF,CACD,KAAK,YAAgB,CACnB,KAAK,OAAO,OAAO,QAAQ,CAAC,QAAS,GAAM,GAAG,CAAC,CAC/C,KAAK,OAAS,EAAE,CAChB,KAAK,SAAS,YAAY,CACtB,KAAK,OAAS,MAAQ,KAAK,eAC7B,KAAK,aAAa,qBAAqB,KAAK,MAAM,CAClD,KAAK,MAAQ,MAEf,KAAK,YAAc,KACnB,KAAK,cAAgB,KACrB,KAAK,aAAe,MAEtB,KAAK,kBACU,CACX,KAAK,SAAS,EAGlB,KAAK,gBAAoB,CAEvB,IAAM,EAAgB,KAAK,QAAQ,QAAU,KAAK,QAAQ,kBAAkB,CAAG,KAC/E,GAAI,KAAK,gBAAkB,EAAe,CAExC,GADA,KAAK,SAAS,CACV,CAAC,EAAe,CAClB,KAAK,aAAa,CAClB,OAEF,KAAK,cAAgB,EACjB,KAAK,eAAiB,kBAAmB,KAAK,cAChD,KAAK,aAAe,KAAK,cAAc,cAAc,YAErD,KAAK,aAAsB,KAAK,eAAqC,QAAW,KAElF,KAAK,cAAc,QAAS,GAAW,CACrC,KAAK,SAAS,QAAQ,EAAO,EAC7B,CACF,KAAK,OAAO,KACV,KAAK,QAAQ,mBAAmB,KAAO,GAAS,CAC9C,KAAK,WAAa,EAClB,KAAK,aAAa,EAClB,CACH,CACD,KAAK,OAAO,KACV,KAAK,QAAQ,qBAAqB,MAAO,EAAQ,IAAgB,CAC/D,KAAK,kBAAoB,EACzB,KAAK,gBAAkB,EAAc,KAAK,iBAAiB,CAAG,EAAS,UAAY,WAAa,KAChG,KAAK,aAAe,EACpB,KAAK,YAAc,EACf,KAAK,aACP,KAAK,yBAAyB,CAEhC,KAAK,aAAa,EAClB,CACH,CACD,KAAK,gBAAgB,KAAK,iBAAiB,CAAE,CAC3C,YAAa,IAAK,GAClB,SAAU,IAAK,GAChB,CAAC,GAGN,KAAK,MAAQ,KACb,KAAK,YACE,KAAK,QAAQ,SAIlB,KAAK,WAAa,KAAK,YAAc,KAAK,QAAQ,YAC3C,KAAK,WAAW,KAAK,QAAQ,WAAa,QAAU,YAJzD,KAAK,WAAa,KACX,GAKX,KAAK,oBACE,KAAK,QAAQ,SAIlB,KAAK,aAAe,KAAK,eAAiB,OAAO,KAAK,QAAQ,eAAkB,WAAa,KAAK,QAAQ,eAAe,CAAG,KAAK,QAAQ,eAClI,KAAK,eAJV,KAAK,aAAe,KACb,GAKX,KAAK,wBAA0B,EAAc,IAAU,CACrD,IAAM,EAA4C,IAAI,IAChD,EAAuC,IAAI,IACjD,IAAK,IAAI,EAAI,EAAQ,EAAG,GAAK,EAAG,IAAK,CACnC,IAAM,EAAc,EAAa,GACjC,GAAI,EAA0B,IAAI,EAAY,KAAK,CACjD,SAEF,IAAM,EAA8B,EAAqB,IACvD,EAAY,KACb,CAMD,GALI,GAA+B,MAAQ,EAAY,IAAM,EAA4B,IACvF,EAAqB,IAAI,EAAY,KAAM,EAAY,CAC9C,EAAY,IAAM,EAA4B,KACvD,EAA0B,IAAI,EAAY,KAAM,GAAK,CAEnD,EAA0B,OAAS,KAAK,QAAQ,MAClD,MAGJ,OAAO,EAAqB,OAAS,KAAK,QAAQ,MAAQ,MAAM,KAAK,EAAqB,QAAQ,CAAC,CAAC,MAAM,EAAG,IACvG,EAAE,MAAQ,EAAE,IACP,EAAE,MAAQ,EAAE,MAEd,EAAE,IAAM,EAAE,IACjB,CAAC,GAAK,IAAK,IAEf,KAAK,sBAAwB,MACrB,CACJ,KAAK,QAAQ,MACb,KAAK,QAAQ,aACb,KAAK,QAAQ,aACb,KAAK,QAAQ,WACb,KAAK,QAAQ,QACb,KAAK,QAAQ,MACd,EACA,EAAO,EAAc,EAAc,EAAY,EAAS,KAClC,KAAK,YAAc,IAAK,IAAK,KAAK,YAAc,IAEnE,KAAK,iBAAmB,IAE1B,KAAK,UAAY,EACjB,KAAK,4BAA8B,EAAE,CAC9B,CACL,QACA,eACA,eACA,aACA,UACA,QACD,EAEH,CACE,IAAK,GACN,CACF,CACD,KAAK,gBAAkB,MACf,CAAC,KAAK,uBAAuB,CAAE,KAAK,cAAc,EACvD,CAAE,QAAO,eAAc,eAAc,aAAY,UAAS,SAAS,IAAkB,CACpF,GAAI,CAAC,EAIH,MAHA,MAAK,kBAAoB,EAAE,CAC3B,KAAK,cAAc,OAAO,CAC1B,KAAK,gBAAgB,OAAO,CACrB,EAAE,CAEX,GAAI,KAAK,gBAAgB,KAAO,MACzB,IAAM,KAAS,KAAK,gBAAgB,MAAM,CACzC,GAAS,GACX,KAAK,gBAAgB,OAAO,EAAM,CAIpC,KAAK,mBACP,KAAK,iBAAmB,GACxB,KAAK,cAAgB,GACrB,KAAK,kBAAoB,EAAE,CAC3B,KAAK,cAAc,OAAO,CAC1B,KAAK,gBAAgB,OAAO,CAC5B,KAAK,4BAA8B,EAAE,EAEnC,KAAK,kBAAkB,SAAW,GAAK,CAAC,KAAK,gBAC/C,KAAK,kBAAoB,KAAK,QAAQ,yBACtC,KAAK,kBAAkB,QAAS,GAAS,CACvC,KAAK,cAAc,IAAI,EAAK,IAAK,EAAK,KAAK,EAC3C,EAEJ,IAAM,EAAM,KAAK,cAAgB,EAAI,KAAK,4BAA4B,OAAS,EAAI,KAAK,IAAI,GAAG,KAAK,4BAA4B,CAAG,EACnI,KAAK,4BAA8B,EAAE,CACjC,KAAK,eAAiB,KAAK,kBAAkB,SAAW,IAC1D,KAAK,cAAgB,IAEvB,IAAM,EAAe,KAAK,kBAAkB,MAAM,EAAG,EAAI,CACnD,EAAoB,MAAM,EAAM,CAAC,KACrC,IAAK,GACN,CACD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,IAAK,CAC5B,IAAM,EAAO,EAAa,GACtB,IACF,EAAc,EAAK,MAAQ,GAG/B,IAAK,IAAI,EAAI,EAAK,EAAI,EAAO,IAAK,CAChC,IAAM,EAAM,EAAW,EAAE,CACnB,EAAa,KAAK,gBAAgB,IAAI,EAAE,CAC1C,EACA,EACJ,GAAI,IAAe,IAAK,IAAK,KAAK,QAAQ,MAAQ,EAAG,CACnD,EAAO,EACP,IAAM,EAAY,EAAc,GAC1B,EAAa,IAAc,IAAK,GAA8B,IAAK,GAA/B,EAAa,GACvD,EAAQ,EAAa,EAAW,IAAM,KAAK,QAAQ,IAAM,EAAe,MACnE,CACL,IAAM,EAAsB,KAAK,QAAQ,QAAU,EAAI,EAAa,EAAI,GAAK,KAAK,uBAAuB,EAAc,EAAE,CACzH,EAAQ,EAAsB,EAAoB,IAAM,KAAK,QAAQ,IAAM,EAAe,EAC1F,EAAO,EAAsB,EAAoB,KAAO,EAAI,KAAK,QAAQ,MACrE,KAAK,QAAQ,MAAQ,GACvB,KAAK,gBAAgB,IAAI,EAAG,EAAK,CAGrC,IAAM,EAAe,EAAc,IAAI,EAAI,CACrC,EAAO,OAAO,GAAiB,SAAW,EAAe,KAAK,QAAQ,aAAa,EAAE,CACrF,EAAM,EAAQ,EACpB,EAAa,GAAK,CAChB,MAAO,EACP,QACA,OACA,MACA,MACA,OACD,CACD,EAAc,GAAQ,EAGxB,MADA,MAAK,kBAAoB,EAClB,GAET,CACE,IAAK,GACL,UAAa,KAAK,QAAQ,MAC3B,CACF,CACD,KAAK,eAAiB,MACd,CACJ,KAAK,iBAAiB,CACtB,KAAK,SAAS,CACd,KAAK,iBAAiB,CACtB,KAAK,QAAQ,MACd,EACA,EAAc,EAAW,EAAc,IAC/B,KAAK,MAAQ,EAAa,OAAS,GAAK,EAAY,EAAI,EAAe,CAC5E,eACA,YACA,eACA,QACD,CAAC,CAAG,KAEP,CACE,IAAK,GACL,UAAa,KAAK,QAAQ,MAC3B,CACF,CACD,KAAK,kBAAoB,MACjB,CACJ,IAAI,EAAa,KACb,EAAW,KACT,EAAQ,KAAK,gBAAgB,CAMnC,OALI,IACF,EAAa,EAAM,WACnB,EAAW,EAAM,UAEnB,KAAK,YAAY,WAAW,CAAC,KAAK,YAAa,EAAY,EAAS,CAAC,CAC9D,CACL,KAAK,QAAQ,eACb,KAAK,QAAQ,SACb,KAAK,QAAQ,MACb,EACA,EACD,GAEF,EAAgB,EAAU,EAAO,EAAY,IACrC,IAAe,MAAQ,IAAa,KAAO,EAAE,CAAG,EAAe,CACpE,aACA,WACA,WACA,QACD,CAAC,CAEJ,CACE,IAAK,GACL,UAAa,KAAK,QAAQ,MAC3B,CACF,CACD,KAAK,iBAAoB,GAAS,CAChC,IAAM,EAAgB,KAAK,QAAQ,eAC7B,EAAW,EAAK,aAAa,EAAc,CAOjD,OANK,EAME,SAAS,EAAU,GAAG,EAL3B,QAAQ,KACN,2BAA2B,EAAc,gCAC1C,CACM,KAIX,KAAK,0BAA6B,GAAU,CAE1C,GAAI,CAAC,KAAK,aAAe,KAAK,YAAY,WAAa,SACrD,MAAO,GAET,IAAM,EAAc,KAAK,YAAY,OAAgB,KAAK,wBAAwB,KAAK,YAAY,iBAAiB,EAAwB,MAC5I,GAAI,IAAgB,IAAK,IAAK,KAAK,MAAO,CACxC,IAAM,EAAa,KAAK,IACtB,KAAK,QAAQ,SACb,KAAK,MAAM,KAAK,MAAM,SAAW,KAAK,MAAM,YAAc,EAAE,CAC7D,CACK,EAAW,KAAK,IAAI,EAAG,EAAc,EAAW,CAChD,EAAW,KAAK,IACpB,KAAK,QAAQ,MAAQ,EACrB,EAAc,EACf,CACD,OAAO,GAAS,GAAY,GAAS,EAEvC,MAAO,IAET,KAAK,eAAkB,GAAS,CAC9B,GAAI,CAAC,EAAM,CACT,KAAK,cAAc,SAAS,EAAQ,IAAS,CACtC,EAAO,cACV,KAAK,SAAS,UAAU,EAAO,CAC/B,KAAK,cAAc,OAAO,EAAK,GAEjC,CACF,OAEF,IAAM,EAAQ,KAAK,iBAAiB,EAAK,CACnC,EAAM,KAAK,QAAQ,WAAW,EAAM,CACpC,EAAW,KAAK,cAAc,IAAI,EAAI,CACxC,IAAa,IACX,GACF,KAAK,SAAS,UAAU,EAAS,CAEnC,KAAK,SAAS,QAAQ,EAAK,CAC3B,KAAK,cAAc,IAAI,EAAK,EAAK,GAE9B,CAAC,KAAK,aAAe,KAAK,cAAgB,KAAK,0BAA0B,EAAM,EAClF,KAAK,WAAW,EAAO,KAAK,QAAQ,eAAe,EAAM,IAAK,GAAG,KAAK,CAAC,EAG3E,KAAK,YAAc,EAAO,IAAS,CAEjC,IAAM,EAAO,KAAK,kBAAkB,GACpC,GAAI,CAAC,EAAM,OAEX,IAAM,EAAQ,GADG,KAAK,cAAc,IAAI,EAAK,IAAI,EAAI,EAAK,MAEtD,IAAU,IACD,KAAK,aAAmC,WAAc,WAAa,KAAK,6CAA+C,IAAK,GAAyE,EAAK,MAAQ,KAAK,iBAAiB,CAAG,KAAK,kBAAhH,KAAK,2CAA2C,EAAM,EAAO,KAAK,GAI3M,KAAK,gBAAgB,KAAK,iBAAiB,CAAE,CAC3C,YAAa,KAAK,mBAAqB,EACvC,SAAU,IAAK,GAChB,CAAC,CAEJ,KAAK,4BAA4B,KAAK,EAAK,MAAM,CACjD,KAAK,cAAgB,IAAI,IAAI,KAAK,cAAc,IAAI,EAAK,IAAK,EAAK,CAAC,CACpE,KAAK,OAAO,GAAM,GAGtB,KAAK,gBAAkB,MACf,CAAC,KAAK,mBAAmB,CAAE,KAAK,iBAAiB,CAAC,EACvD,EAAS,IAAiB,CACzB,IAAM,EAAe,EAAE,CACvB,IAAK,IAAI,EAAI,EAAG,EAAM,EAAQ,OAAQ,EAAI,EAAK,IAAK,CAElD,IAAM,EAAc,EADV,EAAQ,IAElB,EAAa,KAAK,EAAY,CAEhC,OAAO,GAET,CACE,IAAK,GACL,UAAa,KAAK,QAAQ,MAC3B,CACF,CACD,KAAK,wBAA2B,GAAW,CACzC,IAAM,EAAe,KAAK,iBAAiB,CACvC,KAAa,SAAW,EAG5B,OAAO,EACL,EAAa,EACX,EACA,EAAa,OAAS,EACrB,GAAU,EAAa,EAAa,GAAO,CAAC,MAC7C,EACD,EACF,EAEH,KAAK,uBAA2B,CAC9B,GAAI,CAAC,KAAK,cAAe,MAAO,GAChC,GAAI,iBAAkB,KAAK,cACzB,OAAO,KAAK,QAAQ,WAAa,KAAK,cAAc,YAAc,KAAK,cAAc,YAAc,KAAK,cAAc,aAAe,KAAK,cAAc,aACnJ,CACL,IAAM,EAAM,KAAK,cAAc,SAAS,gBACxC,OAAO,KAAK,QAAQ,WAAa,EAAI,YAAc,KAAK,cAAc,WAAa,EAAI,aAAe,KAAK,cAAc,cAG7H,KAAK,uBAAyB,EAAU,EAAO,EAAW,IAAM,CAC9D,GAAI,CAAC,KAAK,cAAe,MAAO,GAChC,IAAM,EAAO,KAAK,SAAS,CACrB,EAAe,KAAK,iBAAiB,CACvC,IAAU,SACZ,EAAQ,GAAY,EAAe,EAAO,MAAQ,SAEhD,IAAU,SACZ,IAAa,EAAW,GAAQ,EACvB,IAAU,QACnB,GAAY,GAEd,IAAM,EAAY,KAAK,oBAAoB,CAC3C,OAAO,KAAK,IAAI,KAAK,IAAI,EAAW,EAAS,CAAE,EAAE,EAEnD,KAAK,mBAAqB,EAAO,EAAQ,SAAW,CAClD,EAAQ,KAAK,IAAI,EAAG,KAAK,IAAI,EAAO,KAAK,QAAQ,MAAQ,EAAE,CAAC,CAC5D,IAAM,EAAO,KAAK,SAAS,CACrB,EAAe,KAAK,iBAAiB,CACrC,EAAO,KAAK,kBAAkB,GACpC,GAAI,CAAC,EAAM,OACX,GAAI,IAAU,OACZ,GAAI,EAAK,KAAO,EAAe,EAAO,KAAK,QAAQ,iBACjD,EAAQ,cACC,EAAK,OAAS,EAAe,KAAK,QAAQ,mBACnD,EAAQ,aAER,MAAO,CAAC,EAAc,EAAM,CAGhC,GAAI,IAAU,OAAS,IAAU,KAAK,QAAQ,MAAQ,EACpD,MAAO,CAAC,KAAK,oBAAoB,CAAE,EAAM,CAE3C,IAAM,EAAW,IAAU,MAAQ,EAAK,IAAM,KAAK,QAAQ,iBAAmB,EAAK,MAAQ,KAAK,QAAQ,mBACxG,MAAO,CACL,KAAK,sBAAsB,EAAU,EAAO,EAAK,KAAK,CACtD,EACD,EAEH,KAAK,gBAAkB,EAAU,CAAE,QAAQ,QAAS,WAAW,QAAW,EAAE,GAAK,CAC/E,IAAM,EAAS,KAAK,sBAAsB,EAAU,EAAM,CAE1D,KAAK,YAAc,CACjB,MAAO,KACP,QACA,WACA,UALU,KAAK,KAAK,CAMpB,iBAAkB,EAClB,aAAc,EACf,CACD,KAAK,gBAAgB,EAAQ,CAAE,YAAa,IAAK,GAAG,WAAU,CAAC,CAC/D,KAAK,yBAAyB,EAEhC,KAAK,eAAiB,EAAO,CAC3B,MAAO,EAAe,OACtB,WAAW,QACT,EAAE,GAAK,CACT,EAAQ,KAAK,IAAI,EAAG,KAAK,IAAI,EAAO,KAAK,QAAQ,MAAQ,EAAE,CAAC,CAC5D,IAAM,EAAa,KAAK,kBAAkB,EAAO,EAAa,CAC9D,GAAI,CAAC,EACH,OAEF,GAAM,CAAC,EAAQ,GAAS,EAClB,EAAM,KAAK,KAAK,CACtB,KAAK,YAAc,CACjB,QACA,QACA,WACA,UAAW,EACX,iBAAkB,EAClB,aAAc,EACf,CACD,KAAK,gBAAgB,EAAQ,CAAE,YAAa,IAAK,GAAG,WAAU,CAAC,CAC/D,KAAK,yBAAyB,EAEhC,KAAK,UAAY,EAAO,CAAE,WAAW,QAAW,EAAE,GAAK,CACrD,IAAM,EAAS,KAAK,iBAAiB,CAAG,EAExC,KAAK,YAAc,CACjB,MAAO,KACP,MAAO,QACP,WACA,UALU,KAAK,KAAK,CAMpB,iBAAkB,EAClB,aAAc,EACf,CACD,KAAK,gBAAgB,EAAQ,CAAE,YAAa,IAAK,GAAG,WAAU,CAAC,CAC/D,KAAK,yBAAyB,EAEhC,KAAK,iBAAqB,CAExB,IAAM,EAAe,KAAK,iBAAiB,CACvC,EACJ,GAAI,EAAa,SAAW,EAC1B,EAAM,KAAK,QAAQ,qBACV,KAAK,QAAQ,QAAU,EAChC,EAAa,EAAa,EAAa,OAAS,IAA0B,KAAQ,MAC7E,CACL,IAAM,EAAY,MAAM,KAAK,QAAQ,MAAM,CAAC,KAAK,KAAK,CAClD,EAAW,EAAa,OAAS,EACrC,KAAO,GAAY,GAAK,EAAU,KAAM,GAAQ,IAAQ,KAAK,EAAE,CAC7D,IAAM,EAAO,EAAa,GACtB,EAAU,EAAK,QAAU,OAC3B,EAAU,EAAK,MAAQ,EAAK,KAE9B,IAEF,EAAM,KAAK,IAAI,GAAG,EAAU,OAAQ,GAAQ,IAAQ,KAAK,CAAC,CAE5D,OAAO,KAAK,IACV,EAAM,KAAK,QAAQ,aAAe,KAAK,QAAQ,WAC/C,EACD,EAEH,KAAK,iBAAmB,EAAQ,CAC9B,cACA,cACI,CACJ,KAAK,QAAQ,WAAW,EAAQ,CAAE,WAAU,cAAa,CAAE,KAAK,EAElE,KAAK,YAAgB,CACnB,KAAK,cAAgC,IAAI,IACzC,KAAK,gBAAkC,IAAI,IAC3C,KAAK,OAAO,GAAM,EAEpB,KAAK,WAAW,EAAK,CAEvB,yBAA0B,CACxB,GAAI,CAAC,KAAK,aAAc,CACtB,KAAK,YAAc,KACnB,OAEE,AACJ,KAAK,QAAQ,KAAK,aAAa,0BAA4B,CACzD,KAAK,MAAQ,KACb,KAAK,iBAAiB,EACtB,CAEJ,iBAAkB,CAGhB,GAFI,CAAC,KAAK,aAEN,CADO,KAAK,cACP,OAET,GAAI,KAAK,KAAK,CAAG,KAAK,YAAY,UADT,IACuC,CAC9D,KAAK,YAAc,KACnB,OAEF,IAAM,EAAa,KAAK,YAAY,OAAS,KAAgF,IAAK,GAA9E,KAAK,kBAAkB,KAAK,YAAY,MAAO,KAAK,YAAY,MAAM,CACpH,EAAe,EAAa,EAAW,GAAK,KAAK,YAAY,iBAE7D,EAAgB,IAAiB,KAAK,YAAY,iBACxD,GAAI,CAAC,GAAiB,EAAY,EAAc,KAAK,iBAAiB,CAAC,CAErE,IADA,KAAK,YAAY,eACb,KAAK,YAAY,cAAgB,EAAe,CAClD,KAAK,YAAc,KACnB,aAGF,KAAK,YAAY,aAAe,EAC5B,IACF,KAAK,YAAY,iBAAmB,EACpC,KAAK,YAAY,SAAW,OAC5B,KAAK,gBAAgB,EAAc,CACjC,YAAa,IAAK,GAClB,SAAU,OACX,CAAC,EAGN,KAAK,yBAAyB,GAG5B,GAA2B,EAAK,EAAM,EAAiB,IAAU,CACrE,KAAO,GAAO,GAAM,CAClB,IAAM,GAAU,EAAM,GAAQ,EAAI,EAC5B,EAAe,EAAgB,EAAO,CAC5C,GAAI,EAAe,EACjB,EAAM,EAAS,UACN,EAAe,EACxB,EAAO,EAAS,OAEhB,OAAO,EAMT,OAHE,EAAM,EACD,EAAM,EAEN,GAGX,SAAS,EAAe,CACtB,eACA,YACA,eACA,SACC,CACD,IAAM,EAAY,EAAa,OAAS,EAClC,EAAa,GAAU,EAAa,GAAO,MACjD,GAAI,EAAa,QAAU,EACzB,MAAO,CACL,WAAY,EACZ,SAAU,EACX,CAEH,IAAI,EAAa,EACf,EACA,EACA,EACA,EACD,CACG,EAAW,EACf,GAAI,IAAU,EACZ,KAAO,EAAW,GAAa,EAAa,GAAU,IAAM,EAAe,GACzE,YAEO,EAAQ,EAAG,CACpB,IAAM,EAAa,MAAM,EAAM,CAAC,KAAK,EAAE,CACvC,KAAO,EAAW,GAAa,EAAW,KAAM,GAAQ,EAAM,EAAe,EAAU,EAAE,CACvF,IAAM,EAAO,EAAa,GAC1B,EAAW,EAAK,MAAQ,EAAK,IAC7B,IAEF,IAAM,EAAe,MAAM,EAAM,CAAC,KAAK,EAAe,EAAU,CAChE,KAAO,GAAc,GAAK,EAAa,KAAM,GAAQ,GAAO,EAAa,EAAE,CACzE,IAAM,EAAO,EAAa,GAC1B,EAAa,EAAK,MAAQ,EAAK,MAC/B,IAEF,EAAa,KAAK,IAAI,EAAG,EAAa,EAAa,EAAM,CACzD,EAAW,KAAK,IAAI,EAAW,GAAY,EAAQ,EAAI,EAAW,GAAO,CAE3E,MAAO,CAAE,aAAY,WAAU,CCh5BjC,IAAM,EAA4B,OAAO,SAAa,IAAA,EAAoB,gBAAA,EAAwB,UAClG,SAAS,EAAmB,CAC1B,eAAe,GACf,GAAG,GACF,CACD,IAAM,EAAA,EAAiB,gBAAkB,EAAE,EAAG,EAAE,CAAC,CAAC,GAC5C,EAAkB,CACtB,GAAG,EACH,UAAW,EAAW,IAAS,CAC7B,IAAI,EACA,GAAgB,GAClB,EAAA,EAAA,WAAU,EAAS,CAEnB,GAAU,EAEX,EAAK,EAAQ,WAAa,MAAgB,EAAG,KAAK,EAAS,EAAW,EAAK,EAE/E,CACK,CAAC,GAAA,EAAkB,aACjB,IAAI,EAAY,EAAgB,CACvC,CAQD,OAPA,EAAS,WAAW,EAAgB,CACpC,MACS,EAAS,WAAW,CAC1B,EAAE,CAAC,CACN,MACS,EAAS,aAAa,CAC7B,CACK,EAET,SAAS,EAAe,EAAS,CAC/B,OAAO,EAAmB,CACxB,qBACA,uBACA,WAAY,EACZ,GAAG,EACJ,CAAC,WCrBJ,SAAgB,EAAW,CAAE,UAAS,kBAAiB,YAA6B,CAClF,IAAM,GAAA,EAAA,EAAA,aAAuB,EAAS,EAAQ,CAAE,CAAC,EAAQ,CAAC,CACpD,CAAC,EAAM,IAAA,EAAA,EAAA,cAAsC,EAAO,KAAK,CACzD,CAAC,EAAS,IAAA,EAAA,EAAA,UAAqC,EAAE,CAAC,CAClD,GAAA,EAAA,EAAA,QAAmC,KAAK,CACxC,GAAA,EAAA,EAAA,QAAyB,GAAM,EAGrC,EAAA,EAAA,eAAgB,CACd,GAAI,EAAgB,QAAS,CAC3B,EAAgB,QAAU,GAC1B,OAEF,EAAQ,EAAO,KAAK,EACnB,CAAC,EAAO,KAAK,CAAC,CAEjB,IAAM,EAAU,EAAO,QAEjB,GAAA,EAAA,EAAA,cACH,EAAkB,EAAkB,IAAkB,CACrD,EAAS,GAAS,CAChB,IAAM,EAAO,EAAK,KAAK,EAAG,IAAO,IAAM,EAAW,CAAC,GAAG,EAAE,CAAG,EAAG,CAI9D,MAHA,GAAK,GAAW,GAAY,EAC5B,EAAgB,QAAU,GAC1B,EAAgB,EAAa,EAAS,EAAK,CAAC,CACrC,GACP,EAEJ,CAAC,EAAS,EAAgB,CAC3B,CAqBK,EAAQ,EAAc,CAC1B,KAAM,EACN,SAAA,EAAA,EAAA,aAnBE,EAAQ,KAAK,EAAG,KAAO,CACrB,GAAI,OAAO,IACX,OAAQ,GAAK,UAAU,EAAI,IAC3B,WAAa,GAAkB,EAAI,IAAM,GACzC,MAAO,CAAE,MAAK,eAAA,EAAA,EAAA,KACX,EAAD,CACE,MAAO,GAAU,CACjB,OAAS,GAAM,EAAW,EAAI,MAAO,EAAG,EAAE,CAChC,WACV,CAAA,CAEJ,KAAM,IACN,QAAS,GACV,EAAE,CACL,CAAC,EAAS,EAAY,EAAS,CAChC,CAKC,MAAO,CAAE,UAAS,CAClB,gBAAiB,EACjB,gBAAiB,GAAiB,CAClC,kBAAmB,GAAmB,CACtC,qBAAsB,GACtB,iBAAkB,WACnB,CAAC,CAEI,CAAE,KAAM,GAAc,EAAM,aAAa,CAEzC,EAAc,EAAe,CACjC,MAAO,EAAU,OACjB,qBAAwB,EAAU,QAClC,iBAAoB,GACpB,SAAU,GACX,CAAC,CAUF,OARI,EAAQ,SAAW,GACrB,EAAA,EAAA,KACG,MAAD,CAAK,UAAU,iFAAwE,iBAEjF,CAAA,EAIV,EAAA,EAAA,KACG,MAAD,CAAK,IAAK,EAAW,UAAU,2CAC5B,QAAD,CAAO,UAAU,oDAAjB,EAAA,EAAA,EAAA,KACG,QAAD,CAAO,UAAU,wEACd,EAAM,iBAAiB,CAAC,IAAK,IAAA,EAAA,EAAA,KAC3B,KAAD,CAAgB,UAAU,uBACvB,EAAG,QAAQ,IAAK,IAAA,EAAA,EAAA,MACd,KAAD,CAEE,UAAU,uJACV,MAAO,CAAE,MAAO,EAAO,SAAS,CAAE,SAAU,EAAO,SAAS,CAAE,CAC9D,QAAS,EAAO,OAAO,yBAAyB,UAJlD,EAAA,EAAA,EAAA,MAMG,MAAD,CAAK,UAAU,mCAAf,WACG,OAAD,CAAM,UAAU,oBACb,EAAW,EAAO,OAAO,UAAU,OAAQ,EAAO,YAAY,CAAC,CAC3D,CAAA,CACN,EAAO,OAAO,aAAa,GAAK,QAAA,EAAA,EAAA,KAAU,EAAD,CAAS,UAAU,kBAAoB,CAAA,CAChF,EAAO,OAAO,aAAa,GAAK,SAAA,EAAA,EAAA,KAAW,EAAD,CAAW,UAAU,kBAAoB,CAAA,CAChF,aAEL,MAAD,CACE,YAAa,EAAO,kBAAkB,CACtC,aAAc,EAAO,kBAAkB,CACvC,QAAU,GAAM,EAAE,iBAAiB,CACnC,UAAU,4FACV,CAAA,CACC,EAnBE,EAAO,GAmBT,CACL,CACC,CAxBI,EAAG,GAwBP,CACL,CACI,CAAA,EAAA,EAAA,EAAA,KACP,QAAD,CAAO,MAAO,CAAE,OAAQ,EAAY,cAAc,CAAE,SAAU,WAAY,QAAS,QAAS,UACzF,EAAY,iBAAiB,CAAC,IAAK,GAAS,CAC3C,IAAM,EAAM,EAAU,EAAK,OAC3B,OAAA,EAAA,EAAA,KACG,KAAD,CAEE,aAAY,EAAK,MACjB,IAAM,GAAS,EAAY,eAAe,EAAK,CAC/C,MAAO,CACL,SAAU,WACV,IAAK,EACL,KAAM,EACN,MAAO,OACP,UAAW,cAAc,EAAK,MAAM,KACpC,QAAS,OACV,UAEA,EAAI,iBAAiB,CAAC,IAAK,IAAA,EAAA,EAAA,KACzB,KAAD,CAEE,UAAW,mFAAmF,EAAW,kCAAoC,aAC7I,MAAO,CAAE,MAAO,EAAK,OAAO,SAAS,CAAE,SAAU,EAAK,OAAO,SAAS,CAAE,UAEvE,EAAW,EAAK,OAAO,UAAU,KAAM,EAAK,YAAY,CAAC,CACvD,CALE,EAAK,GAKP,CACL,CACC,CArBE,EAAI,GAqBN,EAEP,CACI,CAAA,CACF,GACJ,CAAA,CAIV,SAAS,EAAQ,CAAE,QAAO,SAAQ,YAAgF,CAChH,GAAM,CAAC,EAAS,IAAA,EAAA,EAAA,UAAuB,GAAM,CACvC,CAAC,EAAO,IAAA,EAAA,EAAA,UAAqB,EAAM,CACnC,GAAA,EAAA,EAAA,QAA0C,KAAK,CAG/C,GAAA,EAAA,EAAA,aAA0B,GAAmC,CAC5D,IACL,EAAG,MAAM,OAAS,OAClB,EAAG,MAAM,OAAS,GAAG,EAAG,aAAa,MACpC,EAAE,CAAC,CAyBN,OAvBA,EAAA,EAAA,eAAgB,CACV,GAAW,EAAY,UACzB,EAAY,QAAQ,OAAO,CAC3B,EAAW,EAAY,QAAQ,GAEhC,CAAC,EAAS,EAAW,CAAC,CAEpB,GAgBL,EAAA,EAAA,KACG,WAAD,CACE,IAAK,EACL,UAAU,0GACV,MAAO,CAAE,UANO,EAAM,SAAS;EAAK,CAMF,GAAK,GAAI,CAC3C,KAAM,EACN,MAAO,EACP,SAAW,GAAM,CACf,EAAS,EAAE,OAAO,MAAM,CACxB,EAAW,EAAE,OAAO,EAEtB,WAAc,CACZ,EAAW,GAAM,CACb,IAAU,GAAO,EAAO,EAAM,EAEpC,UAAY,GAAM,CACZ,EAAE,MAAQ,SAAW,CAAC,EAAE,UAE1B,EAAE,gBAAgB,CAClB,EAAW,GAAM,CACb,IAAU,GAAO,EAAO,EAAM,EACzB,EAAE,MAAQ,WACnB,EAAW,GAAM,CACjB,EAAS,EAAM,GAGnB,CAAA,EAzCF,EAAA,EAAA,KACG,OAAD,CACE,UAAW,qBAAqB,EAAW,kCAAoC,aAC/E,YAAe,CACb,EAAS,EAAM,CACf,EAAW,GAAK,WAGjB,GAAS,OACL,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"data-grid-overlay-editor-C1UUm7Ob.js","names":["styled"],"sources":["../../../node_modules/.bun/@glideapps+glide-data-grid@6.0.3+20f18e448220509f/node_modules/@glideapps/glide-data-grid/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor-style.js","../../../node_modules/.bun/@glideapps+glide-data-grid@6.0.3+20f18e448220509f/node_modules/@glideapps/glide-data-grid/dist/esm/internal/data-grid-overlay-editor/use-stay-on-screen.js","../../../node_modules/.bun/@glideapps+glide-data-grid@6.0.3+20f18e448220509f/node_modules/@glideapps/glide-data-grid/dist/esm/internal/data-grid-overlay-editor/data-grid-overlay-editor.js"],"sourcesContent":["import { styled } from \"@linaria/react\";\nconst _exp2 = /*#__PURE__*/() => p => p.targetX;\nconst _exp3 = /*#__PURE__*/() => p => p.targetY;\nconst _exp4 = /*#__PURE__*/() => p => p.targetWidth;\nconst _exp5 = /*#__PURE__*/() => p => p.targetHeight;\nconst _exp6 = /*#__PURE__*/() => p => p.targetY + 10;\nconst _exp7 = /*#__PURE__*/() => p => Math.max(0, (p.targetHeight - 28) / 2);\nexport const DataGridOverlayEditorStyle = /*#__PURE__*/styled('div')({\n name: \"DataGridOverlayEditorStyle\",\n class: \"gdg-d19meir1\",\n propsAsIs: false,\n vars: {\n \"d19meir1-0\": [_exp3(), \"px\"],\n \"d19meir1-1\": [_exp2(), \"px\"],\n \"d19meir1-2\": [_exp4(), \"px\"],\n \"d19meir1-3\": [_exp5(), \"px\"],\n \"d19meir1-4\": [_exp6(), \"px\"],\n \"d19meir1-5\": [_exp7(), \"px\"]\n }\n});\n\n","import * as React from \"react\";\nfunction useRefState() {\n const [refState, setRefState] = React.useState();\n return [refState ?? undefined, setRefState];\n}\nexport function useStayOnScreen() {\n const [ref, setRef] = useRefState();\n const [xOffset, setXOffset] = React.useState(0);\n const [isIntersecting, setIsIntersecting] = React.useState(true);\n React.useLayoutEffect(() => {\n if (ref === undefined)\n return;\n if (!(\"IntersectionObserver\" in window))\n return;\n const observer = new IntersectionObserver(ents => {\n if (ents.length === 0)\n return;\n setIsIntersecting(ents[0].isIntersecting);\n }, { threshold: 1 });\n observer.observe(ref);\n return () => observer.disconnect();\n }, [ref]);\n React.useEffect(() => {\n if (isIntersecting || ref === undefined)\n return;\n let rafHandle;\n const fn = () => {\n const { right: refRight } = ref.getBoundingClientRect();\n setXOffset(cv => Math.min(cv + window.innerWidth - refRight - 10, 0));\n rafHandle = requestAnimationFrame(fn);\n };\n rafHandle = requestAnimationFrame(fn);\n return () => {\n if (rafHandle !== undefined) {\n cancelAnimationFrame(rafHandle);\n }\n };\n }, [ref, isIntersecting]);\n const style = React.useMemo(() => {\n return { transform: `translateX(${xOffset}px)` };\n }, [xOffset]);\n return {\n ref: setRef,\n style,\n };\n}\n//# sourceMappingURL=use-stay-on-screen.js.map","import * as React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport ClickOutsideContainer from \"../click-outside-container/click-outside-container.js\";\nimport { makeCSSStyle, ThemeContext } from \"../../common/styles.js\";\nimport { isEditableGridCell, isInnerOnlyCell, isObjectEditorCallbackResult, } from \"../data-grid/data-grid-types.js\";\nimport { DataGridOverlayEditorStyle } from \"./data-grid-overlay-editor-style.js\";\nimport { useStayOnScreen } from \"./use-stay-on-screen.js\";\nconst DataGridOverlayEditor = p => {\n const { target, content, onFinishEditing: onFinishEditingIn, forceEditMode, initialValue, imageEditorOverride, markdownDivCreateNode, highlight, className, theme, id, cell, bloom, validateCell, getCellRenderer, provideEditor, isOutsideClick, } = p;\n const [tempValue, setTempValueRaw] = React.useState(forceEditMode ? content : undefined);\n const lastValueRef = React.useRef(tempValue ?? content);\n lastValueRef.current = tempValue ?? content;\n const [isValid, setIsValid] = React.useState(() => {\n if (validateCell === undefined)\n return true;\n return !(isEditableGridCell(content) && validateCell?.(cell, content, lastValueRef.current) === false);\n });\n const onFinishEditing = React.useCallback((newCell, movement) => {\n onFinishEditingIn(isValid ? newCell : undefined, movement);\n }, [isValid, onFinishEditingIn]);\n const setTempValue = React.useCallback((newVal) => {\n if (validateCell !== undefined && newVal !== undefined && isEditableGridCell(newVal)) {\n const validResult = validateCell(cell, newVal, lastValueRef.current);\n if (validResult === false) {\n setIsValid(false);\n }\n else if (typeof validResult === \"object\") {\n newVal = validResult;\n setIsValid(true);\n }\n else {\n setIsValid(true);\n }\n }\n setTempValueRaw(newVal);\n }, [cell, validateCell]);\n const finished = React.useRef(false);\n const customMotion = React.useRef(undefined);\n const onClickOutside = React.useCallback(() => {\n onFinishEditing(tempValue, [0, 0]);\n finished.current = true;\n }, [tempValue, onFinishEditing]);\n const onEditorFinished = React.useCallback((newValue, movement) => {\n onFinishEditing(newValue, movement ?? customMotion.current ?? [0, 0]);\n finished.current = true;\n }, [onFinishEditing]);\n const onKeyDown = React.useCallback(async (event) => {\n let save = false;\n if (event.key === \"Escape\") {\n event.stopPropagation();\n event.preventDefault();\n customMotion.current = [0, 0];\n }\n else if (event.key === \"Enter\" && !event.shiftKey) {\n event.stopPropagation();\n event.preventDefault();\n customMotion.current = [0, 1];\n save = true;\n }\n else if (event.key === \"Tab\") {\n event.stopPropagation();\n event.preventDefault();\n customMotion.current = [event.shiftKey ? -1 : 1, 0];\n save = true;\n }\n window.setTimeout(() => {\n if (!finished.current && customMotion.current !== undefined) {\n onFinishEditing(save ? tempValue : undefined, customMotion.current);\n finished.current = true;\n }\n }, 0);\n }, [onFinishEditing, tempValue]);\n const targetValue = tempValue ?? content;\n const [editorProvider, useLabel] = React.useMemo(() => {\n if (isInnerOnlyCell(content))\n return [];\n const external = provideEditor?.(content);\n if (external !== undefined)\n return [external, false];\n return [getCellRenderer(content)?.provideEditor?.(content), false];\n }, [content, getCellRenderer, provideEditor]);\n const { ref, style: stayOnScreenStyle } = useStayOnScreen();\n let pad = true;\n let editor;\n let style = true;\n let styleOverride;\n if (editorProvider !== undefined) {\n pad = editorProvider.disablePadding !== true;\n style = editorProvider.disableStyling !== true;\n const isObjectEditor = isObjectEditorCallbackResult(editorProvider);\n if (isObjectEditor) {\n styleOverride = editorProvider.styleOverride;\n }\n const CustomEditor = isObjectEditor ? editorProvider.editor : editorProvider;\n editor = (React.createElement(CustomEditor, { isHighlighted: highlight, onChange: setTempValue, value: targetValue, initialValue: initialValue, onFinishedEditing: onEditorFinished, validatedSelection: isEditableGridCell(targetValue) ? targetValue.selectionRange : undefined, forceEditMode: forceEditMode, target: target, imageEditorOverride: imageEditorOverride, markdownDivCreateNode: markdownDivCreateNode, isValid: isValid, theme: theme }));\n }\n styleOverride = { ...styleOverride, ...stayOnScreenStyle };\n // Consider imperatively creating and adding the element to the dom?\n const portalElement = document.getElementById(\"portal\");\n if (portalElement === null) {\n // eslint-disable-next-line no-console\n console.error('Cannot open Data Grid overlay editor, because portal not found. Please add `<div id=\"portal\" />` as the last child of your `<body>`.');\n return null;\n }\n let classWrap = style ? \"gdg-style\" : \"gdg-unstyle\";\n if (!isValid) {\n classWrap += \" gdg-invalid\";\n }\n if (pad) {\n classWrap += \" gdg-pad\";\n }\n const bloomX = bloom?.[0] ?? 1;\n const bloomY = bloom?.[1] ?? 1;\n return createPortal(React.createElement(ThemeContext.Provider, { value: theme },\n React.createElement(ClickOutsideContainer, { style: makeCSSStyle(theme), className: className, onClickOutside: onClickOutside, isOutsideClick: isOutsideClick },\n React.createElement(DataGridOverlayEditorStyle, { ref: ref, id: id, className: classWrap, style: styleOverride, as: useLabel === true ? \"label\" : undefined, targetX: target.x - bloomX, targetY: target.y - bloomY, targetWidth: target.width + bloomX * 2, targetHeight: target.height + bloomY * 2 },\n React.createElement(\"div\", { className: \"gdg-clip-region\", onKeyDown: onKeyDown }, editor)))), portalElement);\n};\nexport default DataGridOverlayEditor;\n//# sourceMappingURL=data-grid-overlay-editor.js.map"],"x_google_ignoreList":[0,1,2],"mappings":"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"}