diff --git a/packages/doenetml-worker/src/components/CallAction.js b/packages/doenetml-worker/src/components/CallAction.js index 72496e8a7..a4b94581c 100644 --- a/packages/doenetml-worker/src/components/CallAction.js +++ b/packages/doenetml-worker/src/components/CallAction.js @@ -10,7 +10,7 @@ import { returnStandardTriggeringAttributes, } from "../utils/triggering"; import InlineComponent from "./abstract/InlineComponent"; -import me from "math-expressions"; +import { returnSelectedStyleStateVariableDefinition } from "@doenet/utils"; export default class CallAction extends InlineComponent { constructor(args) { @@ -109,6 +109,11 @@ export default class CallAction extends InlineComponent { static returnStateVariableDefinitions() { let stateVariableDefinitions = super.returnStateVariableDefinitions(); + let selectedStyleDefinition = + returnSelectedStyleStateVariableDefinition(); + + Object.assign(stateVariableDefinitions, selectedStyleDefinition); + addStandardTriggeringStateVariableDefinitions( stateVariableDefinitions, "callAction", diff --git a/packages/doenetml-worker/src/components/TriggerSet.js b/packages/doenetml-worker/src/components/TriggerSet.js index 26f282b20..cf73ae85c 100644 --- a/packages/doenetml-worker/src/components/TriggerSet.js +++ b/packages/doenetml-worker/src/components/TriggerSet.js @@ -9,7 +9,7 @@ import { returnStandardTriggeringAttributes, } from "../utils/triggering"; import InlineComponent from "./abstract/InlineComponent"; -import me from "math-expressions"; +import { returnSelectedStyleStateVariableDefinition } from "@doenet/utils"; export default class triggerSet extends InlineComponent { constructor(args) { @@ -72,6 +72,11 @@ export default class triggerSet extends InlineComponent { static returnStateVariableDefinitions() { let stateVariableDefinitions = super.returnStateVariableDefinitions(); + let selectedStyleDefinition = + returnSelectedStyleStateVariableDefinition(); + + Object.assign(stateVariableDefinitions, selectedStyleDefinition); + addStandardTriggeringStateVariableDefinitions( stateVariableDefinitions, "triggerActions", diff --git a/packages/doenetml-worker/src/components/UpdateValue.js b/packages/doenetml-worker/src/components/UpdateValue.js index 2c645cf21..bfb29b78f 100644 --- a/packages/doenetml-worker/src/components/UpdateValue.js +++ b/packages/doenetml-worker/src/components/UpdateValue.js @@ -10,6 +10,7 @@ import { returnStandardTriggeringAttributes, } from "../utils/triggering"; import InlineComponent from "./abstract/InlineComponent"; +import { returnSelectedStyleStateVariableDefinition } from "@doenet/utils"; export default class UpdateValue extends InlineComponent { constructor(args) { @@ -130,6 +131,11 @@ export default class UpdateValue extends InlineComponent { static returnStateVariableDefinitions() { let stateVariableDefinitions = super.returnStateVariableDefinitions(); + let selectedStyleDefinition = + returnSelectedStyleStateVariableDefinition(); + + Object.assign(stateVariableDefinitions, selectedStyleDefinition); + addStandardTriggeringStateVariableDefinitions( stateVariableDefinitions, "updateValue", diff --git a/packages/doenetml-worker/src/test/tagSpecific/callAction.test.ts b/packages/doenetml-worker/src/test/tagSpecific/callAction.test.ts index f8ae883e3..924bec46a 100644 --- a/packages/doenetml-worker/src/test/tagSpecific/callAction.test.ts +++ b/packages/doenetml-worker/src/test/tagSpecific/callAction.test.ts @@ -2613,4 +2613,28 @@ describe("callAction tag tests", async () => { "Disabled 2: true", ); }); + + it("buttons can be styled", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + + + + + + `, + }); + + let stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/ca1"].stateValues.selectedStyle.fillColor).eq( + "green", + ); + expect(stateVariables["/ca2"].stateValues.selectedStyle.fillColor).eq( + "yellow", + ); + }); }); diff --git a/packages/doenetml-worker/src/test/tagSpecific/mathinput.test.ts b/packages/doenetml-worker/src/test/tagSpecific/mathinput.test.ts index b96a28338..1dbba0e81 100644 --- a/packages/doenetml-worker/src/test/tagSpecific/mathinput.test.ts +++ b/packages/doenetml-worker/src/test/tagSpecific/mathinput.test.ts @@ -6,8 +6,6 @@ import { updateMathInputImmediateValue, updateMathInputValue, updateMathInputValueToImmediateValue, - updateMatrixInputValue, - updateTextInputValue, } from "../utils/actions"; const Mock = vi.fn(); diff --git a/packages/doenetml-worker/src/test/tagSpecific/selectsamplerandomnumbers.test.ts b/packages/doenetml-worker/src/test/tagSpecific/selectsamplerandomnumbers.test.ts index 7d612f52d..de726755b 100644 --- a/packages/doenetml-worker/src/test/tagSpecific/selectsamplerandomnumbers.test.ts +++ b/packages/doenetml-worker/src/test/tagSpecific/selectsamplerandomnumbers.test.ts @@ -1597,7 +1597,7 @@ describe("SelectRandomNumbers and SampleRandomNumbers tag tests", async () => { specifiedTo, specifiedStep, sampleComponent: stateVariables["/samples"], - allowedErrorInMean: 0.4, + allowedErrorInMean: 0.6, allowedErrorInVariance: 0.4, checkAllSamples: false, stateVariables, diff --git a/packages/doenetml-worker/src/test/tagSpecific/triggerset.test.ts b/packages/doenetml-worker/src/test/tagSpecific/triggerset.test.ts index e43851bc6..eb05c837b 100644 --- a/packages/doenetml-worker/src/test/tagSpecific/triggerset.test.ts +++ b/packages/doenetml-worker/src/test/tagSpecific/triggerset.test.ts @@ -1558,4 +1558,28 @@ describe("TriggerSet tag tests", async () => { "Disabled 2: true", ); }); + + it("buttons can be styled", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + + + + + + `, + }); + + let stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/ts1"].stateValues.selectedStyle.fillColor).eq( + "green", + ); + expect(stateVariables["/ts2"].stateValues.selectedStyle.fillColor).eq( + "yellow", + ); + }); }); diff --git a/packages/doenetml-worker/src/test/tagSpecific/updatevalue.test.ts b/packages/doenetml-worker/src/test/tagSpecific/updatevalue.test.ts index bc01b0094..5804474a9 100644 --- a/packages/doenetml-worker/src/test/tagSpecific/updatevalue.test.ts +++ b/packages/doenetml-worker/src/test/tagSpecific/updatevalue.test.ts @@ -2898,4 +2898,28 @@ describe("UpdateValue tag tests", async () => { .length, ).eq(2); }); + + it("buttons can be styled", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + + + + + + `, + }); + + let stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/uv1"].stateValues.selectedStyle.fillColor).eq( + "green", + ); + expect(stateVariables["/uv2"].stateValues.selectedStyle.fillColor).eq( + "yellow", + ); + }); }); diff --git a/packages/doenetml/src/DoenetML.css b/packages/doenetml/src/DoenetML.css index 91b32fca4..2d83ad57f 100644 --- a/packages/doenetml/src/DoenetML.css +++ b/packages/doenetml/src/DoenetML.css @@ -144,18 +144,12 @@ div.jxgbox input { } div.jxgbox button { margin: 0; - border-radius: var(--mainBorderRadius); - border-width: 2px; - border-color: var(--mainBlue); - border-style: solid; - padding: 1px 6px; - background-color: var(--mainBlue); + border-radius: 20px; + border-width: 0px; + border-style: hidden; + padding: 0px 10px; color: white; -} -div.jxgbox button:hover { - background-color: var(--lightBlue); - color: black; - border-color: var(--lightBlue); + height: 24px; } div.jxgbox input[type="checkbox"] { margin: 3px 3px 3px 4px; diff --git a/packages/doenetml/src/Viewer/renderers/button.jsx b/packages/doenetml/src/Viewer/renderers/button.jsx index bc77200c3..8bca4b116 100644 --- a/packages/doenetml/src/Viewer/renderers/button.jsx +++ b/packages/doenetml/src/Viewer/renderers/button.jsx @@ -4,6 +4,7 @@ import { Button } from "@doenet/ui-components"; import { BoardContext } from "./graph"; import me from "math-expressions"; import { getPositionFromAnchorByCoordinate } from "./utils/graph"; +import { cesc } from "@doenet/utils"; export default React.memo(function ButtonComponent(props) { let { name, id, SVs, actions, callAction } = useDoenetRenderer( @@ -38,6 +39,8 @@ export default React.memo(function ButtonComponent(props) { let label = SVs.label ? SVs.label : "Button"; + let fillColor = SVs.selectedStyle.fillColor; + useEffect(() => { //On unmount return () => { @@ -54,6 +57,7 @@ export default React.memo(function ButtonComponent(props) { disabled: SVs.disabled, useMathJax: SVs.labelHasLatex, parse: false, + highlight: false, }; let newAnchorPointJXG; @@ -366,7 +370,26 @@ export default React.memo(function ButtonComponent(props) { board.updateRenderer(); } - return ; + // Create css to color the button based on the fillColor from the style definition. + // Note: couldn't figure out how to do it with JSXgraphs cssStyle attribute, + // as that styled the div container rather than the button itself. + // Instead, we're just using an inline style. + let containerId = buttonJXG.current.rendNode.id; + let buttonCSS = ` + #${cesc(containerId)} button { + background-color: ${fillColor}; + } + #${cesc(containerId)} button:hover { + background-color: oklch(from ${fillColor} calc(l * 1.5) c h); + color: black; + }`; + + return ( + + + + + ); } // not in board @@ -384,6 +407,7 @@ export default React.memo(function ButtonComponent(props) { disabled={SVs.disabled} value={label} valueHasLatex={SVs.labelHasLatex} + fillColor={fillColor} /> ); diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json index 3592f4ca1..5a17879e3 100644 --- a/packages/ui-components/package.json +++ b/packages/ui-components/package.json @@ -26,6 +26,9 @@ "command": "vite build", "files": [ "src/**/*.ts", + "src/**/*.js", + "src/**/*.tsx", + "src/**/*.jsx", "tsconfig.json" ], "output": [ diff --git a/packages/ui-components/src/uiComponents/Button.jsx b/packages/ui-components/src/uiComponents/Button.jsx index ad43429dd..1355c2240 100644 --- a/packages/ui-components/src/uiComponents/Button.jsx +++ b/packages/ui-components/src/uiComponents/Button.jsx @@ -11,7 +11,9 @@ const ButtonStyling = styled.button` // border-width: 2px; color: white; background-color: ${(props) => - props.alert ? "var(--mainRed)" : "var(--mainBlue)"}; + props.alert + ? "var(--mainRed)" + : (props.fillColor ?? "var(--mainBlue)")}; border-radius: ${(props) => props.theme.borderRadius}; padding: ${(props) => props.theme.padding}; cursor: pointer; @@ -20,7 +22,11 @@ const ButtonStyling = styled.button` &:hover { background-color: ${(props) => - props.alert ? "var(--lightRed)" : "var(--lightBlue)"}; + props.alert + ? "var(--lightRed)" + : props.fillColor + ? `oklch(from ${props.fillColor} calc(l * 1.5) c h)` + : "var(--lightBlue)"}; color: black; }