diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4e459652..2f344116 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,9 +12,13 @@ updates: commit-message: prefix: "⬆️" open-pull-requests-limit: 100 + labels: + - "dependencies" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" commit-message: prefix: "⬆️" + labels: + - "dependencies" diff --git a/packages/components/package.json b/packages/components/package.json index 08cc88bd..9e027f37 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@quri/squiggle-components", - "version": "0.3.2", + "version": "0.4.1", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^1.0.0", @@ -8,7 +8,7 @@ "@headlessui/react": "^1.6.6", "@heroicons/react": "^1.0.6", "@hookform/resolvers": "^2.9.7", - "@quri/squiggle-lang": "^0.3.0", + "@quri/squiggle-lang": "^0.4.1", "@react-hook/size": "^2.1.2", "clsx": "^1.2.1", "framer-motion": "^7.2.1", @@ -35,12 +35,12 @@ "@storybook/preset-create-react-app": "^4.1.2", "@storybook/react": "^6.5.10", "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.3.0", + "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^14.4.3", "@types/jest": "^27.5.0", "@types/lodash": "^4.14.184", - "@types/node": "^18.7.13", - "@types/react": "^18.0.9", + "@types/node": "^18.7.15", + "@types/react": "^18.0.18", "@types/styled-components": "^5.1.26", "@types/webpack": "^5.28.0", "cross-env": "^7.0.3", @@ -48,6 +48,7 @@ "postcss-cli": "^10.0.0", "postcss-import": "^14.1.0", "postcss-loader": "^7.0.1", + "postcss-nesting": "^10.1.10", "react": "^18.1.0", "react-scripts": "^5.0.1", "style-loader": "^3.3.1", @@ -55,7 +56,7 @@ "ts-loader": "^9.3.0", "tsconfig-paths-webpack-plugin": "^4.0.0", "typescript": "^4.8.2", - "web-vitals": "^3.0.0", + "web-vitals": "^3.0.1", "webpack": "^5.74.0", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.10.0" @@ -66,7 +67,7 @@ }, "scripts": { "start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public", - "build:cjs": "tsc -b", + "build:cjs": "rm -rf dist/src && tsc -b", "build:css": "postcss ./src/styles/main.css -o ./dist/main.css", "build:storybook": "build-storybook -s public", "build": "yarn run build:cjs && yarn run build:css && yarn run build:storybook", @@ -74,7 +75,7 @@ "all": "yarn bundle && yarn build", "lint": "prettier --check .", "format": "prettier --write .", - "prepack": "yarn bundle && tsc -b" + "prepack": "yarn run build:cjs && yarn run bundle" }, "eslintConfig": { "extends": [ diff --git a/packages/components/src/components/DistributionChart.tsx b/packages/components/src/components/DistributionChart.tsx index 79536e12..eba067bb 100644 --- a/packages/components/src/components/DistributionChart.tsx +++ b/packages/components/src/components/DistributionChart.tsx @@ -1,11 +1,11 @@ import * as React from "react"; import { - Distribution, + SqDistribution, result, - distributionError, - distributionErrorToString, - squiggleExpression, + SqDistributionError, resultMap, + SqRecord, + environment, } from "@quri/squiggle-lang"; import { Vega } from "react-vega"; import { ErrorAlert } from "./Alert"; @@ -28,17 +28,16 @@ export type DistributionPlottingSettings = { export type DistributionChartProps = { plot: Plot; + environment: environment; width?: number; height: number; } & DistributionPlottingSettings; -export function defaultPlot(distribution: Distribution): Plot { +export function defaultPlot(distribution: SqDistribution): Plot { return { distributions: [{ name: "default", distribution }] }; } -export function makePlot(record: { - [key: string]: squiggleExpression; -}): Plot | void { +export function makePlot(record: SqRecord): Plot | void { const plotResult = parsePlot(record); if (plotResult.tag === "Ok") { return plotResult.value; @@ -46,22 +45,29 @@ export function makePlot(record: { } export const DistributionChart: React.FC = (props) => { - const { plot, height, showSummary, width, logX, actions = false } = props; + const { + plot, + environment, + height, + showSummary, + width, + logX, + actions = false, + } = props; const [sized] = useSize((size) => { - let shapes = flattenResult( - plot.distributions.map((x) => - resultMap(x.distribution.pointSet(), (shape) => ({ + const shapes = flattenResult( + plot.distributions.map((x) => { + return resultMap(x.distribution.pointSet(environment), (pointSet) => ({ + ...pointSet.asShape(), name: x.name, // color: x.color, // not supported yet - continuous: shape.continuous, - discrete: shape.discrete, - })) - ) + })); + }) ); if (shapes.tag === "Error") { return ( - {distributionErrorToString(shapes.value)} + {shapes.value.toString()} ); } @@ -96,7 +102,10 @@ export const DistributionChart: React.FC = (props) => { )}
{showSummary && plot.distributions.length === 1 && ( - + )}
@@ -120,32 +129,36 @@ const Cell: React.FC<{ children: React.ReactNode }> = ({ children }) => ( ); type SummaryTableProps = { - distribution: Distribution; + distribution: SqDistribution; + environment: environment; }; -const SummaryTable: React.FC = ({ distribution }) => { - const mean = distribution.mean(); - const stdev = distribution.stdev(); - const p5 = distribution.inv(0.05); - const p10 = distribution.inv(0.1); - const p25 = distribution.inv(0.25); - const p50 = distribution.inv(0.5); - const p75 = distribution.inv(0.75); - const p90 = distribution.inv(0.9); - const p95 = distribution.inv(0.95); +const SummaryTable: React.FC = ({ + distribution, + environment, +}) => { + const mean = distribution.mean(environment); + const stdev = distribution.stdev(environment); + const p5 = distribution.inv(environment, 0.05); + const p10 = distribution.inv(environment, 0.1); + const p25 = distribution.inv(environment, 0.25); + const p50 = distribution.inv(environment, 0.5); + const p75 = distribution.inv(environment, 0.75); + const p90 = distribution.inv(environment, 0.9); + const p95 = distribution.inv(environment, 0.95); - const hasResult = (x: result): boolean => + const hasResult = (x: result): boolean => x.tag === "Ok"; const unwrapResult = ( - x: result + x: result ): React.ReactNode => { if (x.tag === "Ok") { return ; } else { return ( - {distributionErrorToString(x.value)} + {x.value.toString()} ); } diff --git a/packages/components/src/components/FunctionChart.tsx b/packages/components/src/components/FunctionChart.tsx index 73378cd8..2da5d367 100644 --- a/packages/components/src/components/FunctionChart.tsx +++ b/packages/components/src/components/FunctionChart.tsx @@ -1,10 +1,5 @@ import * as React from "react"; -import { - lambdaValue, - environment, - runForeign, - errorValueToString, -} from "@quri/squiggle-lang"; +import { SqLambda, environment, SqValueTag } from "@quri/squiggle-lang"; import { FunctionChart1Dist } from "./FunctionChart1Dist"; import { FunctionChart1Number } from "./FunctionChart1Number"; import { DistributionPlottingSettings } from "./DistributionChart"; @@ -17,7 +12,7 @@ export type FunctionChartSettings = { }; interface FunctionChartProps { - fn: lambdaValue; + fn: SqLambda; chartSettings: FunctionChartSettings; distributionPlotSettings: DistributionPlottingSettings; environment: environment; @@ -38,8 +33,8 @@ export const FunctionChart: React.FC = ({ ); } - const result1 = runForeign(fn, [chartSettings.start], environment); - const result2 = runForeign(fn, [chartSettings.stop], environment); + const result1 = fn.call([chartSettings.start]); + const result2 = fn.call([chartSettings.stop]); const getValidResult = () => { if (result1.tag === "Ok") { return result1; @@ -53,14 +48,12 @@ export const FunctionChart: React.FC = ({ if (validResult.tag === "Error") { return ( - - {errorValueToString(validResult.value)} - + {validResult.value.toString()} ); } switch (validResult.value.tag) { - case "distribution": + case SqValueTag.Distribution: return ( = ({ distributionPlotSettings={distributionPlotSettings} /> ); - case "number": + case SqValueTag.Number: return ( ; -type point = { x: number; value: result }; +type point = { x: number; value: result }; -let getPercentiles = ({ chartSettings, fn, environment }) => { +let getPercentiles = ({ + chartSettings, + fn, + environment, +}: { + chartSettings: FunctionChartSettings; + fn: SqLambda; + environment: environment; +}) => { let chartPointsToRender = _rangeByCount( chartSettings.start, chartSettings.stop, @@ -87,9 +94,9 @@ let getPercentiles = ({ chartSettings, fn, environment }) => { ); let chartPointsData: point[] = chartPointsToRender.map((x) => { - let result = runForeign(fn, [x], environment); + let result = fn.call([x]); if (result.tag === "Ok") { - if (result.value.tag === "distribution") { + if (result.value.tag === SqValueTag.Distribution) { return { x, value: { tag: "Ok", value: result.value.value } }; } else { return { @@ -104,13 +111,13 @@ let getPercentiles = ({ chartSettings, fn, environment }) => { } else { return { x, - value: { tag: "Error", value: errorValueToString(result.value) }, + value: { tag: "Error", value: result.value.toString() }, }; } }); let initialPartition: [ - { x: number; value: Distribution }[], + { x: number; value: SqDistribution }[], { x: number; value: string }[] ] = [[], []]; @@ -126,26 +133,23 @@ let getPercentiles = ({ chartSettings, fn, environment }) => { let groupedErrors: errors = _.groupBy(errors, (x) => x.value); let percentiles: percentiles = functionImage.map(({ x, value }) => { - // We convert it to to a pointSet distribution first, so that in case its a sample set - // distribution, it doesn't internally convert it to a pointSet distribution for every - // single inv() call. - let toPointSet: Distribution = unwrap(value.toPointSet()); - return { + const res = { x: x, - p1: unwrap(toPointSet.inv(0.01)), - p5: unwrap(toPointSet.inv(0.05)), - p10: unwrap(toPointSet.inv(0.1)), - p20: unwrap(toPointSet.inv(0.2)), - p30: unwrap(toPointSet.inv(0.3)), - p40: unwrap(toPointSet.inv(0.4)), - p50: unwrap(toPointSet.inv(0.5)), - p60: unwrap(toPointSet.inv(0.6)), - p70: unwrap(toPointSet.inv(0.7)), - p80: unwrap(toPointSet.inv(0.8)), - p90: unwrap(toPointSet.inv(0.9)), - p95: unwrap(toPointSet.inv(0.95)), - p99: unwrap(toPointSet.inv(0.99)), + p1: unwrap(value.inv(environment, 0.01)), + p5: unwrap(value.inv(environment, 0.05)), + p10: unwrap(value.inv(environment, 0.1)), + p20: unwrap(value.inv(environment, 0.2)), + p30: unwrap(value.inv(environment, 0.3)), + p40: unwrap(value.inv(environment, 0.4)), + p50: unwrap(value.inv(environment, 0.5)), + p60: unwrap(value.inv(environment, 0.6)), + p70: unwrap(value.inv(environment, 0.7)), + p80: unwrap(value.inv(environment, 0.8)), + p90: unwrap(value.inv(environment, 0.9)), + p95: unwrap(value.inv(environment, 0.95)), + p99: unwrap(value.inv(environment, 0.99)), }; + return res; }); return { percentiles, errors: groupedErrors }; @@ -168,19 +172,20 @@ export const FunctionChart1Dist: React.FC = ({ const signalListeners = { mousemove: handleHover, mouseout: handleOut }; //TODO: This custom error handling is a bit hacky and should be improved. - let mouseItem: result = !!mouseOverlay - ? runForeign(fn, [mouseOverlay], environment) + let mouseItem: result = !!mouseOverlay + ? fn.call([mouseOverlay]) : { tag: "Error", - value: { - tag: "RETodo", - value: "Hover x-coordinate returned NaN. Expected a number.", - }, + value: SqError.createOtherError( + "Hover x-coordinate returned NaN. Expected a number." + ), }; let showChart = - mouseItem.tag === "Ok" && mouseItem.value.tag === "distribution" ? ( + mouseItem.tag === "Ok" && + mouseItem.value.tag === SqValueTag.Distribution ? ( }; -let getFunctionImage = ({ chartSettings, fn, environment }) => { +let getFunctionImage = ({ + chartSettings, + fn, + environment, +}: { + chartSettings: FunctionChartSettings; + fn: SqLambda; + environment: environment; +}) => { let chartPointsToRender = _rangeByCount( chartSettings.start, chartSettings.stop, @@ -46,9 +49,9 @@ let getFunctionImage = ({ chartSettings, fn, environment }) => { ); let chartPointsData: point[] = chartPointsToRender.map((x) => { - let result = runForeign(fn, [x], environment); + let result = fn.call([x]); if (result.tag === "Ok") { - if (result.value.tag == "number") { + if (result.value.tag === SqValueTag.Number) { return { x, value: { tag: "Ok", value: result.value.value } }; } else { return { @@ -62,7 +65,7 @@ let getFunctionImage = ({ chartSettings, fn, environment }) => { } else { return { x, - value: { tag: "Error", value: errorValueToString(result.value) }, + value: { tag: "Error", value: result.value.toString() }, }; } }); diff --git a/packages/components/src/components/SquiggleChart.tsx b/packages/components/src/components/SquiggleChart.tsx index 00688512..dfc909f9 100644 --- a/packages/components/src/components/SquiggleChart.tsx +++ b/packages/components/src/components/SquiggleChart.tsx @@ -1,15 +1,14 @@ import * as React from "react"; import { - squiggleExpression, - bindings, + SqValue, environment, - jsImports, - defaultImports, - defaultBindings, defaultEnvironment, + resultMap, + SqValueTag, } from "@quri/squiggle-lang"; import { useSquiggle } from "../lib/hooks"; import { SquiggleViewer } from "./SquiggleViewer"; +import { JsImports } from "../lib/jsImports"; export interface SquiggleChartProps { /** The input string for squiggle */ @@ -27,14 +26,12 @@ export interface SquiggleChartProps { /** If the result is a function, the amount of stops sampled */ diagramCount?: number; /** When the squiggle code gets reevaluated */ - onChange?(expr: squiggleExpression | undefined): void; + onChange?(expr: SqValue | undefined): void; /** CSS width of the element */ width?: number; height?: number; - /** Bindings of previous variables declared */ - bindings?: bindings; /** JS imported parameters */ - jsImports?: jsImports; + jsImports?: JsImports; /** Whether to show a summary of the distribution */ showSummary?: boolean; /** Set the x scale to be logarithmic by deault */ @@ -57,6 +54,7 @@ export interface SquiggleChartProps { } const defaultOnChange = () => {}; +const defaultImports: JsImports = {}; export const SquiggleChart: React.FC = React.memo( ({ @@ -65,7 +63,6 @@ export const SquiggleChart: React.FC = React.memo( environment, onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here height = 200, - bindings = defaultBindings, jsImports = defaultImports, showSummary = false, width, @@ -82,9 +79,8 @@ export const SquiggleChart: React.FC = React.memo( distributionChartActions, enableLocalSettings = false, }) => { - const result = useSquiggle({ + const { result, bindings } = useSquiggle({ code, - bindings, environment, jsImports, onChange, @@ -109,9 +105,13 @@ export const SquiggleChart: React.FC = React.memo( count: diagramCount, }; + const resultToRender = resultMap(result, (value) => + value.tag === SqValueTag.Void ? bindings.asValue() : value + ); + return ( = (props) => { ); }; - -export interface SquigglePartialProps { - /** The text inside the input (controlled) */ - code?: string; - /** The default text inside the input (unControlled) */ - defaultCode?: string; - /** when the environment changes. Used again for notebook magic*/ - onChange?(expr: bindings | undefined): void; - /** When the code changes */ - onCodeChange?(code: string): void; - /** Previously declared variables */ - bindings?: bindings; - /** If the output requires monte carlo sampling, the amount of samples */ - environment?: environment; - /** Variables imported from js */ - jsImports?: jsImports; -} - -export const SquigglePartial: React.FC = ({ - code: controlledCode, - defaultCode = "", - onChange, - onCodeChange, - bindings = defaultBindings, - environment, - jsImports = defaultImports, -}: SquigglePartialProps) => { - const [code, setCode] = useMaybeControlledValue({ - value: controlledCode, - defaultValue: defaultCode, - onChange: onCodeChange, - }); - - const result = useSquigglePartial({ - code, - bindings, - environment, - jsImports, - onChange, - }); - - return ( - - - {result.tag !== "Ok" ? : null} - - ); -}; diff --git a/packages/components/src/components/SquiggleEditorWithImportedBindings.tsx b/packages/components/src/components/SquiggleEditorWithImportedBindings.tsx deleted file mode 100644 index 5dcc3241..00000000 --- a/packages/components/src/components/SquiggleEditorWithImportedBindings.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import { SquiggleEditor } from "./SquiggleEditor"; -import type { SquiggleEditorProps } from "./SquiggleEditor"; -import { runPartial, defaultBindings } from "@quri/squiggle-lang"; -import type { - result, - errorValue, - bindings as bindingsType, -} from "@quri/squiggle-lang"; - -function resultDefault(x: result): bindingsType { - switch (x.tag) { - case "Ok": - return x.value; - case "Error": - return defaultBindings; - } -} - -export type SquiggleEditorWithImportedBindingsProps = SquiggleEditorProps & { - bindingsImportUrl: string; -}; - -export const SquiggleEditorWithImportedBindings: React.FC< - SquiggleEditorWithImportedBindingsProps -> = (props) => { - const { bindingsImportUrl, ...editorProps } = props; - const [bindingsResult, setBindingsResult] = React.useState({ - tag: "Ok", - value: defaultBindings, - } as result); - React.useEffect(() => { - async function retrieveBindings(fileName: string) { - let contents = await fetch(fileName).then((response) => { - return response.text(); - }); - setBindingsResult( - runPartial( - contents, - editorProps.bindings, - editorProps.environment, - editorProps.jsImports - ) - ); - } - retrieveBindings(bindingsImportUrl); - }, [bindingsImportUrl]); - const deliveredBindings = resultDefault(bindingsResult); - return ( - - ); -}; diff --git a/packages/components/src/components/SquiggleErrorAlert.tsx b/packages/components/src/components/SquiggleErrorAlert.tsx index 31d7e352..49179497 100644 --- a/packages/components/src/components/SquiggleErrorAlert.tsx +++ b/packages/components/src/components/SquiggleErrorAlert.tsx @@ -1,11 +1,11 @@ -import { errorValue, errorValueToString } from "@quri/squiggle-lang"; +import { SqError } from "@quri/squiggle-lang"; import React from "react"; import { ErrorAlert } from "./Alert"; type Props = { - error: errorValue; + error: SqError; }; export const SquiggleErrorAlert: React.FC = ({ error }) => { - return {errorValueToString(error)}; + return {error.toString()}; }; diff --git a/packages/components/src/components/SquigglePlayground.tsx b/packages/components/src/components/SquigglePlayground.tsx index dad989a8..8039bbe0 100644 --- a/packages/components/src/components/SquigglePlayground.tsx +++ b/packages/components/src/components/SquigglePlayground.tsx @@ -24,7 +24,7 @@ import { } from "@heroicons/react/solid"; import clsx from "clsx"; -import { defaultBindings, environment } from "@quri/squiggle-lang"; +import { environment } from "@quri/squiggle-lang"; import { SquiggleChart, SquiggleChartProps } from "./SquiggleChart"; import { CodeEditor } from "./CodeEditor"; @@ -39,6 +39,7 @@ import { ViewSettings, viewSettingsSchema } from "./ViewSettings"; import { HeadedSection } from "./ui/HeadedSection"; import { defaultTickFormat } from "../lib/distributionSpecBuilder"; import { Button } from "./ui/Button"; +import { JsImports } from "../lib/jsImports"; type PlaygroundProps = SquiggleChartProps & { /** The initial squiggle string to put in the playground */ @@ -112,8 +113,8 @@ const SamplingSettings: React.FC<{ register: UseFormRegister }> = ({ ); const InputVariablesSettings: React.FC<{ - initialImports: any; // TODO - any json type - setImports: (imports: any) => void; + initialImports: JsImports; + setImports: (imports: JsImports) => void; }> = ({ initialImports, setImports }) => { const [importString, setImportString] = useState(() => JSON.stringify(initialImports) @@ -122,7 +123,7 @@ const InputVariablesSettings: React.FC<{ const onChange = (value: string) => { setImportString(value); - let imports = {} as any; + let imports = {}; try { imports = JSON.parse(value); setImportsAreValid(true); @@ -251,7 +252,7 @@ export const SquigglePlayground: FC = ({ onChange: onCodeChange, }); - const [imports, setImports] = useState({}); + const [imports, setImports] = useState({}); const { register, control } = useForm({ resolver: yupResolver(schema), @@ -309,7 +310,6 @@ export const SquigglePlayground: FC = ({ executionId={executionId} environment={env} {...vars} - bindings={defaultBindings} jsImports={imports} enableLocalSettings={true} /> diff --git a/packages/components/src/components/SquiggleViewer/ExpressionViewer.tsx b/packages/components/src/components/SquiggleViewer/ExpressionViewer.tsx index 51f8dcb4..1aa106c8 100644 --- a/packages/components/src/components/SquiggleViewer/ExpressionViewer.tsx +++ b/packages/components/src/components/SquiggleViewer/ExpressionViewer.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import { squiggleExpression, declaration } from "@quri/squiggle-lang"; +import React, { useContext } from "react"; +import { SqDistributionTag, SqValue, SqValueTag } from "@quri/squiggle-lang"; import { NumberShower } from "../NumberShower"; import { DistributionChart, defaultPlot, makePlot } from "../DistributionChart"; import { FunctionChart, FunctionChartSettings } from "../FunctionChart"; @@ -8,7 +8,10 @@ import { VariableBox } from "./VariableBox"; import { ItemSettingsMenu } from "./ItemSettingsMenu"; import { hasMassBelowZero } from "../../lib/distributionUtils"; import { MergedItemSettings } from "./utils"; +import { ViewerContext } from "./ViewerContext"; +/* +// DISABLED FOR 0.4 branch, for now function getRange(x: declaration) { const first = x.args[0]; switch (first.tag) { @@ -31,15 +34,21 @@ function getChartSettings(x: declaration): FunctionChartSettings { count: 20, }; } +*/ const VariableList: React.FC<{ - path: string[]; + value: SqValue; heading: string; children: (settings: MergedItemSettings) => React.ReactNode; -}> = ({ path, heading, children }) => ( - +}> = ({ value, heading, children }) => ( + {(settings) => ( -
+
{children(settings)}
)} @@ -48,51 +57,44 @@ const VariableList: React.FC<{ export interface Props { /** The output of squiggle's run */ - expression: squiggleExpression; - /** Path to the current item, e.g. `['foo', 'bar', '3']` for `foo.bar[3]`; can be empty on the top-level item. */ - path: string[]; + value: SqValue; width?: number; } -export const ExpressionViewer: React.FC = ({ - path, - expression, - width, -}) => { - if (typeof expression !== "object") { - return ( - - {() => `Unknown expression: ${expression}`} - - ); - } - switch (expression.tag) { - case "number": +export const ExpressionViewer: React.FC = ({ value, width }) => { + const { getMergedSettings } = useContext(ViewerContext); + + switch (value.tag) { + case SqValueTag.Number: return ( - + {() => (
- +
)}
); - case "distribution": { - const distType = expression.value.type(); + case SqValueTag.Distribution: { + const distType = value.value.tag; return ( { - const shape = expression.value.pointSet(); + const shape = value.value.pointSet( + getMergedSettings(value.location).environment + ); return ( @@ -102,7 +104,8 @@ export const ExpressionViewer: React.FC = ({ {(settings) => { return ( = ({ ); } - case "string": + case SqValueTag.String: return ( - + {() => ( <> " - {expression.value} + {value.value} " )} ); - case "boolean": + case SqValueTag.Bool: return ( - - {() => expression.value.toString()} + + {() => value.value.toString()} ); - case "symbol": + case SqValueTag.Symbol: return ( - + {() => ( <> Undefined Symbol: - {expression.value} + {value.value} )} ); - case "call": + case SqValueTag.Call: return ( - - {() => expression.value} + + {() => value.value} ); - case "arraystring": + case SqValueTag.ArrayString: return ( - - {() => expression.value.map((r) => `"${r}"`).join(", ")} + + {() => value.value.map((r) => `"${r}"`).join(", ")} ); - case "date": + case SqValueTag.Date: return ( - - {() => expression.value.toDateString()} + + {() => value.value.toDateString()} ); - case "void": + case SqValueTag.Void: return ( - + {() => "Void"} ); - case "timeDuration": { + case SqValueTag.TimeDuration: { return ( - - {() => } + + {() => } ); } - case "lambda": + case SqValueTag.Lambda: return ( { return ( @@ -191,11 +194,11 @@ export const ExpressionViewer: React.FC = ({ > {(settings) => ( <> -
{`function(${expression.value.parameters.join( - "," - )})`}
+
{`function(${value.value + .parameters() + .join(",")})`}
= ({ )}
); - case "lambdaDeclaration": { + case SqValueTag.Declaration: { return ( { return ( ); }} > {(settings) => ( - +
NOT IMPLEMENTED IN 0.4 YET
+ // )}
); } - case "module": { + case SqValueTag.Module: { return ( - + {(_) => - Object.entries(expression.value) - .filter(([key, _]) => !key.match(/^(Math|System)\./)) + value.value + .entries() + .filter(([key, _]) => !key.match(/^(__result__)$/)) .map(([key, r]) => ( )) @@ -256,23 +260,26 @@ export const ExpressionViewer: React.FC = ({ ); } - case "record": - const plot = makePlot(expression.value); + case SqValueTag.Record: + const plot = makePlot(value.value); if (plot) { return ( { let disableLogX = plot.distributions.some((x) => { - let pointSet = x.distribution.pointSet(); + let pointSet = x.distribution.pointSet( + getMergedSettings(value.location).environment + ); return ( - pointSet.tag === "Ok" && hasMassBelowZero(pointSet.value) + pointSet.tag === "Ok" && + hasMassBelowZero(pointSet.value.asShape()) ); }); return ( = ({ return ( = ({ ); } else { return ( - + {(_) => - Object.entries(expression.value).map(([key, r]) => ( - - )) + value.value + .entries() + .map(([key, r]) => ( + + )) } ); } - case "array": + case SqValueTag.Array: return ( - + {(_) => - expression.value.map((r, i) => ( - - )) + value.value + .getValues() + .map((r, i) => ( + + )) } ); default: { return ( - + {() => (
No display for type: {" "} - - {expression.tag} - + {value.tag}
)}
diff --git a/packages/components/src/components/SquiggleViewer/ItemSettingsMenu.tsx b/packages/components/src/components/SquiggleViewer/ItemSettingsMenu.tsx index 49c2eacc..50f8e5ba 100644 --- a/packages/components/src/components/SquiggleViewer/ItemSettingsMenu.tsx +++ b/packages/components/src/components/SquiggleViewer/ItemSettingsMenu.tsx @@ -4,13 +4,14 @@ import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import { Modal } from "../ui/Modal"; import { ViewSettings, viewSettingsSchema } from "../ViewSettings"; -import { Path, pathAsString } from "./utils"; import { ViewerContext } from "./ViewerContext"; import { defaultTickFormat } from "../../lib/distributionSpecBuilder"; import { PlaygroundContext } from "../SquigglePlayground"; +import { SqValue } from "@quri/squiggle-lang"; +import { locationAsString } from "./utils"; type Props = { - path: Path; + value: SqValue; onChange: () => void; disableLogX?: boolean; withFunctionSettings: boolean; @@ -19,7 +20,7 @@ type Props = { const ItemSettingsModal: React.FC< Props & { close: () => void; resetScroll: () => void } > = ({ - path, + value, onChange, disableLogX, withFunctionSettings, @@ -29,7 +30,7 @@ const ItemSettingsModal: React.FC< const { setSettings, getSettings, getMergedSettings } = useContext(ViewerContext); - const mergedSettings = getMergedSettings(path); + const mergedSettings = getMergedSettings(value.location); const { register, watch } = useForm({ resolver: yupResolver(viewSettingsSchema), @@ -53,8 +54,8 @@ const ItemSettingsModal: React.FC< }); useEffect(() => { const subscription = watch((vars) => { - const settings = getSettings(path); // get the latest version - setSettings(path, { + const settings = getSettings(value.location); // get the latest version + setSettings(value.location, { ...settings, distributionPlotSettings: { showSummary: vars.showSummary, @@ -75,7 +76,7 @@ const ItemSettingsModal: React.FC< onChange(); }); return () => subscription.unsubscribe(); - }, [getSettings, setSettings, onChange, path, watch]); + }, [getSettings, setSettings, onChange, value.location, watch]); const { getLeftPanelElement } = useContext(PlaygroundContext); @@ -83,7 +84,7 @@ const ItemSettingsModal: React.FC< Chart settings - {path.length ? ( + {value.location.path.items.length ? ( <> {" for "} - {pathAsString(path)} + {locationAsString(value.location)} {" "} ) : ( @@ -120,7 +121,7 @@ export const ItemSettingsMenu: React.FC = (props) => { if (!enableLocalSettings) { return null; } - const settings = getSettings(props.path); + const settings = getSettings(props.value.location); const resetScroll = () => { if (!ref.current) return; @@ -139,7 +140,7 @@ export const ItemSettingsMenu: React.FC = (props) => { {settings.distributionPlotSettings || settings.chartSettings ? (