@khanacademy/perseus 37.0.1 → 38.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +77 -54
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +77 -54
- package/dist/index.js.map +1 -1
- package/dist/multi-items/item-types.d.ts +4 -3
- package/dist/perseus-api.d.ts +6 -6
- package/dist/perseus-types.d.ts +31 -30
- package/dist/server-item-renderer.d.ts +6 -6
- package/dist/types.d.ts +1 -4
- package/dist/validation.types.d.ts +4 -11
- package/dist/widgets/expression/expression.d.ts +36 -36
- package/dist/widgets/grapher/grapher-types.d.ts +58 -0
- package/dist/widgets/grapher/grapher-validator.d.ts +1 -1
- package/dist/widgets/grapher/util.d.ts +16 -3
- package/dist/widgets/label-image/label-image.d.ts +12 -12
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export { default as WIDGET_PROP_DENYLIST } from "./mixins/widget-prop-denylist";
|
|
|
82
82
|
export type { PerseusOptions } from "./init";
|
|
83
83
|
export type { ILogger, LogErrorOptions } from "./logging/log";
|
|
84
84
|
export type { ServerItemRenderer as ServerItemRendererComponent } from "./server-item-renderer";
|
|
85
|
-
export type { Alignment, APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, DomInsertCheckFn, EditorMode, FocusPath, ImageDict, ImageUploader, JiptLabelStore, JiptRenderer, PerseusDependencies, PerseusScore, Version, VideoData, VideoKind,
|
|
85
|
+
export type { Alignment, APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, DomInsertCheckFn, EditorMode, FocusPath, ImageDict, ImageUploader, JiptLabelStore, JiptRenderer, PerseusDependencies, PerseusScore, Version, VideoData, VideoKind, WidgetExports, SharedRendererProps, } from "./types";
|
|
86
86
|
export type { ParsedValue } from "./util";
|
|
87
87
|
export type { Hint, LegacyButtonSets, LockedFigure, LockedFigureColor, LockedFigureFillType, LockedFigureType, LockedPointType, LockedLineType, LockedVectorType, LockedEllipseType, LockedPolygonType, LockedFunctionType, LockedLabelType, PerseusGraphType, PerseusAnswerArea, PerseusExpressionWidgetOptions, Range, Size, CollinearTuple, MathFormat, InputNumberWidget, // TODO(jeremy): remove?
|
|
88
88
|
PerseusImageBackground, PerseusInputNumberWidgetOptions, PerseusInteractiveGraphWidgetOptions, PerseusItem, PerseusPhetSimulationWidgetOptions, PerseusPlotterWidgetOptions, PerseusPythonProgramWidgetOptions, PerseusRadioWidgetOptions, PerseusExampleWidgetOptions, PerseusSimpleMarkdownTesterWidgetOptions, PerseusRenderer, PerseusWidget, PerseusWidgetsMap, MultiItem, } from "./perseus-types";
|
package/dist/index.js
CHANGED
|
@@ -10084,9 +10084,6 @@ const setLabelMargins = function (span, size) {
|
|
|
10084
10084
|
// Inherited line-height values can really mess up placement.
|
|
10085
10085
|
$container.css("line-height", "normal");
|
|
10086
10086
|
|
|
10087
|
-
// TODO: Verify that this change doesn't impact other graphies
|
|
10088
|
-
// Check the full list of consuming widgets.
|
|
10089
|
-
|
|
10090
10087
|
// If the change in line-height affected the height of the element,
|
|
10091
10088
|
// then the height used for calculations should be updated.
|
|
10092
10089
|
// This can happen when the first label in the container calls this method,
|
|
@@ -28539,7 +28536,7 @@ const Exponential = ___default["default"].extend({}, PlotDefaults, {
|
|
|
28539
28536
|
* coordinate, and `false` uses oldCoord as the resulting coordinate.
|
|
28540
28537
|
*/
|
|
28541
28538
|
extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
28542
|
-
const y =
|
|
28539
|
+
const y = asymptote[0][1];
|
|
28543
28540
|
return ___default["default"].all(coords, coord => coord[1] !== y);
|
|
28544
28541
|
},
|
|
28545
28542
|
extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
@@ -28563,7 +28560,7 @@ const Exponential = ___default["default"].extend({}, PlotDefaults, {
|
|
|
28563
28560
|
getCoefficients: function (coords, asymptote) {
|
|
28564
28561
|
const p1 = coords[0];
|
|
28565
28562
|
const p2 = coords[1];
|
|
28566
|
-
const c =
|
|
28563
|
+
const c = asymptote[0][1];
|
|
28567
28564
|
const b = Math.log((p1[1] - c) / (p2[1] - c)) / (p1[0] - p2[0]);
|
|
28568
28565
|
const a = (p1[1] - c) / Math.exp(b * p1[0]);
|
|
28569
28566
|
return [a, b, c];
|
|
@@ -28590,7 +28587,7 @@ const Logarithm = ___default["default"].extend({}, PlotDefaults, {
|
|
|
28590
28587
|
defaultCoords: [[0.55, 0.5], [0.75, 0.75]],
|
|
28591
28588
|
defaultAsymptote: [[0.5, 0], [0.5, 1.0]],
|
|
28592
28589
|
extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
28593
|
-
const x =
|
|
28590
|
+
const x = asymptote[0][0];
|
|
28594
28591
|
return ___default["default"].all(coords, coord => coord[0] !== x) && coords[0][1] !== coords[1][1];
|
|
28595
28592
|
},
|
|
28596
28593
|
extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
@@ -28618,10 +28615,12 @@ const Logarithm = ___default["default"].extend({}, PlotDefaults, {
|
|
|
28618
28615
|
// logic between the two 'models'.
|
|
28619
28616
|
const flip = coord => [coord[1], coord[0]];
|
|
28620
28617
|
const inverseCoeffs = Exponential.getCoefficients(___default["default"].map(coords, flip), ___default["default"].map(asymptote, flip));
|
|
28621
|
-
|
|
28622
|
-
|
|
28623
|
-
|
|
28624
|
-
|
|
28618
|
+
if (inverseCoeffs) {
|
|
28619
|
+
const c = -inverseCoeffs[2] / inverseCoeffs[0];
|
|
28620
|
+
const b = 1 / inverseCoeffs[0];
|
|
28621
|
+
const a = 1 / inverseCoeffs[1];
|
|
28622
|
+
return [a, b, c];
|
|
28623
|
+
}
|
|
28625
28624
|
},
|
|
28626
28625
|
getFunctionForCoeffs: function (coeffs, x, asymptote) {
|
|
28627
28626
|
const a = coeffs[0],
|
|
@@ -28685,11 +28684,9 @@ const functionTypeMapping = {
|
|
|
28685
28684
|
absolute_value: AbsoluteValue
|
|
28686
28685
|
};
|
|
28687
28686
|
const allTypes = ___default["default"].keys(functionTypeMapping);
|
|
28688
|
-
function functionForType(
|
|
28689
|
-
//
|
|
28690
|
-
//
|
|
28691
|
-
// is a big amount of work/change.
|
|
28692
|
-
type) {
|
|
28687
|
+
function functionForType(type) {
|
|
28688
|
+
// @ts-expect-error: TypeScript doesn't know how to use deal with generics
|
|
28689
|
+
// and conditional types in this way.
|
|
28693
28690
|
return functionTypeMapping[type];
|
|
28694
28691
|
}
|
|
28695
28692
|
const getEquationString = props => {
|
|
@@ -28754,12 +28751,13 @@ const defaultPlotProps = (type, graph) => {
|
|
|
28754
28751
|
// widget before even reading the question; you can't lose, but you
|
|
28755
28752
|
// might get a free win.
|
|
28756
28753
|
const model = functionForType(type);
|
|
28754
|
+
const defaultAsymptote = "defaultAsymptote" in model ? model.defaultAsymptote : null;
|
|
28757
28755
|
const gridStep = [1, 1];
|
|
28758
28756
|
// @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number]'.
|
|
28759
28757
|
const snapStep = Util.snapStepFromGridStep(gridStep);
|
|
28760
28758
|
return {
|
|
28761
28759
|
type,
|
|
28762
|
-
asymptote: maybePointsFromNormalized(
|
|
28760
|
+
asymptote: maybePointsFromNormalized(defaultAsymptote, graph.range, graph.step, snapStep),
|
|
28763
28761
|
coords: null
|
|
28764
28762
|
};
|
|
28765
28763
|
};
|
|
@@ -28819,8 +28817,19 @@ var util = /*#__PURE__*/Object.freeze({
|
|
|
28819
28817
|
typeToButton: typeToButton
|
|
28820
28818
|
});
|
|
28821
28819
|
|
|
28822
|
-
function
|
|
28823
|
-
if (
|
|
28820
|
+
function getCoefficientsByType(data) {
|
|
28821
|
+
if (data.type === "exponential" || data.type === "logarithm") {
|
|
28822
|
+
const grader = functionForType(data.type);
|
|
28823
|
+
return grader.getCoefficients(data.coords, data.asymptote);
|
|
28824
|
+
} else if (data.type === "linear" || data.type === "quadratic" || data.type === "absolute_value" || data.type === "sinusoid" || data.type === "tangent") {
|
|
28825
|
+
const grader = functionForType(data.type);
|
|
28826
|
+
return grader.getCoefficients(data.coords);
|
|
28827
|
+
} else {
|
|
28828
|
+
throw new perseusCore.PerseusError("Invalid grapher type", perseusCore.Errors.InvalidInput);
|
|
28829
|
+
}
|
|
28830
|
+
}
|
|
28831
|
+
function grapherValidator(userInput, rubric) {
|
|
28832
|
+
if (userInput.type !== rubric.correct.type) {
|
|
28824
28833
|
return {
|
|
28825
28834
|
type: "points",
|
|
28826
28835
|
earned: 0,
|
|
@@ -28830,7 +28839,7 @@ function grapherValidator(state, rubric) {
|
|
|
28830
28839
|
}
|
|
28831
28840
|
|
|
28832
28841
|
// We haven't moved the coords
|
|
28833
|
-
if (
|
|
28842
|
+
if (userInput.coords == null) {
|
|
28834
28843
|
return {
|
|
28835
28844
|
type: "invalid",
|
|
28836
28845
|
message: null
|
|
@@ -28838,11 +28847,9 @@ function grapherValidator(state, rubric) {
|
|
|
28838
28847
|
}
|
|
28839
28848
|
|
|
28840
28849
|
// Get new function handler for grading
|
|
28841
|
-
const grader = functionForType(
|
|
28842
|
-
const guessCoeffs =
|
|
28843
|
-
const correctCoeffs =
|
|
28844
|
-
// @ts-expect-error - TS(2339) - Property 'asymptote' does not exist on type '{ type: "absolute_value"; coords: [Coord, Coord]; }'
|
|
28845
|
-
rubric.correct.asymptote);
|
|
28850
|
+
const grader = functionForType(userInput.type);
|
|
28851
|
+
const guessCoeffs = getCoefficientsByType(userInput);
|
|
28852
|
+
const correctCoeffs = getCoefficientsByType(rubric.correct);
|
|
28846
28853
|
if (guessCoeffs == null || correctCoeffs == null) {
|
|
28847
28854
|
return {
|
|
28848
28855
|
type: "invalid",
|
|
@@ -42409,17 +42416,23 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
42409
42416
|
const results = [];
|
|
42410
42417
|
|
|
42411
42418
|
// For convenience, extract some props into separate variables
|
|
42412
|
-
const
|
|
42413
|
-
|
|
42419
|
+
const {
|
|
42420
|
+
range,
|
|
42421
|
+
labelRange,
|
|
42422
|
+
labelStyle,
|
|
42423
|
+
labelTicks,
|
|
42424
|
+
tickStep,
|
|
42425
|
+
numDivisions
|
|
42426
|
+
} = props;
|
|
42414
42427
|
const leftLabel = labelRange[0] == null ? range[0] : labelRange[0];
|
|
42415
42428
|
const rightLabel = labelRange[1] == null ? range[1] : labelRange[1];
|
|
42416
42429
|
|
|
42417
42430
|
// Find base via GCD for non-reduced fractions
|
|
42418
42431
|
let base;
|
|
42419
|
-
if (
|
|
42432
|
+
if (labelStyle === "non-reduced") {
|
|
42420
42433
|
const fractions = [leftLabel, rightLabel];
|
|
42421
|
-
for (let i = 0; i <=
|
|
42422
|
-
const x = range[0] + i *
|
|
42434
|
+
for (let i = 0; i <= numDivisions; i++) {
|
|
42435
|
+
const x = range[0] + i * tickStep;
|
|
42423
42436
|
fractions.push(x);
|
|
42424
42437
|
}
|
|
42425
42438
|
const getDenom = x => kmath.number.toFraction(x)[1];
|
|
@@ -42428,30 +42441,40 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
|
|
|
42428
42441
|
} else {
|
|
42429
42442
|
base = undefined;
|
|
42430
42443
|
}
|
|
42431
|
-
|
|
42432
|
-
// Draw and save the tick marks and tick labels
|
|
42433
|
-
for (let i = 0; i <= props.numDivisions; i++) {
|
|
42434
|
-
const x = range[0] + i * props.tickStep;
|
|
42435
|
-
results.push(graphie.line([x, -0.2], [x, 0.2]));
|
|
42436
|
-
const labelTicks = props.labelTicks;
|
|
42437
|
-
if (labelTicks || props.labelStyle === "decimal ticks") {
|
|
42438
|
-
if (x === leftLabel || x === rightLabel) {
|
|
42439
|
-
results.push(graphie.style({
|
|
42440
|
-
color: KhanColors.BLUE
|
|
42441
|
-
}, () => _label(graphie, props.labelStyle, x, x, base)));
|
|
42442
|
-
} else {
|
|
42443
|
-
results.push(_label(graphie, props.labelStyle, x, x, base));
|
|
42444
|
-
}
|
|
42445
|
-
}
|
|
42446
|
-
}
|
|
42447
|
-
|
|
42448
|
-
// Render the labels' lines
|
|
42449
|
-
graphie.style({
|
|
42444
|
+
const highlightedLineStyle = {
|
|
42450
42445
|
stroke: KhanColors.BLUE,
|
|
42451
42446
|
strokeWidth: 3.5
|
|
42452
|
-
}
|
|
42453
|
-
|
|
42454
|
-
|
|
42447
|
+
};
|
|
42448
|
+
const highlightedTextStyle = {
|
|
42449
|
+
color: KhanColors.BLUE
|
|
42450
|
+
};
|
|
42451
|
+
|
|
42452
|
+
// Generate an array of tick numbers:
|
|
42453
|
+
// `Array(props.numDivisions)` makes an array of null values - one for every division marker
|
|
42454
|
+
// `.keys()` gets the index values for each marker placeholder
|
|
42455
|
+
// `.map()` converts the index values into actual tick numbers
|
|
42456
|
+
const initialTicks = [...Array(numDivisions).keys()].map(index => range[0] + index * tickStep);
|
|
42457
|
+
|
|
42458
|
+
// .sort() comparator
|
|
42459
|
+
const byNumericAscending = (a, b) => a - b;
|
|
42460
|
+
|
|
42461
|
+
// Ensure that any label markers and range endpoints are included in the array
|
|
42462
|
+
// Using `Set()` prevents duplication of tick numbers (and is quite performant)
|
|
42463
|
+
const allTicks = [...new Set([...initialTicks, leftLabel, rightLabel, ...range])].sort(byNumericAscending);
|
|
42464
|
+
|
|
42465
|
+
// Cycle through each tick number and add a tick line, and a label (if needed)
|
|
42466
|
+
allTicks.forEach(tick => {
|
|
42467
|
+
const tickIsHighlighted = tick === leftLabel || tick === rightLabel;
|
|
42468
|
+
const lineStyle = tickIsHighlighted ? highlightedLineStyle : null;
|
|
42469
|
+
const textStyle = tickIsHighlighted ? highlightedTextStyle : null;
|
|
42470
|
+
graphie.style(lineStyle, () => {
|
|
42471
|
+
results.push(graphie.line([tick, -0.2], [tick, 0.2]));
|
|
42472
|
+
});
|
|
42473
|
+
if (labelTicks || tickIsHighlighted || labelStyle === "decimal ticks") {
|
|
42474
|
+
graphie.style(textStyle, () => {
|
|
42475
|
+
results.push(_label(graphie, labelStyle, tick, tick, base));
|
|
42476
|
+
});
|
|
42477
|
+
}
|
|
42455
42478
|
});
|
|
42456
42479
|
return results;
|
|
42457
42480
|
});
|
|
@@ -43145,7 +43168,7 @@ class Orderer extends React__namespace.Component {
|
|
|
43145
43168
|
list.splice(index, 0, newCard);
|
|
43146
43169
|
}
|
|
43147
43170
|
this.props.onChange({
|
|
43148
|
-
// @ts-expect-error - TS2345 - Argument of type '{ current: any[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?:
|
|
43171
|
+
// @ts-expect-error - TS2345 - Argument of type '{ current: any[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?: PerseusWidgetsMap | undefined; images?: ImageDict | undefined; ... 13 more ...; plot?: any; }'.
|
|
43149
43172
|
current: list
|
|
43150
43173
|
});
|
|
43151
43174
|
this.setState({
|
|
@@ -43308,7 +43331,7 @@ class Orderer extends React__namespace.Component {
|
|
|
43308
43331
|
};
|
|
43309
43332
|
});
|
|
43310
43333
|
this.props.onChange({
|
|
43311
|
-
// @ts-expect-error - TS2345 - Argument of type '{ current: { content: string; }[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?:
|
|
43334
|
+
// @ts-expect-error - TS2345 - Argument of type '{ current: { content: string; }[]; }' is not assignable to parameter of type '{ hints?: readonly Hint[] | undefined; replace?: boolean | undefined; content?: string | undefined; widgets?: PerseusWidgetsMap | undefined; images?: ImageDict | undefined; ... 13 more ...; plot?: any; }'.
|
|
43312
43335
|
current: list
|
|
43313
43336
|
});
|
|
43314
43337
|
this.setState({
|
|
@@ -45156,7 +45179,7 @@ const init = function (options) {
|
|
|
45156
45179
|
|
|
45157
45180
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45158
45181
|
const libName = "@khanacademy/perseus";
|
|
45159
|
-
const libVersion = "
|
|
45182
|
+
const libVersion = "38.0.0";
|
|
45160
45183
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45161
45184
|
|
|
45162
45185
|
const apiVersion = {
|