Merge pull request #639 from berekuk/cleanups-and-tailwind
Various components cleanups
This commit is contained in:
		
						commit
						14a67e758e
					
				|  | @ -10,23 +10,32 @@ export const Alert: React.FC<{ | |||
|   backgroundColor: string; | ||||
|   headingColor: string; | ||||
|   bodyColor: string; | ||||
|   icon: React.ReactNode; | ||||
|   children: React.ReactNode; | ||||
|   icon: (props: React.ComponentProps<"svg">) => JSX.Element; | ||||
|   iconColor: string; | ||||
|   children?: React.ReactNode; | ||||
| }> = ({ | ||||
|   heading = "Error", | ||||
|   backgroundColor, | ||||
|   headingColor, | ||||
|   bodyColor, | ||||
|   icon, | ||||
|   icon: Icon, | ||||
|   iconColor, | ||||
|   children, | ||||
| }) => { | ||||
|   return ( | ||||
|     <div className={`rounded-md p-4 ${backgroundColor}`}> | ||||
|       <div className="flex"> | ||||
|         <div className="flex-shrink-0">{icon}</div> | ||||
|         <Icon | ||||
|           className={`h-5 w-5 flex-shrink-0 ${iconColor}`} | ||||
|           aria-hidden="true" | ||||
|         /> | ||||
|         <div className="ml-3"> | ||||
|           <h3 className={`text-sm font-medium ${headingColor}`}>{heading}</h3> | ||||
|           <div className={`mt-2 text-sm ${bodyColor}`}>{children}</div> | ||||
|           <header className={`text-sm font-medium ${headingColor}`}> | ||||
|             {heading} | ||||
|           </header> | ||||
|           {children && React.Children.count(children) ? ( | ||||
|             <div className={`mt-2 text-sm ${bodyColor}`}>{children}</div> | ||||
|           ) : null} | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|  | @ -35,49 +44,42 @@ export const Alert: React.FC<{ | |||
| 
 | ||||
| export const ErrorAlert: React.FC<{ | ||||
|   heading: string; | ||||
|   children: React.ReactNode; | ||||
| }> = ({ heading = "Error", children }) => ( | ||||
|   children?: React.ReactNode; | ||||
| }> = (props) => ( | ||||
|   <Alert | ||||
|     heading={heading} | ||||
|     children={children} | ||||
|     {...props} | ||||
|     backgroundColor="bg-red-100" | ||||
|     headingColor="text-red-800" | ||||
|     bodyColor="text-red-700" | ||||
|     icon={<XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />} | ||||
|     icon={XCircleIcon} | ||||
|     iconColor="text-red-400" | ||||
|   /> | ||||
| ); | ||||
| 
 | ||||
| export const MessageAlert: React.FC<{ | ||||
|   heading: string; | ||||
|   children: React.ReactNode; | ||||
| }> = ({ heading = "Error", children }) => ( | ||||
|   children?: React.ReactNode; | ||||
| }> = (props) => ( | ||||
|   <Alert | ||||
|     heading={heading} | ||||
|     children={children} | ||||
|     {...props} | ||||
|     backgroundColor="bg-slate-100" | ||||
|     headingColor="text-slate-700" | ||||
|     bodyColor="text-slate-700" | ||||
|     icon={ | ||||
|       <InformationCircleIcon | ||||
|         className="h-5 w-5 text-slate-400" | ||||
|         aria-hidden="true" | ||||
|       /> | ||||
|     } | ||||
|     icon={InformationCircleIcon} | ||||
|     iconColor="text-slate-400" | ||||
|   /> | ||||
| ); | ||||
| 
 | ||||
| export const SuccessAlert: React.FC<{ | ||||
|   heading: string; | ||||
|   children: React.ReactNode; | ||||
| }> = ({ heading = "Error", children }) => ( | ||||
|   children?: React.ReactNode; | ||||
| }> = (props) => ( | ||||
|   <Alert | ||||
|     heading={heading} | ||||
|     children={children} | ||||
|     {...props} | ||||
|     backgroundColor="bg-green-50" | ||||
|     headingColor="text-green-800" | ||||
|     bodyColor="text-green-700" | ||||
|     icon={ | ||||
|       <CheckCircleIcon className="h-5 w-5 text-green-400" aria-hidden="true" /> | ||||
|     } | ||||
|     icon={CheckCircleIcon} | ||||
|     iconColor="text-green-400" | ||||
|   /> | ||||
| ); | ||||
|  |  | |||
|  | @ -14,13 +14,13 @@ interface CodeEditorProps { | |||
|   showGutter?: boolean; | ||||
| } | ||||
| 
 | ||||
| export let CodeEditor: FC<CodeEditorProps> = ({ | ||||
| export const CodeEditor: FC<CodeEditorProps> = ({ | ||||
|   value, | ||||
|   onChange, | ||||
|   oneLine = false, | ||||
|   showGutter = false, | ||||
|   height, | ||||
| }: CodeEditorProps) => { | ||||
| }) => { | ||||
|   let lineCount = value.split("\n").length; | ||||
|   let id = _.uniqueId(); | ||||
|   return ( | ||||
|  | @ -48,4 +48,3 @@ export let CodeEditor: FC<CodeEditorProps> = ({ | |||
|     /> | ||||
|   ); | ||||
| }; | ||||
| export default CodeEditor; | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| import * as React from "react"; | ||||
| import _ from "lodash"; | ||||
| import { | ||||
|   Distribution, | ||||
|   result, | ||||
|  | @ -34,71 +33,64 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({ | |||
|   showSummary, | ||||
|   width, | ||||
|   showControls = false, | ||||
| }: DistributionChartProps) => { | ||||
|   let [isLogX, setLogX] = React.useState(false); | ||||
|   let [isExpY, setExpY] = React.useState(false); | ||||
|   let shape = distribution.pointSet(); | ||||
|   const [sized, _] = useSize((size) => { | ||||
|     if (shape.tag === "Ok") { | ||||
|       let massBelow0 = | ||||
|         shape.value.continuous.some((x) => x.x <= 0) || | ||||
|         shape.value.discrete.some((x) => x.x <= 0); | ||||
|       let spec = buildVegaSpec(isLogX, isExpY); | ||||
|       let widthProp = width ? width : size.width; | ||||
|       if (widthProp < 20) { | ||||
|         console.warn( | ||||
|           `Width of Distribution is set to ${widthProp}, which is too small` | ||||
|         ); | ||||
|         widthProp = 20; | ||||
|       } | ||||
| 
 | ||||
|       // Check whether we should disable the checkbox
 | ||||
|       var logCheckbox = ( | ||||
|         <CheckBox label="Log X scale" value={isLogX} onChange={setLogX} /> | ||||
|       ); | ||||
|       if (massBelow0) { | ||||
|         logCheckbox = ( | ||||
|           <CheckBox | ||||
|             label="Log X scale" | ||||
|             value={isLogX} | ||||
|             onChange={setLogX} | ||||
|             disabled={true} | ||||
|             tooltip={ | ||||
|               "Your distribution has mass lower than or equal to 0. Log only works on strictly positive values." | ||||
|             } | ||||
|           /> | ||||
|         ); | ||||
|       } | ||||
| 
 | ||||
|       var result = ( | ||||
|         <div style={{ width: widthProp + "px" }}> | ||||
|           <Vega | ||||
|             spec={spec} | ||||
|             data={{ con: shape.value.continuous, dis: shape.value.discrete }} | ||||
|             width={widthProp - 10} | ||||
|             height={height} | ||||
|             actions={false} | ||||
|           /> | ||||
|           <div className="flex justify-center"> | ||||
|             {showSummary && <SummaryTable distribution={distribution} />} | ||||
|           </div> | ||||
|           {showControls && ( | ||||
|             <div> | ||||
|               {logCheckbox} | ||||
|               <CheckBox label="Exp Y scale" value={isExpY} onChange={setExpY} /> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ); | ||||
|     } else { | ||||
|       var result = ( | ||||
| }) => { | ||||
|   const [isLogX, setLogX] = React.useState(false); | ||||
|   const [isExpY, setExpY] = React.useState(false); | ||||
|   const shape = distribution.pointSet(); | ||||
|   const [sized] = useSize((size) => { | ||||
|     if (shape.tag === "Error") { | ||||
|       return ( | ||||
|         <ErrorAlert heading="Distribution Error"> | ||||
|           {distributionErrorToString(shape.value)} | ||||
|         </ErrorAlert> | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
|     const massBelow0 = | ||||
|       shape.value.continuous.some((x) => x.x <= 0) || | ||||
|       shape.value.discrete.some((x) => x.x <= 0); | ||||
|     const spec = buildVegaSpec(isLogX, isExpY); | ||||
| 
 | ||||
|     let widthProp = width ? width : size.width; | ||||
|     if (widthProp < 20) { | ||||
|       console.warn( | ||||
|         `Width of Distribution is set to ${widthProp}, which is too small` | ||||
|       ); | ||||
|       widthProp = 20; | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div style={{ width: widthProp }}> | ||||
|         <Vega | ||||
|           spec={spec} | ||||
|           data={{ con: shape.value.continuous, dis: shape.value.discrete }} | ||||
|           width={widthProp - 10} | ||||
|           height={height} | ||||
|           actions={false} | ||||
|         /> | ||||
|         <div className="flex justify-center"> | ||||
|           {showSummary && <SummaryTable distribution={distribution} />} | ||||
|         </div> | ||||
|         {showControls && ( | ||||
|           <div> | ||||
|             <CheckBox | ||||
|               label="Log X scale" | ||||
|               value={isLogX} | ||||
|               onChange={setLogX} | ||||
|               // Check whether we should disable the checkbox
 | ||||
|               {...(massBelow0 | ||||
|                 ? { | ||||
|                     disabled: true, | ||||
|                     tooltip: | ||||
|                       "Your distribution has mass lower than or equal to 0. Log only works on strictly positive values.", | ||||
|                   } | ||||
|                 : {})} | ||||
|             /> | ||||
|             <CheckBox label="Exp Y scale" value={isExpY} onChange={setExpY} /> | ||||
|           </div> | ||||
|         )} | ||||
|       </div> | ||||
|     ); | ||||
|   }); | ||||
|   return sized; | ||||
| }; | ||||
|  | @ -121,13 +113,13 @@ interface CheckBoxProps { | |||
|   tooltip?: string; | ||||
| } | ||||
| 
 | ||||
| export const CheckBox = ({ | ||||
| export const CheckBox: React.FC<CheckBoxProps> = ({ | ||||
|   label, | ||||
|   onChange, | ||||
|   value, | ||||
|   disabled = false, | ||||
|   tooltip, | ||||
| }: CheckBoxProps) => { | ||||
| }) => { | ||||
|   return ( | ||||
|     <span title={tooltip}> | ||||
|       <input | ||||
|  | @ -141,22 +133,35 @@ export const CheckBox = ({ | |||
|   ); | ||||
| }; | ||||
| 
 | ||||
| const TableHeadCell: React.FC<{ children: React.ReactNode }> = ({ | ||||
|   children, | ||||
| }) => ( | ||||
|   <th className="border border-slate-200 bg-slate-50 py-1 px-2 text-slate-500 font-semibold"> | ||||
|     {children} | ||||
|   </th> | ||||
| ); | ||||
| 
 | ||||
| const Cell: React.FC<{ children: React.ReactNode }> = ({ children }) => ( | ||||
|   <td className="border border-slate-200 py-1 px-2 text-slate-900"> | ||||
|     {children} | ||||
|   </td> | ||||
| ); | ||||
| 
 | ||||
| type SummaryTableProps = { | ||||
|   distribution: Distribution; | ||||
| }; | ||||
| 
 | ||||
| const SummaryTable: React.FC<SummaryTableProps> = ({ | ||||
|   distribution, | ||||
| }: SummaryTableProps) => { | ||||
|   let mean = distribution.mean(); | ||||
|   let p5 = distribution.inv(0.05); | ||||
|   let p10 = distribution.inv(0.1); | ||||
|   let p25 = distribution.inv(0.25); | ||||
|   let p50 = distribution.inv(0.5); | ||||
|   let p75 = distribution.inv(0.75); | ||||
|   let p90 = distribution.inv(0.9); | ||||
|   let p95 = distribution.inv(0.95); | ||||
|   let unwrapResult = ( | ||||
| const SummaryTable: React.FC<SummaryTableProps> = ({ distribution }) => { | ||||
|   const mean = distribution.mean(); | ||||
|   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 unwrapResult = ( | ||||
|     x: result<number, distributionError> | ||||
|   ): React.ReactNode => { | ||||
|     if (x.tag === "Ok") { | ||||
|  | @ -170,19 +175,6 @@ const SummaryTable: React.FC<SummaryTableProps> = ({ | |||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   let TableHeadCell: React.FC<{ children: React.ReactNode }> = ({ | ||||
|     children, | ||||
|   }) => ( | ||||
|     <th className="border border-slate-200 bg-slate-50 py-1 px-2 text-slate-500 font-semibold"> | ||||
|       {children} | ||||
|     </th> | ||||
|   ); | ||||
|   let Cell: React.FC<{ children: React.ReactNode }> = ({ children }) => ( | ||||
|     <td className="border border-slate-200 py-1 px-2 text-slate-900 "> | ||||
|       {children} | ||||
|     </td> | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <table className="border border-collapse border-slate-400"> | ||||
|       <thead className="bg-slate-50"> | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({ | |||
|   chartSettings, | ||||
|   environment, | ||||
|   height, | ||||
| }: FunctionChartProps) => { | ||||
| }) => { | ||||
|   if (fn.parameters.length > 1) { | ||||
|     return ( | ||||
|       <MessageAlert heading="Function Display Not Supported"> | ||||
|  |  | |||
|  | @ -151,7 +151,7 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({ | |||
|   chartSettings, | ||||
|   environment, | ||||
|   height, | ||||
| }: FunctionChart1DistProps) => { | ||||
| }) => { | ||||
|   let [mouseOverlay, setMouseOverlay] = React.useState(0); | ||||
|   function handleHover(_name: string, value: unknown) { | ||||
|     setMouseOverlay(value as number); | ||||
|  | @ -170,16 +170,14 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({ | |||
|         }, | ||||
|       }; | ||||
|   let showChart = | ||||
|     mouseItem.tag === "Ok" && mouseItem.value.tag == "distribution" ? ( | ||||
|     mouseItem.tag === "Ok" && mouseItem.value.tag === "distribution" ? ( | ||||
|       <DistributionChart | ||||
|         distribution={mouseItem.value.value} | ||||
|         width={400} | ||||
|         height={50} | ||||
|         showSummary={false} | ||||
|       /> | ||||
|     ) : ( | ||||
|       <></> | ||||
|     ); | ||||
|     ) : null; | ||||
| 
 | ||||
|   let getPercentilesMemoized = React.useMemo( | ||||
|     () => getPercentiles({ chartSettings, fn, environment }), | ||||
|  |  | |||
|  | @ -14,15 +14,15 @@ interface CodeEditorProps { | |||
|   showGutter?: boolean; | ||||
| } | ||||
| 
 | ||||
| export let JsonEditor: FC<CodeEditorProps> = ({ | ||||
| export const JsonEditor: FC<CodeEditorProps> = ({ | ||||
|   value, | ||||
|   onChange, | ||||
|   oneLine = false, | ||||
|   showGutter = false, | ||||
|   height, | ||||
| }: CodeEditorProps) => { | ||||
|   let lineCount = value.split("\n").length; | ||||
|   let id = _.uniqueId(); | ||||
| }) => { | ||||
|   const lineCount = value.split("\n").length; | ||||
|   const id = _.uniqueId(); | ||||
|   return ( | ||||
|     <AceEditor | ||||
|       value={value} | ||||
|  | @ -47,5 +47,3 @@ export let JsonEditor: FC<CodeEditorProps> = ({ | |||
|     /> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default JsonEditor; | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| import * as React from "react"; | ||||
| import _ from "lodash"; | ||||
| 
 | ||||
| const orderOfMagnitudeNum = (n: number) => { | ||||
|   return Math.pow(10, n); | ||||
|  | @ -74,25 +73,23 @@ export interface NumberShowerProps { | |||
|   precision?: number; | ||||
| } | ||||
| 
 | ||||
| export let NumberShower: React.FC<NumberShowerProps> = ({ | ||||
| export const NumberShower: React.FC<NumberShowerProps> = ({ | ||||
|   number, | ||||
|   precision = 2, | ||||
| }: NumberShowerProps) => { | ||||
|   let numberWithPresentation = numberShow(number, precision); | ||||
| }) => { | ||||
|   const numberWithPresentation = numberShow(number, precision); | ||||
|   return ( | ||||
|     <span> | ||||
|       {numberWithPresentation.value} | ||||
|       {numberWithPresentation.symbol} | ||||
|       {numberWithPresentation.power ? ( | ||||
|         <span> | ||||
|           {"\u00b710"} | ||||
|           {"\u00b7" /* dot symbol */}10 | ||||
|           <span style={{ fontSize: "0.6em", verticalAlign: "super" }}> | ||||
|             {numberWithPresentation.power} | ||||
|           </span> | ||||
|         </span> | ||||
|       ) : ( | ||||
|         <></> | ||||
|       )} | ||||
|       ) : null} | ||||
|     </span> | ||||
|   ); | ||||
| }; | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| import * as React from "react"; | ||||
| import _ from "lodash"; | ||||
| import { | ||||
|   run, | ||||
|   errorValueToString, | ||||
|  | @ -28,6 +27,7 @@ function getRange<a>(x: declaration<a>) { | |||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function getChartSettings<a>(x: declaration<a>): FunctionChartSettings { | ||||
|   let range = getRange(x); | ||||
|   let min = range.floats ? range.floats.min : 0; | ||||
|  | @ -49,12 +49,12 @@ export const VariableBox: React.FC<VariableBoxProps> = ({ | |||
|   heading = "Error", | ||||
|   children, | ||||
|   showTypes = false, | ||||
| }: VariableBoxProps) => { | ||||
| }) => { | ||||
|   if (showTypes) { | ||||
|     return ( | ||||
|       <div className="bg-white border border-grey-200 m-2"> | ||||
|         <div className="border-b border-grey-200 p-3"> | ||||
|           <h3 className="font-mono">{heading}</h3> | ||||
|           <header className="font-mono">{heading}</header> | ||||
|         </div> | ||||
|         <div className="p-3">{children}</div> | ||||
|       </div> | ||||
|  | @ -90,7 +90,7 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({ | |||
|   showControls = false, | ||||
|   chartSettings, | ||||
|   environment, | ||||
| }: SquiggleItemProps) => { | ||||
| }) => { | ||||
|   switch (expression.tag) { | ||||
|     case "number": | ||||
|       return ( | ||||
|  | @ -108,12 +108,8 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({ | |||
|           showTypes={showTypes} | ||||
|         > | ||||
|           {distType === "Symbolic" && showTypes ? ( | ||||
|             <> | ||||
|               <div>{expression.value.toString()}</div> | ||||
|             </> | ||||
|           ) : ( | ||||
|             <></> | ||||
|           )} | ||||
|             <div>{expression.value.toString()}</div> | ||||
|           ) : null} | ||||
|           <DistributionChart | ||||
|             distribution={expression.value} | ||||
|             height={height} | ||||
|  | @ -157,11 +153,11 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({ | |||
|       return ( | ||||
|         <VariableBox heading="Array" showTypes={showTypes}> | ||||
|           {expression.value.map((r, i) => ( | ||||
|             <div key={i} className="flex flex-row pt-1"> | ||||
|             <div key={i} className="flex pt-1"> | ||||
|               <div className="flex-none bg-slate-100 rounded-sm px-1"> | ||||
|                 <h3 className="text-slate-400 font-mono">{i}</h3> | ||||
|                 <header className="text-slate-400 font-mono">{i}</header> | ||||
|               </div> | ||||
|               <div className="px-2 mb-2 grow "> | ||||
|               <div className="px-2 mb-2 grow"> | ||||
|                 <SquiggleItem | ||||
|                   key={i} | ||||
|                   expression={r} | ||||
|  | @ -181,25 +177,27 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({ | |||
|     case "record": | ||||
|       return ( | ||||
|         <VariableBox heading="Record" showTypes={showTypes}> | ||||
|           {Object.entries(expression.value).map(([key, r]) => ( | ||||
|             <div key={key} className="flex flex-row pt-1"> | ||||
|               <div className="flex-none pr-2"> | ||||
|                 <h3 className="text-slate-500 font-mono">{key}:</h3> | ||||
|           <div className="space-y-3"> | ||||
|             {Object.entries(expression.value).map(([key, r]) => ( | ||||
|               <div key={key} className="flex space-x-2"> | ||||
|                 <div className="flex-none"> | ||||
|                   <header className="text-slate-500 font-mono">{key}:</header> | ||||
|                 </div> | ||||
|                 <div className="px-2 grow bg-gray-50 border border-gray-100 rounded-sm"> | ||||
|                   <SquiggleItem | ||||
|                     expression={r} | ||||
|                     width={width !== undefined ? width - 20 : width} | ||||
|                     height={height / 3} | ||||
|                     showTypes={showTypes} | ||||
|                     showSummary={showSummary} | ||||
|                     showControls={showControls} | ||||
|                     chartSettings={chartSettings} | ||||
|                     environment={environment} | ||||
|                   /> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <div className="pl-2 pr-2 mb-2 grow bg-gray-50 border border-gray-100 rounded-sm"> | ||||
|                 <SquiggleItem | ||||
|                   expression={r} | ||||
|                   width={width !== undefined ? width - 20 : width} | ||||
|                   height={height / 3} | ||||
|                   showTypes={showTypes} | ||||
|                   showSummary={showSummary} | ||||
|                   showControls={showControls} | ||||
|                   chartSettings={chartSettings} | ||||
|                   environment={environment} | ||||
|                 /> | ||||
|               </div> | ||||
|             </div> | ||||
|           ))} | ||||
|             ))} | ||||
|           </div> | ||||
|         </VariableBox> | ||||
|       ); | ||||
|     case "arraystring": | ||||
|  | @ -285,7 +283,7 @@ export interface SquiggleChartProps { | |||
|   showControls?: boolean; | ||||
| } | ||||
| 
 | ||||
| let defaultChartSettings = { start: 0, stop: 10, count: 20 }; | ||||
| const defaultChartSettings = { start: 0, stop: 10, count: 20 }; | ||||
| 
 | ||||
| export const SquiggleChart: React.FC<SquiggleChartProps> = ({ | ||||
|   squiggleString = "", | ||||
|  | @ -299,31 +297,29 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({ | |||
|   showTypes = false, | ||||
|   showControls = false, | ||||
|   chartSettings = defaultChartSettings, | ||||
| }: SquiggleChartProps) => { | ||||
| }) => { | ||||
|   let expressionResult = run(squiggleString, bindings, environment, jsImports); | ||||
|   let e = environment ? environment : defaultEnvironment; | ||||
|   let internal: JSX.Element; | ||||
|   if (expressionResult.tag === "Ok") { | ||||
|     let expression = expressionResult.value; | ||||
|     onChange(expression); | ||||
|     internal = ( | ||||
|       <SquiggleItem | ||||
|         expression={expression} | ||||
|         width={width} | ||||
|         height={height} | ||||
|         showSummary={showSummary} | ||||
|         showTypes={showTypes} | ||||
|         showControls={showControls} | ||||
|         chartSettings={chartSettings} | ||||
|         environment={e} | ||||
|       /> | ||||
|     ); | ||||
|   } else { | ||||
|     internal = ( | ||||
|   if (expressionResult.tag !== "Ok") { | ||||
|     return ( | ||||
|       <ErrorAlert heading={"Parse Error"}> | ||||
|         {errorValueToString(expressionResult.value)} | ||||
|       </ErrorAlert> | ||||
|     ); | ||||
|   } | ||||
|   return internal; | ||||
| 
 | ||||
|   let e = environment ?? defaultEnvironment; | ||||
|   let expression = expressionResult.value; | ||||
|   onChange(expression); | ||||
|   return ( | ||||
|     <SquiggleItem | ||||
|       expression={expression} | ||||
|       width={width} | ||||
|       height={height} | ||||
|       showSummary={showSummary} | ||||
|       showTypes={showTypes} | ||||
|       showControls={showControls} | ||||
|       chartSettings={chartSettings} | ||||
|       environment={e} | ||||
|     /> | ||||
|   ); | ||||
| }; | ||||
|  |  | |||
|  | @ -57,8 +57,8 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({ | |||
|   showControls = false, | ||||
|   showSummary = false, | ||||
| }: SquiggleEditorProps) => { | ||||
|   let [expression, setExpression] = React.useState(initialSquiggleString); | ||||
|   let chartSettings = { | ||||
|   const [expression, setExpression] = React.useState(initialSquiggleString); | ||||
|   const chartSettings = { | ||||
|     start: diagramStart, | ||||
|     stop: diagramStop, | ||||
|     count: diagramCount, | ||||
|  | @ -150,17 +150,17 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({ | |||
|   environment, | ||||
|   jsImports = defaultImports, | ||||
| }: SquigglePartialProps) => { | ||||
|   let [expression, setExpression] = React.useState(initialSquiggleString); | ||||
|   let [error, setError] = React.useState<string | null>(null); | ||||
|   const [expression, setExpression] = React.useState(initialSquiggleString); | ||||
|   const [error, setError] = React.useState<string | null>(null); | ||||
| 
 | ||||
|   let runSquiggleAndUpdateBindings = () => { | ||||
|     let squiggleResult = runPartial( | ||||
|   const runSquiggleAndUpdateBindings = () => { | ||||
|     const squiggleResult = runPartial( | ||||
|       expression, | ||||
|       bindings, | ||||
|       environment, | ||||
|       jsImports | ||||
|     ); | ||||
|     if (squiggleResult.tag == "Ok") { | ||||
|     if (squiggleResult.tag === "Ok") { | ||||
|       if (onChange) onChange(squiggleResult.value); | ||||
|       setError(null); | ||||
|     } else { | ||||
|  | @ -181,11 +181,7 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({ | |||
|           height={20} | ||||
|         /> | ||||
|       </div> | ||||
|       {error !== null ? ( | ||||
|         <ErrorAlert heading="Error">{error}</ErrorAlert> | ||||
|       ) : ( | ||||
|         <></> | ||||
|       )} | ||||
|       {error !== null ? <ErrorAlert heading="Error">{error}</ErrorAlert> : null} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|  |  | |||
|  | @ -1,19 +1,21 @@ | |||
| import _ from "lodash"; | ||||
| import React, { FC, ReactElement, useState } from "react"; | ||||
| import React, { FC, Fragment, useState } from "react"; | ||||
| import ReactDOM from "react-dom"; | ||||
| import { SquiggleChart } from "./SquiggleChart"; | ||||
| import CodeEditor from "./CodeEditor"; | ||||
| import JsonEditor from "./JsonEditor"; | ||||
| import { useForm, useWatch } from "react-hook-form"; | ||||
| import { Path, useForm, UseFormRegister, useWatch } from "react-hook-form"; | ||||
| import * as yup from "yup"; | ||||
| import { yupResolver } from "@hookform/resolvers/yup"; | ||||
| import { defaultBindings, environment } from "@quri/squiggle-lang"; | ||||
| import { Tab } from "@headlessui/react"; | ||||
| import { CodeIcon } from "@heroicons/react/solid"; | ||||
| import { CogIcon } from "@heroicons/react/solid"; | ||||
| import { ChartSquareBarIcon } from "@heroicons/react/solid"; | ||||
| import { CurrencyDollarIcon } from "@heroicons/react/solid"; | ||||
| import { Fragment } from "react"; | ||||
| import { | ||||
|   ChartSquareBarIcon, | ||||
|   CodeIcon, | ||||
|   CogIcon, | ||||
|   CurrencyDollarIcon, | ||||
| } from "@heroicons/react/solid"; | ||||
| 
 | ||||
| import { defaultBindings, environment } from "@quri/squiggle-lang"; | ||||
| 
 | ||||
| import { SquiggleChart } from "./SquiggleChart"; | ||||
| import { CodeEditor } from "./CodeEditor"; | ||||
| import { JsonEditor } from "./JsonEditor"; | ||||
| import { ErrorAlert, SuccessAlert } from "./Alert"; | ||||
| 
 | ||||
| interface PlaygroundProps { | ||||
|  | @ -85,49 +87,20 @@ const schema = yup | |||
|   }) | ||||
|   .required(); | ||||
| 
 | ||||
| type InputProps = { | ||||
|   label: string; | ||||
|   children: ReactElement; | ||||
| }; | ||||
| 
 | ||||
| const InputItem: React.FC<InputProps> = ({ label, children }) => ( | ||||
|   <div className="col-span-4"> | ||||
|     <label className="block text-sm font-medium text-gray-600">{label}</label> | ||||
|     <div className="mt-1">{children}</div> | ||||
|   </div> | ||||
| ); | ||||
| 
 | ||||
| let numberStyle = | ||||
|   "max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"; | ||||
| 
 | ||||
| function classNames(...classes: string[]) { | ||||
|   return classes.filter(Boolean).join(" "); | ||||
| } | ||||
| 
 | ||||
| type StyledTabProps = { | ||||
|   name: string; | ||||
|   iconName: string; | ||||
|   icon: (props: React.ComponentProps<"svg">) => JSX.Element; | ||||
| }; | ||||
| 
 | ||||
| const StyledTab: React.FC<StyledTabProps> = ({ name, iconName }) => { | ||||
|   let iconStyle = (isSelected: boolean) => | ||||
|     classNames( | ||||
|       "-ml-0.5 mr-2 h-4 w-4 ", | ||||
|       isSelected ? "text-slate-500" : "text-gray-400 group-hover:text-gray-900" | ||||
|     ); | ||||
| 
 | ||||
|   let icon = (selected: boolean) => | ||||
|     ({ | ||||
|       code: <CodeIcon className={iconStyle(selected)} />, | ||||
|       cog: <CogIcon className={iconStyle(selected)} />, | ||||
|       squareBar: <ChartSquareBarIcon className={iconStyle(selected)} />, | ||||
|       dollar: <CurrencyDollarIcon className={iconStyle(selected)} />, | ||||
|     }[iconName]); | ||||
| 
 | ||||
| const StyledTab: React.FC<StyledTabProps> = ({ name, icon: Icon }) => { | ||||
|   return ( | ||||
|     <Tab key={name} as={Fragment}> | ||||
|       {({ selected }) => ( | ||||
|         <button className="flex rounded-md focus:outline-none focus-visible:ring-offset-gray-100 "> | ||||
|         <button className="group flex rounded-md focus:outline-none focus-visible:ring-offset-gray-100"> | ||||
|           <span | ||||
|             className={classNames( | ||||
|               "p-1 pl-2.5 pr-3.5 rounded-md flex items-center text-sm font-medium", | ||||
|  | @ -136,7 +109,14 @@ const StyledTab: React.FC<StyledTabProps> = ({ name, iconName }) => { | |||
|                 : "" | ||||
|             )} | ||||
|           > | ||||
|             {icon(selected)} | ||||
|             <Icon | ||||
|               className={classNames( | ||||
|                 "-ml-0.5 mr-2 h-4 w-4", | ||||
|                 selected | ||||
|                   ? "text-slate-500" | ||||
|                   : "text-gray-400 group-hover:text-gray-900" | ||||
|               )} | ||||
|             /> | ||||
|             <span | ||||
|               className={ | ||||
|                 selected | ||||
|  | @ -153,17 +133,77 @@ const StyledTab: React.FC<StyledTabProps> = ({ name, iconName }) => { | |||
|   ); | ||||
| }; | ||||
| 
 | ||||
| let SquigglePlayground: FC<PlaygroundProps> = ({ | ||||
| const HeadedSection: FC<{ title: string; children: React.ReactNode }> = ({ | ||||
|   title, | ||||
|   children, | ||||
| }) => ( | ||||
|   <div> | ||||
|     <header className="text-lg leading-6 font-medium text-gray-900"> | ||||
|       {title} | ||||
|     </header> | ||||
|     <div className="mt-4">{children}</div> | ||||
|   </div> | ||||
| ); | ||||
| 
 | ||||
| const Text: FC<{ children: React.ReactNode }> = ({ children }) => ( | ||||
|   <p className="text-sm text-gray-500">{children}</p> | ||||
| ); | ||||
| 
 | ||||
| function InputItem<T>({ | ||||
|   name, | ||||
|   label, | ||||
|   type, | ||||
|   register, | ||||
| }: { | ||||
|   name: Path<T>; | ||||
|   label: string; | ||||
|   type: "number"; | ||||
|   register: UseFormRegister<T>; | ||||
| }) { | ||||
|   const numberStyle = | ||||
|     "max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"; | ||||
| 
 | ||||
|   return ( | ||||
|     <label className="block"> | ||||
|       <div className="text-sm font-medium text-gray-600 mb-1">{label}</div> | ||||
|       <input type={type} {...register(name)} className={numberStyle} /> | ||||
|     </label> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function Checkbox<T>({ | ||||
|   name, | ||||
|   label, | ||||
|   register, | ||||
| }: { | ||||
|   name: Path<T>; | ||||
|   label: string; | ||||
|   register: UseFormRegister<T>; | ||||
| }) { | ||||
|   return ( | ||||
|     <label className="flex items-center"> | ||||
|       <input | ||||
|         type="checkbox" | ||||
|         {...register(name)} | ||||
|         className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||
|       /> | ||||
|       {/* Clicking on the div makes the checkbox lose focus while mouse button is pressed, leading to annoying blinking; I couldn't figure out how to fix this. */} | ||||
|       <div className="ml-3 text-sm font-medium text-gray-700">{label}</div> | ||||
|     </label> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| const SquigglePlayground: FC<PlaygroundProps> = ({ | ||||
|   initialSquiggleString = "", | ||||
|   height = 500, | ||||
|   showTypes = false, | ||||
|   showControls = false, | ||||
|   showSummary = false, | ||||
| }: PlaygroundProps) => { | ||||
|   let [squiggleString, setSquiggleString] = useState(initialSquiggleString); | ||||
|   let [importString, setImportString] = useState("{}"); | ||||
|   let [imports, setImports] = useState({}); | ||||
|   let [importsAreValid, setImportsAreValid] = useState(true); | ||||
| }) => { | ||||
|   const [squiggleString, setSquiggleString] = useState(initialSquiggleString); | ||||
|   const [importString, setImportString] = useState("{}"); | ||||
|   const [imports, setImports] = useState({}); | ||||
|   const [importsAreValid, setImportsAreValid] = useState(true); | ||||
|   const { register, control } = useForm({ | ||||
|     resolver: yupResolver(schema), | ||||
|     defaultValues: { | ||||
|  | @ -183,16 +223,16 @@ let SquigglePlayground: FC<PlaygroundProps> = ({ | |||
|   const vars = useWatch({ | ||||
|     control, | ||||
|   }); | ||||
|   let chartSettings = { | ||||
|   const chartSettings = { | ||||
|     start: Number(vars.diagramStart), | ||||
|     stop: Number(vars.diagramStop), | ||||
|     count: Number(vars.diagramCount), | ||||
|   }; | ||||
|   let env: environment = { | ||||
|   const env: environment = { | ||||
|     sampleCount: Number(vars.sampleCount), | ||||
|     xyPointLength: Number(vars.xyPointLength), | ||||
|   }; | ||||
|   let getChangeJson = (r: string) => { | ||||
|   const getChangeJson = (r: string) => { | ||||
|     setImportString(r); | ||||
|     try { | ||||
|       setImports(JSON.parse(r)); | ||||
|  | @ -202,217 +242,184 @@ let SquigglePlayground: FC<PlaygroundProps> = ({ | |||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   let samplingSettings = ( | ||||
|   const samplingSettings = ( | ||||
|     <div className="space-y-6 p-3 max-w-xl"> | ||||
|       <InputItem label="Sample Count"> | ||||
|         <> | ||||
|           <input | ||||
|             type="number" | ||||
|             {...register("sampleCount")} | ||||
|             className={numberStyle} | ||||
|           /> | ||||
|           <p className="mt-2 text-sm text-gray-500"> | ||||
|       <div> | ||||
|         <InputItem | ||||
|           name="sampleCount" | ||||
|           type="number" | ||||
|           label="Sample Count" | ||||
|           register={register} | ||||
|         /> | ||||
|         <div className="mt-2"> | ||||
|           <Text> | ||||
|             How many samples to use for Monte Carlo simulations. This can | ||||
|             occasionally be overridden by specific Squiggle programs. | ||||
|           </p> | ||||
|         </> | ||||
|       </InputItem> | ||||
|       <InputItem label="Coordinate Count (For PointSet Shapes)"> | ||||
|         <> | ||||
|           <input | ||||
|             type="number" | ||||
|             {...register("xyPointLength")} | ||||
|             className={numberStyle} | ||||
|           /> | ||||
|           <p className="mt-2 text-sm text-gray-500"> | ||||
|           </Text> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div> | ||||
|         <InputItem | ||||
|           name="xyPointLength" | ||||
|           type="number" | ||||
|           register={register} | ||||
|           label="Coordinate Count (For PointSet Shapes)" | ||||
|         /> | ||||
|         <div className="mt-2"> | ||||
|           <Text> | ||||
|             When distributions are converted into PointSet shapes, we need to | ||||
|             know how many coordinates to use. | ||||
|           </p> | ||||
|         </> | ||||
|       </InputItem> | ||||
|           </Text> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| 
 | ||||
|   let viewSettings = ( | ||||
|   const viewSettings = ( | ||||
|     <div className="space-y-6 p-3 divide-y divide-gray-200 max-w-xl"> | ||||
|       <div className="space-y-2"> | ||||
|         <h3 className="text-lg leading-6 font-medium text-gray-900 pb-2"> | ||||
|           General Display Settings | ||||
|         </h3> | ||||
|         <InputItem label="Chart Height (in pixels)"> | ||||
|           <input | ||||
|       <HeadedSection title="General Display Settings"> | ||||
|         <div className="space-y-4"> | ||||
|           <InputItem | ||||
|             name="chartHeight" | ||||
|             type="number" | ||||
|             {...register("chartHeight")} | ||||
|             className={numberStyle} | ||||
|             register={register} | ||||
|             label="Chart Height (in pixels)" | ||||
|           /> | ||||
|         </InputItem> | ||||
|         <div className="relative flex items-start pt-3"> | ||||
|           <div className="flex items-center h-5"> | ||||
|             <input | ||||
|               type="checkbox" | ||||
|               {...register("showTypes")} | ||||
|               className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||
|           <Checkbox | ||||
|             name="showTypes" | ||||
|             register={register} | ||||
|             label="Show information about displayed types" | ||||
|           /> | ||||
|         </div> | ||||
|       </HeadedSection> | ||||
| 
 | ||||
|       <div className="pt-8"> | ||||
|         <HeadedSection title="Distribution Display Settings"> | ||||
|           <div className="space-y-2"> | ||||
|             <Checkbox | ||||
|               register={register} | ||||
|               name="showControls" | ||||
|               label="Show toggles to adjust scale of x and y axes" | ||||
|             /> | ||||
|             <Checkbox | ||||
|               register={register} | ||||
|               name="showSummary" | ||||
|               label="Show summary statistics" | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="ml-3 text-sm"> | ||||
|             <label className="font-medium text-gray-700"> | ||||
|               Show information about displayed types. | ||||
|             </label> | ||||
|           </div> | ||||
|         </div> | ||||
|         </HeadedSection> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="space-y-2 pt-8"> | ||||
|         <h3 className="text-lg leading-6 font-medium text-gray-900 pb-2"> | ||||
|           Distribution Display Settings | ||||
|         </h3> | ||||
| 
 | ||||
|         <div className="relative flex items-start"> | ||||
|           <div className="flex items-center h-5"> | ||||
|             <input | ||||
|               type="checkbox" | ||||
|               {...register("showControls")} | ||||
|               className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||
|             /> | ||||
|       <div className="pt-8"> | ||||
|         <HeadedSection title="Function Display Settings"> | ||||
|           <div className="space-y-6"> | ||||
|             <Text> | ||||
|               When displaying functions of single variables that return numbers | ||||
|               or distributions, we need to use defaults for the x-axis. We need | ||||
|               to select a minimum and maximum value of x to sample, and a number | ||||
|               n of the number of points to sample. | ||||
|             </Text> | ||||
|             <div className="space-y-4"> | ||||
|               <InputItem | ||||
|                 type="number" | ||||
|                 name="diagramStart" | ||||
|                 register={register} | ||||
|                 label="Min X Value" | ||||
|               /> | ||||
|               <InputItem | ||||
|                 type="number" | ||||
|                 name="diagramStop" | ||||
|                 register={register} | ||||
|                 label="Max X Value" | ||||
|               /> | ||||
|               <InputItem | ||||
|                 type="number" | ||||
|                 name="diagramCount" | ||||
|                 register={register} | ||||
|                 label="Points between X min and X max to sample" | ||||
|               /> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div className="ml-3 text-sm"> | ||||
|             <label className="font-medium text-gray-700"> | ||||
|               Show toggles to adjust scale of x and y axes | ||||
|             </label> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className="relative flex items-start"> | ||||
|           <div className="flex items-center h-5"> | ||||
|             <input | ||||
|               type="checkbox" | ||||
|               {...register("showSummary")} | ||||
|               className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="ml-3 text-sm"> | ||||
|             <label className="font-medium text-gray-700"> | ||||
|               Show summary statistics | ||||
|             </label> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="space-y-2 pt-8"> | ||||
|         <h3 className="text-lg leading-6 font-medium text-gray-900 pb-2"> | ||||
|           Function Display Settings | ||||
|         </h3> | ||||
| 
 | ||||
|         <p className="mt-2 text-sm text-gray-500"> | ||||
|           When displaying functions of single variables that return numbers or | ||||
|           distributions, we need to use defaults for the x-axis. We need to | ||||
|           select a minimum and maximum value of x to sample, and a number n of | ||||
|           the number of points to sample. | ||||
|         </p> | ||||
|         <div className="pt-4 grid grid-cols-1 gap-y-4 gap-x-4"> | ||||
|           <InputItem label="Min X Value"> | ||||
|             <input | ||||
|               type="number" | ||||
|               {...register("diagramStart")} | ||||
|               className={numberStyle} | ||||
|             /> | ||||
|           </InputItem> | ||||
|           <InputItem label="Max X Value"> | ||||
|             <input | ||||
|               type="number" | ||||
|               {...register("diagramStop")} | ||||
|               className={numberStyle} | ||||
|             /> | ||||
|           </InputItem> | ||||
|           <InputItem label="Points between X min and X max to sample"> | ||||
|             <input | ||||
|               type="number" | ||||
|               {...register("diagramCount")} | ||||
|               className={numberStyle} | ||||
|             /> | ||||
|           </InputItem> | ||||
|         </div> | ||||
|         </HeadedSection> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| 
 | ||||
|   let inputVariableSettings = ( | ||||
|     <div className="space-y-6 p-3 max-w-3xl"> | ||||
|       <h3 className="text-lg leading-6 font-medium text-gray-900"> | ||||
|         Import Variables from JSON | ||||
|       </h3> | ||||
|       <p className="mt-2 text-sm text-gray-500"> | ||||
|         You can import variables from JSON into your Squiggle code. Variables | ||||
|         are accessed with dollar signs. For example, "timeNow" would be accessed | ||||
|         as "$timeNow". | ||||
|       </p> | ||||
|       <div className="border border-slate-200 mt-6 mb-2"> | ||||
|         <JsonEditor | ||||
|           value={importString} | ||||
|           onChange={getChangeJson} | ||||
|           oneLine={false} | ||||
|           showGutter={true} | ||||
|           height={150} | ||||
|         /> | ||||
|       </div> | ||||
|       <div className="p-1 pt-2"> | ||||
|         {importsAreValid ? ( | ||||
|           <SuccessAlert heading="Valid Json"> | ||||
|             <></> | ||||
|           </SuccessAlert> | ||||
|         ) : ( | ||||
|           <ErrorAlert heading="Invalid JSON"> | ||||
|             You must use valid json in this editor. | ||||
|           </ErrorAlert> | ||||
|         )} | ||||
|       </div> | ||||
|   const inputVariableSettings = ( | ||||
|     <div className="p-3 max-w-3xl"> | ||||
|       <HeadedSection title="Import Variables from JSON"> | ||||
|         <div className="space-y-6"> | ||||
|           <Text> | ||||
|             You can import variables from JSON into your Squiggle code. | ||||
|             Variables are accessed with dollar signs. For example, "timeNow" | ||||
|             would be accessed as "$timeNow". | ||||
|           </Text> | ||||
|           <div className="border border-slate-200 mt-6 mb-2"> | ||||
|             <JsonEditor | ||||
|               value={importString} | ||||
|               onChange={getChangeJson} | ||||
|               oneLine={false} | ||||
|               showGutter={true} | ||||
|               height={150} | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="p-1 pt-2"> | ||||
|             {importsAreValid ? ( | ||||
|               <SuccessAlert heading="Valid JSON" /> | ||||
|             ) : ( | ||||
|               <ErrorAlert heading="Invalid JSON"> | ||||
|                 You must use valid JSON in this editor. | ||||
|               </ErrorAlert> | ||||
|             )} | ||||
|           </div> | ||||
|         </div> | ||||
|       </HeadedSection> | ||||
|     </div> | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <Tab.Group> | ||||
|       <div className=" flex-col flex"> | ||||
|         <div className="pb-4"> | ||||
|           <Tab.List className="p-0.5 rounded-md bg-slate-100 hover:bg-slate-200 inline-flex"> | ||||
|             <StyledTab name="Code" iconName="code" /> | ||||
|             <StyledTab name="Sampling Settings" iconName="cog" /> | ||||
|             <StyledTab name="View Settings" iconName="squareBar" /> | ||||
|             <StyledTab name="Input Variables" iconName="dollar" /> | ||||
|           </Tab.List> | ||||
|       <div className="pb-4"> | ||||
|         <Tab.List className="flex w-fit p-0.5 rounded-md bg-slate-100 hover:bg-slate-200"> | ||||
|           <StyledTab name="Code" icon={CodeIcon} /> | ||||
|           <StyledTab name="Sampling Settings" icon={CogIcon} /> | ||||
|           <StyledTab name="View Settings" icon={ChartSquareBarIcon} /> | ||||
|           <StyledTab name="Input Variables" icon={CurrencyDollarIcon} /> | ||||
|         </Tab.List> | ||||
|       </div> | ||||
|       <div className="flex" style={{ height }}> | ||||
|         <div className="w-1/2"> | ||||
|           <Tab.Panels> | ||||
|             <Tab.Panel> | ||||
|               <div className="border border-slate-200"> | ||||
|                 <CodeEditor | ||||
|                   value={squiggleString} | ||||
|                   onChange={setSquiggleString} | ||||
|                   oneLine={false} | ||||
|                   showGutter={true} | ||||
|                   height={height - 1} | ||||
|                 /> | ||||
|               </div> | ||||
|             </Tab.Panel> | ||||
|             <Tab.Panel>{samplingSettings}</Tab.Panel> | ||||
|             <Tab.Panel>{viewSettings}</Tab.Panel> | ||||
|             <Tab.Panel>{inputVariableSettings}</Tab.Panel> | ||||
|           </Tab.Panels> | ||||
|         </div> | ||||
|         <div className="flex" style={{ height: height + "px" }}> | ||||
|           <div className="w-1/2"> | ||||
|             <Tab.Panels> | ||||
|               <Tab.Panel> | ||||
|                 <div className="border border-slate-200"> | ||||
|                   <CodeEditor | ||||
|                     value={squiggleString} | ||||
|                     onChange={setSquiggleString} | ||||
|                     oneLine={false} | ||||
|                     showGutter={true} | ||||
|                     height={height - 1} | ||||
|                   /> | ||||
|                 </div> | ||||
|               </Tab.Panel> | ||||
|               <Tab.Panel>{samplingSettings}</Tab.Panel> | ||||
|               <Tab.Panel>{viewSettings}</Tab.Panel> | ||||
|               <Tab.Panel>{inputVariableSettings}</Tab.Panel> | ||||
|             </Tab.Panels> | ||||
|           </div> | ||||
| 
 | ||||
|           <div className="w-1/2 p-2 pl-4"> | ||||
|             <div style={{ maxHeight: height + "px" }}> | ||||
|               <SquiggleChart | ||||
|                 squiggleString={squiggleString} | ||||
|                 environment={env} | ||||
|                 chartSettings={chartSettings} | ||||
|                 height={vars.chartHeight} | ||||
|                 showTypes={vars.showTypes} | ||||
|                 showControls={vars.showControls} | ||||
|                 bindings={defaultBindings} | ||||
|                 jsImports={imports} | ||||
|                 showSummary={vars.showSummary} | ||||
|               /> | ||||
|             </div> | ||||
|         <div className="w-1/2 p-2 pl-4"> | ||||
|           <div style={{ maxHeight: height }}> | ||||
|             <SquiggleChart | ||||
|               squiggleString={squiggleString} | ||||
|               environment={env} | ||||
|               chartSettings={chartSettings} | ||||
|               height={vars.chartHeight} | ||||
|               showTypes={vars.showTypes} | ||||
|               showControls={vars.showControls} | ||||
|               bindings={defaultBindings} | ||||
|               jsImports={imports} | ||||
|               showSummary={vars.showSummary} | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|  | @ -421,7 +428,7 @@ let SquigglePlayground: FC<PlaygroundProps> = ({ | |||
| }; | ||||
| export default SquigglePlayground; | ||||
| export function renderSquigglePlaygroundToDom(props: PlaygroundProps) { | ||||
|   let parent = document.createElement("div"); | ||||
|   const parent = document.createElement("div"); | ||||
|   ReactDOM.render(<SquigglePlayground {...props} />, parent); | ||||
|   return parent; | ||||
| } | ||||
|  |  | |||
|  | @ -5,9 +5,9 @@ export { | |||
|   renderSquiggleEditorToDom, | ||||
|   renderSquigglePartialToDom, | ||||
| } from "./components/SquiggleEditor"; | ||||
| import SquigglePlayground, { | ||||
| export { | ||||
|   default as SquigglePlayground, | ||||
|   renderSquigglePlaygroundToDom, | ||||
| } from "./components/SquigglePlayground"; | ||||
| export { SquigglePlayground, renderSquigglePlaygroundToDom }; | ||||
| 
 | ||||
| export { mergeBindings } from "@quri/squiggle-lang"; | ||||
|  |  | |||
|  | @ -1 +0,0 @@ | |||
| {"version":3,"file":"SquiggleChart.stories.js","sourceRoot":"","sources":["SquiggleChart.stories.tsx"],"names":[],"mappings":";;;AAAA,6BAA8B;AAC9B,iDAA+C;AAG/C,qBAAe;IACb,KAAK,EAAE,uBAAuB;IAC9B,SAAS,EAAE,6BAAa;CACzB,CAAA;AAED,IAAM,QAAQ,GAAG,UAAC,EAAgB;QAAf,cAAc,oBAAA;IAAM,OAAA,oBAAC,6BAAa,IAAC,cAAc,EAAE,cAAc,GAAI;AAAjD,CAAiD,CAAA;AAE3E,QAAA,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACxC,eAAO,CAAC,IAAI,GAAG;IACb,cAAc,EAAE,cAAc;CAC/B,CAAC"} | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user