@khanacademy/math-input 14.1.1 → 14.2.1
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/CHANGELOG.md +23 -0
- package/dist/components/aphrodite-css-transition-group/index.d.ts +51 -0
- package/dist/components/aphrodite-css-transition-group/transition-child.d.ts +11 -0
- package/dist/components/aphrodite-css-transition-group/types.d.ts +18 -0
- package/dist/components/aphrodite-css-transition-group/util.d.ts +7 -0
- package/dist/components/keypad/mobile-keypad.d.ts +10 -12
- package/dist/es/index.js +339 -71
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +340 -71
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/components/aphrodite-css-transition-group/index.tsx +78 -0
- package/src/components/aphrodite-css-transition-group/transition-child.tsx +191 -0
- package/src/components/aphrodite-css-transition-group/types.ts +20 -0
- package/src/components/aphrodite-css-transition-group/util.ts +97 -0
- package/src/components/keypad/__tests__/__snapshots__/mobile-keypad.test.tsx.snap +593 -0
- package/src/components/keypad/__tests__/mobile-keypad.test.tsx +115 -0
- package/src/components/keypad/keypad-pages/keypad-pages.stories.tsx +9 -2
- package/src/components/keypad/keypad.tsx +2 -2
- package/src/components/keypad/mobile-keypad.tsx +66 -79
- package/src/components/keypad/navigation-pad.stories.tsx +2 -1
- package/src/components/keypad-context.tsx +25 -16
- package/src/components/keypad-legacy/text-icon.tsx +1 -1
- package/src/full-keypad.stories.tsx +7 -1
- package/tsconfig-build.tsbuildinfo +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {render, screen} from "@testing-library/react";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import "@testing-library/jest-dom";
|
|
4
|
+
|
|
5
|
+
import MobileKeypad from "../mobile-keypad";
|
|
6
|
+
|
|
7
|
+
describe("mobile keypad", () => {
|
|
8
|
+
it("should render keypad when active", () => {
|
|
9
|
+
// Arrange
|
|
10
|
+
// Act
|
|
11
|
+
const {container} = render(
|
|
12
|
+
<MobileKeypad
|
|
13
|
+
onAnalyticsEvent={async () => undefined}
|
|
14
|
+
setKeypadActive={(keypadActive: boolean) => undefined}
|
|
15
|
+
keypadActive={true}
|
|
16
|
+
/>,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// Assert
|
|
20
|
+
expect(container).toMatchSnapshot();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should not render the keypad when not active", () => {
|
|
24
|
+
// Arrange
|
|
25
|
+
// Act
|
|
26
|
+
const {container} = render(
|
|
27
|
+
<MobileKeypad
|
|
28
|
+
onAnalyticsEvent={async () => undefined}
|
|
29
|
+
setKeypadActive={(keypadActive: boolean) => undefined}
|
|
30
|
+
keypadActive={false}
|
|
31
|
+
/>,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Assert
|
|
35
|
+
expect(container).toMatchSnapshot();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should render the keypad when going from keypadActive=false to keypadActive=true", () => {
|
|
39
|
+
// Arrange
|
|
40
|
+
const {rerender} = render(
|
|
41
|
+
<MobileKeypad
|
|
42
|
+
onAnalyticsEvent={async () => undefined}
|
|
43
|
+
setKeypadActive={(keypadActive: boolean) => undefined}
|
|
44
|
+
keypadActive={false}
|
|
45
|
+
/>,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(screen.queryAllByRole("button")).toHaveLength(0);
|
|
49
|
+
|
|
50
|
+
// Act
|
|
51
|
+
rerender(
|
|
52
|
+
<MobileKeypad
|
|
53
|
+
onAnalyticsEvent={async () => undefined}
|
|
54
|
+
setKeypadActive={(keypadActive: boolean) => undefined}
|
|
55
|
+
keypadActive={true}
|
|
56
|
+
/>,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Assert
|
|
60
|
+
expect(screen.queryAllByRole("tab")).not.toHaveLength(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should fire an 'opened' event when activated", () => {
|
|
64
|
+
// Arrange
|
|
65
|
+
const onAnalyticsEvent = jest.fn();
|
|
66
|
+
|
|
67
|
+
// Act
|
|
68
|
+
render(
|
|
69
|
+
<MobileKeypad
|
|
70
|
+
onAnalyticsEvent={onAnalyticsEvent}
|
|
71
|
+
setKeypadActive={(keypadActive: boolean) => undefined}
|
|
72
|
+
keypadActive={true}
|
|
73
|
+
/>,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Assert
|
|
77
|
+
expect(onAnalyticsEvent).toHaveBeenCalledWith({
|
|
78
|
+
type: "math-input:keypad-opened",
|
|
79
|
+
payload: {
|
|
80
|
+
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V2",
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should fire an 'closed' event when dismissed", async () => {
|
|
86
|
+
const onAnalyticsEvent = jest.fn();
|
|
87
|
+
|
|
88
|
+
// Arrange
|
|
89
|
+
const {rerender, unmount} = render(
|
|
90
|
+
<MobileKeypad
|
|
91
|
+
onAnalyticsEvent={onAnalyticsEvent}
|
|
92
|
+
setKeypadActive={(keypadActive: boolean) => undefined}
|
|
93
|
+
keypadActive={true}
|
|
94
|
+
/>,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Act
|
|
98
|
+
rerender(
|
|
99
|
+
<MobileKeypad
|
|
100
|
+
onAnalyticsEvent={onAnalyticsEvent}
|
|
101
|
+
setKeypadActive={(keypadActive: boolean) => undefined}
|
|
102
|
+
keypadActive={false}
|
|
103
|
+
/>,
|
|
104
|
+
);
|
|
105
|
+
unmount();
|
|
106
|
+
|
|
107
|
+
// Assert
|
|
108
|
+
expect(onAnalyticsEvent).toHaveBeenCalledWith({
|
|
109
|
+
type: "math-input:keypad-closed",
|
|
110
|
+
payload: {
|
|
111
|
+
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V2",
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {action} from "@storybook/addon-actions";
|
|
2
2
|
import {withKnobs} from "@storybook/addon-knobs";
|
|
3
|
+
import {INITIAL_VIEWPORTS} from "@storybook/addon-viewport";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
|
|
5
6
|
import GeometryInputPage from "./geometry-page";
|
|
@@ -13,7 +14,7 @@ export default {
|
|
|
13
14
|
backgrounds: {
|
|
14
15
|
values: [{name: "light background", value: "white", default: true}],
|
|
15
16
|
},
|
|
16
|
-
viewport: {defaultViewport: "iphone6"},
|
|
17
|
+
viewport: {defaultViewport: "iphone6", viewports: INITIAL_VIEWPORTS},
|
|
17
18
|
},
|
|
18
19
|
};
|
|
19
20
|
|
|
@@ -22,7 +23,13 @@ export const NumericInput = (): React.ReactElement => (
|
|
|
22
23
|
);
|
|
23
24
|
|
|
24
25
|
export const PreAlgebraInput = (): React.ReactElement => (
|
|
25
|
-
<PrealgebraInputPage
|
|
26
|
+
<PrealgebraInputPage
|
|
27
|
+
onClickKey={action("onClickKey")}
|
|
28
|
+
preAlgebra={true}
|
|
29
|
+
logarithms={true}
|
|
30
|
+
basicRelations={true}
|
|
31
|
+
advancedRelations={true}
|
|
32
|
+
/>
|
|
26
33
|
);
|
|
27
34
|
|
|
28
35
|
export const TrigonometryInput = (): React.ReactElement => (
|
|
@@ -74,7 +74,7 @@ function getAvailableTabs(props: Props): ReadonlyArray<KeypadPageType> {
|
|
|
74
74
|
// The main (v2) Keypad. Use this component to present an accessible, onscreen
|
|
75
75
|
// keypad to learners for entering math expressions.
|
|
76
76
|
export default function Keypad(props: Props) {
|
|
77
|
-
// If we're using the Fractions
|
|
77
|
+
// If we're using the Fractions keypad, we want to default select that page
|
|
78
78
|
// Otherwise, we want to default to the Numbers page
|
|
79
79
|
const defaultSelectedPage = props.fractionsOnly ? "Fractions" : "Numbers";
|
|
80
80
|
const [selectedPage, setSelectedPage] =
|
|
@@ -105,7 +105,7 @@ export default function Keypad(props: Props) {
|
|
|
105
105
|
? styles.fractionsGrid
|
|
106
106
|
: styles.expressionGrid;
|
|
107
107
|
|
|
108
|
-
// This
|
|
108
|
+
// This useEffect is only used to ensure that we can test the keypad in storybook
|
|
109
109
|
useEffect(() => {
|
|
110
110
|
setSelectedPage(defaultSelectedPage);
|
|
111
111
|
}, [fractionsOnly, defaultSelectedPage]);
|
|
@@ -3,6 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import ReactDOM from "react-dom";
|
|
4
4
|
|
|
5
5
|
import {View} from "../../fake-react-native-web/index";
|
|
6
|
+
import AphroditeCssTransitionGroup from "../aphrodite-css-transition-group";
|
|
6
7
|
|
|
7
8
|
import Keypad from "./keypad";
|
|
8
9
|
import {expandedViewThreshold} from "./utils";
|
|
@@ -17,16 +18,7 @@ import type {
|
|
|
17
18
|
import type {AnalyticsEventHandlerFn} from "@khanacademy/perseus-core";
|
|
18
19
|
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
* This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
|
|
22
|
-
* external API so that it can be hot-swapped with the v1 keypad and
|
|
23
|
-
* is responsible for connecting the keypad with MathInput and the Renderer.
|
|
24
|
-
*
|
|
25
|
-
* Ideally this strategy of attaching methods on the class component for
|
|
26
|
-
* other components to call will be replaced props/callbacks since React
|
|
27
|
-
* doesn't support this type of code anymore (functional components
|
|
28
|
-
* can't have methods attached to them).
|
|
29
|
-
*/
|
|
21
|
+
const AnimationDurationInMS = 200;
|
|
30
22
|
|
|
31
23
|
type Props = {
|
|
32
24
|
onElementMounted?: (arg1: any) => void;
|
|
@@ -39,21 +31,28 @@ type Props = {
|
|
|
39
31
|
|
|
40
32
|
type State = {
|
|
41
33
|
containerWidth: number;
|
|
42
|
-
hasBeenActivated: boolean;
|
|
43
34
|
keypadConfig?: KeypadConfiguration;
|
|
44
35
|
keyHandler?: KeyHandler;
|
|
45
36
|
cursor?: Cursor;
|
|
46
37
|
};
|
|
47
38
|
|
|
39
|
+
/**
|
|
40
|
+
* This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
|
|
41
|
+
* external API so that it can be hot-swapped with the v1 keypad and
|
|
42
|
+
* is responsible for connecting the keypad with MathInput and the Renderer.
|
|
43
|
+
*
|
|
44
|
+
* Ideally this strategy of attaching methods on the class component for
|
|
45
|
+
* other components to call will be replaced props/callbacks since React
|
|
46
|
+
* doesn't support this type of code anymore (functional components
|
|
47
|
+
* can't have methods attached to them).
|
|
48
|
+
*/
|
|
48
49
|
class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
49
50
|
_containerRef = React.createRef<HTMLDivElement>();
|
|
50
51
|
_containerResizeObserver: ResizeObserver | null = null;
|
|
51
52
|
_throttleResize = false;
|
|
52
|
-
hasMounted = false;
|
|
53
53
|
|
|
54
54
|
state: State = {
|
|
55
55
|
containerWidth: 0,
|
|
56
|
-
hasBeenActivated: false,
|
|
57
56
|
};
|
|
58
57
|
|
|
59
58
|
componentDidMount() {
|
|
@@ -78,6 +77,15 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
|
78
77
|
);
|
|
79
78
|
}
|
|
80
79
|
}
|
|
80
|
+
|
|
81
|
+
this.props.onElementMounted?.({
|
|
82
|
+
activate: this.activate,
|
|
83
|
+
dismiss: this.dismiss,
|
|
84
|
+
configure: this.configure,
|
|
85
|
+
setCursor: this.setCursor,
|
|
86
|
+
setKeyHandler: this.setKeyHandler,
|
|
87
|
+
getDOMNode: this.getDOMNode,
|
|
88
|
+
});
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
componentWillUnmount() {
|
|
@@ -109,9 +117,6 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
|
109
117
|
|
|
110
118
|
activate: () => void = () => {
|
|
111
119
|
this.props.setKeypadActive(true);
|
|
112
|
-
this.setState({
|
|
113
|
-
hasBeenActivated: true,
|
|
114
|
-
});
|
|
115
120
|
};
|
|
116
121
|
|
|
117
122
|
dismiss: () => void = () => {
|
|
@@ -161,74 +166,64 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
|
161
166
|
|
|
162
167
|
render(): React.ReactNode {
|
|
163
168
|
const {keypadActive, style} = this.props;
|
|
164
|
-
const {
|
|
165
|
-
this.state;
|
|
169
|
+
const {containerWidth, cursor, keypadConfig} = this.state;
|
|
166
170
|
|
|
167
171
|
const containerStyle = [
|
|
168
|
-
// internal styles
|
|
169
172
|
styles.keypadContainer,
|
|
170
|
-
keypadActive && styles.activeKeypadContainer,
|
|
171
173
|
// styles passed as props
|
|
172
174
|
...(Array.isArray(style) ? style : [style]),
|
|
173
175
|
];
|
|
174
176
|
|
|
175
|
-
// If the keypad is yet to have ever been activated, we keep it invisible
|
|
176
|
-
// so as to avoid, e.g., the keypad flashing at the bottom of the page
|
|
177
|
-
// during the initial render.
|
|
178
|
-
// Done inline (dynamicStyle) since stylesheets might not be loaded yet.
|
|
179
|
-
let dynamicStyle = {};
|
|
180
|
-
if (!keypadActive && !hasBeenActivated) {
|
|
181
|
-
dynamicStyle = {visibility: "hidden"};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
177
|
const isExpression = keypadConfig?.keypadType === "EXPRESSION";
|
|
185
178
|
const convertDotToTimes = keypadConfig?.times;
|
|
186
179
|
|
|
187
180
|
return (
|
|
188
|
-
<
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
} as const;
|
|
207
|
-
|
|
208
|
-
this.hasMounted = true;
|
|
209
|
-
this.props.onElementMounted?.(
|
|
210
|
-
elementWithDispatchMethods,
|
|
211
|
-
);
|
|
212
|
-
}
|
|
181
|
+
<AphroditeCssTransitionGroup
|
|
182
|
+
transitionEnterTimeout={AnimationDurationInMS}
|
|
183
|
+
transitionLeaveTimeout={AnimationDurationInMS}
|
|
184
|
+
transitionStyle={{
|
|
185
|
+
enter: {
|
|
186
|
+
transform: "translate3d(0, 100%, 0)",
|
|
187
|
+
transition: `${AnimationDurationInMS}ms ease-out`,
|
|
188
|
+
},
|
|
189
|
+
enterActive: {
|
|
190
|
+
transform: "translate3d(0, 0, 0)",
|
|
191
|
+
},
|
|
192
|
+
leave: {
|
|
193
|
+
transform: "translate3d(0, 0, 0)",
|
|
194
|
+
transition: `${AnimationDurationInMS}ms ease-out`,
|
|
195
|
+
},
|
|
196
|
+
leaveActive: {
|
|
197
|
+
transform: "translate3d(0, 100%, 0)",
|
|
198
|
+
},
|
|
213
199
|
}}
|
|
214
200
|
>
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
201
|
+
{keypadActive ? (
|
|
202
|
+
<View
|
|
203
|
+
style={containerStyle}
|
|
204
|
+
forwardRef={this._containerRef}
|
|
205
|
+
>
|
|
206
|
+
<Keypad
|
|
207
|
+
onAnalyticsEvent={this.props.onAnalyticsEvent}
|
|
208
|
+
extraKeys={keypadConfig?.extraKeys}
|
|
209
|
+
onClickKey={(key) => this._handleClickKey(key)}
|
|
210
|
+
cursorContext={cursor?.context}
|
|
211
|
+
fractionsOnly={!isExpression}
|
|
212
|
+
convertDotToTimes={convertDotToTimes}
|
|
213
|
+
divisionKey={isExpression}
|
|
214
|
+
trigonometry={isExpression}
|
|
215
|
+
preAlgebra={isExpression}
|
|
216
|
+
logarithms={isExpression}
|
|
217
|
+
basicRelations={isExpression}
|
|
218
|
+
advancedRelations={isExpression}
|
|
219
|
+
expandedView={
|
|
220
|
+
containerWidth > expandedViewThreshold
|
|
221
|
+
}
|
|
222
|
+
showDismiss
|
|
223
|
+
/>
|
|
224
|
+
</View>
|
|
225
|
+
) : null}
|
|
226
|
+
</AphroditeCssTransitionGroup>
|
|
232
227
|
);
|
|
233
228
|
}
|
|
234
229
|
}
|
|
@@ -239,14 +234,6 @@ const styles = StyleSheet.create({
|
|
|
239
234
|
left: 0,
|
|
240
235
|
right: 0,
|
|
241
236
|
position: "fixed",
|
|
242
|
-
transitionProperty: "all",
|
|
243
|
-
transition: `200ms ease-out`,
|
|
244
|
-
visibility: "hidden",
|
|
245
|
-
transform: "translate3d(0, 100%, 0)",
|
|
246
|
-
},
|
|
247
|
-
activeKeypadContainer: {
|
|
248
|
-
transform: "translate3d(0, 0, 0)",
|
|
249
|
-
visibility: "visible",
|
|
250
237
|
},
|
|
251
238
|
});
|
|
252
239
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {action} from "@storybook/addon-actions";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
|
|
3
4
|
import NavigationPad from "./navigation-pad";
|
|
@@ -19,7 +20,7 @@ export default {
|
|
|
19
20
|
export function basic() {
|
|
20
21
|
return (
|
|
21
22
|
<div style={{padding: 50}}>
|
|
22
|
-
<NavigationPad onClickKey={()
|
|
23
|
+
<NavigationPad onClickKey={action("onClickKey")} />
|
|
23
24
|
</div>
|
|
24
25
|
);
|
|
25
26
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Perseus Renderers (Server/Item/Article)
|
|
9
9
|
*/
|
|
10
10
|
import * as React from "react";
|
|
11
|
-
import {useState} from "react";
|
|
11
|
+
import {useState, useMemo} from "react";
|
|
12
12
|
|
|
13
13
|
import type {KeypadAPI, KeypadContextType} from "../types";
|
|
14
14
|
import type {KeypadContextRendererInterface} from "@khanacademy/perseus-core";
|
|
@@ -39,22 +39,31 @@ export function StatefulKeypadContextProvider(props: Props) {
|
|
|
39
39
|
const [scrollableElement, setScrollableElement] =
|
|
40
40
|
useState<HTMLElement | null>();
|
|
41
41
|
|
|
42
|
+
const memoizedValue = useMemo(
|
|
43
|
+
() => ({
|
|
44
|
+
keypadActive,
|
|
45
|
+
setKeypadActive,
|
|
46
|
+
keypadElement,
|
|
47
|
+
setKeypadElement,
|
|
48
|
+
renderer,
|
|
49
|
+
setRenderer,
|
|
50
|
+
scrollableElement,
|
|
51
|
+
setScrollableElement,
|
|
52
|
+
}),
|
|
53
|
+
[
|
|
54
|
+
keypadActive,
|
|
55
|
+
setKeypadActive,
|
|
56
|
+
keypadElement,
|
|
57
|
+
setKeypadElement,
|
|
58
|
+
renderer,
|
|
59
|
+
setRenderer,
|
|
60
|
+
scrollableElement,
|
|
61
|
+
setScrollableElement,
|
|
62
|
+
],
|
|
63
|
+
);
|
|
64
|
+
|
|
42
65
|
return (
|
|
43
|
-
<KeypadContext.Provider
|
|
44
|
-
value={{
|
|
45
|
-
setKeypadActive,
|
|
46
|
-
keypadActive,
|
|
47
|
-
setKeypadElement,
|
|
48
|
-
keypadElement,
|
|
49
|
-
setRenderer,
|
|
50
|
-
renderer,
|
|
51
|
-
// The scrollableElement options can likely be removed after
|
|
52
|
-
// the exercises-package is officially deprecated. They don't appear
|
|
53
|
-
// to be used anywhere except for the exercises-package and tests.
|
|
54
|
-
setScrollableElement,
|
|
55
|
-
scrollableElement,
|
|
56
|
-
}}
|
|
57
|
-
>
|
|
66
|
+
<KeypadContext.Provider value={memoizedValue}>
|
|
58
67
|
{props.children}
|
|
59
68
|
</KeypadContext.Provider>
|
|
60
69
|
);
|
|
@@ -87,7 +87,13 @@ export default {
|
|
|
87
87
|
|
|
88
88
|
const Template: ComponentStory<typeof Keypad> = (
|
|
89
89
|
args: PropsFor<typeof Keypad>,
|
|
90
|
-
): React.ReactElement =>
|
|
90
|
+
): React.ReactElement => (
|
|
91
|
+
<Keypad
|
|
92
|
+
{...args}
|
|
93
|
+
onClickKey={action("onClickKey")}
|
|
94
|
+
onAnalyticsEvent={async (e) => action("onAnalyticsEvent")(e)}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
91
97
|
|
|
92
98
|
export const Default = Template.bind({});
|
|
93
99
|
|