@khanacademy/perseus 36.0.0 → 36.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.
package/dist/es/index.js CHANGED
@@ -2,7 +2,7 @@ import * as KAS from '@khanacademy/kas';
2
2
  import { MathInputI18nContext, CursorContext, getKeyTranslator, createMathField, getCursorContext, DesktopKeypad, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, KeypadType, KeyArray, keypadElementPropType } from '@khanacademy/math-input';
3
3
  import * as PerseusLinter from '@khanacademy/perseus-linter';
4
4
  import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
5
- import { View, RenderStateRoot, UniqueIDProvider, useLatestRef, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
5
+ import { View, RenderStateRoot, UniqueIDProvider, useOnMountEffect, useLatestRef, useUniqueIdWithMock, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
6
6
  import Tooltip$1 from '@khanacademy/wonder-blocks-tooltip';
7
7
  import { HeadingMedium, LabelSmall, Body, LabelMedium } from '@khanacademy/wonder-blocks-typography';
8
8
  import { StyleSheet, css } from 'aphrodite';
@@ -33280,7 +33280,7 @@ function calculateBisectorPoint(point1, point2, vertex, isReflex, allowReflex, a
33280
33280
  return scaledBisector;
33281
33281
  }
33282
33282
 
33283
- const MovablePoint$1 = props => {
33283
+ const MovablePoint$1 = /*#__PURE__*/React.forwardRef((props, pointRef) => {
33284
33284
  const {
33285
33285
  snapStep
33286
33286
  } = useGraphConfig();
@@ -33303,7 +33303,21 @@ const MovablePoint$1 = props => {
33303
33303
  constrainKeyboardMovement: constrain
33304
33304
  });
33305
33305
  return /*#__PURE__*/React.createElement(MovablePointView, {
33306
- ref: elementRef,
33306
+ ref: ref => {
33307
+ // Note: This handles the case where pointRef is either a
33308
+ // function or a MutableRefObject. Mostly this is to satisfy
33309
+ // the type system, the function branch seems to be the only
33310
+ // one that occurs
33311
+ if (typeof pointRef === "function") {
33312
+ pointRef(ref);
33313
+ } else if (pointRef !== null) {
33314
+ pointRef.current = ref;
33315
+ }
33316
+
33317
+ // This ref is for the useDraggable and is not passed up the
33318
+ // chain
33319
+ elementRef.current = ref;
33320
+ },
33307
33321
  point: point,
33308
33322
  color: color$1,
33309
33323
  dragging: dragging,
@@ -33319,7 +33333,7 @@ const MovablePoint$1 = props => {
33319
33333
  },
33320
33334
  cursor: cursor
33321
33335
  });
33322
- };
33336
+ });
33323
33337
 
33324
33338
  const PolygonGraph = props => {
33325
33339
  const [hovered, setHovered] = React.useState(false);
@@ -33899,6 +33913,14 @@ function UnlimitedPointGraph(props) {
33899
33913
  const height = maxY - minY;
33900
33914
  const [[widthPx, heightPx]] = useTransformDimensionsToPixels([width, height]);
33901
33915
  const [[left, top]] = useTransformVectorsToPixels([minX, maxY]);
33916
+ const itemsRef = React.useRef([]);
33917
+ React.useEffect(() => {
33918
+ const focusedIndex = props.graphState.focusedPointIndex;
33919
+ if (focusedIndex != null) {
33920
+ var _itemsRef$current$foc;
33921
+ (_itemsRef$current$foc = itemsRef.current[focusedIndex]) == null || _itemsRef$current$foc.focus();
33922
+ }
33923
+ }, [props.graphState.focusedPointIndex, itemsRef]);
33902
33924
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
33903
33925
  style: {
33904
33926
  fill: "rgba(0,0,0,0)",
@@ -33919,13 +33941,24 @@ function UnlimitedPointGraph(props) {
33919
33941
  key: i,
33920
33942
  point: point,
33921
33943
  onMove: destination => dispatch(actions.pointGraph.movePoint(i, destination)),
33944
+ ref: ref => {
33945
+ itemsRef.current[i] = ref;
33946
+ },
33922
33947
  onFocusChange: (event, isFocused) => {
33923
33948
  if (isFocused) {
33924
33949
  dispatch(actions.pointGraph.focusPoint(i));
33925
33950
  } else {
33926
- var _event$relatedTarget;
33951
+ var _event$relatedTarget, _event$relatedTarget2;
33927
33952
  if (((_event$relatedTarget = event.relatedTarget) == null ? void 0 : _event$relatedTarget.id) === REMOVE_BUTTON_ID) {
33928
33953
  return;
33954
+ // This is an optimization: If the next target
33955
+ // is a point then don't blur because it casues
33956
+ // the remove button to get taken off the page
33957
+ // and then put back on The new point will
33958
+ // receive focus and set the correct state in
33959
+ // the reducer
33960
+ } else if ((_event$relatedTarget2 = event.relatedTarget) != null && _event$relatedTarget2.classList.contains("movable-point")) {
33961
+ return;
33929
33962
  }
33930
33963
  dispatch(actions.pointGraph.blurPoint());
33931
33964
  }
@@ -34101,11 +34134,17 @@ const MafsGraph = props => {
34101
34134
  fullGraphAriaLabel,
34102
34135
  fullGraphAriaDescription
34103
34136
  } = props;
34137
+ const {
34138
+ type
34139
+ } = state;
34104
34140
  const [width, height] = props.box;
34105
34141
  const tickStep = props.step;
34106
34142
  const uniqueId = React.useId();
34107
34143
  const descriptionId = `interactive-graph-description-${uniqueId}`;
34108
34144
  const graphRef = React.useRef(null);
34145
+ const {
34146
+ analytics
34147
+ } = useDependencies();
34109
34148
 
34110
34149
  // Set up the SVG attributes for the nested SVGs that help lock
34111
34150
  // the grid and graph elements to the bounds of the graph.
@@ -34125,6 +34164,14 @@ const MafsGraph = props => {
34125
34164
  const {
34126
34165
  strings
34127
34166
  } = usePerseusI18n();
34167
+ useOnMountEffect(() => {
34168
+ analytics.onAnalyticsEvent({
34169
+ type: "perseus:interactive-graph-widget:rendered",
34170
+ payload: {
34171
+ type
34172
+ }
34173
+ });
34174
+ });
34128
34175
  return /*#__PURE__*/React.createElement(GraphConfigContext.Provider, {
34129
34176
  value: {
34130
34177
  range: state.range,
@@ -34888,10 +34935,13 @@ function doFocusPoint(state, action) {
34888
34935
  function doBlurPoint(state, action) {
34889
34936
  switch (state.type) {
34890
34937
  case "point":
34891
- return _extends({}, state, {
34892
- focusedPointIndex: null,
34938
+ const nextState = _extends({}, state, {
34893
34939
  showRemovePointButton: false
34894
34940
  });
34941
+ if (state.interactionMode === "mouse") {
34942
+ nextState.focusedPointIndex = null;
34943
+ }
34944
+ return nextState;
34895
34945
  default:
34896
34946
  return state;
34897
34947
  }
@@ -35275,16 +35325,23 @@ function doAddPoint(state, action) {
35275
35325
  return _extends({}, state, {
35276
35326
  hasBeenInteractedWith: true,
35277
35327
  coords: [...state.coords, snappedPoint],
35278
- showRemovePointButton: false
35328
+ showRemovePointButton: false,
35329
+ focusedPointIndex: state.coords.length
35279
35330
  });
35280
35331
  }
35281
35332
  function doRemovePoint(state, action) {
35282
35333
  if (state.type !== "point") {
35283
35334
  return state;
35284
35335
  }
35336
+ let nextFocusedPointIndex;
35337
+ if (state.interactionMode === "mouse") {
35338
+ nextFocusedPointIndex = null;
35339
+ } else {
35340
+ nextFocusedPointIndex = state.coords.length > 1 ? state.coords.length - 2 : null;
35341
+ }
35285
35342
  return _extends({}, state, {
35286
35343
  coords: state.coords.filter((_, i) => i !== action.index),
35287
- focusedPointIndex: null,
35344
+ focusedPointIndex: nextFocusedPointIndex,
35288
35345
  showRemovePointButton: false
35289
35346
  });
35290
35347
  }
@@ -44873,7 +44930,7 @@ const init = function init(options) {
44873
44930
 
44874
44931
  // This file is processed by a Rollup plugin (replace) to inject the production
44875
44932
  const libName = "@khanacademy/perseus";
44876
- const libVersion = "36.0.0";
44933
+ const libVersion = "36.1.0";
44877
44934
  addLibraryVersionToPerseusDebug(libName, libVersion);
44878
44935
 
44879
44936
  const apiVersion = {
@@ -48050,6 +48107,38 @@ function injectWidgets(content, widgets, widgetProps) {
48050
48107
  return context;
48051
48108
  }
48052
48109
 
48110
+ /**
48111
+ * Looks through widgets to identify images that do not have alt text.
48112
+ *
48113
+ * We pass in the fuller perseusRenderer object to allow for the possibility
48114
+ * of expanding to include other img data from content & images in the future.
48115
+ *
48116
+ * @param {PerseusRenderer} perseusRenderer
48117
+ * @returns a stringified list of {widgetId, imageUrl} for imgs that don't have alt text
48118
+ */
48119
+ function getImagesWithoutAltData(perseusRenderer) {
48120
+ if (!perseusRenderer.widgets) {
48121
+ return "";
48122
+ }
48123
+ const imgsWithoutAltData = [];
48124
+ Object.entries(perseusRenderer.widgets).forEach(([widgetId, widget]) => {
48125
+ var _widget$options$backg;
48126
+ if (!widget.options) {
48127
+ return;
48128
+ }
48129
+
48130
+ // Add to imagesWithoutAltData if img alt is missing and
48131
+ // image has valid img url data.
48132
+ if (widget.type === "image" && !widget.options.alt && (_widget$options$backg = widget.options.backgroundImage) != null && _widget$options$backg.url) {
48133
+ imgsWithoutAltData.push({
48134
+ widgetId,
48135
+ imgUrl: widget.options.backgroundImage.url
48136
+ });
48137
+ }
48138
+ });
48139
+ return JSON.stringify(imgsWithoutAltData);
48140
+ }
48141
+
48053
48142
  /* Widgets that have individual answers */
48054
48143
  const INDIVIDUAL_ANSWER_WIDGETS = ["interactive-graph", "categorizer", "grapher"];
48055
48144
 
@@ -48319,5 +48408,5 @@ const EditorJsonify = {
48319
48408
  }
48320
48409
  };
48321
48410
 
48322
- export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, 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, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, 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, makeSafeUrl, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
48411
+ export { ApiOptions, ArticleRenderer, BaseRadio, Categorizer$1 as Categorizer, changeable as Changeable, ClassNames, dependencies as Dependencies, EditorJsonify, 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, widgets$1 as Widgets, addWidget, apiVersion, buildEmptyItemTreeForShape, buildMapper, components, constants, contentHasWidgetType, convertWidgetNameToEnum, displaySigFigs, generateTestCategorizerWidget, generateTestExpressionWidget, generateTestInteractiveGraphWidget, generateTestNumericInputWidget, generateTestPerseusItem, generateTestRadioWidget, genericPerseusItemData, getAngleCoords, getAnswerFromUserInput, getAnswersFromWidgets, getCircleCoords, getCorrectAnswerForWidgetId, getImagesWithoutAltData, getLineCoords, getLinearSystemCoords, getPointCoords, getPolygonCoords, getQuadraticCoords, getSegmentCoords, getSinusoidCoords, 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, makeSafeUrl, mediaQueries, parsePerseusItem, plotterPlotTypes, preprocessTex, registerAllWidgetsForTesting, shapes, shouldHaveIndividualAnswer, traverse, usePerseusI18n, violatingWidgets, allWidgets as widgets };
48323
48412
  //# sourceMappingURL=index.js.map