@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/index.js CHANGED
@@ -36,12 +36,12 @@ var caretUpIcon = require('@phosphor-icons/core/bold/caret-up-bold.svg');
36
36
  var trashIcon = require('@phosphor-icons/core/bold/trash-bold.svg');
37
37
  var copyIcon = require('@phosphor-icons/core/assets/regular/copy.svg');
38
38
  var autoPasteIcon = require('@phosphor-icons/core/assets/regular/note-pencil.svg');
39
+ var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
39
40
  var arrowFatDown = require('@phosphor-icons/core/regular/arrow-fat-down.svg');
40
41
  var arrowFatLeft = require('@phosphor-icons/core/regular/arrow-fat-left.svg');
41
42
  var arrowFatRight = require('@phosphor-icons/core/regular/arrow-fat-right.svg');
42
43
  var arrowFatUp = require('@phosphor-icons/core/regular/arrow-fat-up.svg');
43
44
  var minusCircle = require('@phosphor-icons/core/regular/minus-circle.svg');
44
- var plusCircle = require('@phosphor-icons/core/regular/plus-circle.svg');
45
45
  var arrowCounterClockwise = require('@phosphor-icons/core/bold/arrow-counter-clockwise-bold.svg');
46
46
 
47
47
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -85,17 +85,17 @@ var caretUpIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretUpIcon);
85
85
  var trashIcon__default = /*#__PURE__*/_interopDefaultLegacy(trashIcon);
86
86
  var copyIcon__default = /*#__PURE__*/_interopDefaultLegacy(copyIcon);
87
87
  var autoPasteIcon__default = /*#__PURE__*/_interopDefaultLegacy(autoPasteIcon);
88
+ var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
88
89
  var arrowFatDown__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatDown);
89
90
  var arrowFatLeft__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatLeft);
90
91
  var arrowFatRight__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatRight);
91
92
  var arrowFatUp__default = /*#__PURE__*/_interopDefaultLegacy(arrowFatUp);
92
93
  var minusCircle__default = /*#__PURE__*/_interopDefaultLegacy(minusCircle);
93
- var plusCircle__default = /*#__PURE__*/_interopDefaultLegacy(plusCircle);
94
94
  var arrowCounterClockwise__default = /*#__PURE__*/_interopDefaultLegacy(arrowCounterClockwise);
95
95
 
96
96
  // This file is processed by a Rollup plugin (replace) to inject the production
97
97
  const libName = "@khanacademy/perseus-editor";
98
- const libVersion = "14.2.0";
98
+ const libVersion = "14.3.0";
99
99
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
100
100
 
101
101
  function _extends() {
@@ -30769,7 +30769,7 @@ const LockedFigureSettingsActions = props => {
30769
30769
  onClick: onRemove,
30770
30770
  kind: "tertiary",
30771
30771
  style: styles$u.deleteButton
30772
- }, "Delete"), /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30772
+ }, "Delete"), onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(Spring, null), /*#__PURE__*/React__namespace.createElement(IconButton__default["default"], {
30773
30773
  icon: caretDoubleUpIcon__default["default"],
30774
30774
  size: "small",
30775
30775
  "aria-label": `Move locked ${figureType} to the back`,
@@ -30793,7 +30793,7 @@ const LockedFigureSettingsActions = props => {
30793
30793
  "aria-label": `Move locked ${figureType} to the front`,
30794
30794
  onClick: () => onMove("front"),
30795
30795
  style: styles$u.iconButton
30796
- }));
30796
+ })));
30797
30797
  };
30798
30798
  const styles$u = aphrodite.StyleSheet.create({
30799
30799
  container: {
@@ -31294,7 +31294,8 @@ function LockedLabelSettings(props) {
31294
31294
  backgroundColor: wonderBlocksTokens.color.white,
31295
31295
  color: perseus.lockedFigureColors[color]
31296
31296
  }, styles$q.accordionHeader]
31297
- }, text))
31297
+ }, text)),
31298
+ containerStyle: !onMove && styles$q.innerLabelAccordionPanel
31298
31299
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31299
31300
  coord: coord,
31300
31301
  onChange: newCoords => {
@@ -31316,7 +31317,7 @@ function LockedLabelSettings(props) {
31316
31317
  })
31317
31318
  })), /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
31318
31319
  style: styles$q.row
31319
- }, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31320
+ }, onMove && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31320
31321
  selectedValue: color,
31321
31322
  onChange: newColor => {
31322
31323
  onChangeProps({
@@ -31326,7 +31327,7 @@ function LockedLabelSettings(props) {
31326
31327
  style: styles$q.spaceUnder
31327
31328
  }), /*#__PURE__*/React__namespace.createElement(Strut, {
31328
31329
  size: wonderBlocksTokens.spacing.medium_16
31329
- }), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31330
+ })), /*#__PURE__*/React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
31330
31331
  tag: "label",
31331
31332
  style: styles$q.row
31332
31333
  }, "size", /*#__PURE__*/React__namespace.createElement(Strut, {
@@ -31376,6 +31377,9 @@ const styles$q = aphrodite.StyleSheet.create({
31376
31377
  },
31377
31378
  spaceUnder: {
31378
31379
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
31380
+ },
31381
+ innerLabelAccordionPanel: {
31382
+ backgroundColor: wonderBlocksTokens.color.white
31379
31383
  }
31380
31384
  });
31381
31385
 
@@ -31625,24 +31629,127 @@ const styles$n = aphrodite.StyleSheet.create({
31625
31629
  }
31626
31630
  });
31627
31631
 
31628
- /**
31629
- * LockedPointSettings is a component that allows the user to edit the
31630
- * settings of specifically a locked point on the graph.
31631
- *
31632
- * Used in the interactive graph editor's locked figures section.
31633
- */
31632
+ const DEFAULT_COLOR = "grayH";
31633
+ function getDefaultFigureForType(type) {
31634
+ switch (type) {
31635
+ case "point":
31636
+ return {
31637
+ type: "point",
31638
+ coord: [0, 0],
31639
+ color: DEFAULT_COLOR,
31640
+ filled: true,
31641
+ labels: []
31642
+ };
31643
+ case "line":
31644
+ return {
31645
+ type: "line",
31646
+ kind: "line",
31647
+ points: [getDefaultFigureForType("point"), {
31648
+ ...getDefaultFigureForType("point"),
31649
+ coord: [2, 2]
31650
+ }],
31651
+ color: DEFAULT_COLOR,
31652
+ lineStyle: "solid",
31653
+ showPoint1: false,
31654
+ showPoint2: false
31655
+ };
31656
+ case "vector":
31657
+ return {
31658
+ type: "vector",
31659
+ points: [[0, 0], [2, 2]],
31660
+ color: DEFAULT_COLOR
31661
+ };
31662
+ case "ellipse":
31663
+ return {
31664
+ type: "ellipse",
31665
+ center: [0, 0],
31666
+ radius: [1, 1],
31667
+ angle: 0,
31668
+ color: DEFAULT_COLOR,
31669
+ fillStyle: "none",
31670
+ strokeStyle: "solid"
31671
+ };
31672
+ case "polygon":
31673
+ return {
31674
+ type: "polygon",
31675
+ points: [[0, 2], [-1, 0], [1, 0]],
31676
+ color: DEFAULT_COLOR,
31677
+ showVertices: false,
31678
+ fillStyle: "none",
31679
+ strokeStyle: "solid"
31680
+ };
31681
+ case "function":
31682
+ return {
31683
+ type: "function",
31684
+ color: DEFAULT_COLOR,
31685
+ strokeStyle: "solid",
31686
+ equation: "x^2",
31687
+ directionalAxis: "x"
31688
+ };
31689
+ case "label":
31690
+ return {
31691
+ type: "label",
31692
+ coord: [0, 0],
31693
+ text: "",
31694
+ color: DEFAULT_COLOR,
31695
+ size: "medium"
31696
+ };
31697
+ default:
31698
+ throw new wonderStuffCore.UnreachableCaseError(type);
31699
+ }
31700
+ }
31701
+
31634
31702
  const LockedPointSettings = props => {
31635
31703
  const {
31704
+ flags,
31636
31705
  coord,
31637
31706
  color: pointColor,
31638
31707
  filled = true,
31708
+ labels,
31639
31709
  onChangeProps,
31640
31710
  onMove,
31641
31711
  onRemove
31642
31712
  } = props;
31643
31713
  function handleColorChange(newValue) {
31644
- onChangeProps({
31714
+ const newProps = {
31715
+ color: newValue
31716
+ };
31717
+
31718
+ // Update the color of the all labels to match the point
31719
+ newProps.labels = labels.map(label => ({
31720
+ ...label,
31645
31721
  color: newValue
31722
+ }));
31723
+ onChangeProps(newProps);
31724
+ }
31725
+ function handleCoordChange(newCoord) {
31726
+ const xOffset = newCoord[0] - coord[0];
31727
+ const yOffset = newCoord[1] - coord[1];
31728
+ const newProps = {
31729
+ coord: newCoord
31730
+ };
31731
+
31732
+ // Update the coord by the same amount as the point for all labels
31733
+ newProps.labels = labels.map(label => ({
31734
+ ...label,
31735
+ coord: [label.coord[0] + xOffset, label.coord[1] + yOffset]
31736
+ }));
31737
+ onChangeProps(newProps);
31738
+ }
31739
+ function handleLabelChange(updatedLabel, labelIndex) {
31740
+ const updatedLabels = [...labels];
31741
+ updatedLabels[labelIndex] = {
31742
+ ...labels[labelIndex],
31743
+ ...updatedLabel
31744
+ };
31745
+ onChangeProps({
31746
+ labels: updatedLabels
31747
+ });
31748
+ }
31749
+ function handleLabelRemove(labelIndex) {
31750
+ const updatedLabels = labels.filter((_, index) => index !== labelIndex);
31751
+ onChangeProps({
31752
+ labels: updatedLabels
31646
31753
  });
31647
31754
  }
31648
31755
  return /*#__PURE__*/React__namespace.createElement(PerseusEditorAccordion, {
@@ -31662,11 +31769,7 @@ const LockedPointSettings = props => {
31662
31769
  }, /*#__PURE__*/React__namespace.createElement(CoordinatePairInput, {
31663
31770
  coord: coord,
31664
31771
  style: styles$m.spaceUnder,
31665
- onChange: newCoord => {
31666
- onChangeProps({
31667
- coord: newCoord
31668
- });
31669
- }
31772
+ onChange: handleCoordChange
31670
31773
  }), /*#__PURE__*/React__namespace.createElement(ColorSelect, {
31671
31774
  selectedValue: pointColor,
31672
31775
  onChange: handleColorChange,
@@ -31678,8 +31781,38 @@ const LockedPointSettings = props => {
31678
31781
  onChangeProps({
31679
31782
  filled: !newValue
31680
31783
  });
31784
+ },
31785
+ style: styles$m.spaceUnder
31786
+ }), flags?.["mafs"]?.["locked-point-labels"] && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, labels.map((label, labelIndex) => /*#__PURE__*/React__namespace.createElement(LockedLabelSettings, _extends({}, label, {
31787
+ expanded: true,
31788
+ onChangeProps: newLabel => {
31789
+ handleLabelChange(newLabel, labelIndex);
31790
+ },
31791
+ onRemove: () => {
31792
+ handleLabelRemove(labelIndex);
31681
31793
  }
31682
- }), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31794
+ }))), /*#__PURE__*/React__namespace.createElement(Button__default["default"], {
31795
+ kind: "tertiary",
31796
+ startIcon: plusCircle__default["default"],
31797
+ onClick: () => {
31798
+ const newLabel = {
31799
+ ...getDefaultFigureForType("label"),
31800
+ // Place the label at the same position
31801
+ // as the point. Add a small offset to
31802
+ // avoid crowding.
31803
+ coord: [coord[0] + 0.5,
31804
+ // Additional offset for each label so
31805
+ // they don't overlap.
31806
+ coord[1] - 1 * labels?.length],
31807
+ // Default to the same color as the point
31808
+ color: pointColor
31809
+ };
31810
+ onChangeProps({
31811
+ labels: [...labels, newLabel]
31812
+ });
31813
+ },
31814
+ style: styles$m.addButton
31815
+ }, "Add visible label")), /*#__PURE__*/React__namespace.createElement(LockedFigureSettingsActions, {
31683
31816
  figureType: props.type,
31684
31817
  onMove: onMove,
31685
31818
  onRemove: onRemove
@@ -31692,6 +31825,9 @@ const styles$m = aphrodite.StyleSheet.create({
31692
31825
  },
31693
31826
  spaceUnder: {
31694
31827
  marginBottom: wonderBlocksTokens.spacing.xSmall_8
31828
+ },
31829
+ addButton: {
31830
+ alignSelf: "start"
31695
31831
  }
31696
31832
  });
31697
31833
 
@@ -32093,75 +32229,6 @@ const LockedFigureSettings = props => {
32093
32229
  return null;
32094
32230
  };
32095
32231
 
32096
- const DEFAULT_COLOR = "grayH";
32097
- function getDefaultFigureForType(type) {
32098
- switch (type) {
32099
- case "point":
32100
- return {
32101
- type: "point",
32102
- coord: [0, 0],
32103
- color: DEFAULT_COLOR,
32104
- filled: true
32105
- };
32106
- case "line":
32107
- return {
32108
- type: "line",
32109
- kind: "line",
32110
- points: [getDefaultFigureForType("point"), {
32111
- ...getDefaultFigureForType("point"),
32112
- coord: [2, 2]
32113
- }],
32114
- color: DEFAULT_COLOR,
32115
- lineStyle: "solid",
32116
- showPoint1: false,
32117
- showPoint2: false
32118
- };
32119
- case "vector":
32120
- return {
32121
- type: "vector",
32122
- points: [[0, 0], [2, 2]],
32123
- color: DEFAULT_COLOR
32124
- };
32125
- case "ellipse":
32126
- return {
32127
- type: "ellipse",
32128
- center: [0, 0],
32129
- radius: [1, 1],
32130
- angle: 0,
32131
- color: DEFAULT_COLOR,
32132
- fillStyle: "none",
32133
- strokeStyle: "solid"
32134
- };
32135
- case "polygon":
32136
- return {
32137
- type: "polygon",
32138
- points: [[0, 2], [-1, 0], [1, 0]],
32139
- color: DEFAULT_COLOR,
32140
- showVertices: false,
32141
- fillStyle: "none",
32142
- strokeStyle: "solid"
32143
- };
32144
- case "function":
32145
- return {
32146
- type: "function",
32147
- color: DEFAULT_COLOR,
32148
- strokeStyle: "solid",
32149
- equation: "x^2",
32150
- directionalAxis: "x"
32151
- };
32152
- case "label":
32153
- return {
32154
- type: "label",
32155
- coord: [0, 0],
32156
- text: "",
32157
- color: DEFAULT_COLOR,
32158
- size: "medium"
32159
- };
32160
- default:
32161
- throw new wonderStuffCore.UnreachableCaseError(type);
32162
- }
32163
- }
32164
-
32165
32232
  const LockedFiguresSection = props => {
32166
32233
  // Keep track of all figures' accordions' expanded states for the
32167
32234
  // expand/collapse all button. Set the whole array to false initially.
@@ -32265,6 +32332,7 @@ const LockedFiguresSection = props => {
32265
32332
  }), isExpanded && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, null, figures?.map((figure, index) => {
32266
32333
  return /*#__PURE__*/React__namespace.createElement(LockedFigureSettings, _extends({
32267
32334
  key: `${uniqueId}-locked-${figure}-${index}`,
32335
+ flags: props.flags,
32268
32336
  showLabelsFlag: props.showLabelsFlag,
32269
32337
  expanded: expandedStates[index],
32270
32338
  onToggle: newValue => {
@@ -33290,6 +33358,7 @@ class InteractiveGraphEditor extends React__namespace.Component {
33290
33358
  // Only show the "Add locked figure" dropdown if the graph
33291
33359
  // is using Mafs.
33292
33360
  this.props.graph && this.props.apiOptions?.flags?.mafs?.[this.props.graph.type] && /*#__PURE__*/React__namespace.createElement(LockedFiguresSection, {
33361
+ flags: this.props.apiOptions.flags,
33293
33362
  showLabelsFlag: this.props.apiOptions?.flags?.mafs?.["interactive-graph-locked-features-labels"],
33294
33363
  figures: this.props.lockedFigures,
33295
33364
  onChange: this.props.onChange
@@ -37186,14 +37255,6 @@ class TableEditor extends React__namespace.Component {
37186
37255
  });
37187
37256
  };
37188
37257
  render() {
37189
- const tableProps = ___default["default"].pick(this.props, "headers", "answers", "onChange", "apiOptions");
37190
- ___default["default"].extend(tableProps, {
37191
- editableHeaders: true,
37192
- Editor,
37193
- onFocus: () => {},
37194
- onBlur: () => {},
37195
- trackInteraction: () => {}
37196
- });
37197
37258
  return /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("div", {
37198
37259
  className: "perseus-widget-row"
37199
37260
  }, /*#__PURE__*/React__namespace.createElement("label", null, "Number of columns:", " ", /*#__PURE__*/React__namespace.createElement(NumberInput, {
@@ -37218,7 +37279,17 @@ class TableEditor extends React__namespace.Component {
37218
37279
  }
37219
37280
  },
37220
37281
  useArrowKeys: true
37221
- }))), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$1, null, /*#__PURE__*/React__namespace.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__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Table, tableProps)));
37282
+ }))), /*#__PURE__*/React__namespace.createElement("div", null, " ", "Table of answers:", " ", /*#__PURE__*/React__namespace.createElement(InfoTip$1, null, /*#__PURE__*/React__namespace.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__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement(Table, {
37283
+ headers: this.props.headers,
37284
+ answers: this.props.answers,
37285
+ onChange: this.props.onChange,
37286
+ apiOptions: this.props.apiOptions,
37287
+ editableHeaders: true,
37288
+ onFocus: () => {},
37289
+ onBlur: () => {},
37290
+ trackInteraction: () => {},
37291
+ Editor: Editor
37292
+ })));
37222
37293
  }
37223
37294
  }
37224
37295