@khanacademy/perseus 48.1.0 → 49.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 +219 -84
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +47 -2
- package/dist/es/strings.js.map +1 -1
- package/dist/index.js +197 -66
- package/dist/index.js.map +1 -1
- package/dist/strings.d.ts +23 -1
- package/dist/strings.js +59 -2
- package/dist/strings.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/widgets/categorizer/validate-categorizer.d.ts +2 -4
- package/dist/widgets/dropdown/validate-dropdown.d.ts +2 -4
- package/dist/widgets/expression/validate-expression.d.ts +2 -4
- package/dist/widgets/interactive-graphs/utils.d.ts +2 -0
- package/dist/widgets/label-image/answer-choices.d.ts +2 -1
- package/dist/widgets/matrix/validate-matrix.d.ts +2 -4
- package/dist/widgets/orderer/validate-orderer.d.ts +2 -4
- package/dist/widgets/plotter/validate-plotter.d.ts +2 -4
- package/dist/widgets/radio/validate-radio.d.ts +2 -4
- package/dist/widgets/sorter/validate-sorter.d.ts +2 -4
- package/dist/widgets/table/validate-table.d.ts +2 -4
- package/package.json +48 -48
package/dist/es/index.js
CHANGED
|
@@ -44,13 +44,21 @@ import cornersOutIcon from '@phosphor-icons/core/regular/corners-out.svg';
|
|
|
44
44
|
import Link from '@khanacademy/wonder-blocks-link';
|
|
45
45
|
|
|
46
46
|
function _extends() {
|
|
47
|
-
|
|
48
|
-
for (var
|
|
49
|
-
var
|
|
50
|
-
|
|
47
|
+
_extends = Object.assign || function (target) {
|
|
48
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
49
|
+
var source = arguments[i];
|
|
50
|
+
|
|
51
|
+
for (var key in source) {
|
|
52
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
53
|
+
target[key] = source[key];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
51
56
|
}
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
|
|
58
|
+
return target;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return _extends.apply(this, arguments);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/**
|
|
@@ -239,6 +247,8 @@ const mockStrings = {
|
|
|
239
247
|
addPoint: "Add Point",
|
|
240
248
|
removePoint: "Remove Point",
|
|
241
249
|
graphKeyboardPrompt: "Press Shift + Enter to interact with the graph",
|
|
250
|
+
selectAnAnswer: "Select an answer",
|
|
251
|
+
// The following strings are used for interactive graph SR descriptions.
|
|
242
252
|
closePolygon: "Close shape",
|
|
243
253
|
openPolygon: "Re-open shape",
|
|
244
254
|
srPointAtCoordinates: ({
|
|
@@ -250,7 +260,29 @@ const mockStrings = {
|
|
|
250
260
|
elements
|
|
251
261
|
}) => `Interactive elements: ${elements}`,
|
|
252
262
|
srNoInteractiveElements: "No interactive elements",
|
|
253
|
-
|
|
263
|
+
circleGraphAriaLabel: "A circle on a coordinate plane.",
|
|
264
|
+
circleShapeAriaLabel: ({
|
|
265
|
+
centerX,
|
|
266
|
+
centerY
|
|
267
|
+
}) => `Circle. The center point is at ${centerX} comma ${centerY}.`,
|
|
268
|
+
circleRadiusPointAriaLabel: ({
|
|
269
|
+
radiusPointX,
|
|
270
|
+
radiusPointY
|
|
271
|
+
}) => `Radius point at ${radiusPointX} comma ${radiusPointY}.`,
|
|
272
|
+
circleRadiusDescription: ({
|
|
273
|
+
radius
|
|
274
|
+
}) => `Circle radius is ${radius}.`,
|
|
275
|
+
circleOuterPointsDescription: ({
|
|
276
|
+
point1X,
|
|
277
|
+
point1Y,
|
|
278
|
+
point2X,
|
|
279
|
+
point2Y,
|
|
280
|
+
point3X,
|
|
281
|
+
point3Y,
|
|
282
|
+
point4X,
|
|
283
|
+
point4Y
|
|
284
|
+
}) => `Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`
|
|
285
|
+
// The above strings are used for interactive graph SR descriptions.
|
|
254
286
|
};
|
|
255
287
|
|
|
256
288
|
/**
|
|
@@ -3520,9 +3552,9 @@ function loadGraphie(url, onDataLoaded) {
|
|
|
3520
3552
|
};
|
|
3521
3553
|
if (shouldUseLocalizedData()) {
|
|
3522
3554
|
cacheData.localized = false;
|
|
3523
|
-
// If there is isn't any localized data,
|
|
3524
|
-
// the
|
|
3525
|
-
retrieveData(getLocalizedDataUrl(url), dataLoadErrorHandler);
|
|
3555
|
+
// If there is isn't any localized data, use the error callback to try to
|
|
3556
|
+
// load the non-localized data. If that fails too, then we will throw an error.
|
|
3557
|
+
retrieveData(getLocalizedDataUrl(url), () => retrieveData(Util.getDataUrl(url), dataLoadErrorHandler));
|
|
3526
3558
|
} else {
|
|
3527
3559
|
retrieveData(Util.getDataUrl(url), dataLoadErrorHandler);
|
|
3528
3560
|
}
|
|
@@ -4421,14 +4453,17 @@ const InteractiveUtil = {
|
|
|
4421
4453
|
}
|
|
4422
4454
|
};
|
|
4423
4455
|
|
|
4424
|
-
function _classPrivateFieldBase(
|
|
4425
|
-
if (!
|
|
4426
|
-
|
|
4456
|
+
function _classPrivateFieldBase(receiver, privateKey) {
|
|
4457
|
+
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
|
|
4458
|
+
throw new TypeError("attempted to use private field on non-instance");
|
|
4459
|
+
}
|
|
4460
|
+
|
|
4461
|
+
return receiver;
|
|
4427
4462
|
}
|
|
4428
4463
|
|
|
4429
4464
|
var id = 0;
|
|
4430
|
-
function _classPrivateFieldKey(
|
|
4431
|
-
return "__private_" + id++ + "_" +
|
|
4465
|
+
function _classPrivateFieldKey(name) {
|
|
4466
|
+
return "__private_" + id++ + "_" + name;
|
|
4432
4467
|
}
|
|
4433
4468
|
|
|
4434
4469
|
/*!
|
|
@@ -21057,14 +21092,19 @@ TextInput.defaultProps = {
|
|
|
21057
21092
|
disabled: false
|
|
21058
21093
|
};
|
|
21059
21094
|
|
|
21060
|
-
function _objectWithoutPropertiesLoose(
|
|
21061
|
-
if (
|
|
21062
|
-
var
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21095
|
+
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
21096
|
+
if (source == null) return {};
|
|
21097
|
+
var target = {};
|
|
21098
|
+
var sourceKeys = Object.keys(source);
|
|
21099
|
+
var key, i;
|
|
21100
|
+
|
|
21101
|
+
for (i = 0; i < sourceKeys.length; i++) {
|
|
21102
|
+
key = sourceKeys[i];
|
|
21103
|
+
if (excluded.indexOf(key) >= 0) continue;
|
|
21104
|
+
target[key] = source[key];
|
|
21066
21105
|
}
|
|
21067
|
-
|
|
21106
|
+
|
|
21107
|
+
return target;
|
|
21068
21108
|
}
|
|
21069
21109
|
|
|
21070
21110
|
const _excluded$7 = ["position", "visibility", "left", "top"];
|
|
@@ -27345,36 +27385,41 @@ class Dropdown extends React.Component {
|
|
|
27345
27385
|
value: String(i + 1),
|
|
27346
27386
|
label: choice
|
|
27347
27387
|
}))];
|
|
27348
|
-
return
|
|
27349
|
-
|
|
27350
|
-
|
|
27351
|
-
|
|
27352
|
-
|
|
27353
|
-
|
|
27354
|
-
|
|
27355
|
-
|
|
27356
|
-
|
|
27357
|
-
|
|
27358
|
-
|
|
27359
|
-
e
|
|
27360
|
-
|
|
27361
|
-
|
|
27362
|
-
|
|
27363
|
-
|
|
27364
|
-
|
|
27365
|
-
|
|
27366
|
-
|
|
27367
|
-
|
|
27368
|
-
|
|
27369
|
-
|
|
27370
|
-
|
|
27371
|
-
|
|
27372
|
-
|
|
27373
|
-
|
|
27374
|
-
|
|
27375
|
-
|
|
27376
|
-
|
|
27377
|
-
|
|
27388
|
+
return (
|
|
27389
|
+
/*#__PURE__*/
|
|
27390
|
+
// TODO(WB-1812, somewhatabstract): Migrate to Id or useId
|
|
27391
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
27392
|
+
React.createElement(UniqueIDProvider, {
|
|
27393
|
+
scope: "dropdown-widget",
|
|
27394
|
+
mockOnFirstRender: true
|
|
27395
|
+
}, ids => /*#__PURE__*/React.createElement(View
|
|
27396
|
+
// NOTE(jared): These are required to prevent weird behavior
|
|
27397
|
+
// When there's a dropdown in a zoomable table.
|
|
27398
|
+
, {
|
|
27399
|
+
onClick: e => {
|
|
27400
|
+
e.stopPropagation();
|
|
27401
|
+
},
|
|
27402
|
+
onTouchStart: e => {
|
|
27403
|
+
e.stopPropagation();
|
|
27404
|
+
}
|
|
27405
|
+
}, this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelLarge, {
|
|
27406
|
+
tag: "label",
|
|
27407
|
+
htmlFor: ids.get("dropdown")
|
|
27408
|
+
}, this.props.visibleLabel), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
27409
|
+
id: ids.get("dropdown"),
|
|
27410
|
+
placeholder: "",
|
|
27411
|
+
onChange: value => this._handleChange(parseInt(value)),
|
|
27412
|
+
selectedValue: String(this.props.selected),
|
|
27413
|
+
disabled: this.props.apiOptions.readOnly,
|
|
27414
|
+
"aria-label": this.props.ariaLabel || this.props.visibleLabel || this.context.strings.selectAnAnswer
|
|
27415
|
+
// This is currently necessary for SRs to read the labels properly.
|
|
27416
|
+
// However, WB is working on a change to add the "combobox" role to
|
|
27417
|
+
// all dropdowns.
|
|
27418
|
+
// See https://khanacademy.atlassian.net/browse/WB-1671
|
|
27419
|
+
,
|
|
27420
|
+
role: "combobox"
|
|
27421
|
+
}, children)))
|
|
27422
|
+
);
|
|
27378
27423
|
}
|
|
27379
27424
|
}
|
|
27380
27425
|
Dropdown.contextType = PerseusI18nContext;
|
|
@@ -27477,32 +27522,37 @@ class Explanation extends React.Component {
|
|
|
27477
27522
|
"white-space": "normal"
|
|
27478
27523
|
};
|
|
27479
27524
|
const contentStyling = [styles$k.content, this.state.expanded ? styles$k.contentExpanded : styles$k.contentCollapsed, allowTransition && (this.state.expanded ? styles$k.transitionExpanded : styles$k.transitionCollapsed)];
|
|
27480
|
-
return
|
|
27481
|
-
|
|
27482
|
-
|
|
27483
|
-
|
|
27484
|
-
|
|
27485
|
-
|
|
27486
|
-
|
|
27487
|
-
|
|
27488
|
-
|
|
27489
|
-
|
|
27490
|
-
|
|
27491
|
-
|
|
27492
|
-
|
|
27493
|
-
|
|
27494
|
-
|
|
27495
|
-
|
|
27496
|
-
|
|
27497
|
-
|
|
27498
|
-
|
|
27499
|
-
|
|
27500
|
-
|
|
27501
|
-
|
|
27502
|
-
|
|
27503
|
-
|
|
27504
|
-
|
|
27505
|
-
|
|
27525
|
+
return (
|
|
27526
|
+
/*#__PURE__*/
|
|
27527
|
+
// TODO(WB-1812, somewhatabstract): Migrate to Id or useId
|
|
27528
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
27529
|
+
React.createElement(UniqueIDProvider, {
|
|
27530
|
+
mockOnFirstRender: true,
|
|
27531
|
+
scope: "explanation-widget"
|
|
27532
|
+
}, ids => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
|
|
27533
|
+
"aria-expanded": this.state.expanded,
|
|
27534
|
+
"aria-controls": ids.get("content"),
|
|
27535
|
+
endIcon: caretIcon,
|
|
27536
|
+
kind: "tertiary",
|
|
27537
|
+
labelStyle: labelStyle,
|
|
27538
|
+
onClick: this._onClick,
|
|
27539
|
+
size: "small",
|
|
27540
|
+
style: buttonStyleOverrides
|
|
27541
|
+
}, promptText), /*#__PURE__*/React.createElement(View, {
|
|
27542
|
+
id: ids.get("content"),
|
|
27543
|
+
style: contentStyling,
|
|
27544
|
+
"aria-hidden": !this.state.expanded,
|
|
27545
|
+
testId: "content-container"
|
|
27546
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
27547
|
+
style: styles$k.contentWrapper
|
|
27548
|
+
}, /*#__PURE__*/React.createElement(Renderer, {
|
|
27549
|
+
apiOptions: this.props.apiOptions,
|
|
27550
|
+
content: this.props.explanation,
|
|
27551
|
+
widgets: this.props.widgets,
|
|
27552
|
+
linterContext: this.props.linterContext,
|
|
27553
|
+
strings: this.context.strings
|
|
27554
|
+
})))))
|
|
27555
|
+
);
|
|
27506
27556
|
}
|
|
27507
27557
|
}
|
|
27508
27558
|
Explanation.contextType = PerseusI18nContext;
|
|
@@ -34145,21 +34195,96 @@ function CircleGraph(props) {
|
|
|
34145
34195
|
center,
|
|
34146
34196
|
radiusPoint
|
|
34147
34197
|
} = graphState;
|
|
34148
|
-
|
|
34198
|
+
const {
|
|
34199
|
+
strings
|
|
34200
|
+
} = usePerseusI18n();
|
|
34201
|
+
const [radiusPointAriaLive, setRadiusPointAriaLive] = React.useState("off");
|
|
34202
|
+
const radius = getRadius(graphState);
|
|
34203
|
+
const id = React.useId();
|
|
34204
|
+
const circleId = id + "-circle";
|
|
34205
|
+
const radiusId = id + "-radius";
|
|
34206
|
+
const outerPointsId = id + "-outer-points";
|
|
34207
|
+
|
|
34208
|
+
// Aria label strings
|
|
34209
|
+
const circleGraphAriaLabel = strings.circleGraphAriaLabel;
|
|
34210
|
+
const circleShapeAriaLabel = strings.circleShapeAriaLabel({
|
|
34211
|
+
centerX: center[0],
|
|
34212
|
+
centerY: center[1]
|
|
34213
|
+
});
|
|
34214
|
+
const circleRadiusPointAriaLabel = strings.circleRadiusPointAriaLabel({
|
|
34215
|
+
radiusPointX: radiusPoint[0],
|
|
34216
|
+
radiusPointY: radiusPoint[1]
|
|
34217
|
+
});
|
|
34218
|
+
const circleRadiusDescription = strings.circleRadiusDescription({
|
|
34219
|
+
radius
|
|
34220
|
+
});
|
|
34221
|
+
const circleOuterPointsDescription = strings.circleOuterPointsDescription({
|
|
34222
|
+
point1X: center[0] + radius,
|
|
34223
|
+
point1Y: center[1],
|
|
34224
|
+
point2X: center[0],
|
|
34225
|
+
point2Y: center[1] + radius,
|
|
34226
|
+
point3X: center[0] - radius,
|
|
34227
|
+
point3Y: center[1],
|
|
34228
|
+
point4X: center[0],
|
|
34229
|
+
point4Y: center[1] - radius
|
|
34230
|
+
});
|
|
34231
|
+
return /*#__PURE__*/React.createElement("g", {
|
|
34232
|
+
// Outer circle minimal description
|
|
34233
|
+
"aria-label": circleGraphAriaLabel,
|
|
34234
|
+
"aria-describedby": `${circleId} ${radiusId} ${outerPointsId}`
|
|
34235
|
+
}, /*#__PURE__*/React.createElement(MovableCircle, {
|
|
34236
|
+
id: circleId
|
|
34237
|
+
// Focusable circle aria label reads with every update
|
|
34238
|
+
// because of the aria-live property in the circle <g>.
|
|
34239
|
+
,
|
|
34240
|
+
ariaLabel: circleShapeAriaLabel
|
|
34241
|
+
// Aria-describedby describes additional info on focus.
|
|
34242
|
+
,
|
|
34243
|
+
ariaDescribedBy: `${radiusId} ${outerPointsId}`,
|
|
34149
34244
|
center: center,
|
|
34150
|
-
radius:
|
|
34151
|
-
onMove: c =>
|
|
34152
|
-
|
|
34245
|
+
radius: radius,
|
|
34246
|
+
onMove: c => {
|
|
34247
|
+
setRadiusPointAriaLive("off");
|
|
34248
|
+
dispatch(actions.circle.moveCenter(c));
|
|
34249
|
+
}
|
|
34250
|
+
}), /*#__PURE__*/React.createElement(MovablePoint$1
|
|
34251
|
+
// Radius point aria label reads with every update.
|
|
34252
|
+
, {
|
|
34253
|
+
ariaLabel: `${circleRadiusPointAriaLabel} ${circleRadiusDescription}`
|
|
34254
|
+
// Aria-describedby describes additional info on focus.
|
|
34255
|
+
,
|
|
34256
|
+
ariaDescribedBy: `${outerPointsId}`
|
|
34257
|
+
// The radius point's aria-live property is set to "off" when
|
|
34258
|
+
// the circle is moved, so that it doesn't override the circle's
|
|
34259
|
+
// aria-live (since the point is moved along with the circle).
|
|
34260
|
+
// When the radius point is moved, the aria-live is set to
|
|
34261
|
+
// "polite" so that the radius is read out.
|
|
34262
|
+
,
|
|
34263
|
+
ariaLive: radiusPointAriaLive,
|
|
34153
34264
|
point: radiusPoint,
|
|
34154
34265
|
sequenceNumber: 1,
|
|
34155
34266
|
cursor: "ew-resize",
|
|
34156
34267
|
onMove: newRadiusPoint => {
|
|
34268
|
+
setRadiusPointAriaLive("polite");
|
|
34157
34269
|
dispatch(actions.circle.moveRadiusPoint(newRadiusPoint));
|
|
34158
34270
|
}
|
|
34159
|
-
})
|
|
34271
|
+
}), /*#__PURE__*/React.createElement("g", {
|
|
34272
|
+
id: radiusId,
|
|
34273
|
+
style: {
|
|
34274
|
+
display: "hidden"
|
|
34275
|
+
}
|
|
34276
|
+
}, circleRadiusDescription), /*#__PURE__*/React.createElement("g", {
|
|
34277
|
+
id: outerPointsId,
|
|
34278
|
+
style: {
|
|
34279
|
+
display: "hidden"
|
|
34280
|
+
}
|
|
34281
|
+
}, circleOuterPointsDescription));
|
|
34160
34282
|
}
|
|
34161
34283
|
function MovableCircle(props) {
|
|
34162
34284
|
const {
|
|
34285
|
+
id,
|
|
34286
|
+
ariaLabel,
|
|
34287
|
+
ariaDescribedBy,
|
|
34163
34288
|
center,
|
|
34164
34289
|
radius,
|
|
34165
34290
|
onMove
|
|
@@ -34180,7 +34305,11 @@ function MovableCircle(props) {
|
|
|
34180
34305
|
const [centerPx] = useTransformVectorsToPixels(center);
|
|
34181
34306
|
const [radiiPx] = useTransformDimensionsToPixels([radius, radius]);
|
|
34182
34307
|
return /*#__PURE__*/React.createElement("g", {
|
|
34308
|
+
"aria-label": ariaLabel,
|
|
34309
|
+
"aria-describedby": ariaDescribedBy,
|
|
34310
|
+
"aria-live": "polite",
|
|
34183
34311
|
ref: draggableRef,
|
|
34312
|
+
role: "button",
|
|
34184
34313
|
tabIndex: disableKeyboardInteraction ? -1 : 0,
|
|
34185
34314
|
className: `movable-circle ${dragging ? "movable-circle--dragging" : ""}`
|
|
34186
34315
|
}, /*#__PURE__*/React.createElement("ellipse", {
|
|
@@ -34190,6 +34319,7 @@ function MovableCircle(props) {
|
|
|
34190
34319
|
rx: radiiPx[X] + 3,
|
|
34191
34320
|
ry: radiiPx[Y] + 3
|
|
34192
34321
|
}), /*#__PURE__*/React.createElement("ellipse", {
|
|
34322
|
+
id: id,
|
|
34193
34323
|
className: "circle",
|
|
34194
34324
|
cx: centerPx[X],
|
|
34195
34325
|
cy: centerPx[Y],
|
|
@@ -38784,6 +38914,8 @@ const AnswerChoices = props => {
|
|
|
38784
38914
|
};
|
|
38785
38915
|
|
|
38786
38916
|
const HideAnswersToggle = props => {
|
|
38917
|
+
// TODO(WB-1812, somewhatabstract): Migrate to Id or useId
|
|
38918
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
38787
38919
|
const idFactory = useUniqueIdWithMock();
|
|
38788
38920
|
const switchId = idFactory.get("hide-answers-toggle");
|
|
38789
38921
|
const labelId = idFactory.get("hide-answers-label");
|
|
@@ -38829,6 +38961,9 @@ const AnswerPill = props => {
|
|
|
38829
38961
|
focused,
|
|
38830
38962
|
hovered
|
|
38831
38963
|
} = props;
|
|
38964
|
+
|
|
38965
|
+
// TODO(WB-1812, somewhatabstract): Migrate to Id or useId
|
|
38966
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
38832
38967
|
const idFactory = useUniqueIdWithMock();
|
|
38833
38968
|
const {
|
|
38834
38969
|
strings
|
|
@@ -45172,7 +45307,7 @@ const init = function init() {
|
|
|
45172
45307
|
|
|
45173
45308
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
45174
45309
|
const libName = "@khanacademy/perseus";
|
|
45175
|
-
const libVersion = "
|
|
45310
|
+
const libVersion = "49.0.0";
|
|
45176
45311
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
45177
45312
|
|
|
45178
45313
|
const apiVersion = {
|