@khanacademy/perseus 7.1.1 → 7.2.1
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/CHANGELOG.md +18 -0
- package/dist/es/index.css +61 -61
- package/dist/es/index.js +100 -168
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +61 -61
- package/dist/index.js +89 -126
- package/dist/index.js.map +1 -1
- package/dist/util.d.ts +7 -12
- package/dist/util.graphie.d.ts +6 -0
- package/dist/util.graphie.js.flow +14 -0
- package/dist/util.js.flow +7 -12
- package/dist/widgets/plotter.d.ts +47 -13
- package/dist/widgets/plotter.js.flow +47 -13
- package/package.json +2 -2
- package/src/__tests__/item-renderer.test.tsx +1 -1
- package/src/components/__stories__/image-loader.stories.tsx +1 -0
- package/src/components/graph.tsx +1 -0
- package/src/components/icon.tsx +1 -0
- package/src/components/image-loader.tsx +1 -0
- package/src/components/number-input.tsx +1 -0
- package/src/components/sortable.tsx +1 -0
- package/src/components/svg-image.tsx +1 -0
- package/src/components/tex-buttons.tsx +1 -0
- package/src/components/text-input.tsx +1 -0
- package/src/components/text-list-editor.tsx +1 -0
- package/src/components/zoomable.tsx +1 -0
- package/src/hints-renderer.tsx +1 -0
- package/src/index.ts +1 -0
- package/src/item-renderer.tsx +1 -0
- package/src/mixins/provide-keypad.tsx +1 -0
- package/src/multi-items/multi-renderer.tsx +1 -0
- package/src/renderer.tsx +1 -0
- package/src/server-item-renderer.tsx +1 -0
- package/src/styles/articles.less +8 -4
- package/src/styles/perseus-renderer.less +47 -38
- package/src/styles/util.less +1 -1
- package/src/styles/variables.boostrap.less +158 -182
- package/src/styles/variables.less +20 -20
- package/src/styles/variables.shared.less +162 -168
- package/src/styles/widgets/categorizer.less +1 -2
- package/src/styles/widgets/expression.less +7 -4
- package/src/styles/widgets/grapher.less +2 -1
- package/src/styles/widgets/image.less +3 -2
- package/src/styles/widgets/interactive-graph.less +4 -2
- package/src/styles/widgets/label-image.less +2 -1
- package/src/styles/widgets/matrix.less +11 -7
- package/src/styles/widgets/orderer.less +2 -1
- package/src/styles/widgets/passage.less +2 -1
- package/src/styles/widgets/plotter.less +4 -3
- package/src/styles/widgets/radio.less +4 -2
- package/src/styles/widgets/sortable.less +1 -1
- package/src/styles/widgets/table.less +2 -1
- package/src/styles/widgets/transformer.less +2 -1
- package/src/styles/widgets/unit.less +2 -1
- package/src/util.graphie.test.ts +45 -0
- package/src/util.graphie.ts +59 -0
- package/src/util.ts +8 -63
- package/src/widgets/__stories__/plotter.stories.tsx +27 -0
- package/src/widgets/__testdata__/plotter.testdata.ts +36 -0
- package/src/widgets/__tests__/__snapshots__/plotter.test.tsx.snap +863 -0
- package/src/widgets/__tests__/plotter.test.tsx +65 -0
- package/src/widgets/categorizer.tsx +1 -0
- package/src/widgets/graded-group-set.tsx +1 -0
- package/src/widgets/graded-group.tsx +1 -0
- package/src/widgets/interaction.tsx +1 -0
- package/src/widgets/label-image/marker.tsx +1 -0
- package/src/widgets/matcher.tsx +1 -0
- package/src/widgets/orderer.tsx +1 -0
- package/src/widgets/passage-ref-target.tsx +1 -0
- package/src/widgets/plotter.tsx +108 -98
- package/src/widgets/radio/base-radio.tsx +1 -0
- package/src/widgets/radio/choice-icon/choice-icon.tsx +1 -0
- package/src/widgets/sorter.tsx +1 -0
- package/src/widgets/transformer.tsx +1 -0
- package/tsconfig-build.tsbuildinfo +1 -1
package/dist/index.js
CHANGED
|
@@ -3009,8 +3009,6 @@ const defaultContext$2 = {
|
|
|
3009
3009
|
};
|
|
3010
3010
|
const context$1 = /*#__PURE__*/React__namespace.createContext(defaultContext$2);
|
|
3011
3011
|
|
|
3012
|
-
/* eslint-disable @babel/no-invalid-this, getter-return, one-var */
|
|
3013
|
-
let supportsPassive = false;
|
|
3014
3012
|
const svgLabelsRegex = /^web\+graphie:/;
|
|
3015
3013
|
// For offline exercises in the mobile app, we download the graphie data
|
|
3016
3014
|
// (svgs and localized data files) and serve them from the local file
|
|
@@ -3018,6 +3016,50 @@ const svgLabelsRegex = /^web\+graphie:/;
|
|
|
3018
3016
|
// in the perseus json with this `file+graphie` prefix to indicate that
|
|
3019
3017
|
// they should have the `file://` protocol instead of `https://`.
|
|
3020
3018
|
const svgLocalLabelsRegex$1 = /^file\+graphie:/;
|
|
3019
|
+
|
|
3020
|
+
// Sometimes other components want to download the actual image e.g. to
|
|
3021
|
+
// determine its size. Here, we transform an .svg-labels url into the
|
|
3022
|
+
// correct image url, and leave normal image urls alone
|
|
3023
|
+
function getRealImageUrl(graphieUrl) {
|
|
3024
|
+
if (isLabeledSVG(graphieUrl)) {
|
|
3025
|
+
return getSvgUrl(graphieUrl);
|
|
3026
|
+
}
|
|
3027
|
+
return graphieUrl;
|
|
3028
|
+
}
|
|
3029
|
+
function isLabeledSVG(graphieUrl) {
|
|
3030
|
+
return svgLabelsRegex.test(graphieUrl) || svgLocalLabelsRegex$1.test(graphieUrl);
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
// For each graphie, there are two urls we need to download from. This gets
|
|
3034
|
+
// the base url without the suffix, and `getSvgUrl` and `getDataUrl` apply
|
|
3035
|
+
// appropriate suffixes to get the image and other data
|
|
3036
|
+
function getBaseUrl(graphieUrl) {
|
|
3037
|
+
return graphieUrl.replace(svgLabelsRegex, "https:").replace(svgLocalLabelsRegex$1, "file:");
|
|
3038
|
+
}
|
|
3039
|
+
function getSvgUrl(graphieUrl) {
|
|
3040
|
+
return getBaseUrl(graphieUrl) + ".svg";
|
|
3041
|
+
}
|
|
3042
|
+
function getDataUrl(graphieUrl) {
|
|
3043
|
+
return getBaseUrl(graphieUrl) + "-data.json";
|
|
3044
|
+
}
|
|
3045
|
+
async function getImageSizeModern(url) {
|
|
3046
|
+
const image = new Image();
|
|
3047
|
+
return new Promise((resolve, reject) => {
|
|
3048
|
+
// Handle the success case
|
|
3049
|
+
image.onload = () => {
|
|
3050
|
+
resolve([image.naturalWidth, image.naturalHeight]);
|
|
3051
|
+
};
|
|
3052
|
+
|
|
3053
|
+
// Handle the error case
|
|
3054
|
+
image.onerror = reject;
|
|
3055
|
+
|
|
3056
|
+
// Kick off the loading
|
|
3057
|
+
image.src = getRealImageUrl(url);
|
|
3058
|
+
});
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
/* eslint-disable @babel/no-invalid-this, getter-return, one-var */
|
|
3062
|
+
let supportsPassive = false;
|
|
3021
3063
|
const nestedMap$2 = function (children, func, context) {
|
|
3022
3064
|
if (Array.isArray(children)) {
|
|
3023
3065
|
// @ts-expect-error [FEI-5003] - TS2322 - Type '(M | readonly M[])[]' is not assignable to type 'M | readonly M[]'.
|
|
@@ -3683,21 +3725,6 @@ const supportsPassiveEvents = () => {
|
|
|
3683
3725
|
function captureScratchpadTouchStart$4(e) {
|
|
3684
3726
|
e.stopPropagation();
|
|
3685
3727
|
}
|
|
3686
|
-
async function getImageSizeModern(url) {
|
|
3687
|
-
const image = new Image();
|
|
3688
|
-
return new Promise((resolve, reject) => {
|
|
3689
|
-
// Handle the success case
|
|
3690
|
-
image.onload = () => {
|
|
3691
|
-
resolve([image.naturalWidth, image.naturalHeight]);
|
|
3692
|
-
};
|
|
3693
|
-
|
|
3694
|
-
// Handle the error case
|
|
3695
|
-
image.onerror = reject;
|
|
3696
|
-
|
|
3697
|
-
// Kick off the loading
|
|
3698
|
-
image.src = url;
|
|
3699
|
-
});
|
|
3700
|
-
}
|
|
3701
3728
|
function getImageSize(url, callback) {
|
|
3702
3729
|
const img = new Image();
|
|
3703
3730
|
img.onload = function () {
|
|
@@ -3727,32 +3754,6 @@ function getImageSize(url, callback) {
|
|
|
3727
3754
|
img.src = getRealImageUrl(url);
|
|
3728
3755
|
}
|
|
3729
3756
|
|
|
3730
|
-
// Sometimes other components want to download the actual image e.g. to
|
|
3731
|
-
// determine its size. Here, we transform an .svg-labels url into the
|
|
3732
|
-
// correct image url, and leave normal image urls alone
|
|
3733
|
-
function getRealImageUrl(url) {
|
|
3734
|
-
if (isLabeledSVG(url)) {
|
|
3735
|
-
return getSvgUrl(url);
|
|
3736
|
-
}
|
|
3737
|
-
return url;
|
|
3738
|
-
}
|
|
3739
|
-
function isLabeledSVG(url) {
|
|
3740
|
-
return svgLabelsRegex.test(url) || svgLocalLabelsRegex$1.test(url);
|
|
3741
|
-
}
|
|
3742
|
-
|
|
3743
|
-
// For each svg+labels, there are two urls we need to download from. This gets
|
|
3744
|
-
// the base url without the suffix, and `getSvgUrl` and `getDataUrl` apply
|
|
3745
|
-
// appropriate suffixes to get the image and other data
|
|
3746
|
-
function getBaseUrl(url) {
|
|
3747
|
-
return url.replace(svgLabelsRegex, "https:").replace(svgLocalLabelsRegex$1, "file:");
|
|
3748
|
-
}
|
|
3749
|
-
function getSvgUrl(url) {
|
|
3750
|
-
return getBaseUrl(url) + ".svg";
|
|
3751
|
-
}
|
|
3752
|
-
function getDataUrl(url) {
|
|
3753
|
-
return getBaseUrl(url) + "-data.json";
|
|
3754
|
-
}
|
|
3755
|
-
|
|
3756
3757
|
/**
|
|
3757
3758
|
* Gets the word right before where the textarea cursor is
|
|
3758
3759
|
*
|
|
@@ -3832,12 +3833,12 @@ const Util = {
|
|
|
3832
3833
|
supportsPassiveEvents,
|
|
3833
3834
|
captureScratchpadTouchStart: captureScratchpadTouchStart$4,
|
|
3834
3835
|
getImageSize,
|
|
3835
|
-
getImageSizeModern,
|
|
3836
|
-
getRealImageUrl,
|
|
3837
|
-
isLabeledSVG,
|
|
3838
|
-
getBaseUrl,
|
|
3839
|
-
getSvgUrl,
|
|
3840
|
-
getDataUrl,
|
|
3836
|
+
getImageSizeModern: getImageSizeModern,
|
|
3837
|
+
getRealImageUrl: getRealImageUrl,
|
|
3838
|
+
isLabeledSVG: isLabeledSVG,
|
|
3839
|
+
getBaseUrl: getBaseUrl,
|
|
3840
|
+
getSvgUrl: getSvgUrl,
|
|
3841
|
+
getDataUrl: getDataUrl,
|
|
3841
3842
|
textarea,
|
|
3842
3843
|
unescapeMathMode: unescapeMathMode$1,
|
|
3843
3844
|
random: random$1
|
|
@@ -38309,26 +38310,11 @@ var PassageRefTarget$1 = {
|
|
|
38309
38310
|
const {
|
|
38310
38311
|
deepEq: deepEq$1
|
|
38311
38312
|
} = Util;
|
|
38312
|
-
const BAR = "bar"
|
|
38313
|
-
|
|
38314
|
-
|
|
38315
|
-
|
|
38316
|
-
|
|
38317
|
-
({
|
|
38318
|
-
type: PropTypes__default["default"].oneOf([BAR, LINE, PIC, HISTOGRAM, DOTPLOT]),
|
|
38319
|
-
labels: PropTypes__default["default"].arrayOf(PropTypes__default["default"].string),
|
|
38320
|
-
categories: PropTypes__default["default"].arrayOf(PropTypes__default["default"].oneOfType([PropTypes__default["default"].number, PropTypes__default["default"].string])),
|
|
38321
|
-
scaleY: PropTypes__default["default"].number,
|
|
38322
|
-
maxY: PropTypes__default["default"].number,
|
|
38323
|
-
snapsPerLine: PropTypes__default["default"].number,
|
|
38324
|
-
picSize: PropTypes__default["default"].number,
|
|
38325
|
-
pixBoxHeight: PropTypes__default["default"].number,
|
|
38326
|
-
picUrl: PropTypes__default["default"].string,
|
|
38327
|
-
plotDimensions: PropTypes__default["default"].arrayOf(PropTypes__default["default"].number),
|
|
38328
|
-
labelInterval: PropTypes__default["default"].number,
|
|
38329
|
-
starting: PropTypes__default["default"].arrayOf(PropTypes__default["default"].number),
|
|
38330
|
-
static: PropTypes__default["default"].bool
|
|
38331
|
-
});
|
|
38313
|
+
const BAR = "bar";
|
|
38314
|
+
const LINE = "line";
|
|
38315
|
+
const PIC = "pic";
|
|
38316
|
+
const HISTOGRAM = "histogram";
|
|
38317
|
+
const DOTPLOT = "dotplot";
|
|
38332
38318
|
class Plotter extends React__namespace.Component {
|
|
38333
38319
|
constructor() {
|
|
38334
38320
|
super(...arguments);
|
|
@@ -38367,11 +38353,11 @@ class Plotter extends React__namespace.Component {
|
|
|
38367
38353
|
self.graphie = graphie;
|
|
38368
38354
|
self.graphie.pics = [];
|
|
38369
38355
|
self.graphie.dotTicks = [];
|
|
38370
|
-
const isBar = self.props.type === BAR
|
|
38371
|
-
|
|
38372
|
-
|
|
38373
|
-
|
|
38374
|
-
|
|
38356
|
+
const isBar = self.props.type === BAR;
|
|
38357
|
+
const isLine = self.props.type === LINE;
|
|
38358
|
+
const isPic = self.props.type === PIC;
|
|
38359
|
+
const isHistogram = self.props.type === HISTOGRAM;
|
|
38360
|
+
const isDotplot = self.props.type === DOTPLOT;
|
|
38375
38361
|
const isTiledPlot = isPic || isDotplot;
|
|
38376
38362
|
const config = {};
|
|
38377
38363
|
const c = config; // c for short
|
|
@@ -38432,9 +38418,7 @@ class Plotter extends React__namespace.Component {
|
|
|
38432
38418
|
|
|
38433
38419
|
// TODO(michaelpolyak): Handle other plot types: Dot, Histogram, Line.
|
|
38434
38420
|
if (isMobile && (isBar || isTiledPlot)) {
|
|
38435
|
-
const maxCategoryHeight = Math.max(0,
|
|
38436
|
-
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'number'.
|
|
38437
|
-
...Object.values(self.state.categoryHeights));
|
|
38421
|
+
const maxCategoryHeight = Math.max(0, ...Object.values(self.state.categoryHeights));
|
|
38438
38422
|
if (maxCategoryHeight) {
|
|
38439
38423
|
// Account for bottom label position, height.
|
|
38440
38424
|
let offsetY = 25;
|
|
@@ -38487,7 +38471,7 @@ class Plotter extends React__namespace.Component {
|
|
|
38487
38471
|
});
|
|
38488
38472
|
}
|
|
38489
38473
|
}
|
|
38490
|
-
if ((isBar || isLine) && isMobile) {
|
|
38474
|
+
if ((isBar || isLine) && isMobile && !this.props.static) {
|
|
38491
38475
|
self.graphie.dragPrompt = graphie.label([c.dimX / 2, c.dimY / 2], i18n__namespace._("Drag handles to make graph"), "center", false).css("font-weight", "bold").css("color", KhanColors.KA_GREEN).css("display", "none");
|
|
38492
38476
|
}
|
|
38493
38477
|
self.setupCategories(config);
|
|
@@ -38739,8 +38723,8 @@ class Plotter extends React__namespace.Component {
|
|
|
38739
38723
|
config.graph.bars[i].scale(1, Math.max(isMobile ? 0.2 : 0.01, height / config.scaleY), center[0], center[1]);
|
|
38740
38724
|
if (isHistogram) {
|
|
38741
38725
|
// Scale dividers between buckets
|
|
38742
|
-
const leftDivider = config.graph.dividers[i - 1]
|
|
38743
|
-
|
|
38726
|
+
const leftDivider = config.graph.dividers[i - 1];
|
|
38727
|
+
const rightDivider = config.graph.dividers[i];
|
|
38744
38728
|
if (leftDivider) {
|
|
38745
38729
|
const divHeight = Math.min(self.state.values[i - 1], height);
|
|
38746
38730
|
leftDivider.scale(1, Math.max(0.01, divHeight / config.scaleY), center[0], center[1]);
|
|
@@ -39065,38 +39049,13 @@ class Plotter extends React__namespace.Component {
|
|
|
39065
39049
|
return Plotter.validate(this.getUserInput(), rubric);
|
|
39066
39050
|
});
|
|
39067
39051
|
}
|
|
39068
|
-
render() {
|
|
39069
|
-
// TODO(kevinb) actually compute the size of the graphie correctly and
|
|
39070
|
-
// make it that size so we don't have to add extra padding. The value
|
|
39071
|
-
// was determined by eye-balling the layout. :(
|
|
39072
|
-
const paddingForBottomLabel = 75;
|
|
39073
|
-
const style = {
|
|
39074
|
-
marginBottom: this.props.labels[0] ? paddingForBottomLabel : 0
|
|
39075
|
-
};
|
|
39076
|
-
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
39077
|
-
className: "perseus-widget-plotter graphie " + ClassNames.INTERACTIVE
|
|
39078
|
-
// eslint-disable-next-line react/no-string-refs
|
|
39079
|
-
,
|
|
39080
|
-
ref: "graphieDiv",
|
|
39081
|
-
style: style
|
|
39082
|
-
});
|
|
39083
|
-
}
|
|
39084
|
-
componentDidUpdate(prevProps, prevState) {
|
|
39085
|
-
this.shouldSetupGraphie = this.shouldSetupGraphie || !___default["default"].isEqual(this.state.categoryHeights, prevState.categoryHeights);
|
|
39086
|
-
if (this.shouldSetupGraphie) {
|
|
39087
|
-
this.setupGraphie(prevState);
|
|
39088
|
-
}
|
|
39089
|
-
}
|
|
39090
39052
|
componentDidMount() {
|
|
39091
39053
|
this._isMounted = true;
|
|
39092
39054
|
this.setupGraphie(this.state);
|
|
39093
39055
|
}
|
|
39094
39056
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
39095
39057
|
const props = ["type", "labels", "categories", "scaleY", "maxY", "snapsPerLine", "picUrl", "labelInterval", "static"];
|
|
39096
|
-
this.shouldSetupGraphie = ___default["default"].any(props,
|
|
39097
|
-
// @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
39098
|
-
return !___default["default"].isEqual(this.props[prop], nextProps[prop]);
|
|
39099
|
-
}, this);
|
|
39058
|
+
this.shouldSetupGraphie = ___default["default"].any(props, prop => !___default["default"].isEqual(this.props[prop], nextProps[prop]), this);
|
|
39100
39059
|
if (!___default["default"].isEqual(this.props.starting, nextProps.starting) && !___default["default"].isEqual(this.state.values, nextProps.starting)) {
|
|
39101
39060
|
this.shouldSetupGraphie = true;
|
|
39102
39061
|
this.setState({
|
|
@@ -39104,16 +39063,32 @@ class Plotter extends React__namespace.Component {
|
|
|
39104
39063
|
});
|
|
39105
39064
|
}
|
|
39106
39065
|
}
|
|
39066
|
+
componentDidUpdate(prevProps, prevState) {
|
|
39067
|
+
this.shouldSetupGraphie = this.shouldSetupGraphie || !___default["default"].isEqual(this.state.categoryHeights, prevState.categoryHeights);
|
|
39068
|
+
if (this.shouldSetupGraphie) {
|
|
39069
|
+
this.setupGraphie(prevState);
|
|
39070
|
+
}
|
|
39071
|
+
}
|
|
39107
39072
|
componentWillUnmount() {
|
|
39108
39073
|
this._isMounted = false;
|
|
39109
39074
|
}
|
|
39075
|
+
render() {
|
|
39076
|
+
// TODO(kevinb) actually compute the size of the graphie correctly and
|
|
39077
|
+
// make it that size so we don't have to add extra padding. The value
|
|
39078
|
+
// was determined by eye-balling the layout. :(
|
|
39079
|
+
const paddingForBottomLabel = 75;
|
|
39080
|
+
const style = {
|
|
39081
|
+
marginBottom: this.props.labels[0] ? paddingForBottomLabel : 0
|
|
39082
|
+
};
|
|
39083
|
+
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
39084
|
+
className: "perseus-widget-plotter graphie " + ClassNames.INTERACTIVE
|
|
39085
|
+
// eslint-disable-next-line react/no-string-refs
|
|
39086
|
+
,
|
|
39087
|
+
ref: "graphieDiv",
|
|
39088
|
+
style: style
|
|
39089
|
+
});
|
|
39090
|
+
}
|
|
39110
39091
|
}
|
|
39111
|
-
_defineProperty(Plotter, "propTypes", {
|
|
39112
|
-
onChange: PropTypes__default["default"].func.isRequired,
|
|
39113
|
-
trackInteraction: PropTypes__default["default"].func.isRequired
|
|
39114
|
-
// TODO(alex): Figure out why lint chokes on this line
|
|
39115
|
-
// ...widgetPropTypes,
|
|
39116
|
-
});
|
|
39117
39092
|
_defineProperty(Plotter, "defaultProps", {
|
|
39118
39093
|
type: BAR,
|
|
39119
39094
|
labels: ["", ""],
|
|
@@ -44146,17 +44121,7 @@ registerWidgets(allWidgets);
|
|
|
44146
44121
|
const ItemVersion = getVersionVector();
|
|
44147
44122
|
ItemVersion["::renderer::"] = version.itemDataVersion;
|
|
44148
44123
|
|
|
44149
|
-
|
|
44150
|
-
* A mixin that renders a custom software keypad in additional to the base
|
|
44151
|
-
* component. The base component will receive blur events when the keypad is
|
|
44152
|
-
* dismissed and can access the keypad element itself so as to manage its
|
|
44153
|
-
* activation and dismissal.
|
|
44154
|
-
*
|
|
44155
|
-
* TODO(charlie): This would make a nicer higher-order component, except that
|
|
44156
|
-
* we need to expose methods on the base component (i.e., `ItemRenderer`). When
|
|
44157
|
-
* `ItemRenderer` and friends are written as ES6 Classes, we can have them
|
|
44158
|
-
* extend a `ProvideKeypad` component instead of using this mixin.
|
|
44159
|
-
*/
|
|
44124
|
+
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
44160
44125
|
// NOTE: This is not a real component. It's a collection of methods used to
|
|
44161
44126
|
// create and manage a Keypad instances.
|
|
44162
44127
|
// TODO(LP-10789): replace this with a React Context object to pass information
|
|
@@ -47077,9 +47042,7 @@ const EditorJsonify = {
|
|
|
47077
47042
|
}
|
|
47078
47043
|
};
|
|
47079
47044
|
|
|
47080
|
-
|
|
47081
|
-
* Main entry point
|
|
47082
|
-
*/
|
|
47045
|
+
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
47083
47046
|
const apiVersion = version.apiVersion;
|
|
47084
47047
|
const itemDataVersion = version.itemDataVersion;
|
|
47085
47048
|
|