@khanacademy/perseus 1.1.2 → 1.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/es/index.css +4 -5
  3. package/dist/es/index.js +1282 -1429
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.css +4 -5
  6. package/dist/index.js +1283 -1429
  7. package/dist/index.js.map +1 -1
  8. package/package.json +7 -7
  9. package/src/__tests__/__snapshots__/renderer_test.jsx.snap +21 -3
  10. package/src/components/highlighting/ui/highlight-tooltip.jsx +29 -23
  11. package/src/components/highlighting/ui/selection-tracker.jsx +17 -28
  12. package/src/styles/articles.less +0 -2
  13. package/src/styles/perseus-renderer.less +1 -1
  14. package/src/styles/widgets/passage.less +7 -3
  15. package/src/widgets/__stories__/passage-ref.stories.jsx +6 -2
  16. package/src/widgets/__stories__/passage.stories.jsx +9 -1
  17. package/src/widgets/__stories__/radio.stories.jsx +11 -0
  18. package/src/widgets/__testdata__/passage-ref_testdata.js +62 -0
  19. package/src/widgets/__testdata__/passage_testdata.js +25 -0
  20. package/src/widgets/__testdata__/radio_testdata.js +52 -0
  21. package/src/widgets/__tests__/__snapshots__/dropdown_test.jsx.snap +16 -2
  22. package/src/widgets/__tests__/__snapshots__/passage-ref_test.jsx.snap +18 -18
  23. package/src/widgets/__tests__/__snapshots__/passage_test.jsx.snap +36 -36
  24. package/src/widgets/__tests__/passage_test.jsx +6 -8
  25. package/src/widgets/__tests__/radio_test.jsx +3 -1
  26. package/src/widgets/passage.jsx +12 -41
  27. package/src/widgets/radio/widget.jsx +128 -129
  28. package/src/components/new-tooltip/README.md +0 -3
  29. package/src/components/new-tooltip/__stories__/new-tooltip.stories.jsx +0 -665
  30. package/src/components/new-tooltip/__tests__/style-constants_test.js +0 -8
  31. package/src/components/new-tooltip/new-tooltip.jsx +0 -155
  32. package/src/components/new-tooltip/style-constants.js +0 -13
  33. package/src/components/new-tooltip/types.js +0 -183
  34. package/src/widgets/passage/get-line-height-for-node.js +0 -9
@@ -1,665 +0,0 @@
1
- // @flow
2
- import Button from "@khanacademy/wonder-blocks-button";
3
- import {OnePaneDialog} from "@khanacademy/wonder-blocks-modal";
4
- import {StyleSheet, css} from "aphrodite";
5
- import * as React from "react";
6
-
7
- import mediaQueries from "../../../styles/media-queries.js";
8
- import NewTooltip from "../new-tooltip.jsx";
9
-
10
- type StoryArgs = {||};
11
-
12
- type Story = {|
13
- title: string,
14
- |};
15
-
16
- export default ({
17
- title: "Perseus/Components/New Tooltip",
18
- }: Story);
19
-
20
- const styles = StyleSheet.create({
21
- wrapper: {
22
- margin: "50px auto",
23
- border: "1px solid #aaa",
24
- height: 44,
25
- width: 44,
26
- },
27
-
28
- wrapperSmall: {
29
- height: 4,
30
- width: 4,
31
- fontSize: 0,
32
- background: "red",
33
- },
34
-
35
- wrapperLeft: {
36
- marginLeft: 0,
37
- },
38
-
39
- wrapperRight: {
40
- marginRight: 0,
41
- },
42
-
43
- target: {
44
- height: "100%",
45
- width: "100%",
46
- textAlign: "center",
47
- },
48
-
49
- scrollContainer: {
50
- overflow: "scroll",
51
- width: "100%",
52
- height: 100,
53
- },
54
-
55
- scrollContainerPadder: {
56
- paddingTop: 120,
57
- paddingBottom: 120,
58
- paddingLeft: "105%",
59
- paddingRight: "105%",
60
- },
61
-
62
- modal: {
63
- width: "90%",
64
- height: 350,
65
- backgroundColor: "#ffeeff",
66
- border: "solid 1px #eeeeee",
67
- },
68
-
69
- modalScrollTesterCase: {
70
- height: 500,
71
- overflow: "scroll",
72
- },
73
- });
74
-
75
- class DismissDemo extends React.PureComponent<Empty, {|dismissed: boolean|}> {
76
- state = {dismissed: false};
77
-
78
- render(): React.Node {
79
- return (
80
- <div>
81
- <div className={css(styles.wrapper)}>
82
- <NewTooltip
83
- content={content}
84
- dismissed={this.state.dismissed}
85
- dismissOnClickClose
86
- onDismiss={() => this.setState({dismissed: true})}
87
- toggleOnHover={false}
88
- showOnMount
89
- a11y={{title: "Controlled dismissable tooltip"}}
90
- >
91
- <div className={css(styles.target)}>Hover me!</div>
92
- </NewTooltip>
93
- </div>
94
- <div style={{textAlign: "center"}}>
95
- <Button
96
- disabled={!this.state.dismissed}
97
- onClick={(e) => this.setState({dismissed: false})}
98
- >
99
- Undismiss
100
- </Button>
101
- </div>
102
- </div>
103
- );
104
- }
105
- }
106
-
107
- class ContentChangingTooltip extends React.PureComponent<
108
- Empty,
109
- {|now: number|},
110
- > {
111
- _interval: ?IntervalID;
112
- state = {now: Date.now()};
113
-
114
- componentDidMount() {
115
- // TODO(jeff, WEB-1378): Use Wonder Blocks Timing API.
116
- // eslint-disable-next-line no-restricted-syntax
117
- this._interval = setInterval(this._updateTime, 1000);
118
- }
119
-
120
- componentWillUnmount() {
121
- if (this._interval) {
122
- // TODO(jeff, WEB-1378): Use Wonder Blocks Timing API.
123
- // eslint-disable-next-line no-restricted-syntax
124
- clearInterval(this._interval);
125
- }
126
- }
127
-
128
- _updateTime = () => {
129
- this.setState({now: Date.now()});
130
- };
131
-
132
- render(): React.Node {
133
- return (
134
- <div className={css(styles.wrapper)}>
135
- <NewTooltip
136
- content={"Timestamp: " + this.state.now}
137
- toggleOnHover={false}
138
- showOnMount
139
- a11y={{title: "Content-changing permanent tooltip"}}
140
- >
141
- <div className={css(styles.target)}>Hover me!</div>
142
- </NewTooltip>
143
- </div>
144
- );
145
- }
146
- }
147
-
148
- const content = "Hello, world! How are you today? I am quite well!";
149
-
150
- type ModalTesterProps = {||};
151
- type ModalTesterState = {|
152
- showModal: boolean,
153
- |};
154
-
155
- class ModalTester extends React.Component<ModalTesterProps, ModalTesterState> {
156
- state = {
157
- showModal: false,
158
- };
159
-
160
- renderModal() {
161
- const {showModal} = this.state;
162
-
163
- if (!showModal) {
164
- return null;
165
- }
166
-
167
- return (
168
- <OnePaneDialog
169
- style={styles.modal}
170
- onClose={() => this.setState({showModal: false})}
171
- title="Tooltip Demo"
172
- content={
173
- <>
174
- <h1>This is a test of tooltips in modals</h1>
175
- <h2>Scroll down to see more tooltips</h2>
176
-
177
- <div className={css(styles.modalScrollTesterCase)}>
178
- <h2>Mouse over</h2>
179
- <div className={css(styles.wrapper)}>
180
- <NewTooltip
181
- content={content}
182
- a11y={{
183
- title: "Mouse Over Demo",
184
- }}
185
- >
186
- <div className={css(styles.target)}>
187
- Hover me!
188
- </div>
189
- </NewTooltip>
190
- </div>
191
-
192
- <h2 id="tooltiplabel">Static and Scroll</h2>
193
- <p>Scroll</p>
194
- <p>Scroll</p>
195
- <p>Scroll</p>
196
- <p>Scroll</p>
197
- <div className={css(styles.wrapper)}>
198
- <NewTooltip
199
- content={content}
200
- toggleOnHover={false}
201
- showOnMount
202
- a11y={{
203
- title: {id: "tooltiplabel"},
204
- }}
205
- >
206
- <div className={css(styles.target)}>
207
- Hover me!
208
- </div>
209
- </NewTooltip>
210
- </div>
211
- <p>Scroll</p>
212
- <p>Scroll</p>
213
- <p>Scroll</p>
214
- <p>Scroll</p>
215
- <p>Scroll</p>
216
- <p>Scroll</p>
217
- </div>
218
- </>
219
- }
220
- />
221
- );
222
- }
223
-
224
- render(): React.Node {
225
- return (
226
- <div>
227
- <button onClick={() => this.setState({showModal: true})}>
228
- SHOW THE MODAL
229
- </button>
230
- {this.renderModal()}
231
- </div>
232
- );
233
- }
234
- }
235
-
236
- const ShouldNotRender = () => {
237
- throw new Error(
238
- "The always-dismissed tooltip should never be open, so its " +
239
- "content should never render, but it happened anyway!",
240
- );
241
- };
242
-
243
- const Wrapper = (props) => (
244
- <div className={css(styles.wrapper)}>
245
- <NewTooltip {...props} />
246
- </div>
247
- );
248
-
249
- const ScrollWrapper = (props) => (
250
- <div className={css(styles.scrollContainer)}>
251
- <div className={css(styles.scrollContainerPadder)}>
252
- <div className={css(styles.wrapper)}>
253
- <NewTooltip {...props} />
254
- </div>
255
- </div>
256
- </div>
257
- );
258
-
259
- const SmallWrapperLeft = (props) => (
260
- <div
261
- className={css(styles.wrapper, styles.wrapperSmall, styles.wrapperLeft)}
262
- >
263
- <NewTooltip {...props} />
264
- </div>
265
- );
266
-
267
- const SmallWrapperRight = (props) => (
268
- <div
269
- className={css(
270
- styles.wrapper,
271
- styles.wrapperSmall,
272
- styles.wrapperRight,
273
- )}
274
- >
275
- <NewTooltip {...props} />
276
- </div>
277
- );
278
-
279
- export const BasicHoverTooltipAndAriaLive = (args: StoryArgs): React.Node => {
280
- const params = {
281
- content,
282
- a11y: {title: "Basic hover tooltip", assertiveness: "polite"},
283
- children: <div className={css(styles.target)}>Hover me!</div>,
284
- };
285
- return <Wrapper {...params} />;
286
- };
287
-
288
- export const BasicPermanentTooltip = (args: StoryArgs): React.Node => {
289
- const params = {
290
- content,
291
- toggleOnHover: false,
292
- showOnMount: true,
293
- a11y: {title: "Basic permanent tooltip"},
294
- children: <div className={css(styles.target)}>Hover me!</div>,
295
- };
296
- return <Wrapper {...params} />;
297
- };
298
-
299
- export const BasicPermanentTooltipBottom = (args: StoryArgs): React.Node => {
300
- const params = {
301
- content,
302
- side: "bottom",
303
- toggleOnHover: false,
304
- showOnMount: true,
305
- a11y: {title: "Basic permanent tooltip (bottom)"},
306
- children: <div className={css(styles.target)}>Hover me!</div>,
307
- };
308
- return <Wrapper {...params} />;
309
- };
310
-
311
- export const BasicPermanentTooltipLeft = (args: StoryArgs): React.Node => {
312
- const params = {
313
- content,
314
- side: "left",
315
- toggleOnHover: false,
316
- showOnMount: true,
317
- a11y: {title: "Basic permanent tooltip (left)"},
318
- children: <div className={css(styles.target)}>Hover me!</div>,
319
- };
320
- return <Wrapper {...params} />;
321
- };
322
-
323
- export const BasicPermanentTooltipRight = (args: StoryArgs): React.Node => {
324
- const params = {
325
- content,
326
- side: "right",
327
- toggleOnHover: false,
328
- showOnMount: true,
329
- a11y: {title: "Basic permanent tooltip (right)"},
330
- children: <div className={css(styles.target)}>Hover me!</div>,
331
- };
332
- return <Wrapper {...params} />;
333
- };
334
-
335
- export const BasicDismissableTooltip = (args: StoryArgs): React.Node => {
336
- const params = {
337
- content,
338
- dismissOnClickClose: true,
339
- toggleOnHover: false,
340
- showOnMount: true,
341
- a11y: {title: "Basic dismissable tooltip"},
342
- children: <div className={css(styles.target)}>Hover me!</div>,
343
- };
344
- return <Wrapper {...params} />;
345
- };
346
-
347
- export const ControlledDismissableTooltip = (args: StoryArgs): React.Node => {
348
- return <DismissDemo />;
349
- };
350
-
351
- export const AlwaysDismissedTooltip = (args: StoryArgs): React.Node => {
352
- const params = {
353
- content: <ShouldNotRender />,
354
- side: "left",
355
- dismissed: true,
356
- toggleOnHover: false,
357
- showOnMount: true,
358
- a11y: {title: "Always-dismissed tooltip"},
359
- children: <div className={css(styles.target)}>Hover me!</div>,
360
- };
361
- return <Wrapper {...params} />;
362
- };
363
-
364
- // To test that content changes pass through the portal correctly.
365
- export const ContentChangingPermanentTooltip = (
366
- args: StoryArgs,
367
- ): React.Node => {
368
- return <ContentChangingTooltip />;
369
- };
370
-
371
- export const PermanentTooltipInScrollableContainer = (
372
- args: StoryArgs,
373
- ): React.Node => {
374
- const params = {
375
- content,
376
- toggleOnHover: false,
377
- showOnMount: true,
378
- a11y: {
379
- title: "Permanent tooltip in scrollable container",
380
- },
381
- children: <div className={css(styles.target)}>Hover me!</div>,
382
- };
383
- return <ScrollWrapper {...params} />;
384
- };
385
-
386
- export const PermanentTooltipInScrollableContainerBottom = (
387
- args: StoryArgs,
388
- ): React.Node => {
389
- const params = {
390
- content,
391
- side: "bottom",
392
- toggleOnHover: false,
393
- showOnMount: true,
394
- a11y: {
395
- title: "Permanent tooltip in scrollable container (bottom)",
396
- },
397
- children: <div className={css(styles.target)}>Hover me!</div>,
398
- };
399
- return <ScrollWrapper {...params} />;
400
- };
401
-
402
- export const PermanentTooltipInScrollableContainerLeft = (
403
- args: StoryArgs,
404
- ): React.Node => {
405
- const params = {
406
- content,
407
- side: "left",
408
- toggleOnHover: false,
409
- showOnMount: true,
410
- a11y: {
411
- title: "Permanent tooltip in scrollable container (left)",
412
- },
413
- children: <div className={css(styles.target)}>Hover me!</div>,
414
- };
415
- return <ScrollWrapper {...params} />;
416
- };
417
-
418
- export const PermanentTooltipInScrollableContainerRight = (
419
- args: StoryArgs,
420
- ): React.Node => {
421
- const params = {
422
- content,
423
- side: "right",
424
- toggleOnHover: false,
425
- showOnMount: true,
426
- a11y: {
427
- title: "Permanent tooltip in scrollable container (right)",
428
- },
429
- children: <div className={css(styles.target)}>Hover me!</div>,
430
- };
431
- return <ScrollWrapper {...params} />;
432
- };
433
-
434
- export const InvertedPermanentTooltip = (args: StoryArgs): React.Node => {
435
- const params = {
436
- content,
437
- inverted: true,
438
- toggleOnHover: false,
439
- dismissOnClickClose: true,
440
- showOnMount: true,
441
- a11y: {title: "Inverted permanent tooltip"},
442
- children: <div className={css(styles.target)}>Hover me!</div>,
443
- };
444
- return <Wrapper {...params} />;
445
- };
446
-
447
- export const BluePermanentTooltip = (args: StoryArgs): React.Node => {
448
- const params = {
449
- content,
450
- color: "blue",
451
- toggleOnHover: false,
452
- dismissOnClickClose: true,
453
- showOnMount: true,
454
- a11y: {title: "Blue permanent tooltip"},
455
- children: <div className={css(styles.target)}>Hover me!</div>,
456
- };
457
- return <Wrapper {...params} />;
458
- };
459
-
460
- export const InvertedBluePermanentTooltip = (args: StoryArgs): React.Node => {
461
- const params = {
462
- content,
463
- color: "blue",
464
- inverted: true,
465
- dismissOnClickClose: true,
466
- toggleOnHover: false,
467
- showOnMount: true,
468
- a11y: {title: "Inverted blue permanent tooltip"},
469
- children: <div className={css(styles.target)}>Hover me!</div>,
470
- };
471
- return <Wrapper {...params} />;
472
- };
473
-
474
- export const PermanentTooltipAtFarrrLeftSmallTarget = (
475
- args: StoryArgs,
476
- ): React.Node => {
477
- const params = {
478
- content,
479
- showOnMount: true,
480
- a11y: {title: "Permanent tooltip at farrr left (small target)"},
481
- children: <div className={css(styles.target)}>Hover me!</div>,
482
- };
483
- return <SmallWrapperLeft {...params} />;
484
- };
485
-
486
- export const PermanentTooltipAtFarrrRightSmallTarget = (
487
- args: StoryArgs,
488
- ): React.Node => {
489
- const params = {
490
- content,
491
- showOnMount: true,
492
- a11y: {title: "Permanent tooltip at farrr right (small target)"},
493
- children: <div className={css(styles.target)}>Hover me!</div>,
494
- };
495
- return <SmallWrapperRight {...params} />;
496
- };
497
-
498
- export const PermanentTooltipWithArrowTouchingTarget = (
499
- args: StoryArgs,
500
- ): React.Node => {
501
- const params = {
502
- content,
503
- offsetFrom: "arrow",
504
- toggleOnHover: false,
505
- showOnMount: true,
506
- a11y: {title: "Permanent tooltip with arrow touching target"},
507
- children: <div className={css(styles.target)}>Hover me!</div>,
508
- };
509
- return <Wrapper {...params} />;
510
- };
511
-
512
- export const PermanentTooltipWithArrowTouchingTargetBottom = (
513
- args: StoryArgs,
514
- ): React.Node => {
515
- const params = {
516
- content,
517
- side: "bottom",
518
- offsetFrom: "arrow",
519
- toggleOnHover: false,
520
- showOnMount: true,
521
- a11y: {
522
- title: "Permanent tooltip with arrow touching target (bottom)",
523
- },
524
- children: <div className={css(styles.target)}>Hover me!</div>,
525
- };
526
- return <Wrapper {...params} />;
527
- };
528
-
529
- export const PermanentTooltipWithArrowTouchingTargetLeft = (
530
- args: StoryArgs,
531
- ): React.Node => {
532
- const params = {
533
- content,
534
- side: "left",
535
- offsetFrom: "arrow",
536
- toggleOnHover: false,
537
- showOnMount: true,
538
- a11y: {
539
- title: "Permanent tooltip with arrow touching target (left)",
540
- },
541
- children: <div className={css(styles.target)}>Hover me!</div>,
542
- };
543
- return <Wrapper {...params} />;
544
- };
545
-
546
- export const PermanentTooltipWithArrowTouchingTargetRight = (
547
- args: StoryArgs,
548
- ): React.Node => {
549
- const params = {
550
- content,
551
- side: "right",
552
- offsetFrom: "arrow",
553
- toggleOnHover: false,
554
- showOnMount: true,
555
- a11y: {
556
- title: "Permanent tooltip with arrow touching target (right)",
557
- },
558
- children: <div className={css(styles.target)}>Hover me!</div>,
559
- };
560
- return <Wrapper {...params} />;
561
- };
562
-
563
- export const PermanentTooltipWith5pxOffsetFromBubble = (
564
- args: StoryArgs,
565
- ): React.Node => {
566
- const params = {
567
- content,
568
- offset: 5,
569
- toggleOnHover: false,
570
- showOnMount: true,
571
- a11y: {
572
- title: "Permanent tooltip with 5px offset from bubble",
573
- },
574
- children: <div className={css(styles.target)}>Hover me!</div>,
575
- };
576
- return <Wrapper {...params} />;
577
- };
578
-
579
- export const PermanentTooltipWith5pxOffsetFromArrow = (
580
- args: StoryArgs,
581
- ): React.Node => {
582
- const params = {
583
- content,
584
- offset: 5,
585
- offsetFrom: "arrow",
586
- toggleOnHover: false,
587
- showOnMount: true,
588
- a11y: {
589
- title: "Permanent tooltip with 5px offset from arrow",
590
- },
591
- children: <div className={css(styles.target)}>Hover me!</div>,
592
- };
593
- return <Wrapper {...params} />;
594
- };
595
-
596
- export const PermanentTooltipWith25pxMargin = (args: StoryArgs): React.Node => {
597
- const params = {
598
- content,
599
- tooltipMargin: 100,
600
- toggleOnHover: false,
601
- showOnMount: true,
602
- a11y: {
603
- title: "Permanent tooltip with 100px margin",
604
- },
605
- children: <div className={css(styles.target)}>Hover me!</div>,
606
- };
607
- return <Wrapper {...params} />;
608
- };
609
-
610
- export const MobileOnlyTooltip = (args: StoryArgs): React.Node => {
611
- const params = {
612
- content,
613
- toggleOnHover: false,
614
- showOnMount: true,
615
- media: mediaQueries.smOrSmaller,
616
- a11y: {title: "Mobile-only tooltip"},
617
- children: <div className={css(styles.target)}>Hover me!</div>,
618
- };
619
- return (
620
- <div>
621
- <Wrapper {...params} />
622
- <div style={{textAlign: "center"}}>
623
- Resize your browser so that its very narrow to see the tooltip
624
- </div>
625
- </div>
626
- );
627
- };
628
-
629
- export const DesktopMobileTooltipWithDifferentStylesAndAriaLive = (
630
- args: StoryArgs,
631
- ): React.Node => {
632
- const params = {
633
- content: "Hello, mobile! I'm red and on the left!",
634
- side: "left",
635
- color: "red",
636
- toggleOnHover: false,
637
- showOnMount: true,
638
- media: mediaQueries.smOrSmaller,
639
- a11y: {
640
- title: "Mobile tooltip with different style",
641
- assertiveness: "polite",
642
- },
643
- children: (
644
- <NewTooltip
645
- content="Hello, desktop! I'm blue and on the right!"
646
- side="right"
647
- color="blue"
648
- toggleOnHover={false}
649
- showOnMount
650
- media={mediaQueries.mdOrLarger}
651
- a11y={{
652
- title: "Desktop tooltip with different style",
653
- assertiveness: "polite",
654
- }}
655
- >
656
- <div className={css(styles.target)}>Hover me!</div>
657
- </NewTooltip>
658
- ),
659
- };
660
- return <Wrapper {...params} />;
661
- };
662
-
663
- export const TooltipsInModals = (args: StoryArgs): React.Node => {
664
- return <ModalTester />;
665
- };
@@ -1,8 +0,0 @@
1
- // @flow
2
- import * as types from "../style-constants.js";
3
-
4
- describe("style-constants module", () => {
5
- it("has some runtime exports", () => {
6
- expect(Object.keys(types)).not.toHaveLength(0);
7
- });
8
- });