// MNote debug /tree shell DOM patch and hydration helpers. export function patchTreeShellPageActiveDom(context) { if (context.mode !== "page") return; context.appElement.querySelectorAll('[data-rust-rendered-row="page"]').forEach((row) => { if (!(row instanceof HTMLElement)) return; const nodeId = context.normalizeText(row.dataset.nodeId); const isFocused = nodeId === context.focusedNodeId; row.dataset.active = String(nodeId === context.currentActiveDocumentId); row.dataset.focused = String(isFocused); row.tabIndex = isFocused ? 0 : -1; row.dataset.dropFeedback = String(context.activePageDropNodeId === nodeId); }); } export function patchTreeShellPageExpansionDom(context, nodeId) { if (context.mode !== "page") return false; const normalizedNodeId = context.normalizeText(nodeId); if (!normalizedNodeId) return false; const item = context.itemById.get(normalizedNodeId); if (!item) return false; const nodeElement = context.appElement.querySelector( `.tree-node[data-node-id="${CSS.escape(normalizedNodeId)}"]`, ); if (!(nodeElement instanceof HTMLElement)) return false; const row = nodeElement.querySelector( `:scope > .tree-row[data-node-id="${CSS.escape(normalizedNodeId)}"]`, ); const children = context.getSiblings(normalizedNodeId); const hasChildren = item.childCount > 0 && children.length > 0; const isExpanded = hasChildren && context.expanded.has(normalizedNodeId); if (row instanceof HTMLElement) { row.setAttribute("aria-expanded", hasChildren ? String(isExpanded) : "false"); const toggleButton = row.querySelector('[data-testid="tree-node-toggle"]'); if (toggleButton instanceof HTMLButtonElement) { toggleButton.textContent = isExpanded ? "▾" : "▸"; toggleButton.setAttribute( "aria-label", `${isExpanded ? "折叠" : "展开"} ${item.title}`, ); } } if (!hasChildren) { context.patchPageTreeActiveDom(); return true; } let childrenList = Array.from(nodeElement.children).find( (child) => child instanceof HTMLElement && child.classList.contains("tree-children"), ); if (isExpanded) { if (!(childrenList instanceof HTMLElement)) { childrenList = document.createElement("ul"); childrenList.className = "tree-children"; children.forEach((child) => { childrenList.appendChild(context.renderNode(child)); }); nodeElement.appendChild(childrenList); } childrenList.hidden = false; childrenList.style.display = ""; } else if (childrenList instanceof HTMLElement) { childrenList.hidden = true; childrenList.style.display = "none"; } context.patchPageTreeActiveDom(); return true; } export function hydrateTreeShellInitialPageTree(context) { if (context.mode !== "page") return false; const root = context.appElement.querySelector('[data-rust-page-renderer="initial_v1"]'); if (!(root instanceof HTMLElement)) { return false; } root.querySelectorAll('[data-rust-rendered-row="page"]').forEach((row) => { if (!(row instanceof HTMLElement)) return; const nodeId = context.normalizeText(row.dataset.nodeId); const item = context.itemById.get(nodeId); if (!item) return; context.bindPageRowEvents(row, item); }); if (context.focusedNodeId) { context.focusRowElement(context.focusedNodeId); } return true; } export function focusTreeShellPickerRowElement(context, pickerItemKey) { const normalizedItemKey = context.normalizeText(pickerItemKey); window.requestAnimationFrame(() => { const row = normalizedItemKey === "__root__" ? context.appElement.querySelector('[data-rust-rendered-row="picker-root"]') : context.appElement.querySelector( `.tree-row[data-node-id="${CSS.escape(normalizedItemKey)}"]`, ); if (!(row instanceof HTMLElement)) return; row.focus({ preventScroll: true }); row.scrollIntoView({ block: "nearest" }); }); } export function patchTreeShellPickerActiveDom(context) { if (context.mode !== "picker") return; context.appElement .querySelectorAll('[data-rust-rendered-row="picker"], [data-rust-rendered-row="picker-root"]') .forEach((row) => { if (!(row instanceof HTMLElement)) return; const nodeId = context.normalizeText(row.dataset.nodeId); const isRoot = row.dataset.rustRenderedRow === "picker-root"; const isFocused = isRoot ? context.currentActivePickerItemKey === "__root__" : context.currentActivePickerItemKey === nodeId || (!context.currentActivePickerItemKey && context.currentActiveDocumentId === nodeId); row.dataset.focused = String(isFocused); row.tabIndex = isFocused ? 0 : -1; }); } export function hydrateTreeShellInitialPickerTree(context) { if (context.mode !== "picker") return false; const root = context.appElement.querySelector('[data-rust-picker-renderer="initial_v1"]'); if (!(root instanceof HTMLElement)) { return false; } root.querySelectorAll('[data-rust-rendered-row="picker-root"]').forEach((row) => { context.bindPickerRootEvents(row); }); root.querySelectorAll('[data-rust-rendered-row="picker"]').forEach((row) => { if (!(row instanceof HTMLElement)) return; const nodeId = context.normalizeText(row.dataset.nodeId); const item = context.itemById.get(nodeId); if (!item) return; context.bindPickerRowEvents(row, item); }); return true; }