@semcore/carousel 3.42.5 → 3.43.4-prerelease.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/lib/cjs/Carousel.js +79 -57
  3. package/lib/cjs/Carousel.js.map +1 -1
  4. package/lib/cjs/style/carousel.shadow.css +48 -4
  5. package/lib/cjs/translations/de.json +4 -2
  6. package/lib/cjs/translations/en.json +4 -2
  7. package/lib/cjs/translations/es.json +4 -2
  8. package/lib/cjs/translations/fr.json +4 -2
  9. package/lib/cjs/translations/it.json +4 -2
  10. package/lib/cjs/translations/ja.json +4 -2
  11. package/lib/cjs/translations/ko.json +4 -2
  12. package/lib/cjs/translations/nl.json +4 -2
  13. package/lib/cjs/translations/pl.json +4 -2
  14. package/lib/cjs/translations/pt.json +4 -2
  15. package/lib/cjs/translations/sv.json +4 -2
  16. package/lib/cjs/translations/tr.json +4 -2
  17. package/lib/cjs/translations/vi.json +4 -2
  18. package/lib/cjs/translations/zh.json +4 -2
  19. package/lib/es6/Carousel.js +79 -57
  20. package/lib/es6/Carousel.js.map +1 -1
  21. package/lib/es6/style/carousel.shadow.css +48 -4
  22. package/lib/es6/translations/de.json +4 -2
  23. package/lib/es6/translations/en.json +4 -2
  24. package/lib/es6/translations/es.json +4 -2
  25. package/lib/es6/translations/fr.json +4 -2
  26. package/lib/es6/translations/it.json +4 -2
  27. package/lib/es6/translations/ja.json +4 -2
  28. package/lib/es6/translations/ko.json +4 -2
  29. package/lib/es6/translations/nl.json +4 -2
  30. package/lib/es6/translations/pl.json +4 -2
  31. package/lib/es6/translations/pt.json +4 -2
  32. package/lib/es6/translations/sv.json +4 -2
  33. package/lib/es6/translations/tr.json +4 -2
  34. package/lib/es6/translations/vi.json +4 -2
  35. package/lib/es6/translations/zh.json +4 -2
  36. package/lib/types/translations/__intergalactic-dynamic-locales.d.ts +28 -0
  37. package/package.json +8 -8
  38. package/src/Carousel.tsx +62 -32
  39. package/src/style/carousel.shadow.css +48 -4
  40. package/src/translations/de.json +4 -2
  41. package/src/translations/en.json +4 -2
  42. package/src/translations/es.json +4 -2
  43. package/src/translations/fr.json +4 -2
  44. package/src/translations/it.json +4 -2
  45. package/src/translations/ja.json +4 -2
  46. package/src/translations/ko.json +4 -2
  47. package/src/translations/nl.json +4 -2
  48. package/src/translations/pl.json +4 -2
  49. package/src/translations/pt.json +4 -2
  50. package/src/translations/sv.json +4 -2
  51. package/src/translations/tr.json +4 -2
  52. package/src/translations/vi.json +4 -2
  53. package/src/translations/zh.json +4 -2
package/src/Carousel.tsx CHANGED
@@ -32,8 +32,7 @@ const MAP_TRANSFORM: Record<string, 'left' | 'right'> = {
32
32
 
33
33
  const enhance = {
34
34
  uid: uniqueIDEnhancement(),
35
- getI18nText: i18nEnhance(localizedMessages),
36
- keyboardFocusEnhance: keyboardFocusEnhance(),
35
+ i18nEnahnce: i18nEnhance(localizedMessages),
37
36
  };
38
37
  const media = ['(min-width: 481px)', '(max-width: 480px)'];
39
38
  const BreakPoints = createBreakpoints(media);
@@ -43,7 +42,12 @@ class CarouselRoot extends Component<
43
42
  CarouselProps,
44
43
  CarouselContext,
45
44
  CarouselState,
46
- typeof enhance
45
+ typeof enhance & {
46
+ getI18nText: (
47
+ messageId: string,
48
+ variables?: { [key: string]: string | number | undefined },
49
+ ) => string;
50
+ }
47
51
  > {
48
52
  static displayName = 'Carousel';
49
53
  static defaultProps = {
@@ -358,7 +362,7 @@ class CarouselRoot extends Component<
358
362
  };
359
363
 
360
364
  getPrevProps() {
361
- const { bounded, getI18nText } = this.asProps;
365
+ const { bounded, getI18nText, uid } = this.asProps;
362
366
  const { items, selectedIndex } = this.state;
363
367
  let disabled = false;
364
368
  if (items.length && bounded) {
@@ -369,12 +373,12 @@ class CarouselRoot extends Component<
369
373
  onKeyDown: this.bindHandlerKeydownControl('left'),
370
374
  disabled,
371
375
  label: getI18nText('prev'),
372
- tabIndex: -1,
376
+ 'aria-controls': `igc-${uid}-carousel`,
373
377
  };
374
378
  }
375
379
 
376
380
  getNextProps() {
377
- const { bounded, getI18nText } = this.asProps;
381
+ const { bounded, getI18nText, uid } = this.asProps;
378
382
  const { items, selectedIndex } = this.state;
379
383
  let disabled = false;
380
384
  if (items.length && bounded) {
@@ -386,12 +390,13 @@ class CarouselRoot extends Component<
386
390
  onKeyDown: this.bindHandlerKeydownControl('right'),
387
391
  disabled,
388
392
  label: getI18nText('next'),
389
- tabIndex: -1,
393
+ 'aria-controls': `igc-${uid}-carousel`,
390
394
  };
391
395
  }
392
396
 
393
397
  getIndicatorsProps() {
394
398
  const { items } = this.state;
399
+ const { getI18nText } = this.asProps;
395
400
 
396
401
  return {
397
402
  items: items.map((item, key) => ({
@@ -399,6 +404,20 @@ class CarouselRoot extends Component<
399
404
  onClick: this.bindHandlerClickIndicator(key),
400
405
  key,
401
406
  })),
407
+ role: 'tablist',
408
+ 'aria-label': getI18nText('slides'),
409
+ };
410
+ }
411
+
412
+ getIndicatorProps(_: any, index: number) {
413
+ const isCurrent = this.isSelected(index);
414
+ const { getI18nText } = this.asProps;
415
+
416
+ return {
417
+ role: 'tab',
418
+ 'aria-selected': isCurrent,
419
+ 'aria-controls': `igc-${this.asProps.uid}-carousel-item-${index}`,
420
+ 'aria-label': getI18nText('slide', { slideNumber: index + 1 }),
402
421
  };
403
422
  }
404
423
 
@@ -430,7 +449,7 @@ class CarouselRoot extends Component<
430
449
  }
431
450
 
432
451
  isSelected(index: number) {
433
- const { items, selectedIndex } = this.state;
452
+ const { items } = this.state;
434
453
 
435
454
  if (items.length === 0) {
436
455
  return true;
@@ -442,15 +461,7 @@ class CarouselRoot extends Component<
442
461
  renderModal(isSmall: boolean, ComponentItems: any[]) {
443
462
  const SModalContainer = Root;
444
463
  const SModalBox = Box;
445
- const {
446
- styles,
447
- uid,
448
- duration,
449
- zoom: hasZoom,
450
- zoomWidth,
451
- 'aria-label': ariaLabel,
452
- 'aria-roledescription': ariaRoledescription,
453
- } = this.asProps;
464
+ const { styles, uid, duration, zoomWidth } = this.asProps;
454
465
  const { isOpenZoom } = this.state;
455
466
 
456
467
  return sstyled(styles)(
@@ -465,7 +476,7 @@ class CarouselRoot extends Component<
465
476
  <SModalBox>
466
477
  <SModalContainer
467
478
  render={Box}
468
- role='list'
479
+ aria-live='polite'
469
480
  use:duration={`${duration}ms`}
470
481
  ref={this.refModalContainer}
471
482
  use:w={undefined}
@@ -508,6 +519,7 @@ class CarouselRoot extends Component<
508
519
  const {
509
520
  styles,
510
521
  Children,
522
+ uid,
511
523
  zoom: hasZoom,
512
524
  'aria-label': ariaLabel,
513
525
  'aria-roledescription': ariaRoledescription,
@@ -523,21 +535,21 @@ class CarouselRoot extends Component<
523
535
  return sstyled(styles)(
524
536
  <SCarousel
525
537
  render={Box}
526
- role='group'
538
+ role='region'
539
+ roledescription='carousel'
527
540
  onKeyDown={this.handlerKeyDown}
528
541
  onTouchStart={this.handlerTouchStart}
529
542
  onTouchEnd={this.handlerTouchEnd}
530
543
  ref={this.refCarousel}
544
+ id={`igc-${uid}-carousel`}
545
+ aria-roledescription={ariaRoledescription}
531
546
  >
532
547
  {Controls.length === 0 ? (
533
548
  <>
534
549
  <Flex>
535
550
  <Carousel.Prev />
536
551
  <SContentBox>
537
- <Carousel.Container
538
- aria-roledescription={ariaRoledescription}
539
- aria-label={ariaLabel}
540
- >
552
+ <Carousel.Container aria-label={ariaLabel}>
541
553
  <Children />
542
554
  </Carousel.Container>
543
555
  </SContentBox>
@@ -581,11 +593,15 @@ const Container = (props: BoxProps & { duration?: number }) => {
581
593
  const SContainer = Root;
582
594
  const { styles, duration } = props;
583
595
 
584
- return sstyled(styles)(<SContainer render={Box} role='list' use:duration={`${duration}ms`} />);
596
+ return sstyled(styles)(
597
+ <SContainer render={Box} use:duration={`${duration}ms`} aria-live='polite' />,
598
+ );
585
599
  };
586
600
 
587
601
  class Item extends Component<CarouselItemProps> {
588
602
  refItem = React.createRef<HTMLElement>();
603
+ keepFocusTimeout: NodeJS.Timeout | undefined;
604
+ static enhance = [keyboardFocusEnhance(false)];
589
605
 
590
606
  componentDidMount() {
591
607
  const { toggleItem, transform } = this.props;
@@ -603,28 +619,43 @@ class Item extends Component<CarouselItemProps> {
603
619
  const refItem = this.refItem.current;
604
620
 
605
621
  toggleItem && refItem && toggleItem({ node: refItem }, true);
622
+ clearTimeout(this.keepFocusTimeout);
606
623
  }
607
624
 
608
625
  componentDidUpdate(prevProps: CarouselItemProps) {
626
+ clearTimeout(this.keepFocusTimeout);
627
+
609
628
  const transform = this.props.transform;
610
629
  const refItem = this.refItem.current;
611
630
 
612
631
  if (prevProps.transform !== transform && refItem) {
613
632
  refItem.style.transform = `translateX(${transform}%)`;
614
633
  }
634
+ if (this.props.current) {
635
+ this.keepFocusTimeout = setTimeout(() => {
636
+ if (
637
+ document.activeElement !== refItem &&
638
+ (document.activeElement as HTMLElement)?.dataset.carousel === refItem?.dataset.carousel
639
+ ) {
640
+ refItem?.focus();
641
+ }
642
+ }, 100);
643
+ }
615
644
  }
616
645
 
617
646
  render() {
618
- const { styles, index, uid, current, zoomIn, onToggleZoomModal, transform } = this.props;
647
+ const { styles, index, uid, current, zoomIn, onToggleZoomModal } = this.props;
619
648
  const SItem = Root;
620
649
 
621
650
  return sstyled(styles)(
622
651
  <SItem
623
652
  render={Box}
624
653
  ref={this.refItem}
625
- role='listitem'
654
+ role='tabpanel'
655
+ data-carousel={`igc-${uid}-carousel`}
626
656
  id={`igc-${uid}-carousel-item-${index}`}
627
657
  aria-current={current}
658
+ use:tabIndex={current ? 0 : -1}
628
659
  onClick={zoomIn ? onToggleZoomModal : undefined}
629
660
  zoomIn={zoomIn}
630
661
  />,
@@ -633,7 +664,7 @@ class Item extends Component<CarouselItemProps> {
633
664
  }
634
665
 
635
666
  const Prev = (props: CarouselButtonProps) => {
636
- const { styles, children, Children, label, top = 0, inverted, tabIndex } = props;
667
+ const { styles, children, Children, label, top = 0, inverted } = props;
637
668
  const SPrev = Root;
638
669
  const SPrevButton = Button;
639
670
 
@@ -648,7 +679,6 @@ const Prev = (props: CarouselButtonProps) => {
648
679
  theme={inverted ? 'invert' : 'muted'}
649
680
  use={'tertiary'}
650
681
  size={'l'}
651
- tabIndex={tabIndex}
652
682
  />
653
683
  )}
654
684
  </SPrev>,
@@ -656,7 +686,7 @@ const Prev = (props: CarouselButtonProps) => {
656
686
  };
657
687
 
658
688
  const Next = (props: CarouselButtonProps) => {
659
- const { styles, children, Children, label, top = 0, inverted, tabIndex } = props;
689
+ const { styles, children, Children, label, top = 0, inverted } = props;
660
690
  const SNext = Root;
661
691
  const SNextButton = Button;
662
692
 
@@ -671,7 +701,6 @@ const Next = (props: CarouselButtonProps) => {
671
701
  theme={inverted ? 'invert' : 'muted'}
672
702
  use={'tertiary'}
673
703
  size={'l'}
674
- tabIndex={tabIndex}
675
704
  />
676
705
  )}
677
706
  </SNext>,
@@ -682,19 +711,20 @@ const Indicators = ({ items, styles, Children, inverted }: CarouselIndicatorsPro
682
711
  const SIndicators = Root;
683
712
  if (Children.origin) {
684
713
  return sstyled(styles)(
685
- <SIndicators render={Box} aria-hidden='true'>
714
+ <SIndicators render={Box}>
686
715
  <Children />
687
716
  </SIndicators>,
688
717
  );
689
718
  }
690
719
  return sstyled(styles)(
691
- <SIndicators render={Box} aria-hidden='true'>
720
+ <SIndicators render={Box}>
692
721
  {items?.map((item, index) => (
693
722
  <Carousel.Indicator key={index} {...item} inverted={inverted} />
694
723
  ))}
695
724
  </SIndicators>,
696
725
  );
697
726
  };
727
+ Indicators.enhance = [keyboardFocusEnhance()];
698
728
 
699
729
  const Indicator = ({ styles, Children }: CarouselIndicatorProps) => {
700
730
  const SIndicator = Root;
@@ -4,10 +4,6 @@ SCarousel {
4
4
  user-select: none;
5
5
  }
6
6
 
7
- SCarousel[keyboardFocused] {
8
- box-shadow: var(--intergalactic-keyboard-focus, 0px 0px 0px 3px rgba(0, 143, 248, 0.5));
9
- z-index: 1;
10
- }
11
7
 
12
8
  SContainer {
13
9
  display: flex;
@@ -15,8 +11,22 @@ SContainer {
15
11
  }
16
12
 
17
13
  SContentBox, SModalBox {
14
+ position: relative;
18
15
  overflow: hidden;
19
16
  border-radius: var(--intergalactic-surface-rounded, 6px);
17
+ &:has(SItem[keyboardFocused]) {
18
+ &:after {
19
+ content: '';
20
+ display: block;
21
+ position: absolute;
22
+ box-shadow: var(--intergalactic-keyboard-focus, 0px 0px 0px 3px rgba(0, 143, 248, 0.5));
23
+ z-index: 1;
24
+ width: calc(100% - 3px * 2);
25
+ height: calc(100% - 3px * 2);
26
+ top: 3px;
27
+ left: 3px;
28
+ }
29
+ }
20
30
  }
21
31
 
22
32
  SModalContainer {
@@ -31,6 +41,7 @@ SItem {
31
41
  transform: var(--transform);
32
42
  border-radius: var(--intergalactic-surface-rounded, 6px);
33
43
  overflow: hidden;
44
+ outline: none;
34
45
  }
35
46
 
36
47
  SItem[zoomIn] {
@@ -44,6 +55,20 @@ SIndicators {
44
55
  display: flex;
45
56
  justify-content: center;
46
57
  margin-top: var(--intergalactic-spacing-4x, 16px);
58
+ outline: none;
59
+ position: relative;
60
+ }
61
+
62
+ SIndicators[keyboardFocused]:after {
63
+ content: '';
64
+ display: block;
65
+ position: absolute;
66
+ box-shadow: var(--intergalactic-keyboard-focus, 0px 0px 0px 3px rgba(0, 143, 248, 0.5));
67
+ z-index: 1;
68
+ width: calc(100% - 3px * 2);
69
+ height: calc(100% - 3px);
70
+ top: 0;
71
+ left: 3px;
47
72
  }
48
73
 
49
74
  SIndicator {
@@ -83,6 +108,25 @@ SNext {
83
108
  margin-left: calc(2 * var(--intergalactic-spacing-1x, 4px) - 1px);
84
109
  margin-right: calc(2 * var(--intergalactic-spacing-1x, 4px) - 1px);
85
110
  }
111
+
112
+ }
113
+
114
+ SPrevButton, SNextButton {
115
+ &:focus-visible {
116
+ box-shadow: none;
117
+ &:after {
118
+ content: '';
119
+ display: block;
120
+ position: absolute;
121
+ box-shadow: var(--intergalactic-keyboard-focus, 0px 0px 0px 3px rgba(0, 143, 248, 0.5));
122
+ z-index: 1;
123
+ width: calc(100% - 3px * 2);
124
+ height: calc(100% - 3px * 2);
125
+ top: 3px;
126
+ left: 3px;
127
+ border-radius: var(--intergalactic-control-rounded, 6px);
128
+ }
129
+ }
86
130
  }
87
131
 
88
132
  SPrev {
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Weiter",
3
- "prev": "Vorher"
2
+ "next": "Nächste Folie",
3
+ "prev": "Vorherige Folie",
4
+ "slides": "Folien",
5
+ "slide": "Folie {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Next",
3
- "prev": "Previous"
2
+ "next": "Next slide",
3
+ "prev": "Previous slide",
4
+ "slides": "Slides",
5
+ "slide": "Slide {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Siguiente",
3
- "prev": "Anterior"
2
+ "next": "Próxima diapositiva",
3
+ "prev": "Diapositiva anterior",
4
+ "slides": "Diapositivas",
5
+ "slide": "Diapositiva {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Suivant",
3
- "prev": "Précédent"
2
+ "next": "Diapositive suivante",
3
+ "prev": "Diapositive précédente",
4
+ "slides": "Diapositives",
5
+ "slide": "Diapositive {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Succ.",
3
- "prev": "Precedente"
2
+ "next": "Slide successiva",
3
+ "prev": "Slide precedente",
4
+ "slides": "Slide",
5
+ "slide": "Slide {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "次へ",
3
- "prev": "前へ"
2
+ "next": "次のスライド",
3
+ "prev": "前のスライド",
4
+ "slides": "スライド",
5
+ "slide": "スライド{slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "다음",
3
- "prev": "이전"
2
+ "next": "다음 슬라이드",
3
+ "prev": "이전 슬라이드",
4
+ "slides": "슬라이드",
5
+ "slide": "슬라이드 {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Volgende",
3
- "prev": "Vorige"
2
+ "next": "Volgende dia",
3
+ "prev": "Vorige dia",
4
+ "slides": "Dia's",
5
+ "slide": "Dia {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Dalej",
3
- "prev": "Poprzednio"
2
+ "next": "Następny slajd",
3
+ "prev": "Poprzedni slajd",
4
+ "slides": "Slajdy",
5
+ "slide": "Slajd {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Seguinte",
3
- "prev": "Anterior"
2
+ "next": "Próximo slide",
3
+ "prev": "Slide anterior",
4
+ "slides": "Slides",
5
+ "slide": "Slide {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Nästa",
3
- "prev": "Föregående"
2
+ "next": "Nästa bild",
3
+ "prev": "Föregående bild",
4
+ "slides": "Bilder",
5
+ "slide": "Bild {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Sonraki",
3
- "prev": "Önceki"
2
+ "next": "Sonraki slayt",
3
+ "prev": "Önceki slayt",
4
+ "slides": "Slaytlar",
5
+ "slide": "Slayt {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "Tiếp",
3
- "prev": "Trước"
2
+ "next": "Slide tiếp theo",
3
+ "prev": "Slide trước",
4
+ "slides": "Slide",
5
+ "slide": "Slide {slideNumber}"
4
6
  }
@@ -1,4 +1,6 @@
1
1
  {
2
- "next": "下一个",
3
- "prev": "上一个"
2
+ "next": "下一张幻灯片",
3
+ "prev": "上一张幻灯片",
4
+ "slides": "幻灯片",
5
+ "slide": "幻灯片 {slideNumber}"
4
6
  }