diff --git a/packages/components/package.json b/packages/components/package.json index 5015ab35..52a4ebc0 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -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", diff --git a/packages/components/src/components/SquiggleItem.tsx b/packages/components/src/components/SquiggleItem.tsx index e68da76a..647cc08c 100644 --- a/packages/components/src/components/SquiggleItem.tsx +++ b/packages/components/src/components/SquiggleItem.tsx @@ -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(x: declaration) { const first = x.args[0]; @@ -40,59 +40,45 @@ interface VariableBoxProps { name?: string; heading: string; children: React.ReactNode; - showTypes: boolean; } const VariableBox: React.FC = ({ name, heading = "Error", children, - showTypes = false, }) => { const [isCollapsed, setIsCollapsed] = useState(false); return ( - - {name || showTypes ? ( - + {name ? ( +
setIsCollapsed(!isCollapsed)} > - {name ? {name}: : null} - {showTypes ? {heading} : null} + {name ? ( + + {name}: + + ) : null} {isCollapsed ? ( ... ) : null} - +
) : null} - {isCollapsed ? null : ( - - {children} - - )} -
+ {isCollapsed ? null :
{children}
} + ); }; const VariableList: React.FC<{ name?: string; heading: string; - showTypes: boolean; children: React.ReactNode; -}> = ({ name, heading, showTypes, children }) => ( - - - {children} - +}> = ({ name, heading, children }) => ( + +
+ {children} +
); @@ -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 = ({ switch (expression.tag) { case "number": return ( - +
@@ -135,12 +121,10 @@ export const SquiggleItem: React.FC = ({ return ( - {distType === "Symbolic" && showTypes ? ( -
{expression.value.toString()}
- ) : null} = ({ } case "string": return ( - + " {expression.value} @@ -162,45 +146,45 @@ export const SquiggleItem: React.FC = ({ ); case "boolean": return ( - + {expression.value.toString()} ); case "symbol": return ( - + Undefined Symbol: {expression.value} ); case "call": return ( - + {expression.value} ); case "arraystring": return ( - + {expression.value.map((r) => `"${r}"`).join(", ")} ); case "date": return ( - + {expression.value.toDateString()} ); case "timeDuration": { return ( - + ); } case "lambda": return ( - +
{`function(${expression.value.parameters.join( "," )})`}
@@ -218,11 +202,7 @@ export const SquiggleItem: React.FC = ({ ); case "lambdaDeclaration": { return ( - + = ({ } case "module": { return ( - + {Object.entries(expression.value) .filter(([key, r]) => key !== "Math") .map(([key, r]) => ( @@ -248,7 +228,6 @@ export const SquiggleItem: React.FC = ({ 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 = ({ } case "record": return ( - + {Object.entries(expression.value).map(([key, r]) => ( = ({ 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 = ({ ); case "array": return ( - + {expression.value.map((r, i) => ( = ({ width={width !== undefined ? width - 20 : width} height={50} distributionPlotSettings={distributionPlotSettings} - showTypes={showTypes} chartSettings={chartSettings} environment={environment} /> diff --git a/packages/components/src/components/ui/Tooltip.tsx b/packages/components/src/components/ui/Tooltip.tsx new file mode 100644 index 00000000..714f8861 --- /dev/null +++ b/packages/components/src/components/ui/Tooltip.tsx @@ -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 = ({ 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 }) + )} + + {open && ( + +
{text}
+
+ )} +
+ + ); +}; diff --git a/yarn.lock b/yarn.lock index bb697719..a9c08c38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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==