@khanacademy/perseus-editor 4.1.4 → 4.1.6

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.
Files changed (175) hide show
  1. package/dist/es/index.js +1 -1
  2. package/dist/index.js +1 -1
  3. package/package.json +9 -6
  4. package/.babelrc.js +0 -8
  5. package/.eslintrc.js +0 -12
  6. package/CHANGELOG.md +0 -1146
  7. package/src/README.md +0 -7
  8. package/src/__stories__/editor-page.stories.tsx +0 -65
  9. package/src/__stories__/editor.stories.tsx +0 -134
  10. package/src/__stories__/item-editor.stories.tsx +0 -41
  11. package/src/__stories__/tex-error-view.stories.tsx +0 -26
  12. package/src/__testdata__/input-number.testdata.ts +0 -27
  13. package/src/__tests__/editor.test.tsx +0 -142
  14. package/src/__tests__/hint-editor.test.tsx +0 -83
  15. package/src/__tests__/i18n.test.ts +0 -501
  16. package/src/__tests__/integration.test.ts +0 -5
  17. package/src/__tests__/item-extras-editor.test.tsx +0 -85
  18. package/src/__tests__/traversal.test.ts +0 -377
  19. package/src/all-editors.test.ts +0 -16
  20. package/src/all-editors.ts +0 -83
  21. package/src/all-widgets.ts +0 -7
  22. package/src/article-editor.tsx +0 -438
  23. package/src/components/__stories__/blur-input.stories.tsx +0 -22
  24. package/src/components/__stories__/section-control-button.stories.tsx +0 -26
  25. package/src/components/__tests__/blur-input.test.tsx +0 -67
  26. package/src/components/blur-input.tsx +0 -69
  27. package/src/components/checkbox.tsx +0 -194
  28. package/src/components/device-framer.tsx +0 -90
  29. package/src/components/drag-target.tsx +0 -87
  30. package/src/components/dropdown-option.tsx +0 -311
  31. package/src/components/form-wrapped-text-field.tsx +0 -245
  32. package/src/components/graph-points-count-selector.tsx +0 -31
  33. package/src/components/graph-settings.tsx +0 -627
  34. package/src/components/graph-type-selector.tsx +0 -31
  35. package/src/components/hover-behavior.ts +0 -177
  36. package/src/components/json-editor.tsx +0 -121
  37. package/src/components/link.ts +0 -173
  38. package/src/components/section-control-button.tsx +0 -53
  39. package/src/components/segment-count-selector.tsx +0 -27
  40. package/src/components/simple-button.tsx +0 -85
  41. package/src/components/sortable.tsx +0 -187
  42. package/src/components/util.ts +0 -38
  43. package/src/components/viewport-resizer.tsx +0 -72
  44. package/src/components/widget-editor.tsx +0 -222
  45. package/src/components/widget-select.tsx +0 -48
  46. package/src/diffs/__stories__/perseus-diff-wrapper.tsx +0 -11
  47. package/src/diffs/__stories__/structured-item-diff.stories.tsx +0 -855
  48. package/src/diffs/__stories__/tags-diff.stories.tsx +0 -36
  49. package/src/diffs/__stories__/text-diff.stories.tsx +0 -35
  50. package/src/diffs/__tests__/split-diff.test.ts +0 -33
  51. package/src/diffs/__tests__/string-array-diff.test.ts +0 -73
  52. package/src/diffs/__tests__/structured-item-diff.test.ts +0 -433
  53. package/src/diffs/__tests__/widget-diff-performer.test.ts +0 -43
  54. package/src/diffs/article-diff.tsx +0 -69
  55. package/src/diffs/item-diff.tsx +0 -76
  56. package/src/diffs/renderer-diff.tsx +0 -137
  57. package/src/diffs/split-diff.ts +0 -31
  58. package/src/diffs/string-array-diff.ts +0 -74
  59. package/src/diffs/structured-item-diff.tsx +0 -275
  60. package/src/diffs/tags-diff.tsx +0 -49
  61. package/src/diffs/text-diff.tsx +0 -193
  62. package/src/diffs/widget-diff-performer.ts +0 -69
  63. package/src/diffs/widget-diff.tsx +0 -290
  64. package/src/editor-page.tsx +0 -325
  65. package/src/editor.tsx +0 -1099
  66. package/src/hint-editor.tsx +0 -469
  67. package/src/i18n.ts +0 -140
  68. package/src/iframe-content-renderer.tsx +0 -188
  69. package/src/index.ts +0 -30
  70. package/src/item-editor.tsx +0 -158
  71. package/src/item-extras-editor.tsx +0 -230
  72. package/src/katex-mhchem/index.js +0 -73
  73. package/src/katex-mhchem/parser.js +0 -2659
  74. package/src/multirenderer-editor.tsx +0 -1061
  75. package/src/stateful-article-editor.tsx +0 -173
  76. package/src/stateful-editor-page.tsx +0 -88
  77. package/src/styles/perseus-editor.less +0 -1321
  78. package/src/testing-widgets.ts +0 -11
  79. package/src/tex-error-view.tsx +0 -90
  80. package/src/util/points.test.ts +0 -24
  81. package/src/util/points.ts +0 -13
  82. package/src/util/register-all-widgets-and-editors-for-testing.test.ts +0 -17
  83. package/src/util/register-all-widgets-and-editors-for-testing.ts +0 -17
  84. package/src/version.ts +0 -10
  85. package/src/widgets/__stories__/categorizer-editor.stories.tsx +0 -24
  86. package/src/widgets/__stories__/definition-editor.stories.tsx +0 -18
  87. package/src/widgets/__stories__/dropdown-editor.stories.tsx +0 -18
  88. package/src/widgets/__stories__/explanation-editor.stories.tsx +0 -18
  89. package/src/widgets/__stories__/expression-editor.stories.tsx +0 -122
  90. package/src/widgets/__stories__/image-editor.stories.tsx +0 -72
  91. package/src/widgets/__stories__/input-number-editor.stories.tsx +0 -18
  92. package/src/widgets/__stories__/interaction-editor.stories.tsx +0 -37
  93. package/src/widgets/__stories__/label-image-editor.stories.tsx +0 -99
  94. package/src/widgets/__stories__/matcher-editor.stories.tsx +0 -18
  95. package/src/widgets/__stories__/number-line-editor.stories.tsx +0 -18
  96. package/src/widgets/__stories__/numeric-input-editor.stories.tsx +0 -18
  97. package/src/widgets/__stories__/radio-editor.stories.tsx +0 -116
  98. package/src/widgets/__stories__/sorter-editor.stories.tsx +0 -18
  99. package/src/widgets/__tests__/categorizer-editor.test.tsx +0 -51
  100. package/src/widgets/__tests__/definition-editor.test.tsx +0 -41
  101. package/src/widgets/__tests__/dropdown-editor.test.tsx +0 -57
  102. package/src/widgets/__tests__/explanation-editor.test.tsx +0 -59
  103. package/src/widgets/__tests__/expression-editor.test.tsx +0 -403
  104. package/src/widgets/__tests__/input-number-editor.test.tsx +0 -128
  105. package/src/widgets/__tests__/matcher-editor.test.tsx +0 -47
  106. package/src/widgets/__tests__/number-line-editor.test.tsx +0 -144
  107. package/src/widgets/__tests__/numeric-input-editor.test.tsx +0 -177
  108. package/src/widgets/__tests__/radio-editor.test.tsx +0 -118
  109. package/src/widgets/__tests__/sorter-editor.test.tsx +0 -55
  110. package/src/widgets/categorizer-editor.tsx +0 -104
  111. package/src/widgets/cs-program-editor.tsx +0 -256
  112. package/src/widgets/definition-editor.tsx +0 -77
  113. package/src/widgets/deprecated-standin-editor.tsx +0 -29
  114. package/src/widgets/dropdown-editor.tsx +0 -211
  115. package/src/widgets/example-graphie-widget-editor.tsx +0 -70
  116. package/src/widgets/example-graphie-widget.tsx +0 -172
  117. package/src/widgets/example-widget-editor.tsx +0 -62
  118. package/src/widgets/example-widget.tsx +0 -154
  119. package/src/widgets/explanation-editor.tsx +0 -92
  120. package/src/widgets/expression-editor.tsx +0 -557
  121. package/src/widgets/graded-group-editor.tsx +0 -161
  122. package/src/widgets/graded-group-set-editor.tsx +0 -104
  123. package/src/widgets/grapher-editor.tsx +0 -155
  124. package/src/widgets/group-editor.tsx +0 -83
  125. package/src/widgets/iframe-editor.tsx +0 -202
  126. package/src/widgets/image-editor.tsx +0 -367
  127. package/src/widgets/input-number-editor.tsx +0 -288
  128. package/src/widgets/interaction-editor/constraint-editor.tsx +0 -134
  129. package/src/widgets/interaction-editor/function-editor.tsx +0 -108
  130. package/src/widgets/interaction-editor/index.ts +0 -3
  131. package/src/widgets/interaction-editor/interaction-editor.tsx +0 -749
  132. package/src/widgets/interaction-editor/label-editor.tsx +0 -87
  133. package/src/widgets/interaction-editor/line-editor.tsx +0 -125
  134. package/src/widgets/interaction-editor/mathquill-input.tsx +0 -81
  135. package/src/widgets/interaction-editor/movable-line-editor.tsx +0 -121
  136. package/src/widgets/interaction-editor/movable-point-editor.tsx +0 -89
  137. package/src/widgets/interaction-editor/parametric-editor.tsx +0 -117
  138. package/src/widgets/interaction-editor/point-editor.tsx +0 -72
  139. package/src/widgets/interaction-editor/rectangle-editor.tsx +0 -96
  140. package/src/widgets/interactive-graph-editor.tsx +0 -571
  141. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -82
  142. package/src/widgets/label-image/__stories__/behavior.stories.tsx +0 -31
  143. package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -75
  144. package/src/widgets/label-image/__stories__/question-markers.stories.tsx +0 -107
  145. package/src/widgets/label-image/__stories__/select-image.stories.tsx +0 -59
  146. package/src/widgets/label-image/answer-choices.tsx +0 -231
  147. package/src/widgets/label-image/behavior.tsx +0 -122
  148. package/src/widgets/label-image/marker.tsx +0 -290
  149. package/src/widgets/label-image/question-markers.tsx +0 -176
  150. package/src/widgets/label-image/select-image.tsx +0 -81
  151. package/src/widgets/label-image-editor.tsx +0 -252
  152. package/src/widgets/lights-puzzle-editor.tsx +0 -278
  153. package/src/widgets/matcher-editor.tsx +0 -149
  154. package/src/widgets/matrix-editor.tsx +0 -156
  155. package/src/widgets/measurer-editor.tsx +0 -253
  156. package/src/widgets/molecule-editor.tsx +0 -64
  157. package/src/widgets/number-line-editor.tsx +0 -512
  158. package/src/widgets/numeric-input-editor.tsx +0 -536
  159. package/src/widgets/orderer-editor.tsx +0 -172
  160. package/src/widgets/passage-editor.tsx +0 -117
  161. package/src/widgets/passage-ref-editor.tsx +0 -80
  162. package/src/widgets/passage-ref-target-editor.tsx +0 -49
  163. package/src/widgets/plotter-editor.tsx +0 -542
  164. package/src/widgets/radio/editor.tsx +0 -398
  165. package/src/widgets/reaction-diagram-editor.tsx +0 -131
  166. package/src/widgets/sequence-editor.tsx +0 -205
  167. package/src/widgets/simple-markdown-tester-editor.tsx +0 -86
  168. package/src/widgets/simple-markdown-tester.tsx +0 -92
  169. package/src/widgets/simulator-editor.tsx +0 -146
  170. package/src/widgets/sorter-editor.tsx +0 -103
  171. package/src/widgets/table-editor.tsx +0 -164
  172. package/src/widgets/unit-editor.tsx +0 -299
  173. package/src/widgets/video-editor.tsx +0 -73
  174. package/tsconfig-build.json +0 -22
  175. package/tsconfig-build.tsbuildinfo +0 -1
@@ -1,177 +0,0 @@
1
- /* eslint-disable react/sort-comp */
2
- /**
3
- * Add hover behavior to another component.
4
- *
5
- * This component provides hover and focus status updates in a consistent way
6
- * across desktop and mobile.
7
- *
8
- * For advice on when to use this component instead of Button, see README.md.
9
- *
10
- * Many mobile browsers treat :hover as sticky which results in buttons looking
11
- * pressed even when the user has lifted their finger. This component ensures
12
- * that when user lifts their finger the hover state is removed.
13
- *
14
- * We also chnage how the focus state works. Browsers immediately set the
15
- * focus state as soon as you click on a button. This component only sets the
16
- * focus state when a user starts navigating between elements via keybaord.
17
- *
18
- * HoverBehavior accepts a function as 'children' which is passed state and
19
- * an object containing event handlers. The 'children' function should return
20
- * an React Element of some sort.
21
- *
22
- * Example:
23
- *
24
- * class MyButtonLikeComponent extends React.Component {
25
- * render(): React.Node {
26
- * return <HoverBehavior
27
- * disabled={this.props.disabled}
28
- * onClick={this.handleClick}
29
- * >
30
- * {({hovered}, handlers) =>
31
- * <RoundRect
32
- * textcolor='white'
33
- * backgroundColor={hovered ? 'red' : 'blue'}/>}
34
- * {...handlers}
35
- * >
36
- * {this.props.children}
37
- * </RoundRect>
38
- * }
39
- * </HoverBehavior>
40
- * }
41
- * }
42
- *
43
- * This follows a pattern call 'Function as Child Components':
44
- * https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9#.sw0jiio8b
45
- */
46
- import * as React from "react";
47
-
48
- type Handlers = {
49
- onBlur: () => unknown;
50
- onClick: (e: React.MouseEvent) => unknown;
51
- onFocus: () => unknown;
52
- onMouseDown: () => unknown;
53
- onMouseEnter: () => unknown;
54
- onMouseLeave: () => unknown;
55
- onTouchStart: () => unknown;
56
- onTouchEnd: () => unknown;
57
- };
58
-
59
- type State = {
60
- focused: boolean;
61
- hovered: boolean;
62
- };
63
-
64
- type Props = {
65
- children?: (state: State, handlers: Handlers) => React.ReactElement;
66
- disabled?: boolean;
67
- onClick?: (e: React.MouseEvent) => unknown;
68
- startHovered: boolean;
69
- shouldUpdate: () => boolean;
70
- };
71
-
72
- export default class HoverBehavior extends React.Component<Props, State> {
73
- static defaultProps: {
74
- shouldUpdate: () => boolean;
75
- startHovered: boolean;
76
- } = {
77
- startHovered: false,
78
- shouldUpdate: () => true,
79
- };
80
-
81
- constructor(props: Props) {
82
- super(props);
83
-
84
- this.state = {
85
- focused: false,
86
- hovered: props.startHovered,
87
- };
88
- }
89
-
90
- // @ts-expect-error - TS2564 - Property 'focusFlag' has no initializer and is not definitely assigned in the constructor.
91
- focusFlag: boolean;
92
- // @ts-expect-error - TS2564 - Property 'waitingForClick' has no initializer and is not definitely assigned in the constructor.
93
- waitingForClick: boolean;
94
-
95
- handleClick: (e: React.MouseEvent) => void = (e: React.MouseEvent) => {
96
- if (!this.props.disabled) {
97
- if (this.props.shouldUpdate()) {
98
- this.waitingForClick = false;
99
- }
100
- if (this.props.onClick && !this.props.disabled) {
101
- this.props.onClick(e);
102
- }
103
- }
104
- };
105
-
106
- handleMouseEnter: () => void = () => {
107
- if (
108
- !this.props.disabled &&
109
- this.props.shouldUpdate() &&
110
- !this.waitingForClick
111
- ) {
112
- this.setState({hovered: true});
113
- }
114
- };
115
-
116
- handleMouseLeave: () => void = () => {
117
- if (
118
- !this.props.disabled &&
119
- this.props.shouldUpdate() &&
120
- !this.waitingForClick
121
- ) {
122
- this.setState({hovered: false});
123
- }
124
- };
125
-
126
- handleTouchStart: () => void = () => {
127
- if (!this.props.disabled && this.props.shouldUpdate()) {
128
- this.setState({hovered: true});
129
- }
130
- };
131
-
132
- handleTouchEnd: () => void = () => {
133
- if (!this.props.disabled && this.props.shouldUpdate()) {
134
- this.setState({hovered: false});
135
- this.waitingForClick = true;
136
- }
137
- };
138
-
139
- handleMouseDown: () => void = () => {
140
- if (!this.props.disabled && this.props.shouldUpdate()) {
141
- this.setState({focused: false});
142
- this.focusFlag = true;
143
- }
144
- };
145
-
146
- handleBlur: () => void = () => {
147
- if (!this.props.disabled && this.props.shouldUpdate()) {
148
- this.setState({focused: false});
149
- }
150
- };
151
-
152
- handleFocus: () => void = () => {
153
- if (!this.props.disabled && this.props.shouldUpdate()) {
154
- if (this.focusFlag) {
155
- this.focusFlag = false;
156
- } else {
157
- this.setState({focused: true});
158
- }
159
- }
160
- };
161
-
162
- render(): React.ReactNode {
163
- const handlers = {
164
- onBlur: this.handleBlur,
165
- onClick: this.handleClick,
166
- onFocus: this.handleFocus,
167
- onMouseDown: this.handleMouseDown,
168
- onMouseEnter: this.handleMouseEnter,
169
- onMouseLeave: this.handleMouseLeave,
170
- onTouchStart: this.handleTouchStart,
171
- onTouchEnd: this.handleTouchEnd,
172
- } as const;
173
-
174
- const {children} = this.props;
175
- return children?.(this.state, handlers) || null;
176
- }
177
- }
@@ -1,121 +0,0 @@
1
- /* eslint-disable @babel/no-invalid-this */
2
- /* eslint-disable react/no-unsafe */
3
- /* eslint-disable react/sort-comp */
4
- import createReactClass from "create-react-class";
5
- import * as React from "react";
6
- import _ from "underscore";
7
-
8
- const JsonEditor: any = createReactClass({
9
- displayName: "JsonEditor",
10
-
11
- getInitialState: function () {
12
- return {
13
- currentValue: JSON.stringify(this.props.value, null, 4),
14
- valid: true,
15
- };
16
- },
17
-
18
- UNSAFE_componentWillReceiveProps: function (nextProps) {
19
- const shouldReplaceContent =
20
- !this.state.valid ||
21
- !_.isEqual(nextProps.value, JSON.parse(this.state.currentValue));
22
-
23
- if (shouldReplaceContent) {
24
- this.setState(this.getInitialState());
25
- }
26
- },
27
-
28
- render: function () {
29
- const classes =
30
- "perseus-json-editor " + (this.state.valid ? "valid" : "invalid");
31
-
32
- return (
33
- <textarea
34
- className={classes}
35
- value={this.state.currentValue}
36
- onChange={this.handleChange}
37
- onKeyDown={this.handleKeyDown}
38
- onBlur={this.handleBlur}
39
- />
40
- );
41
- },
42
-
43
- handleKeyDown: function (e) {
44
- // This handler allows the tab character to be entered by pressing
45
- // tab, instead of jumping to the next (non-existant) field
46
- if (e.key === "Tab") {
47
- const cursorPos = e.target.selectionStart;
48
- const v = e.target.value;
49
- const textBefore = v.substring(0, cursorPos);
50
- const textAfter = v.substring(cursorPos, v.length);
51
- e.target.value = textBefore + " " + textAfter;
52
- e.target.selectionStart = textBefore.length + 4;
53
- e.target.selectionEnd = textBefore.length + 4;
54
-
55
- e.preventDefault();
56
- this.handleChange(e);
57
- }
58
- },
59
-
60
- handleChange: function (e) {
61
- const nextString = e.target.value;
62
- try {
63
- let json = JSON.parse(nextString);
64
- // Some extra handling to allow copy-pasting from /api/vi
65
- if (_.isString(json)) {
66
- json = JSON.parse(json);
67
- }
68
- // This callback unfortunately causes multiple renders,
69
- // but seems to be necessary to avoid componentWillReceiveProps
70
- // being called before setState has gone through
71
- this.setState(
72
- {
73
- currentValue: nextString,
74
- valid: true,
75
- },
76
- function () {
77
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
78
- this.props.onChange(json);
79
- },
80
- );
81
- } catch (ex: any) {
82
- this.setState({
83
- currentValue: nextString,
84
- valid: false,
85
- });
86
- }
87
- },
88
-
89
- // You can type whatever you want as you're typing, but if it's not valid
90
- // when you blur, it will revert to the last valid value.
91
- handleBlur: function (e) {
92
- const nextString = e.target.value;
93
- try {
94
- let json = JSON.parse(nextString);
95
- // Some extra handling to allow copy-pasting from /api/vi
96
- if (_.isString(json)) {
97
- json = JSON.parse(json);
98
- }
99
- // This callback unfortunately causes multiple renders,
100
- // but seems to be necessary to avoid componentWillReceiveProps
101
- // being called before setState has gone through
102
- this.setState(
103
- {
104
- currentValue: JSON.stringify(json, null, 4),
105
- valid: true,
106
- },
107
- function () {
108
- // @ts-expect-error - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
109
- this.props.onChange(json);
110
- },
111
- );
112
- } catch (ex: any) {
113
- this.setState({
114
- currentValue: JSON.stringify(this.props.value, null, 4),
115
- valid: true,
116
- });
117
- }
118
- },
119
- });
120
-
121
- export default JsonEditor;
@@ -1,173 +0,0 @@
1
- /**
2
- * A generic link that removes common link styles.
3
- *
4
- * This is useful for wrapping many child components in a link and making sure
5
- * that "link" styles don't get applied to all you content.
6
- */
7
- import {StyleSheet, css} from "aphrodite";
8
- import * as React from "react";
9
-
10
- import type {CSSProperties} from "aphrodite";
11
-
12
- // TODO(diedra): This is terrible! If we don't have a href for a link, it should
13
- // be a button instead. We just need to make sure we override the default browser
14
- // button styling (backgroundColor, border, and padding).
15
- const DEFAULT_HREF = "javascript:void(0)";
16
-
17
- type DefaultProps = {
18
- element: React.ElementType;
19
- // Whether the link should appear in a 'highlighted' state. In
20
- // practice, this will apply the same styles that are applied on-hover.
21
- highlighted: boolean;
22
- href: string;
23
- // Pass through styles but also add our own to normalize
24
- style: CSSProperties | Array<CSSProperties>;
25
- };
26
-
27
- type Props = DefaultProps & {
28
- children?: React.ReactNode;
29
- // An additional class name to add. This is supported so-as to allow
30
- // Perseus to add class-based styles to links when using this
31
- // component as its base link class.
32
- className?: string;
33
- // Additional direct styles to add.
34
- inlineStyles?: {
35
- [key: string]: any;
36
- };
37
- // Optional referrer query parameter to add to the end of the URL, used
38
- // for analytics purposes.
39
- referrer?: string;
40
- // A target window to open a link in
41
- target?: string;
42
- // The relationship between the linked page and the current page.
43
- // Mostly used to prevent abuse from linked sites.
44
- rel?: string;
45
- // The data-test-id attribute
46
- testId?: string;
47
- // Specify either an HTML tag (like "a") or a React component (like
48
- // React Router's `Link`) to be used as the underlying element.
49
-
50
- onClick?: (e: React.MouseEvent) => unknown;
51
- onMouseOver?: (e: React.MouseEvent) => unknown;
52
- onMouseLeave?: (e: React.MouseEvent) => unknown;
53
- onMouseEnter?: (e: React.MouseEvent) => unknown;
54
- onBlur?: (e: React.SyntheticEvent) => unknown;
55
- onFocus?: (e: React.SyntheticEvent) => unknown;
56
- onKeyDown?: (e: React.KeyboardEvent) => unknown;
57
- ["aria-label"]?: string;
58
- ["aria-selected"]?: boolean;
59
- ["aria-current"]?: boolean;
60
- role?: "tab";
61
- title?: string;
62
- id?: string;
63
- tabIndex?: number;
64
- };
65
-
66
- /**
67
- * A wrapper that creates an anchor tag with normalized styles
68
- */
69
- class Link extends React.Component<Props> {
70
- static defaultProps: DefaultProps = {
71
- highlighted: false,
72
- href: DEFAULT_HREF,
73
- style: [] as Array<CSSProperties>,
74
- element: "a",
75
- };
76
-
77
- render(): React.ReactNode {
78
- const {
79
- children,
80
- className,
81
- highlighted,
82
- href,
83
- inlineStyles,
84
- referrer,
85
- style,
86
- target,
87
- testId,
88
- element,
89
- ...otherProps
90
- } = this.props;
91
-
92
- // We need to make sure the hash goes at the end of the <a>'s href, so
93
- // we'll split for now and re-add after potentially adding ?ref=
94
- // Even though we have defined a default prop for href, if href is
95
- // set to null, we will still get the null, so we need to handle that.
96
- const [hrefWithoutHash, hash] = href ? href.split("#") : [DEFAULT_HREF];
97
- let url = hrefWithoutHash;
98
-
99
- if (referrer) {
100
- if (url.indexOf("?") > -1) {
101
- url += "&ref=" + referrer;
102
- } else {
103
- url += "?ref=" + referrer;
104
- }
105
- }
106
-
107
- if (hash) {
108
- url += "#" + hash;
109
- }
110
-
111
- const delegatedStyles = [
112
- styles.link,
113
- highlighted && styles.highlighted,
114
- ];
115
-
116
- if (Array.isArray(style)) {
117
- delegatedStyles.push(...style);
118
- } else {
119
- delegatedStyles.push(style);
120
- }
121
-
122
- const delegatedClassName = className ? " " + className : "";
123
-
124
- // When passing an anchor tag, we want to use the native `href`.
125
- // ReactRouter links, though, need a special `to` prop instead.
126
- const urlProp = element === "a" ? {href: url} : {to: url};
127
-
128
- // When the link is set to open in a new window, we want to append
129
- // some `rel` attributes. This is to ensure that the links we're
130
- // sending folks to can't hijack the existing page.
131
- // More info: https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/
132
- //
133
- // If `rel` is already defined, we assume the caller knows what they're
134
- // doing. In the future, we may wish to check what keywords are passed,
135
- // and add in `noopener` and `noreferrer`.
136
- let rel = otherProps.rel;
137
- if (target === "_blank" && !rel) {
138
- rel = "noopener noreferrer";
139
- }
140
-
141
- return React.createElement(
142
- element,
143
- {
144
- "data-test-id": testId,
145
- ...otherProps,
146
- ...urlProp,
147
- className: css(...delegatedStyles) + delegatedClassName,
148
- style: inlineStyles,
149
- target,
150
- rel,
151
- },
152
- children,
153
- );
154
- }
155
- }
156
-
157
- const styles = StyleSheet.create({
158
- link: {
159
- // Remove the gray background color from active links in IE 10
160
- // https://necolas.github.io/normalize.css/3.0.2/normalize.css
161
- backgroundColor: "transparent",
162
- color: "inherit",
163
- textDecoration: "none",
164
- ":hover": {
165
- textDecoration: "underline",
166
- },
167
- },
168
- highlighted: {
169
- textDecoration: "underline",
170
- },
171
- });
172
-
173
- export default Link;
@@ -1,53 +0,0 @@
1
- import {components} from "@khanacademy/perseus";
2
- import Clickable from "@khanacademy/wonder-blocks-clickable";
3
- import Color from "@khanacademy/wonder-blocks-color";
4
- import {StyleSheet} from "aphrodite";
5
- import * as React from "react";
6
-
7
- import type {PropsFor} from "@khanacademy/wonder-blocks-core";
8
-
9
- const {InlineIcon} = components;
10
-
11
- type InlineIconProps = PropsFor<typeof InlineIcon>;
12
-
13
- type SectionControlButtonProps = {
14
- icon: InlineIconProps;
15
- onClick: () => unknown;
16
- title: string;
17
- };
18
-
19
- export default class SectionControlButton extends React.Component<SectionControlButtonProps> {
20
- render(): React.ReactNode {
21
- const {icon, onClick, title} = this.props;
22
-
23
- return (
24
- <Clickable
25
- className={
26
- "section-control-button " +
27
- "simple-button " +
28
- "simple-button--small "
29
- }
30
- onClick={(e) => {
31
- e.preventDefault();
32
- onClick();
33
- }}
34
- role="button"
35
- hideDefaultFocusRing={true}
36
- aria-label={title}
37
- style={styles.button}
38
- >
39
- {({hovered, focused, pressed}) => <InlineIcon {...icon} />}
40
- </Clickable>
41
- );
42
- }
43
- }
44
-
45
- const styles = StyleSheet.create({
46
- button: {
47
- backgroundColor: Color.gold,
48
- margin: 2,
49
- paddingRight: 10,
50
- paddingLeft: 10,
51
- paddingBottom: 2,
52
- },
53
- });
@@ -1,27 +0,0 @@
1
- import * as React from "react";
2
- import _ from "underscore";
3
-
4
- const SegmentCountSelector = ({
5
- numSegments = 1,
6
- onChange,
7
- }: {
8
- numSegments?: number;
9
- onChange: (numSegments: number) => void;
10
- }) => (
11
- <select
12
- key="segment-select"
13
- value={numSegments}
14
- onChange={(e) => {
15
- const num = +e.target.value;
16
- onChange(num);
17
- }}
18
- >
19
- {_.range(1, 7).map((n) => (
20
- <option key={n} value={n}>
21
- {`${n} segment${n > 1 ? "s" : ""}`}
22
- </option>
23
- ))}
24
- </select>
25
- );
26
-
27
- export default SegmentCountSelector;
@@ -1,85 +0,0 @@
1
- /**
2
- * Provides a simple styled button
3
- *
4
- */
5
-
6
- import {StyleSheet, css} from "aphrodite";
7
- import PropTypes from "prop-types";
8
- import * as React from "react";
9
-
10
- class SimpleButton extends React.Component<any> {
11
- static propTypes = {
12
- children: PropTypes.node,
13
- color: PropTypes.oneOf(["orange", "green"]),
14
- onClick: PropTypes.func,
15
- };
16
-
17
- static defaultProps: any = {
18
- children: null,
19
- color: "green",
20
- onClick: () => {},
21
- };
22
-
23
- render(): React.ReactNode {
24
- const {children, color, onClick, ...otherProps} = this.props;
25
- return (
26
- <div
27
- className={css(
28
- styles.baseButton,
29
- color === "green" && styles.green,
30
- color === "orange" && styles.orange,
31
- )}
32
- onClick={onClick}
33
- {...otherProps}
34
- >
35
- {children}
36
- </div>
37
- );
38
- }
39
- }
40
-
41
- const styles = StyleSheet.create({
42
- baseButton: {
43
- top: "0",
44
- fontSize: "11px",
45
- padding: "3px 10px",
46
- backgroundRepeat: "repeat-x",
47
- borderColor: `
48
- rgba(0, 0, 0, 0.1)
49
- rgba(0, 0, 0, 0.1)
50
- rgba(0, 0, 0, 0.25)
51
- `,
52
- color: "#ffffff",
53
- borderRadius: "3px",
54
- lineHeight: "15px",
55
- cursor: "pointer",
56
- transition: "box-shadow ease-in-out 0.15s",
57
- appearance: "none",
58
- textDecoration: "none",
59
- textAlign: "center",
60
- ":hover": {
61
- boxShadow: `0 1px 1px rgba(0, 0, 0, 0.35),
62
- inset 0 0 50px 5px rgba(255, 255, 255, 0.2)`,
63
- },
64
- },
65
- green: {
66
- border: "1px solid #7fab07",
67
- backgroundColor: "#80ac07",
68
- backgroundImage: "linear-gradient(to bottom, #8aba08, #719807)",
69
- ":hover": {
70
- borderBottomColor: "#547105",
71
- backgroundColor: "#719807",
72
- },
73
- },
74
- orange: {
75
- border: "1px solid #d45704",
76
- backgroundColor: "#d55704",
77
- backgroundImage: "linear-gradient(to bottom, #e35d04, #c04f03)",
78
- ":hover": {
79
- borderBottomColor: "#983e03",
80
- backgroundColor: "#c04f03",
81
- },
82
- },
83
- });
84
-
85
- export default SimpleButton;