@khanacademy/perseus 27.0.2 → 27.1.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.
@@ -27,7 +27,7 @@ type Props = {
27
27
  * Overrides deprecated `buttonSets` prop.
28
28
  */
29
29
  keypadButtonSets?: KeypadButtonSets;
30
- labelText?: string;
30
+ ariaLabel: string;
31
31
  onFocus?: () => void;
32
32
  onBlur?: () => void;
33
33
  hasError?: boolean;
@@ -83,6 +83,7 @@ declare class MathInput extends React.Component<Props, State> {
83
83
  }>;
84
84
  context: React.ContextType<typeof MathInputI18nContext>;
85
85
  inputRef: React.RefObject<InnerMathInput>;
86
+ static defaultProps: Pick<Props, "ariaLabel">;
86
87
  blur(): void;
87
88
  focus(): void;
88
89
  insert(value: any): void;
package/dist/es/index.css CHANGED
@@ -3329,6 +3329,7 @@ body.mobile .framework-perseus table.perseus-widget-table-of-values.non-markdown
3329
3329
  }
3330
3330
  .perseus-widget-container.widget-inline-block {
3331
3331
  display: inline-block;
3332
+ vertical-align: bottom;
3332
3333
  }
3333
3334
  .bibliotron-exercise .perseus-hint-renderer {
3334
3335
  border-left: 4px solid #f6f7f7;
package/dist/es/index.js CHANGED
@@ -5,18 +5,19 @@ import * as PerseusLinter from '@khanacademy/perseus-linter';
5
5
  import { linterContextDefault, Rule, linterContextProps } from '@khanacademy/perseus-linter';
6
6
  import { View, RenderStateRoot, UniqueIDProvider, useLatestRef, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
7
7
  import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
8
+ import { LabelSmall, Body, LabelMedium } from '@khanacademy/wonder-blocks-typography';
9
+ import { StyleSheet, css } from 'aphrodite';
8
10
  import classNames from 'classnames';
9
11
  import * as React from 'react';
10
12
  import React__default, { useContext, useState, useEffect, useRef, createContext, forwardRef, useImperativeHandle } from 'react';
13
+ import * as ReactDOM from 'react-dom';
14
+ import ReactDOM__default from 'react-dom';
11
15
  import _, { debounce as debounce$1 } from 'underscore';
12
16
  import Clickable from '@khanacademy/wonder-blocks-clickable';
13
17
  import { Popover, PopoverContentCore, PopoverContent } from '@khanacademy/wonder-blocks-popover';
14
18
  import { color, spacing } from '@khanacademy/wonder-blocks-tokens';
15
- import { StyleSheet, css } from 'aphrodite';
16
19
  import $ from 'jquery';
17
20
  import PropTypes from 'prop-types';
18
- import * as ReactDOM from 'react-dom';
19
- import ReactDOM__default from 'react-dom';
20
21
  import { number, point, vector as vector$1, line } from '@khanacademy/kmath';
21
22
  import { entries, UnreachableCaseError, keys } from '@khanacademy/wonder-stuff-core';
22
23
  import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
@@ -32,7 +33,6 @@ import caretUp from '@phosphor-icons/core/regular/caret-up.svg';
32
33
  import debounce$2 from 'lodash.debounce';
33
34
  import { vec, Coordinates, Ellipse, Plot as Plot$3, Line as Line$4, Point as Point$2, Polygon, useTransformContext, Text as Text$1, Mafs } from 'mafs';
34
35
  import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
35
- import { Body, LabelSmall, LabelMedium } from '@khanacademy/wonder-blocks-typography';
36
36
  import questionIcon from '@phosphor-icons/core/regular/question.svg';
37
37
  import createReactClass from 'create-react-class';
38
38
  import { useDrag } from '@use-gesture/react';
@@ -79,6 +79,7 @@ function _objectWithoutPropertiesLoose(source, excluded) {
79
79
  const mockStrings = {
80
80
  closeKeypad: "close math keypad",
81
81
  openKeypad: "open math keypad",
82
+ mathInputBox: "Math input box",
82
83
  removeHighlight: "Remove highlight",
83
84
  addHighlight: "Add highlight",
84
85
  hintPos: ({
@@ -337,6 +338,7 @@ class InnerMathInput extends React.Component {
337
338
  input == null || input.focus();
338
339
  };
339
340
  this.mathField = () => {
341
+ var _this$__mathField;
340
342
  if (!this.__mathField && this.__mathFieldWrapperRef) {
341
343
  const {
342
344
  locale
@@ -403,6 +405,7 @@ class InnerMathInput extends React.Component {
403
405
  }
404
406
  }));
405
407
  }
408
+ (_this$__mathField = this.__mathField) == null || _this$__mathField.setAriaLabel(this.props.ariaLabel);
406
409
  return this.__mathField;
407
410
  };
408
411
  this.focus = () => {
@@ -473,7 +476,7 @@ class InnerMathInput extends React.Component {
473
476
  className = className + " " + this.props.className;
474
477
  }
475
478
  return /*#__PURE__*/React.createElement(View, {
476
- style: [styles$D.outerWrapper, this.state.focused && styles$D.wrapperFocused, this.props.hasError && styles$D.wrapperError]
479
+ style: [styles$E.outerWrapper, this.state.focused && styles$E.wrapperFocused, this.props.hasError && styles$E.wrapperError]
477
480
  }, /*#__PURE__*/React.createElement("div", {
478
481
  style: {
479
482
  display: "flex",
@@ -495,7 +498,6 @@ class InnerMathInput extends React.Component {
495
498
  }, /*#__PURE__*/React.createElement("span", {
496
499
  className: className,
497
500
  ref: ref => this.__mathFieldWrapperRef = ref,
498
- "aria-label": this.props.labelText,
499
501
  onFocus: () => this.focus(),
500
502
  onBlur: () => this.blur()
501
503
  }), /*#__PURE__*/React.createElement(Popover, {
@@ -506,7 +508,7 @@ class InnerMathInput extends React.Component {
506
508
  var _this$props$keypadBut, _this$props;
507
509
  return /*#__PURE__*/React.createElement(PopoverContentCore, {
508
510
  closeButtonVisible: true,
509
- style: styles$D.popoverContent
511
+ style: styles$E.popoverContent
510
512
  }, /*#__PURE__*/React.createElement(DesktopKeypad, _extends({
511
513
  onAnalyticsEvent: this.props.analytics.onAnalyticsEvent,
512
514
  extraKeys: this.props.extraKeys,
@@ -562,6 +564,9 @@ class MathInput extends React.Component {
562
564
  }
563
565
  }
564
566
  MathInput.contextType = MathInputI18nContext;
567
+ MathInput.defaultProps = {
568
+ ariaLabel: "Math input"
569
+ };
565
570
  const MathInputIcon = ({
566
571
  hovered,
567
572
  focused,
@@ -579,9 +584,9 @@ const MathInputIcon = ({
579
584
  fillColor = color.offBlack;
580
585
  break;
581
586
  }
582
- const dynamicClass = active || focused ? styles$D.iconActive : styles$D.iconInactive;
587
+ const dynamicClass = active || focused ? styles$E.iconActive : styles$E.iconInactive;
583
588
  return /*#__PURE__*/React.createElement(View, {
584
- style: [styles$D.iconContainer, dynamicClass]
589
+ style: [styles$E.iconContainer, dynamicClass]
585
590
  }, /*#__PURE__*/React.createElement("svg", {
586
591
  xmlns: "http://www.w3.org/2000/svg",
587
592
  width: "16",
@@ -626,7 +631,7 @@ const inputFocused = {
626
631
  borderColor: color.blue,
627
632
  margin: -1
628
633
  };
629
- const styles$D = StyleSheet.create({
634
+ const styles$E = StyleSheet.create({
630
635
  iconContainer: {
631
636
  display: "flex",
632
637
  justifyContent: "center",
@@ -2150,6 +2155,7 @@ const getDecimalSeparator = locale => {
2150
2155
  class Expression extends React.Component {
2151
2156
  constructor(..._args) {
2152
2157
  super(..._args);
2158
+ this._textareaId = `expression_textarea_${Date.now()}`;
2153
2159
  this._isMounted = false;
2154
2160
  this.displayName = "Expression";
2155
2161
  this.state = {
@@ -2163,6 +2169,17 @@ class Expression extends React.Component {
2163
2169
  // TODO(scottgrant): This is a hack to remove the deprecated call to
2164
2170
  // this.isMounted() but is still considered an anti-pattern.
2165
2171
  this._isMounted = true;
2172
+
2173
+ // HACK: imperatively add an ID onto the Mathquill input
2174
+ // (which in mobile is a span; desktop a textarea)
2175
+ // in order to associate a visual label with it
2176
+ if (this.refs.input) {
2177
+ const isMobile = this.props.apiOptions.customKeypad;
2178
+ const container = ReactDOM__default.findDOMNode(this.refs.input);
2179
+ const selector = isMobile ? ".mq-textarea > span" : "textarea";
2180
+ const inputElement = container.querySelector(selector);
2181
+ inputElement == null || inputElement.setAttribute("id", this._textareaId);
2182
+ }
2166
2183
  };
2167
2184
  // Whenever the input value changes, attempt to parse it.
2168
2185
  //
@@ -2457,10 +2474,16 @@ class Expression extends React.Component {
2457
2474
  render() {
2458
2475
  var _this$props$keypadCon, _this$props$analytics3;
2459
2476
  if (this.props.apiOptions.customKeypad) {
2460
- return /*#__PURE__*/React.createElement(KeypadInput
2477
+ return /*#__PURE__*/React.createElement(View, {
2478
+ className: css(styles$D.mobileLabelInputWrapper)
2479
+ }, !!this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelSmall, {
2480
+ htmlFor: this._textareaId,
2481
+ tag: "label"
2482
+ }, this.props.visibleLabel), /*#__PURE__*/React.createElement(KeypadInput
2461
2483
  // eslint-disable-next-line react/no-string-refs
2462
2484
  , {
2463
2485
  ref: "input",
2486
+ ariaLabel: this.props.ariaLabel || this.context.strings.mathInputBox,
2464
2487
  value: this.props.value,
2465
2488
  keypadElement: this.props.keypadElement,
2466
2489
  onChange: this.changeAndTrack,
@@ -2476,7 +2499,7 @@ class Expression extends React.Component {
2476
2499
  });
2477
2500
  },
2478
2501
  onBlur: this._handleBlur
2479
- });
2502
+ }));
2480
2503
  }
2481
2504
  const className = classNames({
2482
2505
  "perseus-widget-expression": true,
@@ -2486,7 +2509,12 @@ class Expression extends React.Component {
2486
2509
  ERROR_MESSAGE,
2487
2510
  ERROR_TITLE
2488
2511
  } = this.context.strings;
2489
- return /*#__PURE__*/React.createElement("div", {
2512
+ return /*#__PURE__*/React.createElement(View, {
2513
+ className: css(styles$D.desktopLabelInputWrapper)
2514
+ }, !!this.props.visibleLabel && /*#__PURE__*/React.createElement(LabelSmall, {
2515
+ htmlFor: this._textareaId,
2516
+ tag: "label"
2517
+ }, this.props.visibleLabel), /*#__PURE__*/React.createElement("div", {
2490
2518
  className: className,
2491
2519
  onBlur: () => this.state.invalid && this.setState({
2492
2520
  showErrorTooltip: true,
@@ -2515,13 +2543,33 @@ class Expression extends React.Component {
2515
2543
  onFocus: this._handleFocus,
2516
2544
  onBlur: this._handleBlur,
2517
2545
  hasError: this.state.showErrorStyle,
2546
+ ariaLabel: this.props.ariaLabel || this.context.strings.mathInputBox,
2518
2547
  extraKeys: (_this$props$keypadCon = this.props.keypadConfiguration) == null ? void 0 : _this$props$keypadCon.extraKeys,
2519
2548
  analytics: (_this$props$analytics3 = this.props.analytics) != null ? _this$props$analytics3 : {
2520
2549
  onAnalyticsEvent: async function () {}
2521
2550
  }
2522
- })));
2551
+ }))));
2523
2552
  }
2524
2553
  }
2554
+ Expression.contextType = PerseusI18nContext;
2555
+ Expression.defaultProps = {
2556
+ value: "",
2557
+ times: false,
2558
+ functions: [],
2559
+ buttonSets: ["basic", "trig", "prealgebra", "logarithms"],
2560
+ onFocus: () => {},
2561
+ onBlur: () => {},
2562
+ apiOptions: ApiOptions.defaults,
2563
+ linterContext: linterContextDefault
2564
+ };
2565
+ const styles$D = StyleSheet.create({
2566
+ mobileLabelInputWrapper: {
2567
+ padding: "15px 4px 0"
2568
+ },
2569
+ desktopLabelInputWrapper: {
2570
+ margin: "5px 5px 0"
2571
+ }
2572
+ });
2525
2573
 
2526
2574
  /**
2527
2575
  * Determine the keypad configuration parameters for the input, based on the
@@ -2534,17 +2582,6 @@ class Expression extends React.Component {
2534
2582
  * to be included as keys on the keypad. These are scraped from the answer
2535
2583
  * forms.
2536
2584
  */
2537
- Expression.contextType = PerseusI18nContext;
2538
- Expression.defaultProps = {
2539
- value: "",
2540
- times: false,
2541
- functions: [],
2542
- buttonSets: ["basic", "trig", "prealgebra", "logarithms"],
2543
- onFocus: () => {},
2544
- onBlur: () => {},
2545
- apiOptions: ApiOptions.defaults,
2546
- linterContext: linterContextDefault
2547
- };
2548
2585
  const keypadConfigurationForProps = widgetOptions => {
2549
2586
  // Always use the Expression keypad, regardless of the button sets that have
2550
2587
  // been enabled.
@@ -2602,6 +2639,8 @@ const propUpgrades$2 = {
2602
2639
  buttonSets: v0props.buttonSets,
2603
2640
  functions: v0props.functions,
2604
2641
  buttonsVisible: v0props.buttonsVisible,
2642
+ visibleLabel: v0props.visibleLabel,
2643
+ ariaLabel: v0props.ariaLabel,
2605
2644
  answerForms: [{
2606
2645
  considered: "correct",
2607
2646
  form: v0props.form,
@@ -2639,14 +2678,18 @@ var Expression$1 = {
2639
2678
  times,
2640
2679
  functions,
2641
2680
  buttonSets,
2642
- buttonsVisible
2681
+ buttonsVisible,
2682
+ visibleLabel,
2683
+ ariaLabel
2643
2684
  } = widgetOptions;
2644
2685
  return {
2645
2686
  keypadConfiguration: keypadConfigurationForProps(widgetOptions),
2646
2687
  times,
2647
2688
  functions,
2648
2689
  buttonSets,
2649
- buttonsVisible
2690
+ buttonsVisible,
2691
+ visibleLabel,
2692
+ ariaLabel
2650
2693
  };
2651
2694
  },
2652
2695
  version: {
@@ -32095,16 +32138,17 @@ function getQuadraticCoords(graph, range, step) {
32095
32138
  return normalizePoints(range, step, defaultCoords, true);
32096
32139
  }
32097
32140
  function getCircleCoords(graph) {
32141
+ var _graph$startCoords3;
32098
32142
  if (graph.center != null && graph.radius != null) {
32099
32143
  return {
32100
32144
  center: graph.center,
32101
32145
  radiusPoint: vec.add(graph.center, [graph.radius, 0])
32102
32146
  };
32103
32147
  }
32104
- if (graph.startCoords) {
32148
+ if ((_graph$startCoords3 = graph.startCoords) != null && _graph$startCoords3.center && graph.startCoords.radius) {
32105
32149
  return {
32106
- center: graph.startCoords,
32107
- radiusPoint: vec.add(graph.startCoords, [2, 0])
32150
+ center: graph.startCoords.center,
32151
+ radiusPoint: vec.add(graph.startCoords.center, [graph.startCoords.radius, 0])
32108
32152
  };
32109
32153
  }
32110
32154
  return {
@@ -44114,7 +44158,7 @@ const init = function init(options) {
44114
44158
 
44115
44159
  // This file is processed by a Rollup plugin (replace) to inject the production
44116
44160
  const libName = "@khanacademy/perseus";
44117
- const libVersion = "27.0.2";
44161
+ const libVersion = "27.1.0";
44118
44162
  addLibraryVersionToPerseusDebug(libName, libVersion);
44119
44163
 
44120
44164
  const apiVersion = {
@@ -47694,5 +47738,5 @@ const EditorJsonify = {
47694
47738
  }
47695
47739
  };
47696
47740
 
47697
- export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCorrectAnswerForWidgetId, getLineCoords, getLinearSystemCoords, getSegmentCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
47741
+ export { ApiOptions, ArrowPicker, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, ColorPicker, DashPicker, dependencies as Dependencies, EditorJsonify, ElementContainer, Expression, util as GrapherUtil, Grapher$1 as GrapherWidget, HintRenderer, HintsRenderer, InputNumber$1 as InputNumber, InteractiveGraph$1 as InteractiveGraphWidget, ItemExtras, JiptParagraphs, KhanColors, KhanMath, context as LoadingContext, Log, Matrix$1 as MatrixWidget, MultiItems, NumericInput$1 as NumericInput, PerseusExpressionAnswerFormConsidered, PerseusI18nContext, PerseusI18nContextProvider, PerseusMarkdown, Plotter$1 as PlotterWidget, QUESTION_WIDGETS, Radio, Renderer, ref as ServerItemRenderer, sizingUtils as SizingUtils, Table$1 as TableWidget, Util, denylist as WIDGET_PROP_DENYLIST, WidgetJsonifyDeprecated, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getLineCoords, getLinearSystemCoords, getSegmentCoords, getValidWidgetIds, getWidgetFromWidgetMap, getWidgetIdsFromContent, getWidgetIdsFromContentByType, getWidgetTypeByWidgetId, getWidgetsFromWidgetMap, getWidgetsMapFromItemData, globalConstants, globalStyles, iconPaths as icons, init, injectWidgets, interactiveSizes$1 as interactiveSizes, isItemRenderableByVersion, isWidgetIdInContent, isWrongAnswerSupported, itemDataVersion, itemToTree, ItemVersion as itemVersion, libVersion, lockedFigureColors, lockedFigureFillStyles, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
47698
47742
  //# sourceMappingURL=index.js.map