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", "version": "0.2.20",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@floating-ui/react-dom": "^0.7.2",
"@floating-ui/react-dom-interactions": "^0.6.6",
"@headlessui/react": "^1.6.5", "@headlessui/react": "^1.6.5",
"@heroicons/react": "^1.0.6", "@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^2.9.3", "@hookform/resolvers": "^2.9.3",

View File

@ -11,7 +11,7 @@ import {
} from "./DistributionChart"; } from "./DistributionChart";
import { FunctionChart, FunctionChartSettings } from "./FunctionChart"; import { FunctionChart, FunctionChartSettings } from "./FunctionChart";
import clsx from "clsx"; import clsx from "clsx";
import { LayoutGroup, motion } from "framer-motion"; import { Tooltip } from "./ui/Tooltip";
function getRange<a>(x: declaration<a>) { function getRange<a>(x: declaration<a>) {
const first = x.args[0]; const first = x.args[0];
@ -40,59 +40,45 @@ interface VariableBoxProps {
name?: string; name?: string;
heading: string; heading: string;
children: React.ReactNode; children: React.ReactNode;
showTypes: boolean;
} }
const VariableBox: React.FC<VariableBoxProps> = ({ const VariableBox: React.FC<VariableBoxProps> = ({
name, name,
heading = "Error", heading = "Error",
children, children,
showTypes = false,
}) => { }) => {
const [isCollapsed, setIsCollapsed] = useState(false); const [isCollapsed, setIsCollapsed] = useState(false);
return ( return (
<motion.div layout transition={{ type: "tween" }}> <div>
{name || showTypes ? ( {name ? (
<motion.header <header
layout="position"
transition={{ type: "tween" }}
className="inline-flex space-x-1 text-slate-500 font-mono text-sm cursor-pointer" className="inline-flex space-x-1 text-slate-500 font-mono text-sm cursor-pointer"
onClick={() => setIsCollapsed(!isCollapsed)} onClick={() => setIsCollapsed(!isCollapsed)}
> >
{name ? <span>{name}:</span> : null} {name ? (
{showTypes ? <span>{heading}</span> : null} <Tooltip text={heading}>
<span>{name}:</span>
</Tooltip>
) : null}
{isCollapsed ? ( {isCollapsed ? (
<span className="bg-slate-200 rounded p-0.5 font-xs">...</span> <span className="bg-slate-200 rounded p-0.5 font-xs">...</span>
) : null} ) : null}
</motion.header> </header>
) : null} ) : null}
{isCollapsed ? null : ( {isCollapsed ? null : <div>{children}</div>}
<motion.div layout="position" transition={{ type: "tween" }}> </div>
{children}
</motion.div>
)}
</motion.div>
); );
}; };
const VariableList: React.FC<{ const VariableList: React.FC<{
name?: string; name?: string;
heading: string; heading: string;
showTypes: boolean;
children: React.ReactNode; children: React.ReactNode;
}> = ({ name, heading, showTypes, children }) => ( }> = ({ name, heading, children }) => (
<VariableBox name={name} heading={heading} showTypes={showTypes}> <VariableBox name={name} heading={heading}>
<motion.div <div className={clsx("space-y-3", name ? "border-l pl-4 pt-1 mt-1" : null)}>
layout="position" {children}
transition={{ type: "tween" }} </div>
className={clsx(
"space-y-3",
name ? "border-l pl-4" : null,
name || showTypes ? "pt-1 mt-1" : null
)}
>
<LayoutGroup>{children}</LayoutGroup>
</motion.div>
</VariableBox> </VariableBox>
); );
@ -103,8 +89,8 @@ export interface SquiggleItemProps {
width?: number; width?: number;
height: number; height: number;
distributionPlotSettings: DistributionPlottingSettings; distributionPlotSettings: DistributionPlottingSettings;
/** Whether to show type information */ /** Whether to show type information; deprecated */
showTypes: boolean; showTypes?: boolean;
/** Settings for displaying functions */ /** Settings for displaying functions */
chartSettings: FunctionChartSettings; chartSettings: FunctionChartSettings;
/** Environment for further function executions */ /** Environment for further function executions */
@ -124,7 +110,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
switch (expression.tag) { switch (expression.tag) {
case "number": case "number":
return ( return (
<VariableBox name={name} heading="Number" showTypes={showTypes}> <VariableBox name={name} heading="Number">
<div className="font-semibold text-slate-600"> <div className="font-semibold text-slate-600">
<NumberShower precision={3} number={expression.value} /> <NumberShower precision={3} number={expression.value} />
</div> </div>
@ -135,12 +121,10 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
return ( return (
<VariableBox <VariableBox
name={name} name={name}
heading={`Distribution (${distType})`} heading={`Distribution (${distType})\n${
showTypes={showTypes} distType === "Symbolic" ? expression.value.toString() : ""
}`}
> >
{distType === "Symbolic" && showTypes ? (
<div>{expression.value.toString()}</div>
) : null}
<DistributionChart <DistributionChart
distribution={expression.value} distribution={expression.value}
{...distributionPlotSettings} {...distributionPlotSettings}
@ -152,7 +136,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
} }
case "string": case "string":
return ( return (
<VariableBox name={name} heading="String" showTypes={showTypes}> <VariableBox name={name} heading="String">
<span className="text-slate-400">"</span> <span className="text-slate-400">"</span>
<span className="text-slate-600 font-semibold font-mono"> <span className="text-slate-600 font-semibold font-mono">
{expression.value} {expression.value}
@ -162,45 +146,45 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
); );
case "boolean": case "boolean":
return ( return (
<VariableBox name={name} heading="Boolean" showTypes={showTypes}> <VariableBox name={name} heading="Boolean">
{expression.value.toString()} {expression.value.toString()}
</VariableBox> </VariableBox>
); );
case "symbol": case "symbol":
return ( 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-500 mr-2">Undefined Symbol:</span>
<span className="text-slate-600">{expression.value}</span> <span className="text-slate-600">{expression.value}</span>
</VariableBox> </VariableBox>
); );
case "call": case "call":
return ( return (
<VariableBox name={name} heading="Call" showTypes={showTypes}> <VariableBox name={name} heading="Call">
{expression.value} {expression.value}
</VariableBox> </VariableBox>
); );
case "arraystring": case "arraystring":
return ( return (
<VariableBox name={name} heading="Array String" showTypes={showTypes}> <VariableBox name={name} heading="Array String">
{expression.value.map((r) => `"${r}"`).join(", ")} {expression.value.map((r) => `"${r}"`).join(", ")}
</VariableBox> </VariableBox>
); );
case "date": case "date":
return ( return (
<VariableBox name={name} heading="Date" showTypes={showTypes}> <VariableBox name={name} heading="Date">
{expression.value.toDateString()} {expression.value.toDateString()}
</VariableBox> </VariableBox>
); );
case "timeDuration": { case "timeDuration": {
return ( return (
<VariableBox name={name} heading="Time Duration" showTypes={showTypes}> <VariableBox name={name} heading="Time Duration">
<NumberShower precision={3} number={expression.value} /> <NumberShower precision={3} number={expression.value} />
</VariableBox> </VariableBox>
); );
} }
case "lambda": case "lambda":
return ( 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 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> )})`}</div>
@ -218,11 +202,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
); );
case "lambdaDeclaration": { case "lambdaDeclaration": {
return ( return (
<VariableBox <VariableBox name={name} heading="Function Declaration">
name={name}
heading="Function Declaration"
showTypes={showTypes}
>
<FunctionChart <FunctionChart
fn={expression.value.fn} fn={expression.value.fn}
chartSettings={getChartSettings(expression.value)} chartSettings={getChartSettings(expression.value)}
@ -238,7 +218,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
} }
case "module": { case "module": {
return ( return (
<VariableList name={name} heading="Module" showTypes={showTypes}> <VariableList name={name} heading="Module">
{Object.entries(expression.value) {Object.entries(expression.value)
.filter(([key, r]) => key !== "Math") .filter(([key, r]) => key !== "Math")
.map(([key, r]) => ( .map(([key, r]) => (
@ -248,7 +228,6 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression={r} expression={r}
width={width !== undefined ? width - 20 : width} width={width !== undefined ? width - 20 : width}
height={height / 3} height={height / 3}
showTypes={showTypes}
distributionPlotSettings={distributionPlotSettings} distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment} environment={environment}
@ -259,7 +238,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
} }
case "record": case "record":
return ( return (
<VariableList name={name} heading="Record" showTypes={showTypes}> <VariableList name={name} heading="Record">
{Object.entries(expression.value).map(([key, r]) => ( {Object.entries(expression.value).map(([key, r]) => (
<SquiggleItem <SquiggleItem
key={key} key={key}
@ -267,7 +246,6 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression={r} expression={r}
width={width !== undefined ? width - 20 : width} width={width !== undefined ? width - 20 : width}
height={height / 3} height={height / 3}
showTypes={showTypes}
distributionPlotSettings={distributionPlotSettings} distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment} environment={environment}
@ -277,7 +255,7 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
); );
case "array": case "array":
return ( return (
<VariableList name={name} heading="Array" showTypes={showTypes}> <VariableList name={name} heading="Array">
{expression.value.map((r, i) => ( {expression.value.map((r, i) => (
<SquiggleItem <SquiggleItem
key={i} key={i}
@ -286,7 +264,6 @@ export const SquiggleItem: React.FC<SquiggleItemProps> = ({
width={width !== undefined ? width - 20 : width} width={width !== undefined ? width - 20 : width}
height={50} height={50}
distributionPlotSettings={distributionPlotSettings} distributionPlotSettings={distributionPlotSettings}
showTypes={showTypes}
chartSettings={chartSettings} chartSettings={chartSettings}
environment={environment} 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" minimatch "^3.1.2"
strip-json-comments "^3.1.1" 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": "@gar/promisify@^1.0.1":
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
@ -4421,10 +4450,10 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react@*", "@types/react@^18.0.1", "@types/react@^18.0.9": "@types/react@*", "@types/react@17.0.43", "@types/react@^18.0.9":
version "18.0.14" version "17.0.43"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.14.tgz#e016616ffff51dba01b04945610fe3671fdbe06d" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55"
integrity sha512-x4gGuASSiWmo0xjDLpm5mPb52syZHJx02VKbqUKdLmKtAwIh63XClGsiTI1K6DO5q7ox4xAsQrU+Gl3+gGXF9Q== integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==
dependencies: dependencies:
"@types/prop-types" "*" "@types/prop-types" "*"
"@types/scheduler" "*" "@types/scheduler" "*"
@ -5373,6 +5402,13 @@ argv@0.0.2:
resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab"
integrity sha512-dEamhpPEwRUBpLNHeuCm/v+g0anFByHahxodVO/BbAarHVBBg2MccCwf9K+o1Pof+2btdnkJelYVUWjW/VrATw== 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: aria-query@^4.2.2:
version "4.2.2" version "4.2.2"
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" 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" prop-types "^15.8.1"
vega-embed "^6.5.1" vega-embed "^6.5.1"
react@^18.0.0, react@^18.1.0: react@^18.1.0:
version "18.2.0" version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
@ -17071,7 +17107,7 @@ tsconfig-paths@^3.14.1, tsconfig-paths@^3.9.0:
minimist "^1.2.6" minimist "^1.2.6"
strip-bom "^3.0.0" strip-bom "^3.0.0"
tslib@^1.8.1: tslib@^1.0.0, tslib@^1.8.1:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==