Files
jsonhero-web/app/components/ColumnItem.tsx
T
2022-03-01 09:31:09 +00:00

79 lines
2.7 KiB
TypeScript

import { ChevronRightIcon } from "@heroicons/react/outline";
import { Mono } from "./Primitives/Mono";
import { useEffect, useMemo, useRef } from "react";
import { ColumnViewNode } from "~/useColumnView";
import {
useJsonColumnViewAPI,
useJsonColumnViewState,
} from "../hooks/useJsonColumnView";
import { useJson } from "../hooks/useJson";
import { colorForItemAtPath } from "~/utilities/colors";
import { Body } from "./Primitives/Body";
export function ColumnItem({ item }: { item: ColumnViewNode }) {
const { title, subtitle, children, id } = item;
const [json] = useJson();
const { selectedPath, highlightedPath } = useJsonColumnViewState();
const { goToNodeId } = useJsonColumnViewAPI();
const htmlElement = useRef<HTMLDivElement>(null);
const showArrow = children.length > 0;
const isHighlighted = (path: string[], id: string) => {
return path[path.length - 1] === id;
};
const isSelected = (path: string[], id: string) => {
return path.includes(id);
};
const stateStyle = useMemo<string>(() => {
if (highlightedPath.length === 0) {
return "";
}
if (isHighlighted(highlightedPath, id)) {
return "bg-slate-300 text-slate-700 hover:bg-slate-400 hover:bg-opacity-60 transition duration-75 ease-out dark:bg-white dark:bg-opacity-[15%] dark:text-slate-400";
}
if (isSelected(selectedPath, id)) {
return "bg-slate-200 hover:bg-slate-300 transition duration-75 ease-out dark:bg-white dark:bg-opacity-[5%] dark:hover:bg-white dark:hover:bg-opacity-[10%] dark:text-slate-400";
}
return "hover:bg-slate-100 transition duration-75 ease-out dark:hover:bg-white dark:hover:bg-opacity-[5%] dark:text-slate-400";
}, [highlightedPath, selectedPath, id]);
const iconColor = colorForItemAtPath(id, json);
useEffect(() => {
if (isSelected(selectedPath, id) || isHighlighted(highlightedPath, id)) {
htmlElement.current?.scrollIntoView({ block: "nearest" });
}
}, [highlightedPath, selectedPath, id]);
return (
<div
className={`flex h-9 items-center justify-items-stretch mx-1 px-1 py-1 my-1 rounded-sm ${stateStyle}`}
onClick={() => goToNodeId(id)}
ref={htmlElement}
>
<div className="w-4 flex-none flex-col justify-items-center">
{item.icon && <item.icon className={`${iconColor} h-5 w-5`} />}
</div>
<div className="flex flex-grow flex-shrink items-baseline justify-between truncate">
<Body className="flex-grow flex-shrink-0 pl-3 pr-2">{title}</Body>
{subtitle && (
<Mono className="truncate text-gray-400 pr-1 transition dark:text-gray-500">
{subtitle}
</Mono>
)}
</div>
{showArrow && (
<ChevronRightIcon className="flex-none w-4 h-4 text-gray-400" />
)}
</div>
);
}