// SPDX-License-Identifier: MIT // Copyright (c) 2022-2023 The Pybricks Authors /***/ // react-complex-tree renderers for bluetprintjs integration // based on https://github.com/lukasbach/react-complex-tree/blob/239fb0c5f49f3c24e307142fb3d7e828440c3f55/packages/blueprintjs-renderers/src/renderers.tsx // Copyright (c) 2021 Lukas Bach import { Button, Classes, Colors, Icon, IconName, InputGroup, MaybeElement, } from '@blueprintjs/core'; import React, { createContext } from 'react'; import { TreeItem, TreeRenderProps } from 'react-complex-tree'; import { useBoolean } from 'usehooks-ts'; import { assert } from '.'; /** Combines class names into a string. */ const cx = (...classNames: Array): string => classNames.filter((cn) => !!cn).join(' '); /** Node item data similar to blueprintsjs TreeNodeInfo */ export type TreeItemData = { readonly icon?: IconName | MaybeElement; readonly secondaryLabel?: string | MaybeElement; }; /** * Tree item context that can be used to get a reference to the tree item in * elements passed to TreeItemData. */ export const TreeItemContext = createContext>({ index: '', data: {}, }); type RendererFuncs = Omit; /** * The type of the `props` parameter of a react-complex-tree render function. * @typeParam T The name of the render function. */ export type RenderProps = Parameters< RendererFuncs[T] >[0]; const TreeContainer: React.FunctionComponent> = ( props, ) => { return (
{props.children}
); }; const ItemsContainer: React.FunctionComponent> = ( props, ) => (
    {props.children}
); const Item: React.FunctionComponent> = (props) => { const { value: isHover, setTrue: setIsHoverTrue, setFalse: setIsHoverFalse, } = useBoolean(false); return (
  • e.stopPropagation()} onMouseEnter={setIsHoverTrue} onMouseLeave={setIsHoverFalse} {...props.context.itemContainerWithChildrenProps} {...props.context.interactiveElementProps} >
    {props.item.isFolder ? ( props.arrow ) : ( )} {props.title} {props.item.data.secondaryLabel && isHover && ( {props.item.data.secondaryLabel} )}
    {props.context.isExpanded && props.children}
  • ); }; const ItemArrow: React.FunctionComponent> = (props) => ( , 'title' | 'children' >)} /> ); const ItemTitle: React.FunctionComponent> = ({ title, context, info, }) => { if (!info.isSearching || !context.isSearchMatching || !info.search) { return {title}; } else { const startIndex = title.toLowerCase().indexOf(info.search.toLowerCase()); return ( {startIndex > 0 && {title.slice(0, startIndex)}} {title.slice(startIndex, startIndex + info.search.length)} {startIndex + info.search.length < title.length && ( {title.slice(startIndex + info.search.length, title.length)} )} ); } }; const DragBetweenLine: React.FunctionComponent< RenderProps<'renderDragBetweenLine'> > = ({ draggingPosition, lineProps }) => (
    ); const RenameInput: React.FunctionComponent> = ( props, ) => (