@khanacademy/perseus-editor 5.2.3 → 5.2.5

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.
@@ -1,15 +1,11 @@
1
1
  /**
2
2
  * A component that displays its contents inside a device frame.
3
3
  */
4
- import PropTypes from "prop-types";
5
4
  import * as React from "react";
6
- type Props = any;
7
- declare class DeviceFramer extends React.Component<Props> {
8
- static propTypes: {
9
- children: PropTypes.Validator<PropTypes.ReactElementLike>;
10
- deviceType: PropTypes.Validator<NonNullable<"phone" | "tablet" | "desktop">>;
11
- nochrome: PropTypes.Requireable<boolean>;
12
- };
13
- render(): React.ReactNode;
14
- }
5
+ import type { DeviceType } from "@khanacademy/perseus";
6
+ type Props = React.PropsWithChildren<{
7
+ deviceType?: DeviceType;
8
+ nochrome: boolean;
9
+ }>;
10
+ declare const DeviceFramer: ({ children, deviceType, nochrome, }: Props) => React.ReactElement;
15
11
  export default DeviceFramer;
@@ -1,16 +1,13 @@
1
- import PropTypes from "prop-types";
2
- import * as React from "react";
1
+ /// <reference types="react" />
3
2
  import type { DeviceType } from "@khanacademy/perseus";
4
3
  type Props = {
4
+ /** The current device type that is selected. */
5
5
  deviceType: DeviceType;
6
- onViewportSizeChanged: (arg1: DeviceType) => unknown;
6
+ /**
7
+ * A callback that is passed (width, height) as the dimensions of the
8
+ * viewport to resize to.
9
+ */
10
+ onViewportSizeChanged: (deviceType: DeviceType) => unknown;
7
11
  };
8
- declare class ViewportResizer extends React.Component<Props> {
9
- static propTypes: {
10
- deviceType: PropTypes.Validator<string>;
11
- onViewportSizeChanged: PropTypes.Validator<(...args: any[]) => any>;
12
- };
13
- handleChange: (value: DeviceType) => void;
14
- render(): React.ReactNode;
15
- }
12
+ declare const ViewportResizer: (props: Props) => JSX.Element;
16
13
  export default ViewportResizer;
@@ -6,7 +6,7 @@ type WidgetEditorProps = {
6
6
  onChange: (widgetInfo: PerseusWidget, cb?: () => unknown, silent?: boolean) => unknown;
7
7
  onRemove: () => unknown;
8
8
  apiOptions: any;
9
- } & PerseusWidget;
9
+ } & Omit<PerseusWidget, "key">;
10
10
  type WidgetEditorState = {
11
11
  showWidget: boolean;
12
12
  widgetInfo: PerseusWidget;
package/dist/es/index.js CHANGED
@@ -3,12 +3,12 @@ import { constants, components, Widgets, icons, WIDGET_PROP_DENYLIST, Util, Log,
3
3
  import * as React from 'react';
4
4
  import { useRef, useEffect } from 'react';
5
5
  import _ from 'underscore';
6
- import PropTypes from 'prop-types';
7
6
  import createReactClass from 'create-react-class';
8
7
  import Clickable from '@khanacademy/wonder-blocks-clickable';
9
- import Color from '@khanacademy/wonder-blocks-color';
8
+ import { color, spacing } from '@khanacademy/wonder-blocks-tokens';
10
9
  import { StyleSheet, css } from 'aphrodite';
11
10
  import $ from 'jquery';
11
+ import PropTypes from 'prop-types';
12
12
  import { View, useUniqueIdWithMock } from '@khanacademy/wonder-blocks-core';
13
13
  import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
14
14
  import caretRight from '@phosphor-icons/core/bold/caret-right-bold.svg';
@@ -20,9 +20,7 @@ import { isTruthy } from '@khanacademy/wonder-stuff-core';
20
20
  import { createMathField } from '@khanacademy/math-input';
21
21
  import { SingleSelect, OptionItem, ActionMenu, ActionItem } from '@khanacademy/wonder-blocks-dropdown';
22
22
  import { TextField, Checkbox as Checkbox$1 } from '@khanacademy/wonder-blocks-form';
23
- import Spacing from '@khanacademy/wonder-blocks-spacing';
24
23
  import { LabelSmall, LabelLarge, LabelMedium, BodyMonospace } from '@khanacademy/wonder-blocks-typography';
25
- import { spacing, color } from '@khanacademy/wonder-blocks-tokens';
26
24
  import IconButton from '@khanacademy/wonder-blocks-icon-button';
27
25
  import trashIcon from '@phosphor-icons/core/bold/trash-bold.svg';
28
26
  import Button from '@khanacademy/wonder-blocks-button';
@@ -30,7 +28,7 @@ import * as i18n$1 from '@khanacademy/wonder-blocks-i18n';
30
28
 
31
29
  // This file is processed by a Rollup plugin (replace) to inject the production
32
30
  const libName = "@khanacademy/perseus-editor";
33
- const libVersion = "5.2.3";
31
+ const libVersion = "5.2.5";
34
32
  addLibraryVersionToPerseusDebug(libName, libVersion);
35
33
 
36
34
  function _extends() {
@@ -50,9 +48,6 @@ function _extends() {
50
48
  return _extends.apply(this, arguments);
51
49
  }
52
50
 
53
- /**
54
- * A component that displays its contents inside a device frame.
55
- */
56
51
  const SCREEN_SIZES = {
57
52
  phone: {
58
53
  width: 320,
@@ -70,47 +65,46 @@ const SCREEN_SIZES = {
70
65
  framedWidth: 688
71
66
  }
72
67
  };
73
- class DeviceFramer extends React.Component {
74
- render() {
75
- const deviceType = this.props.deviceType;
76
- if (this.props.nochrome) {
77
- // Render content inside a variable height iframe. Used on the
78
- // "edit" table of the content editor. In this mode, PerseusFrame
79
- // will draw the border and reserve space on the right for
80
- // lint indicators.
81
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
82
- key: "screen",
83
- style: {
84
- width: SCREEN_SIZES[deviceType].framedWidth + 2 * constants.perseusFrameBorderWidth + constants.lintGutterWidth
85
- }
86
- }, /*#__PURE__*/React.createElement("div", null, this.props.children)));
87
- }
88
- const scale = SCREEN_SIZES[deviceType].framedWidth / SCREEN_SIZES[deviceType].width;
89
-
90
- // In this mode we draw our own border and don't reserve
91
- // space for a lint gutter.
92
- const screenStyle = {
93
- backgroundColor: "white",
94
- color: "black",
95
- textAlign: "left",
96
- width: SCREEN_SIZES[deviceType].width,
97
- height: SCREEN_SIZES[deviceType].height,
98
- border: "solid 1px #CCC",
99
- margin: 8,
100
- zoom: scale
101
- };
68
+ const DeviceFramer = ({
69
+ children,
70
+ deviceType: _deviceType = "phone",
71
+ nochrome
72
+ }) => {
73
+ const scale = React.useMemo(() => SCREEN_SIZES[_deviceType].framedWidth / SCREEN_SIZES[_deviceType].width, [_deviceType]);
74
+
75
+ // In this mode we draw our own border and don't reserve
76
+ // space for a lint gutter.
77
+ const withChromeStyle = React.useMemo(() => ({
78
+ backgroundColor: "white",
79
+ overflow: "scroll",
80
+ color: "black",
81
+ textAlign: "left",
82
+ width: SCREEN_SIZES[_deviceType].width,
83
+ height: SCREEN_SIZES[_deviceType].height,
84
+ border: "solid 1px #CCC",
85
+ margin: 8,
86
+ zoom: scale
87
+ }), [_deviceType, scale]);
88
+ if (nochrome) {
89
+ // Render content inside a variable height iframe. Used on the
90
+ // "edit" table of the content editor. In this mode, PerseusFrame
91
+ // will draw the border and reserve space on the right for
92
+ // lint indicators.
102
93
  return /*#__PURE__*/React.createElement("div", {
103
94
  key: "screen",
104
- className: "screen",
105
- style: screenStyle
106
- }, this.props.children);
95
+ style: {
96
+ overflow: "scroll",
97
+ width: SCREEN_SIZES[_deviceType].framedWidth + 2 * constants.perseusFrameBorderWidth + constants.lintGutterWidth
98
+ }
99
+ }, /*#__PURE__*/React.createElement("div", null, children));
107
100
  }
108
- }
109
- DeviceFramer.propTypes = {
110
- children: PropTypes.element.isRequired,
111
- deviceType: PropTypes.oneOf([constants.devices.PHONE, constants.devices.TABLET, constants.devices.DESKTOP]).isRequired,
112
- // TODO(kevinb) rename to variableHeight
113
- nochrome: PropTypes.bool
101
+ return /*#__PURE__*/React.createElement("div", {
102
+ key: "screen",
103
+ className: "screen",
104
+ style: _extends({}, withChromeStyle, {
105
+ textAlign: "start"
106
+ })
107
+ }, children);
114
108
  };
115
109
 
116
110
  /* eslint-disable @babel/no-invalid-this */
@@ -236,7 +230,7 @@ class SectionControlButton extends React.Component {
236
230
  }
237
231
  const styles$q = StyleSheet.create({
238
232
  button: {
239
- backgroundColor: Color.gold,
233
+ backgroundColor: color.gold,
240
234
  margin: 2,
241
235
  paddingRight: 10,
242
236
  paddingLeft: 10,
@@ -21163,6 +21157,9 @@ class Editor extends React.Component {
21163
21157
  // eg. If there is an "image 2" already present in the editor and we're
21164
21158
  // about to paste in two new images, return
21165
21159
  // { "image 1": "image 3", "image 2": "image 4" }
21160
+ //
21161
+ // TODO switch to UUIDs rather than these fragile IDs
21162
+ // see: LEMS-1845
21166
21163
 
21167
21164
  // List of widgets about to be pasted as [[name, number], ...]
21168
21165
  const widgets = _.keys(widgetData).map(name => name.split(" "));
@@ -21421,7 +21418,8 @@ class Editor extends React.Component {
21421
21418
  }
21422
21419
  return /*#__PURE__*/React.createElement(WidgetEditor, _extends({
21423
21420
  ref: id,
21424
- id: id
21421
+ id: id,
21422
+ key: id
21425
21423
  // eslint-disable-next-line react/jsx-no-bind
21426
21424
  ,
21427
21425
  onChange: this._handleWidgetEditorChange.bind(this, id)
@@ -22086,44 +22084,29 @@ const {
22086
22084
  iconMobilePhone,
22087
22085
  iconTablet
22088
22086
  } = icons;
22089
- class ViewportResizer extends React.Component {
22090
- constructor(...args) {
22091
- super(...args);
22092
- this.handleChange = value => {
22093
- this.props.onViewportSizeChanged(value);
22094
- };
22095
- }
22096
- render() {
22097
- const phoneButtonContents = /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(InlineIcon$8, iconMobilePhone), " Phone");
22098
- const tabletButtonContents = /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(InlineIcon$8, iconTablet), " Tablet");
22099
- const desktopButtonContents = /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(InlineIcon$8, iconDesktop), " Desktop");
22100
-
22101
- // TODO(david): Allow input of custom viewport sizes.
22102
- return /*#__PURE__*/React.createElement("span", {
22103
- className: "viewport-resizer"
22104
- }, "Viewport:", " ", /*#__PURE__*/React.createElement(ButtonGroup$5, {
22105
- value: this.props.deviceType,
22106
- allowEmpty: false,
22107
- buttons: [{
22108
- value: devices.PHONE,
22109
- content: phoneButtonContents
22110
- }, {
22111
- value: devices.TABLET,
22112
- content: tabletButtonContents
22113
- }, {
22114
- value: devices.DESKTOP,
22115
- content: desktopButtonContents
22116
- }],
22117
- onChange: this.handleChange
22118
- }));
22119
- }
22120
- }
22121
- ViewportResizer.propTypes = {
22122
- // The current device type that is selected.
22123
- deviceType: PropTypes.string.isRequired,
22124
- // A callback that is passed (width, height) as the dimensions of the
22125
- // viewport to resize to.
22126
- onViewportSizeChanged: PropTypes.func.isRequired
22087
+ const ViewportResizer = props => {
22088
+ const phoneButtonContents = /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(InlineIcon$8, iconMobilePhone), " Phone");
22089
+ const tabletButtonContents = /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(InlineIcon$8, iconTablet), " Tablet");
22090
+ const desktopButtonContents = /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(InlineIcon$8, iconDesktop), " Desktop");
22091
+
22092
+ // TODO(david): Allow input of custom viewport sizes.
22093
+ return /*#__PURE__*/React.createElement("span", {
22094
+ className: "viewport-resizer"
22095
+ }, "Viewport:", " ", /*#__PURE__*/React.createElement(ButtonGroup$5, {
22096
+ value: props.deviceType,
22097
+ allowEmpty: false,
22098
+ buttons: [{
22099
+ value: devices.PHONE,
22100
+ content: phoneButtonContents
22101
+ }, {
22102
+ value: devices.TABLET,
22103
+ content: tabletButtonContents
22104
+ }, {
22105
+ value: devices.DESKTOP,
22106
+ content: desktopButtonContents
22107
+ }],
22108
+ onChange: props.onViewportSizeChanged
22109
+ }));
22127
22110
  };
22128
22111
 
22129
22112
  /*
@@ -26816,6 +26799,7 @@ class ExpressionEditor extends React.Component {
26816
26799
  widgetId: this.props.widgetId + "-" + ans.key
26817
26800
  };
26818
26801
  return lens(ans).merge([], {
26802
+ key,
26819
26803
  draggable: true,
26820
26804
  onChange: props => {
26821
26805
  var _ans$key;
@@ -27299,10 +27283,11 @@ const GraphSettings = createReactClass({
27299
27283
  }
27300
27284
  },
27301
27285
  renderLabelChoices: function (choices) {
27302
- return _.map(choices, function (nameAndValue) {
27286
+ return _.map(choices, function ([name, value]) {
27303
27287
  return /*#__PURE__*/React.createElement("option", {
27304
- value: nameAndValue[1]
27305
- }, nameAndValue[0]);
27288
+ key: value,
27289
+ value: value
27290
+ }, name);
27306
27291
  });
27307
27292
  },
27308
27293
  validRange: function (range) {
@@ -27662,6 +27647,7 @@ const GraphSettings = createReactClass({
27662
27647
  value: this.props.rulerTicks
27663
27648
  }, _.map([1, 2, 4, 8, 10, 16], function (n) {
27664
27649
  return /*#__PURE__*/React.createElement("option", {
27650
+ key: n,
27665
27651
  value: n
27666
27652
  }, n);
27667
27653
  })))))));
@@ -28442,9 +28428,9 @@ const styles$k = StyleSheet.create({
28442
28428
  display: "inline-block",
28443
28429
  borderStyle: "solid",
28444
28430
  borderWidth: 1,
28445
- borderColor: Color.offBlack50,
28431
+ borderColor: color.offBlack50,
28446
28432
  borderRadius: 3,
28447
- background: Color.white
28433
+ background: color.white
28448
28434
  }
28449
28435
  });
28450
28436
 
@@ -29504,6 +29490,7 @@ const GraphPointsCountSelector = ({
29504
29490
  value: `${n}`,
29505
29491
  label: `${n} point${n > 1 ? "s" : ""}`
29506
29492
  })), /*#__PURE__*/React.createElement(OptionItem, {
29493
+ key: "unlimited",
29507
29494
  value: UNLIMITED,
29508
29495
  label: "unlimited"
29509
29496
  })]);
@@ -30657,6 +30644,7 @@ class InteractiveGraphEditor extends React.Component {
30657
30644
  },
30658
30645
  style: styles$a.singleSelectShort
30659
30646
  }, [...POLYGON_SIDES, /*#__PURE__*/React.createElement(OptionItem, {
30647
+ key: "unlimited",
30660
30648
  value: "unlimited",
30661
30649
  label: "unlimited sides"
30662
30650
  })])), /*#__PURE__*/React.createElement(LabeledRow, {
@@ -30784,7 +30772,7 @@ class InteractiveGraphEditor extends React.Component {
30784
30772
  style: {
30785
30773
  fontSize: 12,
30786
30774
  backgroundColor: "#eee",
30787
- paddingInline: Spacing.xxSmall_6,
30775
+ paddingInline: spacing.xxSmall_6,
30788
30776
  borderColor: "#ccc",
30789
30777
  borderStyle: "solid",
30790
30778
  borderWidth: 1
@@ -30840,7 +30828,7 @@ const styles$a = StyleSheet.create({
30840
30828
  },
30841
30829
  row: {
30842
30830
  flexDirection: "row",
30843
- marginTop: Spacing.xSmall_8,
30831
+ marginTop: spacing.xSmall_8,
30844
30832
  alignItems: "center"
30845
30833
  }
30846
30834
  });
@@ -30885,7 +30873,7 @@ class FormWrappedTextField extends React.Component {
30885
30873
  backgroundColor,
30886
30874
  focusBorderColor,
30887
30875
  borderColor,
30888
- color,
30876
+ color: color$1,
30889
30877
  onSubmit,
30890
30878
  leftSideIcon,
30891
30879
  id,
@@ -30915,10 +30903,10 @@ class FormWrappedTextField extends React.Component {
30915
30903
  }
30916
30904
 
30917
30905
  // Add text color if specified.
30918
- if (color) {
30919
- extraStyles.color = color;
30906
+ if (color$1) {
30907
+ extraStyles.color = color$1;
30920
30908
  }
30921
- const borderColorStyle = focused ? focusBorderColor || Color.blue : borderColor || Color.offBlack16;
30909
+ const borderColorStyle = focused ? focusBorderColor || color.blue : borderColor || color.offBlack16;
30922
30910
  extraStyles.border = `1px solid ${borderColorStyle}`;
30923
30911
  const wrappedIcon = icon && /*#__PURE__*/React.createElement("span", {
30924
30912
  className: css(styles$9.icon)