95 lines
2.5 KiB
TypeScript
95 lines
2.5 KiB
TypeScript
import { useEffect, useRef, ReactNode } from 'react';
|
|
import * as React from 'react';
|
|
|
|
import { useContentOutlineContext } from './ContentOutlineContext';
|
|
|
|
type INDENT_LEVELS = 'root' | 'child';
|
|
|
|
export type ITEM_TYPES = 'scrollIntoView' | 'filter';
|
|
|
|
export interface ContentOutlineItemBaseProps {
|
|
panelId: string;
|
|
title: string;
|
|
icon: string;
|
|
/**
|
|
* Custom offset from the top of the Explore container when scrolling to this item.
|
|
* Items like query row need some offset so the top of the query row is not hidden behind the header.
|
|
*/
|
|
customTopOffset?: number;
|
|
/**
|
|
* The level of indentation for this item.
|
|
* - `root` is the top level item.
|
|
* - `child` is an item that is a child of an item with `root` level.
|
|
*/
|
|
level?: INDENT_LEVELS;
|
|
/**
|
|
* Merges a single child of this item with this item.
|
|
* e.g. It doesn't make sense to nest a single query row under a queries container
|
|
* because user can navigate to the query row by navigating to the queries container.
|
|
*/
|
|
mergeSingleChild?: boolean;
|
|
// callback that is called when the item is clicked
|
|
// need this for filtering logs
|
|
onClick?: (e: React.MouseEvent) => void;
|
|
type?: ITEM_TYPES;
|
|
/**
|
|
* Client can additionally mark filter actions as highlighted
|
|
*/
|
|
highlight?: boolean;
|
|
onRemove?: (id: string) => void;
|
|
/**
|
|
* Child that will always be on top of the list
|
|
* e.g. pinned log in Logs section
|
|
*/
|
|
childOnTop?: boolean;
|
|
expanded?: boolean;
|
|
}
|
|
|
|
interface ContentOutlineItemProps extends ContentOutlineItemBaseProps {
|
|
children: ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export function ContentOutlineItem({
|
|
panelId,
|
|
title,
|
|
icon,
|
|
customTopOffset,
|
|
children,
|
|
className,
|
|
level = 'root',
|
|
mergeSingleChild,
|
|
type = 'scrollIntoView',
|
|
onClick,
|
|
}: ContentOutlineItemProps) {
|
|
const { register, unregister } = useContentOutlineContext() ?? {};
|
|
const ref = useRef(null);
|
|
|
|
useEffect(() => {
|
|
if (!register || !unregister) {
|
|
return;
|
|
}
|
|
|
|
// When the component mounts, register it and get its unique ID.
|
|
const id = register({
|
|
panelId: panelId,
|
|
title: title,
|
|
icon: icon,
|
|
ref: ref.current,
|
|
customTopOffset: customTopOffset,
|
|
level: level,
|
|
mergeSingleChild,
|
|
type,
|
|
});
|
|
|
|
// When the component unmounts, unregister it using its unique ID.
|
|
return () => unregister(id);
|
|
}, [panelId, title, icon, customTopOffset, level, mergeSingleChild, register, unregister, type, onClick]);
|
|
|
|
return (
|
|
<div className={className} ref={ref}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|