@gravity-ui/page-constructor 5.27.0 → 5.27.1-alpha.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 (88) hide show
  1. package/README.md +54 -0
  2. package/build/cjs/blocks/HeaderSlider/HeaderSlider.css +0 -10
  3. package/build/cjs/blocks/HeaderSlider/HeaderSlider.js +2 -2
  4. package/build/cjs/blocks/Slider/Slider.css +2 -0
  5. package/build/cjs/blocks/Slider/Slider.d.ts +1 -0
  6. package/build/cjs/blocks/Slider/Slider.js +85 -31
  7. package/build/cjs/blocks/Slider/i18n/en.json +3 -1
  8. package/build/cjs/blocks/Slider/i18n/index.d.ts +1 -1
  9. package/build/cjs/blocks/Slider/i18n/ru.json +3 -1
  10. package/build/cjs/blocks/Slider/utils.d.ts +10 -0
  11. package/build/cjs/blocks/Slider/utils.js +85 -1
  12. package/build/cjs/blocks/SliderNew/Arrow/Arrow.css +23 -19
  13. package/build/cjs/blocks/SliderNew/Arrow/Arrow.d.ts +4 -1
  14. package/build/cjs/blocks/SliderNew/Arrow/Arrow.js +5 -4
  15. package/build/cjs/blocks/SliderNew/Slider.css +104 -15
  16. package/build/cjs/blocks/SliderNew/Slider.d.ts +2 -1
  17. package/build/cjs/blocks/SliderNew/Slider.js +22 -9
  18. package/build/cjs/blocks/SliderNew/i18n/en.json +3 -1
  19. package/build/cjs/blocks/SliderNew/i18n/index.d.ts +1 -1
  20. package/build/cjs/blocks/SliderNew/i18n/ru.json +3 -1
  21. package/build/cjs/blocks/SliderNew/useSlider.d.ts +8 -6
  22. package/build/cjs/blocks/SliderNew/useSlider.js +4 -2
  23. package/build/cjs/blocks/SliderNew/useSliderPagination.d.ts +9 -0
  24. package/build/cjs/blocks/SliderNew/useSliderPagination.js +36 -0
  25. package/build/cjs/blocks/SliderNew/utils.d.ts +2 -0
  26. package/build/cjs/blocks/SliderNew/utils.js +13 -1
  27. package/build/cjs/components/FullscreenImage/FullscreenImage.css +91 -16
  28. package/build/cjs/components/FullscreenImage/FullscreenImage.d.ts +5 -0
  29. package/build/cjs/components/FullscreenImage/FullscreenImage.js +19 -5
  30. package/build/cjs/components/Media/Image/Image.d.ts +1 -0
  31. package/build/cjs/components/Media/Image/Image.js +7 -5
  32. package/build/cjs/components/Media/Media.css +4 -0
  33. package/build/cjs/components/Media/Media.d.ts +1 -0
  34. package/build/cjs/components/Media/Media.js +3 -2
  35. package/build/cjs/components/MediaBase/MediaBase.js +1 -1
  36. package/build/cjs/components/ReactPlayer/ReactPlayer.js +1 -1
  37. package/build/cjs/constructor-items.d.ts +1 -1
  38. package/build/cjs/models/constructor-items/blocks.d.ts +2 -1
  39. package/build/cjs/models/constructor-items/blocks.js +1 -0
  40. package/build/cjs/navigation/hooks/useShowBorder.js +3 -2
  41. package/build/cjs/sub-blocks/Content/Content.css +14 -4
  42. package/build/cjs/sub-blocks/ImageCard/ImageCard.css +8 -0
  43. package/build/esm/blocks/HeaderSlider/HeaderSlider.css +0 -10
  44. package/build/esm/blocks/HeaderSlider/HeaderSlider.js +1 -1
  45. package/build/esm/blocks/Slider/Slider.css +2 -0
  46. package/build/esm/blocks/Slider/Slider.d.ts +1 -0
  47. package/build/esm/blocks/Slider/Slider.js +86 -32
  48. package/build/esm/blocks/Slider/i18n/en.json +3 -1
  49. package/build/esm/blocks/Slider/i18n/index.d.ts +1 -1
  50. package/build/esm/blocks/Slider/i18n/ru.json +3 -1
  51. package/build/esm/blocks/Slider/utils.d.ts +10 -0
  52. package/build/esm/blocks/Slider/utils.js +82 -0
  53. package/build/esm/blocks/SliderNew/Arrow/Arrow.css +23 -19
  54. package/build/esm/blocks/SliderNew/Arrow/Arrow.d.ts +4 -1
  55. package/build/esm/blocks/SliderNew/Arrow/Arrow.js +5 -4
  56. package/build/esm/blocks/SliderNew/Slider.css +104 -15
  57. package/build/esm/blocks/SliderNew/Slider.d.ts +2 -1
  58. package/build/esm/blocks/SliderNew/Slider.js +22 -9
  59. package/build/esm/blocks/SliderNew/i18n/en.json +3 -1
  60. package/build/esm/blocks/SliderNew/i18n/index.d.ts +1 -1
  61. package/build/esm/blocks/SliderNew/i18n/ru.json +3 -1
  62. package/build/esm/blocks/SliderNew/useSlider.d.ts +8 -6
  63. package/build/esm/blocks/SliderNew/useSlider.js +6 -3
  64. package/build/esm/blocks/SliderNew/useSliderPagination.d.ts +9 -0
  65. package/build/esm/blocks/SliderNew/useSliderPagination.js +32 -0
  66. package/build/esm/blocks/SliderNew/utils.d.ts +2 -0
  67. package/build/esm/blocks/SliderNew/utils.js +10 -0
  68. package/build/esm/components/FullscreenImage/FullscreenImage.css +91 -16
  69. package/build/esm/components/FullscreenImage/FullscreenImage.d.ts +5 -0
  70. package/build/esm/components/FullscreenImage/FullscreenImage.js +20 -6
  71. package/build/esm/components/Media/Image/Image.d.ts +1 -0
  72. package/build/esm/components/Media/Image/Image.js +7 -5
  73. package/build/esm/components/Media/Media.css +4 -0
  74. package/build/esm/components/Media/Media.d.ts +1 -0
  75. package/build/esm/components/Media/Media.js +3 -2
  76. package/build/esm/components/MediaBase/MediaBase.js +1 -1
  77. package/build/esm/components/ReactPlayer/ReactPlayer.js +1 -1
  78. package/build/esm/constructor-items.d.ts +1 -1
  79. package/build/esm/models/constructor-items/blocks.d.ts +2 -1
  80. package/build/esm/models/constructor-items/blocks.js +1 -0
  81. package/build/esm/navigation/hooks/useShowBorder.js +1 -1
  82. package/build/esm/sub-blocks/Content/Content.css +14 -4
  83. package/build/esm/sub-blocks/ImageCard/ImageCard.css +8 -0
  84. package/package.json +2 -1
  85. package/server/models/constructor-items/blocks.d.ts +2 -1
  86. package/server/models/constructor-items/blocks.js +1 -0
  87. package/styles/mixins.scss +1 -1
  88. package/widget/index.js +1 -1
@@ -1,3 +1,4 @@
1
+ import { useEffect, useRef, useState } from 'react';
1
2
  import pickBy from 'lodash/pickBy';
2
3
  import { BREAKPOINTS } from '../../constants';
3
4
  import { SliderBreakpointNames } from './models';
@@ -8,6 +9,37 @@ export const DEFAULT_SLIDE_BREAKPOINTS = {
8
9
  [SliderBreakpointNames.Sm]: 1.15,
9
10
  };
10
11
  const BREAKPOINT_NAMES_BY_VALUES = Object.entries(BREAKPOINTS).reduce((acc, [key, value]) => (Object.assign(Object.assign({}, acc), { [value]: key })), {});
12
+ export const isFocusable = (element) => {
13
+ if (!(element instanceof HTMLElement)) {
14
+ return false;
15
+ }
16
+ const tabIndexAttr = element.getAttribute('tabindex');
17
+ const hasTabIndex = tabIndexAttr !== null;
18
+ const tabIndex = Number(tabIndexAttr);
19
+ if (element.ariaHidden === 'true' || (hasTabIndex && tabIndex < 0)) {
20
+ return false;
21
+ }
22
+ if (hasTabIndex && tabIndex >= 0) {
23
+ return true;
24
+ }
25
+ // without this jest fails here for some reason
26
+ let htmlElement;
27
+ switch (true) {
28
+ case element instanceof HTMLAnchorElement:
29
+ htmlElement = element;
30
+ return Boolean(htmlElement.href);
31
+ case element instanceof HTMLInputElement:
32
+ htmlElement = element;
33
+ return htmlElement.type !== 'hidden' && !htmlElement.disabled;
34
+ case element instanceof HTMLSelectElement:
35
+ case element instanceof HTMLTextAreaElement:
36
+ case element instanceof HTMLButtonElement:
37
+ htmlElement = element;
38
+ return !htmlElement.disabled;
39
+ default:
40
+ return false;
41
+ }
42
+ };
11
43
  export function getSlidesToShowWithDefaults({ contentLength, breakpoints, mobileFullscreen, }) {
12
44
  let result;
13
45
  if (typeof breakpoints === 'number') {
@@ -31,3 +63,53 @@ export function getSlidesCountByBreakpoint(breakpoint, breakpoints) {
31
63
  export function getSlidesToShowCount(breakpoints) {
32
64
  return Math.floor(Math.max(...Object.values(breakpoints)));
33
65
  }
66
+ const getRovingListItemId = (uniqId, index) => `${uniqId}-roving-tabindex-item-${index}`;
67
+ export function useRovingTabIndex(props) {
68
+ const { itemCount, activeIndex, firstIndex = 0, uniqId } = props;
69
+ const [currentIndex, setCurrentIndex] = useState(firstIndex);
70
+ const hasFocusRef = useRef(false);
71
+ const lastIndex = itemCount + firstIndex - 1;
72
+ const getRovingItemProps = (index) => {
73
+ return {
74
+ id: getRovingListItemId(uniqId, index),
75
+ tabIndex: index === activeIndex ? 0 : -1,
76
+ onFocus: () => {
77
+ setCurrentIndex(index);
78
+ hasFocusRef.current = true;
79
+ },
80
+ };
81
+ };
82
+ useEffect(() => {
83
+ var _a;
84
+ if (!hasFocusRef.current) {
85
+ return;
86
+ }
87
+ (_a = document.getElementById(getRovingListItemId(uniqId, currentIndex))) === null || _a === void 0 ? void 0 : _a.focus();
88
+ }, [activeIndex, currentIndex, uniqId]);
89
+ const setNextIndex = () => setCurrentIndex((prev) => (prev >= lastIndex ? firstIndex : prev + 1));
90
+ const setPrevIndex = () => setCurrentIndex((prev) => (prev <= firstIndex ? lastIndex : prev - 1));
91
+ const onRovingListKeyDown = (e) => {
92
+ const key = e.key.toLowerCase();
93
+ if (key !== 'tab' && key !== 'enter') {
94
+ e.preventDefault();
95
+ }
96
+ switch (key) {
97
+ case 'arrowleft':
98
+ case 'arrowup':
99
+ setPrevIndex();
100
+ return;
101
+ case 'arrowright':
102
+ case 'arrowdown':
103
+ setNextIndex();
104
+ return;
105
+ }
106
+ };
107
+ const onRovingListBlur = () => {
108
+ hasFocusRef.current = false;
109
+ };
110
+ const rovingListProps = {
111
+ onKeyDown: onRovingListKeyDown,
112
+ onBlur: onRovingListBlur,
113
+ };
114
+ return { getRovingItemProps, rovingListProps };
115
+ }
@@ -1,33 +1,25 @@
1
- .pc-slider-new-block-arrow__button {
1
+ .pc-slider-new-block-arrow__inner {
2
2
  box-shadow: 0px 4px 24px var(--pc-color-sfx-shadow), 0px 2px 8px var(--pc-color-sfx-shadow);
3
3
  }
4
4
 
5
- .pc-slider-new-block-arrow__button:hover {
5
+ .pc-slider-new-block-arrow__inner:hover {
6
6
  box-shadow: 0px 4px 24px var(--g-color-sfx-shadow), 0px 2px 8px var(--g-color-sfx-shadow);
7
7
  cursor: pointer;
8
8
  }
9
9
 
10
10
  /* use this for style redefinitions to awoid problems with
11
11
  unpredictable css rules order in build */
12
- .pc-slider-new-block-arrow__icon-wrapper, .pc-slider-new-block-arrow__button, .pc-slider-new-block-arrow {
12
+ .pc-slider-new-block-arrow__icon-wrapper, .pc-slider-new-block-arrow__inner, .pc-slider-new-block-arrow {
13
13
  display: flex;
14
14
  align-items: center;
15
15
  justify-content: center;
16
16
  }
17
17
 
18
- .pc-slider-new-block-arrow {
19
- width: 42px;
20
- height: 42px;
21
- cursor: pointer;
22
- }
23
18
  @media (max-width: 576px) {
24
19
  .pc-slider-new-block-arrow {
25
20
  display: none;
26
21
  }
27
22
  }
28
- .pc-slider-new-block-arrow_type_left .pc-slider-new-block-arrow__icon-wrapper {
29
- transform: rotate(180deg);
30
- }
31
23
  .pc-slider-new-block-arrow__button {
32
24
  display: inline-block;
33
25
  margin: 0;
@@ -38,13 +30,6 @@ unpredictable css rules order in build */
38
30
  color: inherit;
39
31
  background: none;
40
32
  cursor: pointer;
41
- width: 42px;
42
- height: 42px;
43
- color: var(--g-color-text-secondary);
44
- border-radius: 100%;
45
- background-color: var(--g-color-base-background);
46
- box-shadow: 0 4px 24px var(--pc-color-sfx-shadow), 0 2px 8px var(--pc-color-sfx-shadow);
47
- transition: box-shadow 0.3s cubic-bezier(0.22, 0.61, 0.36, 1), color 0.3s cubic-bezier(0.22, 0.61, 0.36, 1);
48
33
  }
49
34
  .pc-slider-new-block-arrow__button:focus {
50
35
  outline: 2px solid var(--g-color-line-focus);
@@ -53,10 +38,29 @@ unpredictable css rules order in build */
53
38
  .pc-slider-new-block-arrow__button:focus:not(:focus-visible) {
54
39
  outline: 0;
55
40
  }
56
- .pc-slider-new-block-arrow:hover .pc-slider-new-block-arrow__button {
41
+ .pc-slider-new-block-arrow__inner {
42
+ width: 42px;
43
+ height: 42px;
44
+ color: var(--g-color-text-secondary);
45
+ border-radius: 100%;
46
+ background-color: var(--g-color-base-background);
47
+ box-shadow: 0 4px 24px var(--pc-color-sfx-shadow), 0 2px 8px var(--pc-color-sfx-shadow);
48
+ transition: box-shadow 0.3s cubic-bezier(0.22, 0.61, 0.36, 1), color 1s cubic-bezier(0.22, 0.61, 0.36, 1);
49
+ }
50
+ .pc-slider-new-block-arrow__inner_type_left .pc-slider-new-block-arrow__icon-wrapper {
51
+ transform: rotate(180deg);
52
+ }
53
+ .pc-slider-new-block-arrow__inner:hover {
57
54
  color: var(--g-color-text-primary);
58
55
  box-shadow: 0 2px 12px var(--pc-color-sfx-shadow), 0 4px 24px var(--pc-color-sfx-shadow);
59
56
  }
57
+ .pc-slider-new-block-arrow__inner_transparent {
58
+ background-color: transparent;
59
+ box-shadow: none;
60
+ }
61
+ .pc-slider-new-block-arrow__inner_transparent:hover {
62
+ box-shadow: none;
63
+ }
60
64
  .pc-slider-new-block-arrow__icon {
61
65
  position: relative;
62
66
  }
@@ -1,10 +1,13 @@
1
+ import React from 'react';
1
2
  import { ClassNameProps } from '../../../models';
2
3
  import './Arrow.css';
3
4
  export type ArrowType = 'left' | 'right';
4
5
  export interface ArrowProps {
5
6
  type: ArrowType;
7
+ transparent?: boolean;
6
8
  onClick?: () => void;
7
9
  size?: number;
10
+ extraProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;
8
11
  }
9
- declare const Arrow: ({ type, onClick, className, size }: ArrowProps & ClassNameProps) => JSX.Element;
12
+ declare const Arrow: ({ type, transparent, onClick, className, size, extraProps, }: ArrowProps & ClassNameProps) => JSX.Element;
10
13
  export default Arrow;
@@ -4,8 +4,9 @@ import { block } from '../../../utils';
4
4
  import { i18n } from '../i18n';
5
5
  import './Arrow.css';
6
6
  const b = block('slider-new-block-arrow');
7
- const Arrow = ({ type, onClick, className, size = 16 }) => (React.createElement("div", { className: b({ type }, className) },
8
- React.createElement("button", { className: b('button'), onClick: onClick, "aria-label": i18n(`arrow-${type}`) },
9
- React.createElement("span", { className: b('icon-wrapper') },
10
- React.createElement(ToggleArrow, { size: size, type: 'horizontal', iconType: "navigation", className: b('icon') })))));
7
+ const Arrow = ({ type, transparent, onClick, className, size = 16, extraProps, }) => (React.createElement("div", { className: b(null, className) },
8
+ React.createElement("button", Object.assign({ className: b('button'), onClick: onClick, "aria-label": i18n(`arrow-${type}`) }, extraProps),
9
+ React.createElement("div", { className: b('inner', { type, transparent }) },
10
+ React.createElement("span", { className: b('icon-wrapper') },
11
+ React.createElement(ToggleArrow, { size: size, type: 'horizontal', iconType: "navigation", className: b('icon') }))))));
11
12
  export default Arrow;
@@ -27,6 +27,14 @@ unpredictable css rules order in build */
27
27
  .pc-SliderNewBlock__slide.swiper-slide.swiper-slide-visible {
28
28
  animation: safari-fix 300ms;
29
29
  }
30
+ .pc-SliderNewBlock__slide.swiper-slide .pc-SliderNewBlock__slide-item {
31
+ width: 100%;
32
+ height: 100%;
33
+ }
34
+ .pc-SliderNewBlock .pc-SliderNewBlock__slide-item {
35
+ width: 100%;
36
+ height: 100%;
37
+ }
30
38
  .pc-SliderNewBlock__arrow {
31
39
  position: absolute;
32
40
  top: -2px;
@@ -48,6 +56,7 @@ unpredictable css rules order in build */
48
56
  background-color: var(--g-color-line-generic-accent);
49
57
  cursor: pointer;
50
58
  display: inline-block;
59
+ transition: background-color 1s;
51
60
  }
52
61
  .pc-SliderNewBlock__dot:hover {
53
62
  background-color: var(--g-color-line-generic-accent-hover);
@@ -712,7 +721,7 @@ unpredictable css rules order in build */
712
721
  padding: 0;
713
722
  }
714
723
  @media (max-width: 577px) {
715
- .pc-SliderNewBlock_type_media-card:not(.pc-SliderNewBlock_type_media-card_one-slide) {
724
+ .pc-SliderNewBlock_type_media-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) {
716
725
  margin-left: 0;
717
726
  padding-left: 0;
718
727
  width: 100%;
@@ -747,7 +756,7 @@ unpredictable css rules order in build */
747
756
  padding-top: 0;
748
757
  }
749
758
  @media (max-width: 577px) {
750
- .pc-SliderNewBlock_type_header-card:not(.pc-SliderNewBlock_type_header-card_one-slide) {
759
+ .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) {
751
760
  margin-left: 0;
752
761
  padding-left: 0;
753
762
  width: 100%;
@@ -775,32 +784,109 @@ unpredictable css rules order in build */
775
784
  left: 0;
776
785
  margin-right: 0;
777
786
  }
778
- .pc-SliderNewBlock_type_header-card .pc-SliderNewBlock__arrow button {
779
- background-color: transparent;
780
- box-shadow: none;
787
+ .pc-SliderNewBlock_type_header-card:has(.swiper-slide-active .pc-header-block_controls-view_light) .pc-slider-new-block-arrow__inner {
788
+ color: var(--g-color-text-dark-primary);
789
+ }
790
+ .pc-SliderNewBlock_type_header-card:has(.swiper-slide-active .pc-header-block_controls-view_light) .pc-SliderNewBlock__dot {
791
+ background-color: var(--g-color-private-black-150);
792
+ }
793
+ .pc-SliderNewBlock_type_header-card:has(.swiper-slide-active .pc-header-block_controls-view_light) .pc-SliderNewBlock__dot_active {
794
+ background-color: var(--g-color-private-black-300);
781
795
  }
782
- .pc-SliderNewBlock_type_header-card .pc-SliderNewBlock__arrow button:hover {
783
- box-shadow: none;
796
+ .pc-SliderNewBlock_type_header-card:has(.swiper-slide-active .pc-header-block_controls-view_dark) .pc-slider-new-block-arrow__inner {
797
+ color: var(--g-color-text-light-primary);
784
798
  }
785
- .pc-SliderNewBlock_type_header-card .pc-SliderNewBlock__arrow:hover button {
786
- box-shadow: none;
799
+ .pc-SliderNewBlock_type_header-card:has(.swiper-slide-active .pc-header-block_controls-view_dark) .pc-SliderNewBlock__dot {
800
+ background-color: var(--g-color-private-white-150);
801
+ }
802
+ .pc-SliderNewBlock_type_header-card:has(.swiper-slide-active .pc-header-block_controls-view_dark) .pc-SliderNewBlock__dot_active {
803
+ background-color: var(--g-color-private-white-300);
787
804
  }
788
805
  .pc-SliderNewBlock_type_header-card .pc-SliderNewBlock__slide {
789
806
  padding: 0;
790
807
  }
808
+ @media (max-width: 769px) {
809
+ .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) {
810
+ margin-left: -8px;
811
+ padding-left: 0;
812
+ width: calc(100% + 8px);
813
+ }
814
+ }
791
815
  @media (max-width: 577px) {
792
816
  .pc-SliderNewBlock_type_header-card .pc-SliderNewBlock__arrow {
793
817
  display: none;
794
818
  }
795
- .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_type_header-card_one-slide) .pc-SliderNewBlock__slider {
819
+ .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) .pc-SliderNewBlock__slider {
796
820
  margin-left: 0;
797
821
  }
798
- .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_type_header-card_one-slide) .pc-SliderNewBlock__slide {
799
- padding-right: 0;
822
+ .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) .swiper-wrapper {
800
823
  padding-left: 0;
801
824
  }
802
- .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_type_header-card_one-slide) .pc-SliderNewBlock__slide:last-child {
825
+ .pc-SliderNewBlock_type_header-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) .pc-SliderNewBlock__slide {
803
826
  padding-right: 0;
827
+ padding-left: 0;
828
+ }
829
+ }
830
+ .pc-SliderNewBlock_type_fullscreen-card {
831
+ padding-top: 0;
832
+ }
833
+ @media (max-width: 577px) {
834
+ .pc-SliderNewBlock_type_fullscreen-card.pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) {
835
+ margin-left: 0;
836
+ padding-left: 0;
837
+ width: 100%;
838
+ overflow: inherit;
839
+ }
840
+ }
841
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__slider {
842
+ padding: 24px 0 40px;
843
+ height: 100vh;
844
+ margin: 0;
845
+ }
846
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__slider .swiper-pagination {
847
+ bottom: 11px;
848
+ }
849
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__slider .pc-SliderNewBlock__dot {
850
+ background-color: var(--g-color-text-light-hint);
851
+ }
852
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__slider .pc-SliderNewBlock__dot_active {
853
+ background-color: var(--g-color-text-light-primary);
854
+ }
855
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__slider .pc-SliderNewBlock__slide {
856
+ height: 100%;
857
+ padding: 0 120px;
858
+ }
859
+ .pc-SliderNewBlock_type_fullscreen-card:hover .pc-SliderNewBlock__arrow {
860
+ display: flex;
861
+ }
862
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__arrow {
863
+ display: none;
864
+ width: 120px;
865
+ top: 40px;
866
+ bottom: 40px;
867
+ }
868
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__arrow_prev {
869
+ left: 0;
870
+ margin-right: 0;
871
+ }
872
+ @media (max-width: 769px) {
873
+ .pc-SliderNewBlock_type_fullscreen-card {
874
+ margin-left: 0;
875
+ }
876
+ .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock_slider {
877
+ margin-left: 0;
878
+ width: 100%;
879
+ }
880
+ .pc-SliderNewBlock_type_fullscreen-card:hover .pc-SliderNewBlock__arrow {
881
+ display: none;
882
+ }
883
+ }
884
+ @media (max-width: 577px) {
885
+ .pc-SliderNewBlock_type_fullscreen-card:not(.pc-SliderNewBlock_one-slide) .pc-SliderNewBlock__slider {
886
+ margin-left: 0;
887
+ }
888
+ .pc-SliderNewBlock_type_fullscreen-card:not(.pc-SliderNewBlock_one-slide) .swiper-wrapper {
889
+ padding-left: 0;
804
890
  }
805
891
  }
806
892
  @media (max-width: 769px) {
@@ -821,8 +907,11 @@ unpredictable css rules order in build */
821
907
  overflow-x: auto;
822
908
  }
823
909
  .pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) .pc-SliderNewBlock__slider {
824
- padding: 24px 24px 48px;
825
- margin: 0 0 0 -24px;
910
+ margin-left: -24px;
911
+ margin-right: 0;
912
+ }
913
+ .pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) .swiper-wrapper {
914
+ padding-left: 16px;
826
915
  }
827
916
  .pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) .pc-SliderNewBlock__slide {
828
917
  padding: 0 8px;
@@ -9,6 +9,7 @@ export interface SliderNewProps extends Omit<SliderParams, 'children'>, Partial<
9
9
  dotsClassName?: string;
10
10
  blockClassName?: string;
11
11
  arrowSize?: number;
12
+ initialSlide?: number;
12
13
  }
13
- export declare const SliderNewBlock: ({ animated, title, description, type, anchorId, arrows, adaptive, autoplay: autoplayMs, dots, className, dotsClassName, disclaimer, children, blockClassName, arrowSize, slidesToShow, onSlideChange, onSlideChangeTransitionStart, onSlideChangeTransitionEnd, onActiveIndexChange, onBreakpoint, }: PropsWithChildren<SliderNewProps>) => JSX.Element;
14
+ export declare const SliderNewBlock: ({ animated, title, description, type, anchorId, arrows, adaptive, autoplay: autoplayMs, dots, initialSlide, className, dotsClassName, disclaimer, children, blockClassName, arrowSize, slidesToShow, onSlideChange, onSlideChangeTransitionStart, onSlideChangeTransitionEnd, onActiveIndexChange, onBreakpoint, }: PropsWithChildren<SliderNewProps>) => JSX.Element;
14
15
  export default SliderNewBlock;
@@ -4,20 +4,33 @@ import { Swiper, SwiperSlide } from 'swiper/react';
4
4
  import Anchor from '../../components/Anchor/Anchor';
5
5
  import AnimateBlock from '../../components/AnimateBlock/AnimateBlock';
6
6
  import Title from '../../components/Title/Title';
7
+ import { SliderType } from '../../models';
7
8
  import { block } from '../../utils';
8
9
  import Arrow from './Arrow/Arrow';
10
+ import { i18n } from './i18n';
9
11
  import { useSlider } from './useSlider';
12
+ import { useSliderPagination } from './useSliderPagination';
10
13
  import './Slider.css';
11
14
  import 'swiper/swiper-bundle.css';
12
15
  const b = block('SliderNewBlock');
13
16
  SwiperCore.use([Autoplay, A11y, Pagination]);
14
- export const SliderNewBlock = ({ animated, title, description, type, anchorId, arrows = true, adaptive, autoplay: autoplayMs, dots = true, className, dotsClassName, disclaimer, children, blockClassName, arrowSize, slidesToShow, onSlideChange, onSlideChangeTransitionStart, onSlideChangeTransitionEnd, onActiveIndexChange, onBreakpoint, }) => {
15
- const { childrenCount, breakpoints, autoplay, onSwiper, onPrev, onNext, isLocked, setIsLocked } = useSlider({
17
+ export const SliderNewBlock = ({ animated, title, description, type, anchorId, arrows = true, adaptive, autoplay: autoplayMs, dots = true, initialSlide = 0, className, dotsClassName, disclaimer, children, blockClassName, arrowSize, slidesToShow, onSlideChange, onSlideChangeTransitionStart, onSlideChangeTransitionEnd, onActiveIndexChange, onBreakpoint, }) => {
18
+ const { autoplay, isLocked, childrenCount, breakpoints, onSwiper, onPrev, onNext, setIsLocked } = useSlider({
16
19
  slidesToShow,
17
20
  children,
18
21
  type,
19
22
  autoplayMs,
20
23
  });
24
+ const isA11yControlHidden = Boolean(autoplay);
25
+ const controlTabIndex = isA11yControlHidden ? -1 : 0;
26
+ const paginationProps = useSliderPagination({
27
+ enabled: dots,
28
+ isA11yControlHidden,
29
+ controlTabIndex,
30
+ bulletClass: b('dot', dotsClassName),
31
+ bulletActiveClass: b('dot_active'),
32
+ paginationLabel: i18n('pagination-label'),
33
+ });
21
34
  return (React.createElement("div", { className: b({
22
35
  'one-slide': childrenCount === 1,
23
36
  'only-arrows': !(title === null || title === void 0 ? void 0 : title.text) && !description && arrows,
@@ -27,14 +40,14 @@ export const SliderNewBlock = ({ animated, title, description, type, anchorId, a
27
40
  anchorId && React.createElement(Anchor, { id: anchorId }),
28
41
  React.createElement(Title, { title: title, subtitle: description, className: b('header', { 'no-description': !description }) }),
29
42
  React.createElement(AnimateBlock, { className: b('animate-slides'), animate: animated },
30
- React.createElement(Swiper, { className: b('slider', className), onSwiper: onSwiper, pagination: dots && {
31
- clickable: true,
32
- bulletClass: b('dot', dotsClassName),
33
- bulletActiveClass: b('dot_active'),
34
- }, speed: 1000, autoplay: autoplay, autoHeight: adaptive, initialSlide: 0, noSwiping: false, breakpoints: breakpoints, onSlideChange: onSlideChange, onSlideChangeTransitionStart: onSlideChangeTransitionStart, onSlideChangeTransitionEnd: onSlideChangeTransitionEnd, onActiveIndexChange: onActiveIndexChange, onBreakpoint: onBreakpoint, onLock: () => setIsLocked(true), onUnlock: () => setIsLocked(false), watchSlidesVisibility: true, watchOverflow: true }, React.Children.map(children, (elem, index) => (React.createElement(SwiperSlide, { className: b('slide'), key: index }, elem)))),
43
+ React.createElement(Swiper, Object.assign({ className: b('slider', className), onSwiper: onSwiper, speed: 1000, autoplay: autoplay, autoHeight: adaptive, initialSlide: initialSlide, noSwiping: false, breakpoints: breakpoints, onSlideChange: onSlideChange, onSlideChangeTransitionStart: onSlideChangeTransitionStart, onSlideChangeTransitionEnd: onSlideChangeTransitionEnd, onActiveIndexChange: onActiveIndexChange, onBreakpoint: onBreakpoint, onLock: () => setIsLocked(true), onUnlock: () => setIsLocked(false), watchSlidesVisibility: true, watchOverflow: true, a11y: {
44
+ slideLabelMessage: '',
45
+ paginationBulletMessage: i18n('dot-label', { index: '{{index}}' }),
46
+ } }, paginationProps), React.Children.map(children, (elem, index) => (React.createElement(SwiperSlide, { className: b('slide'), key: index }, ({ isVisible }) => (React.createElement("div", { className: b('slide-item'), "aria-hidden": !isA11yControlHidden && !isVisible }, elem)))))),
35
47
  arrows && !isLocked && (React.createElement(Fragment, null,
36
- React.createElement(Arrow, { className: b('arrow', { prev: true }), type: "left", onClick: onPrev, size: arrowSize }),
37
- React.createElement(Arrow, { className: b('arrow', { next: true }), type: "right", onClick: onNext, size: arrowSize }))),
48
+ React.createElement("div", { "aria-hidden": isA11yControlHidden },
49
+ React.createElement(Arrow, { className: b('arrow', { prev: true }), type: "left", transparent: type === SliderType.HeaderCard, onClick: onPrev, size: arrowSize, extraProps: { tabIndex: controlTabIndex } }),
50
+ React.createElement(Arrow, { className: b('arrow', { next: true }), type: "right", transparent: type === SliderType.HeaderCard, onClick: onNext, size: arrowSize, extraProps: { tabIndex: controlTabIndex } })))),
38
51
  React.createElement("div", { className: b('footer') }, disclaimer ? (React.createElement("div", { className: b('disclaimer', { size: (disclaimer === null || disclaimer === void 0 ? void 0 : disclaimer.size) || 'm' }) }, disclaimer === null || disclaimer === void 0 ? void 0 : disclaimer.text)) : null))));
39
52
  };
40
53
  export default SliderNewBlock;
@@ -1,4 +1,6 @@
1
1
  {
2
2
  "arrow-right": "Next",
3
- "arrow-left": "Previous"
3
+ "arrow-left": "Previous",
4
+ "dot-label": "Page {{index}}",
5
+ "pagination-label": "Pages"
4
6
  }
@@ -1 +1 @@
1
- export declare const i18n: (key: "arrow-right" | "arrow-left", params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ export declare const i18n: (key: "arrow-right" | "arrow-left" | "dot-label" | "pagination-label", params?: import("@gravity-ui/i18n").Params | undefined) => string;
@@ -1,4 +1,6 @@
1
1
  {
2
2
  "arrow-right": "Дальше",
3
- "arrow-left": "Назад"
3
+ "arrow-left": "Назад",
4
+ "dot-label": "Страница {{index}}",
5
+ "pagination-label": "Страницы"
4
6
  }
@@ -1,11 +1,12 @@
1
1
  import React, { PropsWithChildren } from 'react';
2
2
  import type { Swiper } from 'swiper';
3
3
  import { SlidesToShow } from '../../models';
4
- export declare const useSlider: ({ children, autoplayMs, type, slidesToShow, }: React.PropsWithChildren<{
5
- autoplayMs?: number | undefined;
6
- type?: string | undefined;
7
- slidesToShow?: SlidesToShow | undefined;
8
- }>) => {
4
+ type UseSliderProps = PropsWithChildren<{
5
+ autoplayMs?: number;
6
+ type?: string;
7
+ slidesToShow?: SlidesToShow;
8
+ }>;
9
+ export declare const useSlider: ({ children, autoplayMs, type, ...props }: UseSliderProps) => {
9
10
  slider: Swiper | undefined;
10
11
  onSwiper: React.Dispatch<React.SetStateAction<Swiper | undefined>>;
11
12
  onNext: () => void;
@@ -15,7 +16,8 @@ export declare const useSlider: ({ children, autoplayMs, type, slidesToShow, }:
15
16
  isLocked: boolean;
16
17
  setIsLocked: React.Dispatch<React.SetStateAction<boolean>>;
17
18
  autoplay: false | {
18
- delay: number | undefined;
19
+ delay: number;
19
20
  disableOnInteraction: boolean;
20
21
  };
21
22
  };
23
+ export {};
@@ -1,11 +1,14 @@
1
+ import { __rest } from "tslib";
1
2
  import React, { useEffect, useMemo, useState } from 'react';
2
3
  import { SliderType } from '../../models';
3
- import { getSliderResponsiveParams } from './utils';
4
- export const useSlider = ({ children, autoplayMs, type, slidesToShow, }) => {
4
+ import { getSliderResponsiveParams, useMemoized } from './utils';
5
+ export const useSlider = (_a) => {
6
+ var { children, autoplayMs, type } = _a, props = __rest(_a, ["children", "autoplayMs", "type"]);
5
7
  const [slider, setSlider] = useState();
6
8
  const [isLocked, setIsLocked] = useState(false);
9
+ const slidesToShow = useMemoized(props.slidesToShow);
7
10
  const childrenCount = React.Children.count(children);
8
- const autoplayEnabled = useMemo(() => Boolean(autoplayMs), [autoplayMs]);
11
+ const autoplayEnabled = autoplayMs !== undefined && autoplayMs > 0;
9
12
  const breakpoints = useMemo(() => {
10
13
  return getSliderResponsiveParams({
11
14
  contentLength: childrenCount,
@@ -0,0 +1,9 @@
1
+ import { Swiper as SwiperProps } from 'swiper/swiper-react';
2
+ export declare const useSliderPagination: (props: {
3
+ enabled: boolean;
4
+ isA11yControlHidden: boolean;
5
+ controlTabIndex: number;
6
+ bulletClass: string;
7
+ bulletActiveClass: string;
8
+ paginationLabel: string;
9
+ }) => Pick<SwiperProps, 'pagination' | 'onPaginationUpdate'> | undefined;
@@ -0,0 +1,32 @@
1
+ import { setElementAtrributes } from './utils';
2
+ export const useSliderPagination = (props) => {
3
+ if (!props.enabled) {
4
+ return undefined;
5
+ }
6
+ const { isA11yControlHidden, controlTabIndex, bulletClass, bulletActiveClass, paginationLabel } = props;
7
+ return {
8
+ pagination: {
9
+ clickable: true,
10
+ bulletClass,
11
+ bulletActiveClass,
12
+ },
13
+ onPaginationUpdate: (slider) => {
14
+ const pagination = slider.pagination.el;
15
+ setElementAtrributes(pagination, {
16
+ role: 'menu',
17
+ 'aria-hidden': isA11yControlHidden,
18
+ 'aria-label': paginationLabel,
19
+ });
20
+ const bullets = pagination.querySelectorAll(`.${bulletClass}`);
21
+ bullets.forEach((bullet) => {
22
+ const isActive = bullet.classList.contains(bulletActiveClass);
23
+ setElementAtrributes(bullet, {
24
+ role: 'menuitemradio',
25
+ 'aria-hidden': isA11yControlHidden,
26
+ 'aria-checked': isActive,
27
+ tabindex: controlTabIndex,
28
+ });
29
+ });
30
+ },
31
+ };
32
+ };
@@ -12,3 +12,5 @@ export interface GetSlidesToShowParams {
12
12
  mobileFullscreen?: boolean;
13
13
  }
14
14
  export declare function getSliderResponsiveParams({ contentLength, slidesToShow, mobileFullscreen, }: GetSlidesToShowParams): Record<number, SwiperOptions>;
15
+ export declare const useMemoized: <T>(value: T) => T;
16
+ export declare const setElementAtrributes: (element: Element, attributes: Record<string, unknown>) => void;
@@ -1,3 +1,5 @@
1
+ import { useEffect, useState } from 'react';
2
+ import isEqual from 'lodash/isEqual';
1
3
  import pickBy from 'lodash/pickBy';
2
4
  import { BREAKPOINTS } from '../../constants';
3
5
  import { SliderBreakpointNames } from './models';
@@ -24,3 +26,11 @@ export function getSliderResponsiveParams({ contentLength, slidesToShow, mobileF
24
26
  return res;
25
27
  }, {});
26
28
  }
29
+ export const useMemoized = (value) => {
30
+ const [memoizedValue, setMemoizedValue] = useState(value);
31
+ useEffect(() => {
32
+ setMemoizedValue((memoized) => value && typeof value === 'object' && isEqual(memoized, value) ? memoized : value);
33
+ }, [value]);
34
+ return memoizedValue;
35
+ };
36
+ export const setElementAtrributes = (element, attributes) => Object.entries(attributes).forEach(([attribute, value]) => element.setAttribute(attribute, String(value)));