@khanacademy/perseus-editor 14.2.0 → 14.3.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
@@ -34,17 +34,17 @@ import caretUpIcon from '@phosphor-icons/core/bold/caret-up-bold.svg';
34
34
  import trashIcon from '@phosphor-icons/core/bold/trash-bold.svg';
35
35
  import copyIcon from '@phosphor-icons/core/assets/regular/copy.svg';
36
36
  import autoPasteIcon from '@phosphor-icons/core/assets/regular/note-pencil.svg';
37
+ import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
37
38
  import arrowFatDown from '@phosphor-icons/core/regular/arrow-fat-down.svg';
38
39
  import arrowFatLeft from '@phosphor-icons/core/regular/arrow-fat-left.svg';
39
40
  import arrowFatRight from '@phosphor-icons/core/regular/arrow-fat-right.svg';
40
41
  import arrowFatUp from '@phosphor-icons/core/regular/arrow-fat-up.svg';
41
42
  import minusCircle from '@phosphor-icons/core/regular/minus-circle.svg';
42
- import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
43
43
  import arrowCounterClockwise from '@phosphor-icons/core/bold/arrow-counter-clockwise-bold.svg';
44
44
 
45
45
  // This file is processed by a Rollup plugin (replace) to inject the production
46
46
  const libName = "@khanacademy/perseus-editor";
47
- const libVersion = "14.2.0";
47
+ const libVersion = "14.3.0";
48
48
  addLibraryVersionToPerseusDebug(libName, libVersion);
49
49
 
50
50
  function _extends() {
@@ -30661,7 +30661,7 @@ const LockedFigureSettingsActions = props => {
30661
30661
  onClick: onRemove,
30662
30662
  kind: "tertiary",
30663
30663
  style: styles$u.deleteButton
30664
- }, "Delete"), /*#__PURE__*/React.createElement(Spring, null), /*#__PURE__*/React.createElement(IconButton, {
30664
+ }, "Delete"), onMove && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Spring, null), /*#__PURE__*/React.createElement(IconButton, {
30665
30665
  icon: caretDoubleUpIcon,
30666
30666
  size: "small",
30667
30667
  "aria-label": `Move locked ${figureType} to the back`,
@@ -30685,7 +30685,7 @@ const LockedFigureSettingsActions = props => {
30685
30685
  "aria-label": `Move locked ${figureType} to the front`,
30686
30686
  onClick: () => onMove("front"),
30687
30687
  style: styles$u.iconButton
30688
- }));
30688
+ })));
30689
30689
  };
30690
30690
  const styles$u = StyleSheet.create({
30691
30691
  container: {
@@ -31186,7 +31186,8 @@ function LockedLabelSettings(props) {
31186
31186
  backgroundColor: color.white,
31187
31187
  color: lockedFigureColors[color$1]
31188
31188
  }, styles$q.accordionHeader]
31189
- }, text))
31189
+ }, text)),
31190
+ containerStyle: !onMove && styles$q.innerLabelAccordionPanel
31190
31191
  }, /*#__PURE__*/React.createElement(CoordinatePairInput, {
31191
31192
  coord: coord,
31192
31193
  onChange: newCoords => {
@@ -31208,7 +31209,7 @@ function LockedLabelSettings(props) {
31208
31209
  })
31209
31210
  })), /*#__PURE__*/React.createElement(View, {
31210
31211
  style: styles$q.row
31211
- }, /*#__PURE__*/React.createElement(ColorSelect, {
31212
+ }, onMove && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorSelect, {
31212
31213
  selectedValue: color$1,
31213
31214
  onChange: newColor => {
31214
31215
  onChangeProps({
@@ -31218,7 +31219,7 @@ function LockedLabelSettings(props) {
31218
31219
  style: styles$q.spaceUnder
31219
31220
  }), /*#__PURE__*/React.createElement(Strut, {
31220
31221
  size: spacing.medium_16
31221
- }), /*#__PURE__*/React.createElement(LabelMedium, {
31222
+ })), /*#__PURE__*/React.createElement(LabelMedium, {
31222
31223
  tag: "label",
31223
31224
  style: styles$q.row
31224
31225
  }, "size", /*#__PURE__*/React.createElement(Strut, {
@@ -31268,6 +31269,9 @@ const styles$q = StyleSheet.create({
31268
31269
  },
31269
31270
  spaceUnder: {
31270
31271
  marginBottom: spacing.xSmall_8
31272
+ },
31273
+ innerLabelAccordionPanel: {
31274
+ backgroundColor: color.white
31271
31275
  }
31272
31276
  });
31273
31277
 
@@ -31512,24 +31516,122 @@ const styles$n = StyleSheet.create({
31512
31516
  }
31513
31517
  });
31514
31518
 
31515
- /**
31516
- * LockedPointSettings is a component that allows the user to edit the
31517
- * settings of specifically a locked point on the graph.
31518
- *
31519
- * Used in the interactive graph editor's locked figures section.
31520
- */
31519
+ const DEFAULT_COLOR = "grayH";
31520
+ function getDefaultFigureForType(type) {
31521
+ switch (type) {
31522
+ case "point":
31523
+ return {
31524
+ type: "point",
31525
+ coord: [0, 0],
31526
+ color: DEFAULT_COLOR,
31527
+ filled: true,
31528
+ labels: []
31529
+ };
31530
+ case "line":
31531
+ return {
31532
+ type: "line",
31533
+ kind: "line",
31534
+ points: [getDefaultFigureForType("point"), _extends({}, getDefaultFigureForType("point"), {
31535
+ coord: [2, 2]
31536
+ })],
31537
+ color: DEFAULT_COLOR,
31538
+ lineStyle: "solid",
31539
+ showPoint1: false,
31540
+ showPoint2: false
31541
+ };
31542
+ case "vector":
31543
+ return {
31544
+ type: "vector",
31545
+ points: [[0, 0], [2, 2]],
31546
+ color: DEFAULT_COLOR
31547
+ };
31548
+ case "ellipse":
31549
+ return {
31550
+ type: "ellipse",
31551
+ center: [0, 0],
31552
+ radius: [1, 1],
31553
+ angle: 0,
31554
+ color: DEFAULT_COLOR,
31555
+ fillStyle: "none",
31556
+ strokeStyle: "solid"
31557
+ };
31558
+ case "polygon":
31559
+ return {
31560
+ type: "polygon",
31561
+ points: [[0, 2], [-1, 0], [1, 0]],
31562
+ color: DEFAULT_COLOR,
31563
+ showVertices: false,
31564
+ fillStyle: "none",
31565
+ strokeStyle: "solid"
31566
+ };
31567
+ case "function":
31568
+ return {
31569
+ type: "function",
31570
+ color: DEFAULT_COLOR,
31571
+ strokeStyle: "solid",
31572
+ equation: "x^2",
31573
+ directionalAxis: "x"
31574
+ };
31575
+ case "label":
31576
+ return {
31577
+ type: "label",
31578
+ coord: [0, 0],
31579
+ text: "",
31580
+ color: DEFAULT_COLOR,
31581
+ size: "medium"
31582
+ };
31583
+ default:
31584
+ throw new UnreachableCaseError(type);
31585
+ }
31586
+ }
31587
+
31521
31588
  const LockedPointSettings = props => {
31589
+ var _flags$mafs;
31522
31590
  const {
31591
+ flags,
31523
31592
  coord,
31524
31593
  color: pointColor,
31525
31594
  filled = true,
31595
+ labels,
31526
31596
  onChangeProps,
31527
31597
  onMove,
31528
31598
  onRemove
31529
31599
  } = props;
31530
31600
  function handleColorChange(newValue) {
31531
- onChangeProps({
31601
+ const newProps = {
31532
31602
  color: newValue
31603
+ };
31604
+
31605
+ // Update the color of the all labels to match the point
31606
+ newProps.labels = labels.map(label => _extends({}, label, {
31607
+ color: newValue
31608
+ }));
31609
+ onChangeProps(newProps);
31610
+ }
31611
+ function handleCoordChange(newCoord) {
31612
+ const xOffset = newCoord[0] - coord[0];
31613
+ const yOffset = newCoord[1] - coord[1];
31614
+ const newProps = {
31615
+ coord: newCoord
31616
+ };
31617
+
31618
+ // Update the coord by the same amount as the point for all labels
31619
+ newProps.labels = labels.map(label => _extends({}, label, {
31620
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31621
+ }));
31622
+ onChangeProps(newProps);
31623
+ }
31624
+ function handleLabelChange(updatedLabel, labelIndex) {
31625
+ const updatedLabels = [...labels];
31626
+ updatedLabels[labelIndex] = _extends({}, labels[labelIndex], updatedLabel);
31627
+ onChangeProps({
31628
+ labels: updatedLabels
31629
+ });
31630
+ }
31631
+ function handleLabelRemove(labelIndex) {
31632
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31633
+ onChangeProps({
31634
+ labels: updatedLabels
31533
31635
  });
31534
31636
  }
31535
31637
  return /*#__PURE__*/React.createElement(PerseusEditorAccordion, {
@@ -31549,11 +31651,7 @@ const LockedPointSettings = props => {
31549
31651
  }, /*#__PURE__*/React.createElement(CoordinatePairInput, {
31550
31652
  coord: coord,
31551
31653
  style: styles$m.spaceUnder,
31552
- onChange: newCoord => {
31553
- onChangeProps({
31554
- coord: newCoord
31555
- });
31556
- }
31654
+ onChange: handleCoordChange
31557
31655
  }), /*#__PURE__*/React.createElement(ColorSelect, {
31558
31656
  selectedValue: pointColor,
31559
31657
  onChange: handleColorChange,
@@ -31565,8 +31663,37 @@ const LockedPointSettings = props => {
31565
31663
  onChangeProps({
31566
31664
  filled: !newValue
31567
31665
  });
31666
+ },
31667
+ style: styles$m.spaceUnder
31668
+ }), (flags == null || (_flags$mafs = flags["mafs"]) == null ? void 0 : _flags$mafs["locked-point-labels"]) && /*#__PURE__*/React.createElement(React.Fragment, null, labels.map((label, labelIndex) => /*#__PURE__*/React.createElement(LockedLabelSettings, _extends({}, label, {
31669
+ expanded: true,
31670
+ onChangeProps: newLabel => {
31671
+ handleLabelChange(newLabel, labelIndex);
31672
+ },
31673
+ onRemove: () => {
31674
+ handleLabelRemove(labelIndex);
31568
31675
  }
31569
- }), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
31676
+ }))), /*#__PURE__*/React.createElement(Button, {
31677
+ kind: "tertiary",
31678
+ startIcon: plusCircle,
31679
+ onClick: () => {
31680
+ const newLabel = _extends({}, getDefaultFigureForType("label"), {
31681
+ // Place the label at the same position
31682
+ // as the point. Add a small offset to
31683
+ // avoid crowding.
31684
+ coord: [coord[0] + 0.5,
31685
+ // Additional offset for each label so
31686
+ // they don't overlap.
31687
+ coord[1] - 1 * (labels == null ? void 0 : labels.length)],
31688
+ // Default to the same color as the point
31689
+ color: pointColor
31690
+ });
31691
+ onChangeProps({
31692
+ labels: [...labels, newLabel]
31693
+ });
31694
+ },
31695
+ style: styles$m.addButton
31696
+ }, "Add visible label")), /*#__PURE__*/React.createElement(LockedFigureSettingsActions, {
31570
31697
  figureType: props.type,
31571
31698
  onMove: onMove,
31572
31699
  onRemove: onRemove
@@ -31579,6 +31706,9 @@ const styles$m = StyleSheet.create({
31579
31706
  },
31580
31707
  spaceUnder: {
31581
31708
  marginBottom: spacing.xSmall_8
31709
+ },
31710
+ addButton: {
31711
+ alignSelf: "start"
31582
31712
  }
31583
31713
  });
31584
31714
 
@@ -31968,74 +32098,6 @@ const LockedFigureSettings = props => {
31968
32098
  return null;
31969
32099
  };
31970
32100
 
31971
- const DEFAULT_COLOR = "grayH";
31972
- function getDefaultFigureForType(type) {
31973
- switch (type) {
31974
- case "point":
31975
- return {
31976
- type: "point",
31977
- coord: [0, 0],
31978
- color: DEFAULT_COLOR,
31979
- filled: true
31980
- };
31981
- case "line":
31982
- return {
31983
- type: "line",
31984
- kind: "line",
31985
- points: [getDefaultFigureForType("point"), _extends({}, getDefaultFigureForType("point"), {
31986
- coord: [2, 2]
31987
- })],
31988
- color: DEFAULT_COLOR,
31989
- lineStyle: "solid",
31990
- showPoint1: false,
31991
- showPoint2: false
31992
- };
31993
- case "vector":
31994
- return {
31995
- type: "vector",
31996
- points: [[0, 0], [2, 2]],
31997
- color: DEFAULT_COLOR
31998
- };
31999
- case "ellipse":
32000
- return {
32001
- type: "ellipse",
32002
- center: [0, 0],
32003
- radius: [1, 1],
32004
- angle: 0,
32005
- color: DEFAULT_COLOR,
32006
- fillStyle: "none",
32007
- strokeStyle: "solid"
32008
- };
32009
- case "polygon":
32010
- return {
32011
- type: "polygon",
32012
- points: [[0, 2], [-1, 0], [1, 0]],
32013
- color: DEFAULT_COLOR,
32014
- showVertices: false,
32015
- fillStyle: "none",
32016
- strokeStyle: "solid"
32017
- };
32018
- case "function":
32019
- return {
32020
- type: "function",
32021
- color: DEFAULT_COLOR,
32022
- strokeStyle: "solid",
32023
- equation: "x^2",
32024
- directionalAxis: "x"
32025
- };
32026
- case "label":
32027
- return {
32028
- type: "label",
32029
- coord: [0, 0],
32030
- text: "",
32031
- color: DEFAULT_COLOR,
32032
- size: "medium"
32033
- };
32034
- default:
32035
- throw new UnreachableCaseError(type);
32036
- }
32037
- }
32038
-
32039
32101
  const LockedFiguresSection = props => {
32040
32102
  var _props$figures;
32041
32103
  // Keep track of all figures' accordions' expanded states for the
@@ -32137,6 +32199,7 @@ const LockedFiguresSection = props => {
32137
32199
  }), isExpanded && /*#__PURE__*/React.createElement(View, null, figures == null ? void 0 : figures.map((figure, index) => {
32138
32200
  return /*#__PURE__*/React.createElement(LockedFigureSettings, _extends({
32139
32201
  key: `${uniqueId}-locked-${figure}-${index}`,
32202
+ flags: props.flags,
32140
32203
  showLabelsFlag: props.showLabelsFlag,
32141
32204
  expanded: expandedStates[index],
32142
32205
  onToggle: newValue => {
@@ -33130,6 +33193,7 @@ class InteractiveGraphEditor extends React.Component {
33130
33193
  // Only show the "Add locked figure" dropdown if the graph
33131
33194
  // is using Mafs.
33132
33195
  this.props.graph && ((_this$props$apiOption3 = this.props.apiOptions) == null || (_this$props$apiOption3 = _this$props$apiOption3.flags) == null || (_this$props$apiOption3 = _this$props$apiOption3.mafs) == null ? void 0 : _this$props$apiOption3[this.props.graph.type]) && /*#__PURE__*/React.createElement(LockedFiguresSection, {
33196
+ flags: this.props.apiOptions.flags,
33133
33197
  showLabelsFlag: (_this$props$apiOption4 = this.props.apiOptions) == null || (_this$props$apiOption4 = _this$props$apiOption4.flags) == null || (_this$props$apiOption4 = _this$props$apiOption4.mafs) == null ? void 0 : _this$props$apiOption4["interactive-graph-locked-features-labels"],
33134
33198
  figures: this.props.lockedFigures,
33135
33199
  onChange: this.props.onChange
@@ -36927,14 +36991,6 @@ class TableEditor extends React.Component {
36927
36991
  };
36928
36992
  }
36929
36993
  render() {
36930
- const tableProps = _.pick(this.props, "headers", "answers", "onChange", "apiOptions");
36931
- _.extend(tableProps, {
36932
- editableHeaders: true,
36933
- Editor,
36934
- onFocus: () => {},
36935
- onBlur: () => {},
36936
- trackInteraction: () => {}
36937
- });
36938
36994
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
36939
36995
  className: "perseus-widget-row"
36940
36996
  }, /*#__PURE__*/React.createElement("label", null, "Number of columns:", " ", /*#__PURE__*/React.createElement(NumberInput, {
@@ -36959,7 +37015,17 @@ class TableEditor extends React.Component {
36959
37015
  }
36960
37016
  },
36961
37017
  useArrowKeys: true
36962
- }))), /*#__PURE__*/React.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React.createElement(InfoTip$1, null, /*#__PURE__*/React.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Table, tableProps)));
37018
+ }))), /*#__PURE__*/React.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React.createElement(InfoTip$1, null, /*#__PURE__*/React.createElement("p", null, "The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Table, {
37019
+ headers: this.props.headers,
37020
+ answers: this.props.answers,
37021
+ onChange: this.props.onChange,
37022
+ apiOptions: this.props.apiOptions,
37023
+ editableHeaders: true,
37024
+ onFocus: () => {},
37025
+ onBlur: () => {},
37026
+ trackInteraction: () => {},
37027
+ Editor: Editor
37028
+ })));
36963
37029
  }
36964
37030
  }
36965
37031
  TableEditor.propTypes = {