remove collapse animation; tooltips with types

This commit is contained in:
Vyacheslav Matyukhin 2022-07-08 16:58:34 +04:00
parent 0ef2428c80
commit c401f39520
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
4 changed files with 142 additions and 64 deletions

View File

@ -3,6 +3,8 @@
"version": "0.2.20",
"license": "MIT",
"dependencies": {
"@floating-ui/react-dom": "^0.7.2",
"@floating-ui/react-dom-interactions": "^0.6.6",
"@headlessui/react": "^1.6.5",
"@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^2.9.3",

View File

@ -11,7 +11,7 @@ import {
} from "./DistributionChart";
import { FunctionChart, FunctionChartSettings } from "./FunctionChart";
import clsx from "clsx";
import { LayoutGroup, motion } from "framer-motion";
import { Tooltip } from "./ui/Tooltip";
function getRange<a>(x: declaration<a>) {
const first = x.args[0];
@ -40,59 +40,45 @@ interface VariableBoxProps {
name?: string;
heading: string;
children: React.ReactNode;
showTypes: boolean;
}
const VariableBox: React.FC<VariableBoxProps> = ({
name,
heading = "Error",
children,
showTypes = false,
}) => {
const [isCollapsed, setIsCollapsed] = useState(false);
return (
<motion.div layout transition={{ type: "tween" }}>
{name || showTypes ? (
<motion.header
layout="position"
transition={{ type: "tween" }}
<div>
{name ? (
<header
className="inline-flex space-x-1 text-slate-500 font-mono text-sm cursor-pointer"
onClick={() => setIsCollapsed(!isCollapsed)}
>
{name ? <span>{name}:</span> : null}
{showTypes ? <span>{heading}</span> : null}
{name ? (
<Tooltip text={heading}>
<span>{name}:</span>
</Tooltip>
) : null}
{isCollapsed ? (
<span className="bg-slate-200 rounded p-0.5 font-xs">...</span>
) : null}
</motion.header>
</header>
) : null}
{isCollapsed ? null : (
<motion.div layout="position" transition={{ type: "tween" }}>
{children}
</motion.div>
)}
</motion.div>
{isCollapsed ? null : <div>{children}</div>}
</div>
);
};
const VariableList: React.FC<{
name?: string;
heading: string;
showTypes: boolean;
children: React.ReactNode;
}> = ({ name, heading, showTypes, children }) => (
<VariableBox name={name} heading={heading} showTypes={showTypes}>
<motion.div
layout="position"
transition={{ type: "tween" }}
className={clsx(
"space-y-3",
name ? "border-l pl-4" : null,
name || showTypes ? "pt-1 mt-1" : null
)}
>
<LayoutGroup>{children}</LayoutGroup>
</motion.div>
}> = ({ name, heading, children }) => (
<VariableBox name={name} heading={heading}>
<div className={clsx("space-y-3", name ? "border-l pl-4 pt-1 mt-1" : null)}>
{children}
</div>
</VariableBox>
);
@ -103,8 +89,8 @@ export interface SquiggleItemProps {
width?: number;
height: number;
distributionPlotSettings: DistributionPlottingSettings;
/** Whether to show type information */
showTypes: boolean;
/** Whether to show type information; deprecated */
showTypes?: boolean;
/** Settings for displaying functions */
chartSettings: FunctionChartSettings;
/** Environment for further function executions */
@ -124,7 +110,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
switch (expression.tag) {
case "number":
return (
<VariableBox name={name} heading="Number" showTypes={showTypes}>
<VariableBox name={name} heading="Number">
<div className="font-semibold text-slate-600">
<NumberShower precision={3} number={expression.value} />
</div>
@ -135,12 +121,10 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
return (
<VariableBox
name={name}
heading={`Distribution (${distType})`}
showTypes={showTypes}
heading={`Distribution (${distType})\n${
distType === "Symbolic" ? expression.value.toString() : ""
}`}
>
{distType === "Symbolic" && showTypes ? (
<div>{expression.value.toString()}</div>
) : null}
<DistributionChart
distribution={expression.value}
{...distributionPlotSettings}
@ -152,7 +136,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
}
case "string":
return (
<VariableBox name={name} heading="String" showTypes={showTypes}>
<VariableBox name={name} heading="String">
<span className="text-slate-400">"</span>
<span className="text-slate-600 font-semibold font-mono">
{expression.value}
@ -162,45 +146,45 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
);
case "boolean":
return (
<VariableBox name={name} heading="Boolean" showTypes={showTypes}>
<VariableBox name={name} heading="Boolean">
{expression.value.toString()}
</VariableBox>
);
case "symbol":
return (
<VariableBox name={name} heading="Symbol" showTypes={showTypes}>
<VariableBox name={name} heading="Symbol">
<span className="text-slate-500 mr-2">Undefined Symbol:</span>
<span className="text-slate-600">{expression.value}</span>
</VariableBox>
);
case "call":
return (
<VariableBox name={name} heading="Call" showTypes={showTypes}>
<VariableBox name={name} heading="Call">
{expression.value}
</VariableBox>
);
case "arraystring":
return (
<VariableBox name={name} heading="Array String" showTypes={showTypes}>
<VariableBox name={name} heading="Array String">
{expression.value.map((r) => `"${r}"`).join(", ")}
</VariableBox>
);
case "date":
return (
<VariableBox name={name} heading="Date" showTypes={showTypes}>
<VariableBox name={name} heading="Date">
{expression.value.toDateString()}
</VariableBox>
);
case "timeDuration": {
return (
<VariableBox name={name} heading="Time Duration" showTypes={showTypes}>
<VariableBox name={name} heading="Time Duration">
<NumberShower precision={3} number={expression.value} />
</VariableBox>
);
}
case "lambda":
return (
<VariableBox name={name} heading="Function" showTypes={showTypes}>
<VariableBox name={name} heading="Function">
<div className="text-amber-700 bg-amber-100 rounded-md font-mono p-1 pl-2 mb-3 mt-1 text-sm">{`function(${expression.value.parameters.join(
","
)})`}</div>
@ -218,11 +202,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
);
case "lambdaDeclaration": {
return (
<VariableBox
name={name}
heading="Function Declaration"
showTypes={showTypes}
>
<VariableBox name={name} heading="Function Declaration">
<FunctionChart
fn={expression.value.fn}
chartSettings={getChartSettings(expression.value)}
@ -238,7 +218,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
}
case "module": {
return (
<VariableList name={name} heading="Module" showTypes={showTypes}>
<VariableList name={name} heading="Module">
{Object.entries(expression.value)
.filter(([key, r]) => key !== "Math")
.map(([key, r]) => (
@ -248,7 +228,6 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression={r}
width={width !== undefined ? width - 20 : width}
height={height / 3}
showTypes={showTypes}
distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings}
environment={environment}
@ -259,7 +238,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
}
case "record":
return (
<VariableList name={name} heading="Record" showTypes={showTypes}>
<VariableList name={name} heading="Record">
{Object.entries(expression.value).map(([key, r]) => (
<SquiggleItem
key={key}
@ -267,7 +246,6 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression={r}
width={width !== undefined ? width - 20 : width}
height={height / 3}
showTypes={showTypes}
distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings}
environment={environment}
@ -277,7 +255,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
);
case "array":
return (
<VariableList name={name} heading="Array" showTypes={showTypes}>
<VariableList name={name} heading="Array">
{expression.value.map((r, i) => (
<SquiggleItem
key={i}
@ -286,7 +264,6 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
width={width !== undefined ? width - 20 : width}
height={50}
distributionPlotSettings={distributionPlotSettings}
showTypes={showTypes}
chartSettings={chartSettings}
environment={environment}
/>

View File

@ -0,0 +1,63 @@
import React, { cloneElement, useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import {
shift,
useDismiss,
useFloating,
useHover,
useInteractions,
useRole,
} from "@floating-ui/react-dom-interactions";
interface Props {
text: string;
children: JSX.Element;
}
export const Tooltip: React.FC<Props> = ({ text, children }) => {
const [open, setOpen] = useState(false);
const { x, y, reference, floating, strategy, context } = useFloating({
placement: "top",
open,
onOpenChange: setOpen,
middleware: [shift()],
});
const { getReferenceProps, getFloatingProps } = useInteractions([
useHover(context),
useRole(context, { role: "tooltip" }),
useDismiss(context),
]);
return (
<>
{cloneElement(
children,
getReferenceProps({ ref: reference, ...children.props })
)}
<AnimatePresence>
{open && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.15 }}
{...getFloatingProps({
ref: floating,
className:
"text-xs p-2 border border-gray-300 rounded bg-white z-10",
style: {
position: strategy,
top: y ?? 0,
left: x ?? 0,
},
})}
>
<pre>{text}</pre>
</motion.div>
)}
</AnimatePresence>
</>
);
};

View File

@ -1829,6 +1829,35 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@floating-ui/core@^0.7.3":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86"
integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==
"@floating-ui/dom@^0.5.3":
version "0.5.4"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1"
integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==
dependencies:
"@floating-ui/core" "^0.7.3"
"@floating-ui/react-dom-interactions@^0.6.6":
version "0.6.6"
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom-interactions/-/react-dom-interactions-0.6.6.tgz#8542e8c4bcbee2cd0d512de676c6a493e0a2d168"
integrity sha512-qnao6UPjSZNHnXrF+u4/n92qVroQkx0Umlhy3Avk1oIebm/5ee6yvDm4xbHob0OjY7ya8WmUnV3rQlPwX3Atwg==
dependencies:
"@floating-ui/react-dom" "^0.7.2"
aria-hidden "^1.1.3"
use-isomorphic-layout-effect "^1.1.1"
"@floating-ui/react-dom@^0.7.2":
version "0.7.2"
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-0.7.2.tgz#0bf4ceccb777a140fc535c87eb5d6241c8e89864"
integrity sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==
dependencies:
"@floating-ui/dom" "^0.5.3"
use-isomorphic-layout-effect "^1.1.1"
"@gar/promisify@^1.0.1":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
@ -4421,10 +4450,10 @@
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.1", "@types/react@^18.0.9":
version "18.0.14"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.14.tgz#e016616ffff51dba01b04945610fe3671fdbe06d"
integrity sha512-x4gGuASSiWmo0xjDLpm5mPb52syZHJx02VKbqUKdLmKtAwIh63XClGsiTI1K6DO5q7ox4xAsQrU+Gl3+gGXF9Q==
"@types/react@*", "@types/react@17.0.43", "@types/react@^18.0.9":
version "17.0.43"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55"
integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@ -5373,6 +5402,13 @@ argv@0.0.2:
resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab"
integrity sha512-dEamhpPEwRUBpLNHeuCm/v+g0anFByHahxodVO/BbAarHVBBg2MccCwf9K+o1Pof+2btdnkJelYVUWjW/VrATw==
aria-hidden@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.3.tgz#bb48de18dc84787a3c6eee113709c473c64ec254"
integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==
dependencies:
tslib "^1.0.0"
aria-query@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
@ -14872,7 +14908,7 @@ react-vega@^7.5.1:
prop-types "^15.8.1"
vega-embed "^6.5.1"
react@^18.0.0, react@^18.1.0:
react@^18.1.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
@ -17071,7 +17107,7 @@ tsconfig-paths@^3.14.1, tsconfig-paths@^3.9.0:
minimist "^1.2.6"
strip-bom "^3.0.0"
tslib@^1.8.1:
tslib@^1.0.0, tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==