@khanacademy/perseus 32.0.0 → 33.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/index.d.ts CHANGED
@@ -30,10 +30,6 @@ export { default as MatrixWidget } from "./widgets/matrix";
30
30
  export { default as TableWidget } from "./widgets/table";
31
31
  export { default as PlotterWidget } from "./widgets/plotter";
32
32
  export { default as GrapherWidget } from "./widgets/grapher";
33
- export { default as ArrowPicker } from "./widgets/interaction/arrow-picker";
34
- export { default as ColorPicker } from "./widgets/interaction/color-picker";
35
- export { default as DashPicker } from "./widgets/interaction/dash-picker";
36
- export { default as ElementContainer } from "./widgets/interaction/element-container";
37
33
  export * as GrapherUtil from "./widgets/grapher/util";
38
34
  /**
39
35
  * Misc
package/dist/index.js CHANGED
@@ -3272,45 +3272,6 @@ function constrainedTickStepsFromTickSteps(tickSteps, ranges) {
3272
3272
  return [constrainTickStep(tickSteps[0], ranges[0]), constrainTickStep(tickSteps[1], ranges[1])];
3273
3273
  }
3274
3274
 
3275
- /**
3276
- * Transparently update deprecated props so that the code to deal
3277
- * with them only lives in one place: (Widget).deprecatedProps
3278
- *
3279
- * For example, if a boolean `foo` was deprecated in favor of a
3280
- * number 'bar':
3281
- * deprecatedProps: {
3282
- * foo: function(props) {
3283
- * return {bar: props.foo ? 1 : 0};
3284
- * }
3285
- * }
3286
- */
3287
- const DeprecationMixin$1 = {
3288
- // This lifecycle stage is only called before first render
3289
- // TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
3290
- UNSAFE_componentWillMount: function () {
3291
- const newProps = {};
3292
- ___default["default"].each(this.deprecatedProps, function (func, prop) {
3293
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
3294
- if (___default["default"].has(this.props, prop)) {
3295
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
3296
- ___default["default"].extend(newProps, func(this.props));
3297
- }
3298
- }, this);
3299
- if (!___default["default"].isEmpty(newProps)) {
3300
- // Set new props directly so that widget renders correctly
3301
- // when it first mounts, even though these will be overwritten
3302
- // almost immediately afterwards...
3303
- ___default["default"].extend(this.props, newProps);
3304
-
3305
- // ...when we propagate the new props upwards and they come
3306
- // back down again.
3307
- // TODO(jeff, CP-3128): Use Wonder Blocks Timing API
3308
- // eslint-disable-next-line no-restricted-syntax
3309
- setTimeout(this.props.onChange, 0, newProps);
3310
- }
3311
- }
3312
- };
3313
-
3314
3275
  /**
3315
3276
  * Approximate equality on numbers and primitives.
3316
3277
  */
@@ -3656,7 +3617,6 @@ const Util = {
3656
3617
  gridStepFromTickStep,
3657
3618
  tickStepFromNumTicks,
3658
3619
  constrainedTickStepsFromTickSteps,
3659
- DeprecationMixin: DeprecationMixin$1,
3660
3620
  eq: eq$3,
3661
3621
  deepEq: deepEq$5,
3662
3622
  parseQueryString,
@@ -10187,11 +10147,35 @@ const setLabelMargins = function (span, size) {
10187
10147
  marginTop: -height / 2 - y * scale
10188
10148
  });
10189
10149
  } else {
10150
+ const $container = $span.closest(".svg-image");
10151
+ // Ensuring that the line-height of the text doesn't throw off placement of the text element.
10152
+ // Inherited line-height values can really mess up placement.
10153
+ $container.css("line-height", "normal");
10154
+
10155
+ // The 'max-width' value is the same as the expected (100% scale) width of the graphie.
10156
+ // We are using jQuery to get this information since we don't have a way to pass it to this function.
10157
+ const expectedWidth = $container.css("max-width") ?? "0px";
10158
+ // We can calculate the true scale of the graphie by taking actual width and dividing by the expected width.
10159
+ // NOTE: Using 'slice' to remove the "px" unit from the end of the expected width value.
10160
+ const scale = ($container.width() ?? 0) / parseInt(expectedWidth.replace(/px$/, "")) * 100;
10161
+
10162
+ // Any padding needs to be scaled accordingly.
10163
+ const currentPadding = $span.css("padding") ?? "0px";
10164
+ const newPadding = Math.round(parseInt(currentPadding.slice(0, -2)) * scale) / 100;
10165
+
10166
+ // "multipliers" basically move the position of the text by using 1, 0, -1
10167
+ // 'margin-left' and 'margin-top' are used to position the text.
10168
+ // Margin and font size need to be scaled accordingly.
10190
10169
  const multipliers = labelDirections[direction || "center"];
10191
- $span.css({
10192
- marginLeft: Math.round(width * multipliers[0]),
10193
- marginTop: Math.round(height * multipliers[1])
10194
- });
10170
+ const styling = {
10171
+ marginLeft: Math.round(width * multipliers[0] * scale) / 100,
10172
+ marginTop: Math.round(height * multipliers[1] * scale) / 100,
10173
+ padding: `${newPadding}px`
10174
+ };
10175
+ if (scale !== 1) {
10176
+ styling["fontSize"] = `${Math.round(scale * 100) / 100}%`;
10177
+ }
10178
+ $span.css(styling);
10195
10179
  }
10196
10180
  };
10197
10181
  const GraphUtils = {
@@ -17576,9 +17560,16 @@ class SvgImage extends React__namespace.Component {
17576
17560
  // without coordinates. They don't seem to have any content, so
17577
17561
  // it seems fine to just ignore them (rather than error), but
17578
17562
  // we should figure out why this is happening.
17579
- const label = graphie.label(labelData.coordinates, labelData.content, labelData.alignment, labelData.typesetAsMath, {
17563
+
17564
+ // 'styling' - When a default scale (1) is used,
17565
+ // setting the font size to 100% is redundant.
17566
+ // Also, setting the font size to 100% can counteract other scale-based styling.
17567
+ // Therefore, when the scale is not applicable,
17568
+ // we set the value to 'null' so that no additional styling will be set.
17569
+ const styling = this.props.scale !== 1 ? {
17580
17570
  "font-size": 100 * this.props.scale + "%"
17581
- });
17571
+ } : null;
17572
+ const label = graphie.label(labelData.coordinates, labelData.content, labelData.alignment, labelData.typesetAsMath, styling);
17582
17573
 
17583
17574
  // Convert absolute positioning css from pixels to percentages
17584
17575
  // TODO(alex): Dynamically resize font-size as well. This
@@ -32370,10 +32361,14 @@ const MafsGraph = props => {
32370
32361
  state,
32371
32362
  dispatch,
32372
32363
  labels,
32373
- readOnly
32364
+ readOnly,
32365
+ fullGraphAriaLabel,
32366
+ fullGraphAriaDescription
32374
32367
  } = props;
32375
32368
  const [width, height] = props.box;
32376
32369
  const tickStep = props.step;
32370
+ const uniqueId = React__namespace.useId();
32371
+ const descriptionId = `interactive-graph-description-${uniqueId}`;
32377
32372
  const graphRef = React__namespace.useRef(null);
32378
32373
  return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
32379
32374
  value: {
@@ -32408,9 +32403,19 @@ const MafsGraph = props => {
32408
32403
  graphRef.current?.focus();
32409
32404
  }
32410
32405
  },
32406
+ "aria-label": fullGraphAriaLabel,
32407
+ "aria-describedby": fullGraphAriaDescription ? descriptionId : undefined,
32411
32408
  ref: graphRef,
32412
32409
  tabIndex: 0
32413
- }, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
32410
+ }, fullGraphAriaDescription && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32411
+ id: descriptionId,
32412
+ tabIndex: -1,
32413
+ style: {
32414
+ width: 0,
32415
+ height: 0,
32416
+ overflow: "hidden"
32417
+ }
32418
+ }, fullGraphAriaDescription), /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
32414
32419
  box: props.box,
32415
32420
  backgroundImage: props.backgroundImage
32416
32421
  }), props.showLabelsFlag && props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLabelsLayer, {
@@ -33693,9 +33698,6 @@ const StatefulMafsGraph = /*#__PURE__*/React__namespace.forwardRef((props, ref)
33693
33698
  }));
33694
33699
  });
33695
33700
 
33696
- const {
33697
- DeprecationMixin
33698
- } = Util;
33699
33701
  const TRASH_ICON_URI = "https://ka-perseus-graphie.s3.amazonaws.com/b1452c0d79fd0f7ff4c3af9488474a0a0decb361.png";
33700
33702
  const defaultBackgroundImage = {
33701
33703
  url: null
@@ -33724,13 +33726,6 @@ function capitalize(str) {
33724
33726
  function numSteps(range, step) {
33725
33727
  return Math.floor((range[1] - range[0]) / step);
33726
33728
  }
33727
- const deprecatedProps = {
33728
- showGraph: function (props) {
33729
- return {
33730
- markings: props.showGraph ? "graph" : "none"
33731
- };
33732
- }
33733
- };
33734
33729
  const _getShouldShowInstructions = props => {
33735
33730
  return _isClickToAddPoints(props) && (
33736
33731
  // @ts-expect-error - TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'. | TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'.
@@ -33788,11 +33783,6 @@ class LegacyInteractiveGraph extends React__namespace.Component {
33788
33783
  state = {
33789
33784
  shouldShowInstructions: _getShouldShowInstructions(this.props)
33790
33785
  };
33791
-
33792
- // TODO(jangmi, CP-3288): Remove usage of `UNSAFE_componentWillMount`
33793
- UNSAFE_componentWillMount() {
33794
- DeprecationMixin.UNSAFE_componentWillMount.call(this);
33795
- }
33796
33786
  componentDidMount() {
33797
33787
  if (this.refs.graph) {
33798
33788
  // eslint-disable-next-line react/no-string-refs
@@ -33831,7 +33821,6 @@ class LegacyInteractiveGraph extends React__namespace.Component {
33831
33821
  // @ts-expect-error - TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'. | TS2339 - Property 'coords' does not exist on type 'PerseusGraphType'.
33832
33822
  props.graph.coords == null || props.graph.coords.length === 0);
33833
33823
  };
33834
- deprecatedProps = deprecatedProps;
33835
33824
  setGraphie = newGraphie => {
33836
33825
  this.graphie = newGraphie;
33837
33826
  this.setupGraphie();
@@ -43526,7 +43515,7 @@ class PhetSimulation extends React__namespace.Component {
43526
43515
  // http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
43527
43516
  const sandboxProperties = "allow-same-origin allow-scripts";
43528
43517
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
43529
- style: styles$6.container
43518
+ style: styles$6.widgetContainer
43530
43519
  }, this.state.banner !== null &&
43531
43520
  /*#__PURE__*/
43532
43521
  // TODO(anna): Make this banner focusable
@@ -43538,18 +43527,16 @@ class PhetSimulation extends React__namespace.Component {
43538
43527
  layout: "floating",
43539
43528
  kind: this.state.banner.kind,
43540
43529
  text: this.state.banner.message
43541
- })), /*#__PURE__*/React__namespace.createElement("iframe", {
43530
+ })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
43531
+ style: styles$6.iframeContainer
43532
+ }, /*#__PURE__*/React__namespace.createElement("iframe", {
43542
43533
  ref: this.iframeRef,
43543
43534
  title: this.props.description,
43544
43535
  sandbox: sandboxProperties,
43545
- style: {
43546
- height: 225,
43547
- width: "100%",
43548
- borderWidth: 0
43549
- },
43536
+ className: aphrodite.css(styles$6.iframeResponsive),
43550
43537
  src: this.state.url?.toString(),
43551
43538
  allow: "fullscreen"
43552
- }), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
43539
+ })), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
43553
43540
  icon: cornersOutIcon__default["default"],
43554
43541
  onClick: () => {
43555
43542
  this.iframeRef.current?.requestFullscreen();
@@ -43579,14 +43566,29 @@ const makeSafeUrl = (urlString, locale) => {
43579
43566
  return url;
43580
43567
  };
43581
43568
  const styles$6 = aphrodite.StyleSheet.create({
43582
- container: {
43569
+ widgetContainer: {
43583
43570
  borderRadius: borderRadiusLarge,
43584
43571
  borderWidth: 1,
43585
43572
  borderColor: basicBorderColor,
43586
43573
  padding: wonderBlocksTokens.spacing.medium_16,
43587
- paddingBottom: 0,
43588
- // Include space for medium_16 padding on each side
43589
- width: 400 + wonderBlocksTokens.spacing.xLarge_32
43574
+ paddingBottom: 0
43575
+ },
43576
+ iframeContainer: {
43577
+ position: "relative",
43578
+ overflow: "hidden",
43579
+ width: "100%",
43580
+ // 16:9 aspect ratio
43581
+ paddingTop: "56.25%"
43582
+ },
43583
+ iframeResponsive: {
43584
+ borderWidth: 0,
43585
+ position: "absolute",
43586
+ top: 0,
43587
+ left: 0,
43588
+ bottom: 0,
43589
+ right: 0,
43590
+ width: "100%",
43591
+ height: "100%"
43590
43592
  }
43591
43593
  });
43592
43594
  var PhetSimulation$1 = {
@@ -45097,7 +45099,7 @@ const init = function (options) {
45097
45099
 
45098
45100
  // This file is processed by a Rollup plugin (replace) to inject the production
45099
45101
  const libName = "@khanacademy/perseus";
45100
- const libVersion = "32.0.0";
45102
+ const libVersion = "33.0.0";
45101
45103
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
45102
45104
 
45103
45105
  const apiVersion = {
@@ -45991,128 +45993,6 @@ const ref = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__
45991
45993
  }));
45992
45994
  }));
45993
45995
 
45994
- class ArrowPicker extends React__namespace.Component {
45995
- static defaultProps = {
45996
- value: ""
45997
- };
45998
- render() {
45999
- return /*#__PURE__*/React__namespace.createElement(ButtonGroup, {
46000
- value: this.props.value,
46001
- allowEmpty: false,
46002
- buttons: [{
46003
- value: "",
46004
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2014")
46005
- }, {
46006
- value: "->",
46007
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2192")
46008
- }
46009
- /*
46010
- TODO(eater): fix khan-exercises so these are supported
46011
- {value: "<-", content: <span>&#x2190;</span>},
46012
- {value: "<->", content: <span>&#x2194;</span>}
46013
- */],
46014
-
46015
- onChange: this.props.onChange
46016
- });
46017
- }
46018
- }
46019
-
46020
- const COLORS = [KhanColors.BLACK, KhanColors.BLUE, KhanColors.GREEN, KhanColors.PINK, KhanColors.PURPLE, KhanColors.RED, KhanColors.GRAY];
46021
- const LIGHT_COLORS = [KhanColors.LIGHT_BLUE, KhanColors.LIGHT_ORANGE, KhanColors.LIGHT_PINK, KhanColors.LIGHT_GREEN, KhanColors.LIGHT_PURPLE, KhanColors.LIGHT_RED, "#fff"];
46022
- class ColorPicker extends React__namespace.Component {
46023
- static defaultProps = {
46024
- value: KhanColors.BLACK,
46025
- lightColors: false
46026
- };
46027
- render() {
46028
- const colors = this.props.lightColors ? LIGHT_COLORS : COLORS;
46029
- return /*#__PURE__*/React__namespace.createElement(ButtonGroup, {
46030
- value: this.props.value,
46031
- allowEmpty: false,
46032
- buttons: ___default["default"].map(colors, color => {
46033
- return {
46034
- value: color,
46035
- content: /*#__PURE__*/React__namespace.createElement("span", null, /*#__PURE__*/React__namespace.createElement("span", {
46036
- className: "colorpicker-circle",
46037
- style: {
46038
- background: color
46039
- }
46040
- }), "\xA0")
46041
- };
46042
- }),
46043
- onChange: this.props.onChange
46044
- });
46045
- }
46046
- }
46047
-
46048
- class DashPicker extends React__namespace.Component {
46049
- static defaultProps = {
46050
- value: ""
46051
- };
46052
- render() {
46053
- return /*#__PURE__*/React__namespace.createElement(ButtonGroup, {
46054
- value: this.props.value,
46055
- allowEmpty: false,
46056
- buttons: [{
46057
- value: "",
46058
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2014")
46059
- }, {
46060
- value: "-",
46061
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2013\u2013\u2013")
46062
- }, {
46063
- value: "- ",
46064
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2013\xA0\xA0\u2013")
46065
- }, {
46066
- value: ".",
46067
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\xB7\xB7\xB7\xB7")
46068
- }, {
46069
- value: ". ",
46070
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\xB7 \xB7 \xB7")
46071
- }],
46072
- onChange: this.props.onChange
46073
- });
46074
- }
46075
- }
46076
-
46077
- /* eslint-disable jsx-a11y/anchor-is-valid */
46078
- class ElementContainer extends React__namespace.Component {
46079
- static defaultProps = {
46080
- initiallyVisible: false,
46081
- title: "More"
46082
- };
46083
- constructor(props) {
46084
- super(props);
46085
- this.state = {
46086
- show: props.initiallyVisible
46087
- };
46088
- }
46089
- toggle = e => {
46090
- e.preventDefault();
46091
- this.setState({
46092
- show: !this.state.show
46093
- });
46094
- };
46095
- render() {
46096
- return /*#__PURE__*/React__namespace.createElement("div", {
46097
- className: "perseus-interaction-element"
46098
- }, /*#__PURE__*/React__namespace.createElement("a", {
46099
- href: "#",
46100
- className: "perseus-interaction-element-title " + (this.state.show ? "open" : "closed"),
46101
- onClick: this.toggle
46102
- }, this.state.show ? /*#__PURE__*/React__namespace.createElement(InlineIcon, iconChevronDown) : /*#__PURE__*/React__namespace.createElement(InlineIcon, iconChevronRight), this.props.title), /*#__PURE__*/React__namespace.createElement("div", {
46103
- className: "perseus-interaction-element-content " + (this.state.show ? "enter" : "leave")
46104
- }, this.props.children, (this.props.onUp != null || this.props.onDown != null || this.props.onDelete != null) && /*#__PURE__*/React__namespace.createElement("div", {
46105
- className: "edit-controls"
46106
- }, this.props.onUp != null && /*#__PURE__*/React__namespace.createElement("button", {
46107
- onClick: this.props.onUp
46108
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleArrowUp)), this.props.onDown != null && /*#__PURE__*/React__namespace.createElement("button", {
46109
- onClick: this.props.onDown
46110
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleArrowDown)), this.props.onDelete != null && /*#__PURE__*/React__namespace.createElement("button", {
46111
- onClick: this.props.onDelete
46112
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconTrash)))));
46113
- }
46114
- }
46115
-
46116
45996
  const devices = {
46117
45997
  PHONE: "phone",
46118
45998
  TABLET: "tablet",
@@ -48698,17 +48578,13 @@ const EditorJsonify = {
48698
48578
  };
48699
48579
 
48700
48580
  exports.ApiOptions = ApiOptions;
48701
- exports.ArrowPicker = ArrowPicker;
48702
48581
  exports.ArticleRenderer = ArticleRenderer;
48703
48582
  exports.BaseRadio = BaseRadio;
48704
48583
  exports.Categorizer = Categorizer$1;
48705
48584
  exports.Changeable = changeable;
48706
48585
  exports.ClassNames = ClassNames;
48707
- exports.ColorPicker = ColorPicker;
48708
- exports.DashPicker = DashPicker;
48709
48586
  exports.Dependencies = dependencies;
48710
48587
  exports.EditorJsonify = EditorJsonify;
48711
- exports.ElementContainer = ElementContainer;
48712
48588
  exports.Expression = Expression;
48713
48589
  exports.GrapherUtil = util;
48714
48590
  exports.GrapherWidget = Grapher$1;