UNPKG

@neo4j-ndl/react

Version:

React implementation of Neo4j Design System

149 lines 6.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); /** * * Copyright (c) "Neo4j" * Neo4j Sweden AB [http://neo4j.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ require("@neo4j-ndl/base/lib/neo4j-ds-styles.css"); const icons_1 = require("@neo4j-ndl/react/icons"); const next_1 = require("@neo4j-ndl/react/next"); const react_1 = require("react"); const TREE_DATA = [ { children: [ { children: [ { id: 'app-tsx', label: 'App.tsx' }, { id: 'index-tsx', label: 'index.tsx' }, { id: 'styles-css', label: 'styles.css' }, ], id: 'frontend', label: 'Frontend', }, { children: [ { id: 'server-ts', label: 'server.ts' }, { id: 'routes-ts', label: 'routes.ts' }, ], id: 'backend', label: 'Backend', }, { id: 'readme-md', label: 'README.md' }, ], id: 'projects', label: 'Projects', }, { children: [ { children: [ { id: 'beach-jpg', label: 'beach.jpg' }, { id: 'sunset-jpg', label: 'sunset.jpg' }, ], id: 'vacation', label: 'Vacation', }, { id: 'profile-png', label: 'profile.png' }, ], id: 'photos', label: 'Photos', }, { children: [ { id: 'resume-pdf', label: 'resume.pdf' }, { id: 'cover-letter-pdf', label: 'cover-letter.pdf' }, { id: 'notes-txt', label: 'notes.txt' }, ], id: 'documents', label: 'Documents', }, { children: [ { children: [ { id: 'chill-m3u', label: 'chill.m3u' }, { id: 'workout-m3u', label: 'workout.m3u' }, ], id: 'playlists', label: 'Playlists', }, { id: 'favorites-m3u', label: 'favorites.m3u' }, ], id: 'music', label: 'Music', }, { id: 'todo-txt', label: 'TODO.txt' }, ]; const LOAD_DELAY_MS = 600; function iconForNode(node) { if (node.children) { return (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}); } if (/\.(jpg|jpeg|png|gif|svg)$/i.test(node.label)) { return (0, jsx_runtime_1.jsx)(icons_1.PhotoIconOutline, {}); } return (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}); } const INITIAL_NODE_STATE = { hasLoaded: false, isExpanded: false, isLoading: false, }; function useTreeState() { const [nodeStates, setNodeStates] = (0, react_1.useState)({}); const [selectedId, setSelectedId] = (0, react_1.useState)(null); const timers = (0, react_1.useRef)({}); const getNodeState = (0, react_1.useCallback)((id) => { var _a; return (_a = nodeStates[id]) !== null && _a !== void 0 ? _a : INITIAL_NODE_STATE; }, [nodeStates]); const handleExpand = (0, react_1.useCallback)((id, expanded) => { setNodeStates((prev) => { var _a; const current = (_a = prev[id]) !== null && _a !== void 0 ? _a : INITIAL_NODE_STATE; if (expanded && !current.hasLoaded) { if (timers.current[id]) { clearTimeout(timers.current[id]); } timers.current[id] = setTimeout(() => { setNodeStates((p) => (Object.assign(Object.assign({}, p), { [id]: { hasLoaded: true, isExpanded: true, isLoading: false } }))); delete timers.current[id]; }, LOAD_DELAY_MS); return Object.assign(Object.assign({}, prev), { [id]: { hasLoaded: false, isExpanded: true, isLoading: true } }); } return Object.assign(Object.assign({}, prev), { [id]: Object.assign(Object.assign({}, current), { isExpanded: expanded }) }); }); }, []); const handleSelect = (0, react_1.useCallback)((id) => setSelectedId((prev) => (prev === id ? null : id)), []); return { getNodeState, handleExpand, handleSelect, selectedId }; } function renderNode(node, ctx) { const hasChildren = node.children !== undefined && node.children !== null && node.children.length > 0; const state = ctx.getNodeState(node.id); return ((0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: node.label, hasChildren: hasChildren, isExpanded: state.isExpanded, isLoading: state.isLoading, isSelected: ctx.selectedId === node.id, leadingVisual: iconForNode(node), onExpandedChange: (expanded) => ctx.handleExpand(node.id, expanded), onSelectedChange: () => ctx.handleSelect(node.id), children: [hasChildren && state.isLoading && !state.hasLoaded && ((0, jsx_runtime_1.jsx)(next_1.TreeView.SkeletonItem, { rows: 2 })), hasChildren && state.hasLoaded && node.children.map((child) => renderNode(child, ctx))] }, node.id)); } const Component = () => { const { getNodeState, selectedId, handleExpand, handleSelect } = useTreeState(); const ctx = (0, react_1.useMemo)(() => ({ getNodeState, handleExpand, handleSelect, selectedId }), [getNodeState, selectedId, handleExpand, handleSelect]); return ((0, jsx_runtime_1.jsx)(next_1.TreeView, { ariaLabel: "Lazy-loaded file explorer", children: TREE_DATA.map((node) => renderNode(node, ctx)) })); }; exports.default = Component; //# sourceMappingURL=tree-view-lazy.story.js.map