export declare const treeTemplate = "\"use client\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport styled, { css } from \"styled-components\";\nimport { Theme } from \"@/app/theme\";\nimport { Icon } from \"@/components/layout/Icon\";\nimport { thinScrollbar } from \"@/components/layout/SharedStyled\";\nimport type { TreeNode } from \"@/components/layout/TreeData\";\n\nconst TYPE_AHEAD_RESET_MS = 600;\n\ninterface FlatItem {\n node: TreeNode;\n parentId: string | null;\n}\n\n// The prose container styles every descendant \"ul li\" (bullet dots, padding,\n// min-height) at (0,1,2)+ specificity, so the tree's own lists and items use\n// && to reach (0,2,0) and win.\nconst StyledTree = styled.ul<{ theme: Theme }>`\n && {\n background: ${({ theme }) => theme.colors.light};\n border: solid 1px ${({ theme }) => theme.colors.grayLight};\n border-radius: ${({ theme }) => theme.spacing.radius.lg};\n padding: 12px;\n margin: 0;\n width: 100%;\n list-style: none;\n overflow-x: auto;\n ${thinScrollbar};\n }\n`;\n\nconst StyledTreeGroup = styled.ul<{ theme: Theme }>`\n && {\n list-style: none;\n margin: 0 0 0 13px;\n padding: 0 0 0 9px;\n border-left: solid 1px ${({ theme }) => theme.colors.grayLight};\n }\n`;\n\nconst StyledTreeRow = styled.span<{ theme: Theme; $isInteractive: boolean }>`\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 6px;\n border-radius: ${({ theme }) => theme.spacing.radius.xs};\n transition: background 0.2s ease;\n\n ${({ $isInteractive, theme }) =>\n $isInteractive &&\n css`\n cursor: pointer;\n\n &:hover {\n background: ${theme.colors.grayLight};\n }\n `}\n`;\n\nconst StyledTreeItem = styled.li<{ theme: Theme }>`\n && {\n display: block;\n padding: 0;\n margin: 0;\n min-height: 0;\n outline: none;\n }\n\n &&::before {\n content: none;\n }\n\n &:focus-visible > ${StyledTreeRow} {\n box-shadow: 0 0 0 2px ${({ theme }) => theme.colors.primaryLight};\n }\n`;\n\nconst StyledTreeChevron = styled.span<{ theme: Theme; $isOpen: boolean }>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 16px;\n height: 16px;\n color: ${({ theme }) => theme.colors.gray};\n transition: transform 0.2s ease;\n\n ${({ $isOpen }) =>\n $isOpen &&\n css`\n transform: rotate(90deg);\n `}\n`;\n\nconst StyledTreeSpacer = styled.span`\n flex-shrink: 0;\n width: 16px;\n height: 16px;\n`;\n\nconst StyledTreeIcon = styled.span<{ theme: Theme }>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n color: ${({ theme }) => theme.colors.gray};\n`;\n\nconst StyledTreeName = styled.span<{ theme: Theme; $isFolder: boolean }>`\n font-family: ${({ theme }) => theme.fonts.mono};\n font-size: 14px;\n line-height: 1.6;\n white-space: nowrap;\n color: ${({ theme, $isFolder }) =>\n $isFolder ? theme.colors.dark : theme.colors.grayDark};\n`;\n\ninterface TreeProps {\n nodes: TreeNode[];\n}\n\n// Renders the TreeNode data that the Tree compound in MDXComponents parses\n// out of either authoring syntax. Receiving plain data (never elements)\n// keeps the server/client boundary trivially serializable.\nfunction Tree({ nodes }: TreeProps) {\n // Open state is stored as overrides on top of each folder's defaultOpen so\n // nodes parsed after a re-render keep their authored state until toggled.\n const [overrides, setOverrides] = useState>({});\n const [focusedId, setFocusedId] = useState(null);\n const itemRefs = useRef>(new Map());\n const typeAheadBuffer = useRef(\"\");\n const typeAheadTimer = useRef | null>(null);\n\n useEffect(\n () => () => {\n if (typeAheadTimer.current) clearTimeout(typeAheadTimer.current);\n },\n [],\n );\n\n const isOpen = useCallback(\n (node: TreeNode) => overrides[node.id] ?? node.defaultOpen,\n [overrides],\n );\n\n // The flattened list of currently visible items drives keyboard\n // navigation in document order.\n const visible = useMemo(() => {\n const out: FlatItem[] = [];\n const walk = (list: TreeNode[], parentId: string | null) => {\n list.forEach((node) => {\n out.push({ node, parentId });\n if (node.isFolder && isOpen(node)) {\n walk(node.children, node.id);\n }\n });\n };\n walk(nodes, null);\n return out;\n }, [nodes, isOpen]);\n\n // Roving tabindex: exactly one visible item is tabbable. Falls back to the\n // first item when focus points at a node hidden by a collapsed ancestor.\n const activeId = useMemo(() => {\n if (focusedId && visible.some((item) => item.node.id === focusedId)) {\n return focusedId;\n }\n return visible.length > 0 ? visible[0].node.id : null;\n }, [focusedId, visible]);\n\n const setOpen = (node: TreeNode, open: boolean) => {\n if (!node.isFolder || !node.openable) return;\n setOverrides((prev) => ({ ...prev, [node.id]: open }));\n };\n\n const focusItem = (id: string) => {\n setFocusedId(id);\n itemRefs.current.get(id)?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.ctrlKey || event.metaKey || event.altKey) return;\n const index = visible.findIndex((item) => item.node.id === activeId);\n if (index < 0) return;\n const current = visible[index];\n const node = current.node;\n const key = event.key;\n\n if (key === \"ArrowDown\") {\n event.preventDefault();\n if (index + 1 < visible.length) focusItem(visible[index + 1].node.id);\n } else if (key === \"ArrowUp\") {\n event.preventDefault();\n if (index > 0) focusItem(visible[index - 1].node.id);\n } else if (key === \"ArrowRight\") {\n event.preventDefault();\n if (!node.isFolder) return;\n if (!isOpen(node)) setOpen(node, true);\n else if (node.children.length > 0) focusItem(node.children[0].id);\n } else if (key === \"ArrowLeft\") {\n event.preventDefault();\n if (node.isFolder && isOpen(node) && node.openable) {\n setOpen(node, false);\n } else if (current.parentId) {\n focusItem(current.parentId);\n }\n } else if (key === \"Home\") {\n event.preventDefault();\n focusItem(visible[0].node.id);\n } else if (key === \"End\") {\n event.preventDefault();\n focusItem(visible[visible.length - 1].node.id);\n } else if (key === \"Enter\" || key === \" \") {\n event.preventDefault();\n setOpen(node, !isOpen(node));\n } else if (key === \"*\") {\n event.preventDefault();\n setOverrides((prev) => {\n const next = { ...prev };\n visible.forEach((item) => {\n if (\n item.parentId === current.parentId &&\n item.node.isFolder &&\n item.node.openable\n ) {\n next[item.node.id] = true;\n }\n });\n return next;\n });\n } else if (key.length === 1 && key !== \" \") {\n // Type-ahead: buffered characters jump to the next item whose name\n // starts with what was typed.\n if (typeAheadTimer.current) clearTimeout(typeAheadTimer.current);\n typeAheadBuffer.current += key.toLowerCase();\n typeAheadTimer.current = setTimeout(() => {\n typeAheadBuffer.current = \"\";\n }, TYPE_AHEAD_RESET_MS);\n const query = typeAheadBuffer.current;\n const start = query.length === 1 ? index + 1 : index;\n for (let offset = 0; offset < visible.length; offset++) {\n const item = visible[(start + offset) % visible.length];\n if (item.node.name.toLowerCase().startsWith(query)) {\n focusItem(item.node.id);\n break;\n }\n }\n }\n };\n\n const renderItems = (list: TreeNode[], level: number) =>\n list.map((node, index) => {\n const open = node.isFolder && isOpen(node);\n const isInteractive = node.isFolder && node.openable;\n return (\n {\n if (element) itemRefs.current.set(node.id, element);\n else itemRefs.current.delete(node.id);\n }}\n onFocus={(event) => {\n // Focus events bubble through nested treeitems; without this a\n // child's focus would also mark every ancestor as focused.\n event.stopPropagation();\n setFocusedId(node.id);\n }}\n >\n {/* Safari does not reliably focus the item on click, so focus is\n set explicitly before toggling. */}\n {\n event.stopPropagation();\n focusItem(node.id);\n if (isInteractive) setOpen(node, !open);\n }}\n >\n {isInteractive ? (\n \n \n \n ) : (\n \n )}\n \n \n \n \n {node.name}\n \n \n {node.isFolder && open && node.children.length > 0 && (\n \n {renderItems(node.children, level + 1)}\n \n )}\n \n );\n });\n\n if (nodes.length === 0) return null;\n\n return (\n \n {renderItems(nodes, 1)}\n \n );\n}\n\nexport { Tree };\n";