@gravity-ui/page-constructor 5.18.1-alpha.2 → 5.18.1-alpha.3

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 (201) hide show
  1. package/build/cjs/blocks/Banner/Banner.js +2 -2
  2. package/build/cjs/blocks/CardLayout/schema.d.ts +32 -0
  3. package/build/cjs/blocks/ContentLayout/schema.d.ts +34 -6
  4. package/build/cjs/blocks/Header/Header.css +3 -0
  5. package/build/cjs/blocks/Header/Header.js +2 -1
  6. package/build/cjs/blocks/Header/schema.d.ts +30 -3
  7. package/build/cjs/blocks/HeaderSlider/schema.d.ts +11 -1
  8. package/build/cjs/blocks/Media/schema.d.ts +16 -2
  9. package/build/cjs/blocks/PromoFeaturesBlock/schema.d.ts +8 -1
  10. package/build/cjs/blocks/Slider/Arrow/Arrow.css +1 -1
  11. package/build/cjs/blocks/Slider/Slider.css +20 -1
  12. package/build/cjs/blocks/Slider/Slider.js +83 -29
  13. package/build/cjs/blocks/Slider/i18n/en.json +3 -1
  14. package/build/cjs/blocks/Slider/i18n/index.d.ts +1 -1
  15. package/build/cjs/blocks/Slider/i18n/ru.json +3 -1
  16. package/build/cjs/blocks/Slider/utils.d.ts +10 -0
  17. package/build/cjs/blocks/Slider/utils.js +85 -1
  18. package/build/cjs/blocks/SliderNew/Arrow/Arrow.d.ts +3 -1
  19. package/build/cjs/blocks/SliderNew/Arrow/Arrow.js +2 -2
  20. package/build/cjs/blocks/SliderNew/Slider.css +4 -1
  21. package/build/cjs/blocks/SliderNew/Slider.js +20 -8
  22. package/build/cjs/blocks/SliderNew/i18n/en.json +3 -1
  23. package/build/cjs/blocks/SliderNew/i18n/index.d.ts +1 -1
  24. package/build/cjs/blocks/SliderNew/i18n/ru.json +3 -1
  25. package/build/cjs/blocks/SliderNew/useSlider.d.ts +8 -6
  26. package/build/cjs/blocks/SliderNew/useSlider.js +4 -2
  27. package/build/cjs/blocks/SliderNew/useSliderPagination.d.ts +9 -0
  28. package/build/cjs/blocks/SliderNew/useSliderPagination.js +36 -0
  29. package/build/cjs/blocks/SliderNew/utils.d.ts +2 -0
  30. package/build/cjs/blocks/SliderNew/utils.js +13 -1
  31. package/build/cjs/blocks/Tabs/schema.d.ts +8 -1
  32. package/build/cjs/components/ButtonTabs/ButtonTabs.js +3 -2
  33. package/build/cjs/components/DefaultVideo/DefaultVideo.js +3 -3
  34. package/build/cjs/components/FullscreenImage/FullscreenImage.css +6 -2
  35. package/build/cjs/components/HeaderBreadcrumbs/HeaderBreadcrumbs.css +14 -11
  36. package/build/cjs/components/HeaderBreadcrumbs/HeaderBreadcrumbs.js +4 -2
  37. package/build/cjs/components/Image/Image.js +2 -2
  38. package/build/cjs/components/Image/schema.d.ts +40 -0
  39. package/build/cjs/components/Image/schema.js +8 -0
  40. package/build/cjs/components/ImageBase/ImageBase.d.ts +1 -1
  41. package/build/cjs/components/ImageBase/ImageBase.js +8 -2
  42. package/build/cjs/components/Media/Media.js +4 -3
  43. package/build/cjs/components/Media/Video/Video.js +2 -2
  44. package/build/cjs/components/ReactPlayer/ReactPlayer.css +7 -0
  45. package/build/cjs/components/ReactPlayer/ReactPlayer.d.ts +1 -0
  46. package/build/cjs/components/ReactPlayer/ReactPlayer.js +15 -4
  47. package/build/cjs/components/VideoBlock/VideoBlock.d.ts +1 -0
  48. package/build/cjs/components/VideoBlock/VideoBlock.js +24 -37
  49. package/build/cjs/constructor-items.d.ts +4 -4
  50. package/build/cjs/containers/PageConstructor/PageConstructor.js +3 -1
  51. package/build/cjs/context/imageContext/imageContext.d.ts +2 -3
  52. package/build/cjs/context/projectSettingsContext/ProjectSettingsContext.d.ts +1 -0
  53. package/build/cjs/editor/components/AddBlock/AddBlock.js +23 -6
  54. package/build/cjs/editor/data/index.d.ts +3 -2
  55. package/build/cjs/editor/data/index.js +19 -12
  56. package/build/cjs/models/constructor-items/common.d.ts +9 -4
  57. package/build/cjs/models/constructor-items/sub-blocks.d.ts +2 -1
  58. package/build/cjs/models/navigation.d.ts +8 -0
  59. package/build/cjs/navigation/components/DesktopNavigation/DesktopNavigation.css +42 -3
  60. package/build/cjs/navigation/components/DesktopNavigation/DesktopNavigation.d.ts +1 -1
  61. package/build/cjs/navigation/components/DesktopNavigation/DesktopNavigation.js +7 -2
  62. package/build/cjs/navigation/components/Logo/Logo.d.ts +1 -1
  63. package/build/cjs/navigation/components/Logo/Logo.js +3 -1
  64. package/build/cjs/navigation/components/MobileNavigation/MobileNavigation.d.ts +1 -1
  65. package/build/cjs/navigation/components/MobileNavigation/MobileNavigation.js +3 -1
  66. package/build/cjs/navigation/components/Navigation/Navigation.d.ts +2 -2
  67. package/build/cjs/navigation/components/Navigation/Navigation.js +5 -24
  68. package/build/cjs/navigation/components/NavigationItem/NavigationItem.d.ts +1 -1
  69. package/build/cjs/navigation/components/NavigationItem/NavigationItem.js +3 -1
  70. package/build/cjs/navigation/components/NavigationItem/hooks/useNavigationItemMap.d.ts +5 -5
  71. package/build/cjs/navigation/components/NavigationListItem/NavigationListItem.d.ts +1 -1
  72. package/build/cjs/navigation/components/NavigationListItem/NavigationListItem.js +3 -1
  73. package/build/cjs/navigation/components/Standalone/index.d.ts +2 -2
  74. package/build/cjs/navigation/containers/Layout/Layout.js +2 -1
  75. package/build/cjs/navigation/hooks/index.d.ts +2 -0
  76. package/build/cjs/navigation/hooks/index.js +10 -0
  77. package/build/cjs/navigation/hooks/useActiveNavItem.d.ts +26 -0
  78. package/build/cjs/navigation/hooks/useActiveNavItem.js +15 -0
  79. package/build/cjs/navigation/hooks/useShowBorder.d.ts +2 -0
  80. package/build/cjs/navigation/hooks/useShowBorder.js +21 -0
  81. package/build/cjs/navigation/index.d.ts +14 -0
  82. package/build/cjs/navigation/index.js +16 -4
  83. package/build/cjs/navigation/models.d.ts +1 -0
  84. package/build/cjs/schema/constants.d.ts +16 -1
  85. package/build/cjs/schema/validators/common.d.ts +14 -1
  86. package/build/cjs/schema/validators/common.js +8 -1
  87. package/build/cjs/sub-blocks/BackgroundCard/schema.d.ts +8 -0
  88. package/build/cjs/sub-blocks/BannerCard/BannerCard.js +3 -3
  89. package/build/cjs/sub-blocks/Content/Content.css +4 -4
  90. package/build/cjs/sub-blocks/HubspotForm/HubspotForm.css +8 -4
  91. package/build/cjs/sub-blocks/ImageCard/ImageCard.css +34 -1
  92. package/build/cjs/sub-blocks/ImageCard/ImageCard.js +1 -1
  93. package/build/cjs/sub-blocks/LayoutItem/schema.d.ts +8 -1
  94. package/build/cjs/sub-blocks/LayoutItem/utils.d.ts +1 -1
  95. package/build/cjs/sub-blocks/LayoutItem/utils.js +1 -1
  96. package/build/cjs/sub-blocks/MediaCard/schema.d.ts +8 -1
  97. package/build/cjs/text-transform/utils.js +1 -1
  98. package/build/esm/blocks/Banner/Banner.js +2 -2
  99. package/build/esm/blocks/CardLayout/schema.d.ts +32 -0
  100. package/build/esm/blocks/ContentLayout/schema.d.ts +34 -6
  101. package/build/esm/blocks/Header/Header.css +3 -0
  102. package/build/esm/blocks/Header/Header.js +2 -1
  103. package/build/esm/blocks/Header/schema.d.ts +30 -3
  104. package/build/esm/blocks/HeaderSlider/schema.d.ts +11 -1
  105. package/build/esm/blocks/Media/schema.d.ts +16 -2
  106. package/build/esm/blocks/PromoFeaturesBlock/schema.d.ts +8 -1
  107. package/build/esm/blocks/Slider/Arrow/Arrow.css +1 -1
  108. package/build/esm/blocks/Slider/Slider.css +20 -1
  109. package/build/esm/blocks/Slider/Slider.js +84 -30
  110. package/build/esm/blocks/Slider/i18n/en.json +3 -1
  111. package/build/esm/blocks/Slider/i18n/index.d.ts +1 -1
  112. package/build/esm/blocks/Slider/i18n/ru.json +3 -1
  113. package/build/esm/blocks/Slider/utils.d.ts +10 -0
  114. package/build/esm/blocks/Slider/utils.js +82 -0
  115. package/build/esm/blocks/SliderNew/Arrow/Arrow.d.ts +3 -1
  116. package/build/esm/blocks/SliderNew/Arrow/Arrow.js +2 -2
  117. package/build/esm/blocks/SliderNew/Slider.css +4 -1
  118. package/build/esm/blocks/SliderNew/Slider.js +20 -8
  119. package/build/esm/blocks/SliderNew/i18n/en.json +3 -1
  120. package/build/esm/blocks/SliderNew/i18n/index.d.ts +1 -1
  121. package/build/esm/blocks/SliderNew/i18n/ru.json +3 -1
  122. package/build/esm/blocks/SliderNew/useSlider.d.ts +8 -6
  123. package/build/esm/blocks/SliderNew/useSlider.js +6 -3
  124. package/build/esm/blocks/SliderNew/useSliderPagination.d.ts +9 -0
  125. package/build/esm/blocks/SliderNew/useSliderPagination.js +32 -0
  126. package/build/esm/blocks/SliderNew/utils.d.ts +2 -0
  127. package/build/esm/blocks/SliderNew/utils.js +10 -0
  128. package/build/esm/blocks/Tabs/schema.d.ts +8 -1
  129. package/build/esm/components/ButtonTabs/ButtonTabs.js +3 -2
  130. package/build/esm/components/DefaultVideo/DefaultVideo.js +3 -3
  131. package/build/esm/components/FullscreenImage/FullscreenImage.css +6 -2
  132. package/build/esm/components/HeaderBreadcrumbs/HeaderBreadcrumbs.css +14 -11
  133. package/build/esm/components/HeaderBreadcrumbs/HeaderBreadcrumbs.js +4 -2
  134. package/build/esm/components/Image/Image.js +2 -2
  135. package/build/esm/components/Image/schema.d.ts +40 -0
  136. package/build/esm/components/Image/schema.js +8 -0
  137. package/build/esm/components/ImageBase/ImageBase.d.ts +1 -1
  138. package/build/esm/components/ImageBase/ImageBase.js +9 -2
  139. package/build/esm/components/Media/Media.js +5 -4
  140. package/build/esm/components/Media/Video/Video.js +2 -2
  141. package/build/esm/components/ReactPlayer/ReactPlayer.css +7 -0
  142. package/build/esm/components/ReactPlayer/ReactPlayer.d.ts +1 -0
  143. package/build/esm/components/ReactPlayer/ReactPlayer.js +15 -4
  144. package/build/esm/components/VideoBlock/VideoBlock.d.ts +1 -0
  145. package/build/esm/components/VideoBlock/VideoBlock.js +25 -38
  146. package/build/esm/constructor-items.d.ts +4 -4
  147. package/build/esm/containers/PageConstructor/PageConstructor.js +4 -2
  148. package/build/esm/context/imageContext/imageContext.d.ts +2 -3
  149. package/build/esm/context/projectSettingsContext/ProjectSettingsContext.d.ts +1 -0
  150. package/build/esm/editor/components/AddBlock/AddBlock.js +24 -7
  151. package/build/esm/editor/data/index.d.ts +3 -2
  152. package/build/esm/editor/data/index.js +18 -12
  153. package/build/esm/models/constructor-items/common.d.ts +9 -4
  154. package/build/esm/models/constructor-items/sub-blocks.d.ts +2 -1
  155. package/build/esm/models/navigation.d.ts +8 -0
  156. package/build/esm/navigation/components/DesktopNavigation/DesktopNavigation.css +42 -3
  157. package/build/esm/navigation/components/DesktopNavigation/DesktopNavigation.d.ts +1 -1
  158. package/build/esm/navigation/components/DesktopNavigation/DesktopNavigation.js +4 -1
  159. package/build/esm/navigation/components/Logo/Logo.d.ts +1 -1
  160. package/build/esm/navigation/components/Logo/Logo.js +1 -1
  161. package/build/esm/navigation/components/MobileNavigation/MobileNavigation.d.ts +1 -1
  162. package/build/esm/navigation/components/MobileNavigation/MobileNavigation.js +1 -1
  163. package/build/esm/navigation/components/Navigation/Navigation.d.ts +2 -2
  164. package/build/esm/navigation/components/Navigation/Navigation.js +6 -25
  165. package/build/esm/navigation/components/NavigationItem/NavigationItem.d.ts +1 -1
  166. package/build/esm/navigation/components/NavigationItem/NavigationItem.js +1 -1
  167. package/build/esm/navigation/components/NavigationItem/hooks/useNavigationItemMap.d.ts +5 -5
  168. package/build/esm/navigation/components/NavigationListItem/NavigationListItem.d.ts +1 -1
  169. package/build/esm/navigation/components/NavigationListItem/NavigationListItem.js +1 -1
  170. package/build/esm/navigation/components/Standalone/index.d.ts +2 -2
  171. package/build/esm/navigation/containers/Layout/Layout.js +2 -1
  172. package/build/esm/navigation/hooks/index.d.ts +2 -0
  173. package/build/esm/navigation/hooks/index.js +2 -0
  174. package/build/esm/navigation/hooks/useActiveNavItem.d.ts +26 -0
  175. package/build/esm/navigation/hooks/useActiveNavItem.js +13 -0
  176. package/build/esm/navigation/hooks/useShowBorder.d.ts +2 -0
  177. package/build/esm/navigation/hooks/useShowBorder.js +19 -0
  178. package/build/esm/navigation/index.d.ts +14 -0
  179. package/build/esm/navigation/index.js +14 -0
  180. package/build/esm/navigation/models.d.ts +1 -0
  181. package/build/esm/schema/constants.d.ts +16 -1
  182. package/build/esm/schema/validators/common.d.ts +14 -1
  183. package/build/esm/schema/validators/common.js +8 -1
  184. package/build/esm/sub-blocks/BackgroundCard/schema.d.ts +8 -0
  185. package/build/esm/sub-blocks/BannerCard/BannerCard.js +3 -3
  186. package/build/esm/sub-blocks/Content/Content.css +4 -4
  187. package/build/esm/sub-blocks/HubspotForm/HubspotForm.css +8 -4
  188. package/build/esm/sub-blocks/ImageCard/ImageCard.css +34 -1
  189. package/build/esm/sub-blocks/ImageCard/ImageCard.js +1 -1
  190. package/build/esm/sub-blocks/LayoutItem/schema.d.ts +8 -1
  191. package/build/esm/sub-blocks/LayoutItem/utils.d.ts +1 -1
  192. package/build/esm/sub-blocks/LayoutItem/utils.js +1 -1
  193. package/build/esm/sub-blocks/MediaCard/schema.d.ts +8 -1
  194. package/build/esm/text-transform/utils.js +1 -1
  195. package/package.json +8 -5
  196. package/server/models/constructor-items/common.d.ts +9 -4
  197. package/server/models/constructor-items/sub-blocks.d.ts +2 -1
  198. package/server/models/navigation.d.ts +8 -0
  199. package/server/text-transform/utils.js +1 -1
  200. package/styles/variables.scss +1 -0
  201. package/widget/index.js +1 -1
@@ -165,6 +165,9 @@ export declare const HeaderSliderBlock: {
165
165
  ariaLabel: {
166
166
  type: string;
167
167
  };
168
+ contain: {
169
+ type: string;
170
+ };
168
171
  };
169
172
  } & {
170
173
  optionName: string;
@@ -366,11 +369,17 @@ export declare const HeaderSliderBlock: {
366
369
  ariaLabel: {
367
370
  type: string;
368
371
  };
372
+ contain: {
373
+ type: string;
374
+ };
369
375
  };
370
376
  };
371
377
  youtube: {
372
378
  type: string;
373
379
  };
380
+ videoIframe: {
381
+ type: string;
382
+ };
374
383
  parallax: {
375
384
  type: string;
376
385
  };
@@ -482,7 +491,8 @@ export declare const HeaderSliderBlock: {
482
491
  })[];
483
492
  };
484
493
  ratio: {
485
- type: string;
494
+ type: string[];
495
+ pattern: string;
486
496
  };
487
497
  iframe: {
488
498
  type: string;
@@ -156,11 +156,17 @@ export declare const Media: {
156
156
  ariaLabel: {
157
157
  type: string;
158
158
  };
159
+ contain: {
160
+ type: string;
161
+ };
159
162
  };
160
163
  };
161
164
  youtube: {
162
165
  type: string;
163
166
  };
167
+ videoIframe: {
168
+ type: string;
169
+ };
164
170
  parallax: {
165
171
  type: string;
166
172
  };
@@ -272,7 +278,8 @@ export declare const Media: {
272
278
  })[];
273
279
  };
274
280
  ratio: {
275
- type: string;
281
+ type: string[];
282
+ pattern: string;
276
283
  };
277
284
  iframe: {
278
285
  type: string;
@@ -779,11 +786,17 @@ export declare const MediaBlock: {
779
786
  ariaLabel: {
780
787
  type: string;
781
788
  };
789
+ contain: {
790
+ type: string;
791
+ };
782
792
  };
783
793
  };
784
794
  youtube: {
785
795
  type: string;
786
796
  };
797
+ videoIframe: {
798
+ type: string;
799
+ };
787
800
  parallax: {
788
801
  type: string;
789
802
  };
@@ -895,7 +908,8 @@ export declare const MediaBlock: {
895
908
  })[];
896
909
  };
897
910
  ratio: {
898
- type: string;
911
+ type: string[];
912
+ pattern: string;
899
913
  };
900
914
  iframe: {
901
915
  type: string;
@@ -172,11 +172,17 @@ export declare const PromoFeaturesItem: {
172
172
  ariaLabel: {
173
173
  type: string;
174
174
  };
175
+ contain: {
176
+ type: string;
177
+ };
175
178
  };
176
179
  };
177
180
  youtube: {
178
181
  type: string;
179
182
  };
183
+ videoIframe: {
184
+ type: string;
185
+ };
180
186
  parallax: {
181
187
  type: string;
182
188
  };
@@ -288,7 +294,8 @@ export declare const PromoFeaturesItem: {
288
294
  })[];
289
295
  };
290
296
  ratio: {
291
- type: string;
297
+ type: string[];
298
+ pattern: string;
292
299
  };
293
300
  iframe: {
294
301
  type: string;
@@ -47,7 +47,7 @@ unpredictable css rules order in build */
47
47
  border-radius: 100%;
48
48
  background-color: var(--g-color-base-background);
49
49
  box-shadow: 0 4px 24px var(--pc-color-sfx-shadow), 0 2px 8px var(--pc-color-sfx-shadow);
50
- 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);
50
+ 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);
51
51
  }
52
52
  .pc-slider-block-arrow__button:focus {
53
53
  outline: 2px solid var(--g-color-line-focus);
@@ -105,7 +105,7 @@ unpredictable css rules order in build */
105
105
  height: auto;
106
106
  }
107
107
  .pc-SliderBlock .slick-track .slick-slide > div {
108
- height: 100%;
108
+ display: flex;
109
109
  }
110
110
  .pc-SliderBlock .slick-arrow {
111
111
  position: absolute;
@@ -146,6 +146,7 @@ unpredictable css rules order in build */
146
146
  border-radius: 100%;
147
147
  background-color: var(--g-color-line-generic-accent);
148
148
  cursor: pointer;
149
+ transition: background-color 1s;
149
150
  }
150
151
  .pc-SliderBlock__dot:hover {
151
152
  background-color: var(--g-color-line-generic-accent-hover);
@@ -606,6 +607,24 @@ unpredictable css rules order in build */
606
607
  .pc-SliderBlock_type_header-card .slick-arrow:hover button {
607
608
  box-shadow: none;
608
609
  }
610
+ .pc-SliderBlock_type_header-card:has(.slick-active .pc-header-block_controls-view_light) .pc-slider-block-arrow__button {
611
+ color: var(--g-color-text-dark-primary);
612
+ }
613
+ .pc-SliderBlock_type_header-card:has(.slick-active .pc-header-block_controls-view_light) .pc-SliderBlock__dot {
614
+ background-color: var(--g-color-private-black-150);
615
+ }
616
+ .pc-SliderBlock_type_header-card:has(.slick-active .pc-header-block_controls-view_light) .pc-SliderBlock__dot_active {
617
+ background-color: var(--g-color-private-black-300);
618
+ }
619
+ .pc-SliderBlock_type_header-card:has(.slick-active .pc-header-block_controls-view_dark) .pc-slider-block-arrow__button {
620
+ color: var(--g-color-text-light-primary);
621
+ }
622
+ .pc-SliderBlock_type_header-card:has(.slick-active .pc-header-block_controls-view_dark) .pc-SliderBlock__dot {
623
+ background-color: var(--g-color-private-white-150);
624
+ }
625
+ .pc-SliderBlock_type_header-card:has(.slick-active .pc-header-block_controls-view_dark) .pc-SliderBlock__dot_active {
626
+ background-color: var(--g-color-private-white-300);
627
+ }
609
628
  .pc-SliderBlock_type_header-card .slick-slide {
610
629
  padding: 0;
611
630
  }
@@ -1,4 +1,5 @@
1
1
  import React, { Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
2
+ import { useUniqId } from '@gravity-ui/uikit';
2
3
  import debounce from 'lodash/debounce';
3
4
  import get from 'lodash/get';
4
5
  import noop from 'lodash/noop';
@@ -15,7 +16,8 @@ import useFocus from '../../hooks/useFocus';
15
16
  import { SliderType, } from '../../models';
16
17
  import { block } from '../../utils';
17
18
  import Arrow from './Arrow/Arrow';
18
- import { getSliderResponsiveParams, getSlidesCountByBreakpoint, getSlidesToShowCount, getSlidesToShowWithDefaults, } from './utils';
19
+ import { i18n } from './i18n';
20
+ import { getSliderResponsiveParams, getSlidesCountByBreakpoint, getSlidesToShowCount, getSlidesToShowWithDefaults, isFocusable, useRovingTabIndex, } from './utils';
19
21
  import './Slider.css';
20
22
  const b = block('SliderBlock');
21
23
  const slick = block('slick-origin');
@@ -23,12 +25,15 @@ const DOT_WIDTH = 8;
23
25
  const DOT_GAP = 16;
24
26
  export const SliderBlock = (props) => {
25
27
  var _a;
26
- const { animated, title, description, type, anchorId, arrows = true, adaptive, autoplay = undefined, dots = true, dotsClassName, disclaimer, children, className, blockClassName, lazyLoad, arrowSize, onAfterChange: handleAfterChange, onBeforeChange: handleBeforeChange, initialIndex = 0, } = props;
28
+ const { animated, title, description, type, anchorId, arrows = true, adaptive, autoplay: autoplaySpeed, dots = true, dotsClassName, disclaimer, children, className, blockClassName, lazyLoad, arrowSize, onAfterChange: handleAfterChange, onBeforeChange: handleBeforeChange, initialIndex = 0, } = props;
27
29
  const { isServer } = useContext(SSRContext);
28
30
  const isMobile = useContext(MobileContext);
29
31
  const [breakpoint, setBreakpoint] = useState(BREAKPOINTS.xl);
30
- const disclosedChildren = useMemo(() => discloseAllNestedChildren(children), [children]);
32
+ const sliderId = useUniqId();
33
+ const disclosedChildren = useMemo(() => discloseAllNestedChildren(children, sliderId), [children, sliderId]);
31
34
  const childrenCount = disclosedChildren.length;
35
+ const isAutoplayEnabled = autoplaySpeed !== undefined && autoplaySpeed > 0;
36
+ const isUserInteractionRef = useRef(false);
32
37
  const [slidesToShow] = useState(getSlidesToShowWithDefaults({
33
38
  contentLength: childrenCount,
34
39
  breakpoints: props.slidesToShow,
@@ -39,8 +44,13 @@ export const SliderBlock = (props) => {
39
44
  const [currentIndex, setCurrentIndex] = useState(initialIndex);
40
45
  const [childStyles, setChildStyles] = useState({});
41
46
  const [slider, setSlider] = useState();
47
+ const prevIndexRef = useRef(0);
42
48
  const autoplayTimeId = useRef();
43
49
  const { hasFocus, unsetFocus } = useFocus((_a = slider === null || slider === void 0 ? void 0 : slider.innerSlider) === null || _a === void 0 ? void 0 : _a.list);
50
+ const asUserInteraction = (fn) => (...args) => {
51
+ isUserInteractionRef.current = true;
52
+ return fn(...args);
53
+ };
44
54
  // eslint-disable-next-line react-hooks/exhaustive-deps
45
55
  const onResize = useCallback(debounce(() => {
46
56
  if (!slider) {
@@ -55,7 +65,7 @@ export const SliderBlock = (props) => {
55
65
  }, 100), [slider, breakpoint]);
56
66
  const scrollLastSlide = useCallback((current) => {
57
67
  const lastSlide = childrenCount - slidesToShowCount;
58
- if (autoplay && lastSlide === current) {
68
+ if (isAutoplayEnabled && lastSlide === current) {
59
69
  // Slick doesn't support autoplay with no infinity scroll
60
70
  autoplayTimeId.current = setTimeout(() => {
61
71
  if (slider) {
@@ -67,9 +77,9 @@ export const SliderBlock = (props) => {
67
77
  slider.slickPlay();
68
78
  }
69
79
  }, 500);
70
- }, autoplay);
80
+ }, autoplaySpeed);
71
81
  }
72
- }, [autoplay, childrenCount, slider, slidesToShowCount]);
82
+ }, [autoplaySpeed, childrenCount, isAutoplayEnabled, slider, slidesToShowCount]);
73
83
  useEffect(() => {
74
84
  if (hasFocus && autoplayTimeId.current) {
75
85
  clearTimeout(autoplayTimeId.current);
@@ -83,7 +93,7 @@ export const SliderBlock = (props) => {
83
93
  window.addEventListener('resize', onResize, { passive: true });
84
94
  return () => window.removeEventListener('resize', onResize);
85
95
  }, [onResize]);
86
- const handleArrowClick = useCallback((direction) => {
96
+ const handleArrowClick = (direction) => {
87
97
  let nextIndex;
88
98
  if (direction === 'right') {
89
99
  nextIndex =
@@ -96,11 +106,12 @@ export const SliderBlock = (props) => {
96
106
  if (slider) {
97
107
  slider.slickGoTo(nextIndex);
98
108
  }
99
- }, [childrenCount, currentIndex, slider, slidesCountByBreakpoint]);
109
+ };
100
110
  const onBeforeChange = useCallback((current, next) => {
101
111
  if (handleBeforeChange) {
102
112
  handleBeforeChange(current, next);
103
113
  }
114
+ prevIndexRef.current = current;
104
115
  setCurrentIndex(Math.ceil(next));
105
116
  }, [handleBeforeChange]);
106
117
  const onAfterChange = useCallback((current) => {
@@ -113,16 +124,33 @@ export const SliderBlock = (props) => {
113
124
  if (!hasFocus) {
114
125
  scrollLastSlide(current);
115
126
  }
116
- }, [handleAfterChange, hasFocus, scrollLastSlide]);
117
- const handleDotClick = useCallback((index) => {
127
+ if (isUserInteractionRef.current) {
128
+ const focusIndex = prevIndexRef.current >= current
129
+ ? current
130
+ : Math.max(current, prevIndexRef.current + slidesCountByBreakpoint);
131
+ const firstNewSlide = document.getElementById(getSlideId(sliderId, focusIndex));
132
+ if (firstNewSlide) {
133
+ const focusableChild = Array.from(firstNewSlide.querySelectorAll('*')).find(isFocusable);
134
+ focusableChild === null || focusableChild === void 0 ? void 0 : focusableChild.focus();
135
+ }
136
+ }
137
+ isUserInteractionRef.current = false;
138
+ }, [handleAfterChange, hasFocus, scrollLastSlide, sliderId, slidesCountByBreakpoint]);
139
+ const handleDotClick = (index) => {
118
140
  const nextIndex = index > currentIndex ? index + 1 - slidesCountByBreakpoint : index;
119
141
  if (slider) {
120
142
  slider.slickGoTo(nextIndex);
121
143
  }
122
- }, [slider, currentIndex, slidesCountByBreakpoint]);
123
- const barSlidesCount = childrenCount - slidesToShowCount + 1;
144
+ };
145
+ const barSlidesCount = childrenCount - slidesCountByBreakpoint + 1;
124
146
  const barPosition = (DOT_GAP + DOT_WIDTH) * currentIndex;
125
147
  const barWidth = DOT_WIDTH + (DOT_GAP + DOT_WIDTH) * (slidesCountByBreakpoint - 1);
148
+ const { getRovingItemProps, rovingListProps } = useRovingTabIndex({
149
+ itemCount: barSlidesCount,
150
+ activeIndex: currentIndex + 1,
151
+ firstIndex: 1,
152
+ uniqId: sliderId,
153
+ });
126
154
  const renderBar = () => {
127
155
  return (slidesCountByBreakpoint > 1 && (React.createElement("li", { className: b('bar'), style: {
128
156
  left: barPosition,
@@ -133,19 +161,22 @@ export const SliderBlock = (props) => {
133
161
  const renderAccessibleBar = (index) => {
134
162
  return (
135
163
  // To have this key differ from keys used in renderDot function, added `-accessible-bar` part
136
- React.createElement(Fragment, { key: `${index}-accessible-bar` }, slidesCountByBreakpoint > 0 && (React.createElement("li", { className: b('accessible-bar'), "aria-current": true, "aria-label": `Slide ${currentIndex + 1} of ${barSlidesCount}`, style: {
164
+ React.createElement(Fragment, { key: `${index}-accessible-bar` }, slidesCountByBreakpoint > 0 && (React.createElement("li", Object.assign({ className: b('accessible-bar'), role: "menuitemradio", "aria-checked": true, "aria-label": i18n('dot-label', {
165
+ index: currentIndex + 1,
166
+ count: barSlidesCount,
167
+ }), style: {
137
168
  left: barPosition,
138
169
  width: barWidth,
139
- } }))));
170
+ } }, getRovingItemProps(currentIndex + 1))))));
140
171
  };
141
172
  const getCurrentSlideNumber = (index) => {
142
173
  const currentIndexDiff = index - currentIndex;
143
174
  let currentSlideNumber;
144
- if (0 <= currentIndexDiff && currentIndexDiff < slidesToShowCount) {
175
+ if (0 <= currentIndexDiff && currentIndexDiff < slidesCountByBreakpoint) {
145
176
  currentSlideNumber = currentIndex + 1;
146
177
  }
147
- else if (currentIndexDiff >= slidesToShowCount) {
148
- currentSlideNumber = index - slidesToShowCount + 2;
178
+ else if (currentIndexDiff >= slidesCountByBreakpoint) {
179
+ currentSlideNumber = index - slidesCountByBreakpoint + 2;
149
180
  }
150
181
  else {
151
182
  currentSlideNumber = index + 1;
@@ -154,12 +185,24 @@ export const SliderBlock = (props) => {
154
185
  };
155
186
  const isVisibleSlide = (index) => {
156
187
  const currentIndexDiff = index - currentIndex;
157
- return (slidesCountByBreakpoint > 0 &&
188
+ const result = slidesCountByBreakpoint > 0 &&
158
189
  0 <= currentIndexDiff &&
159
- currentIndexDiff < slidesToShowCount);
190
+ currentIndexDiff < slidesCountByBreakpoint;
191
+ return result;
160
192
  };
161
193
  const renderDot = (index) => {
162
- return (React.createElement("li", { key: index, className: b('dot', { active: index === currentIndex }), onClick: () => handleDotClick(index), "aria-hidden": isVisibleSlide(index) ? true : undefined, "aria-label": `Slide ${getCurrentSlideNumber(index)} of ${barSlidesCount}` }));
194
+ const isVisible = isVisibleSlide(index);
195
+ const currentSlideNumber = getCurrentSlideNumber(index);
196
+ const rovingItemProps = isVisible ? undefined : getRovingItemProps(currentSlideNumber);
197
+ return (React.createElement("li", Object.assign({ key: index, className: b('dot', { active: index === currentIndex }), onClick: asUserInteraction(() => handleDotClick(index)), onKeyDown: (e) => {
198
+ const key = e.key.toLowerCase();
199
+ if (key === 'space' || key === 'enter') {
200
+ e.currentTarget.click();
201
+ }
202
+ }, role: "menuitemradio", "aria-checked": false, tabIndex: -1, "aria-hidden": isVisible, "aria-label": i18n('dot-label', {
203
+ index: currentSlideNumber,
204
+ count: barSlidesCount,
205
+ }) }, rovingItemProps)));
163
206
  };
164
207
  const renderNavigation = () => {
165
208
  if (childrenCount <= slidesCountByBreakpoint || !dots || childrenCount === 1) {
@@ -170,7 +213,7 @@ export const SliderBlock = (props) => {
170
213
  .map((_item, index) => renderDot(index));
171
214
  dotsList.splice(currentIndex, 0, renderAccessibleBar(currentIndex));
172
215
  return (React.createElement("div", { className: b('dots', dotsClassName) },
173
- React.createElement("ul", { className: b('dots-list') },
216
+ React.createElement("ul", Object.assign({ className: b('dots-list'), role: "menu", "aria-label": i18n('pagination-label') }, rovingListProps),
174
217
  renderBar(),
175
218
  dotsList)));
176
219
  };
@@ -189,17 +232,18 @@ export const SliderBlock = (props) => {
189
232
  infinite: false,
190
233
  speed: 1000,
191
234
  adaptiveHeight: adaptive,
192
- autoplay: Boolean(autoplay),
193
- autoplaySpeed: autoplay,
235
+ autoplay: isAutoplayEnabled,
236
+ autoplaySpeed,
194
237
  slidesToShow: slidesToShowCount,
195
238
  slidesToScroll: 1,
196
239
  responsive: getSliderResponsiveParams(slidesToShow),
197
240
  beforeChange: onBeforeChange,
198
241
  afterChange: onAfterChange,
199
242
  initialSlide: initialIndex,
200
- nextArrow: React.createElement(Arrow, { type: "right", handleClick: handleArrowClick, size: arrowSize }),
201
- prevArrow: React.createElement(Arrow, { type: "left", handleClick: handleArrowClick, size: arrowSize }),
243
+ nextArrow: (React.createElement(Arrow, { type: "right", handleClick: asUserInteraction(handleArrowClick), size: arrowSize })),
244
+ prevArrow: (React.createElement(Arrow, { type: "left", handleClick: asUserInteraction(handleArrowClick), size: arrowSize })),
202
245
  lazyLoad,
246
+ accessibility: false,
203
247
  };
204
248
  return (React.createElement(OutsideClick, { onOutsideClick: isMobile ? unsetFocus : noop },
205
249
  React.createElement(SlickSlider, Object.assign({}, settings), disclosedChildren),
@@ -219,23 +263,33 @@ export const SliderBlock = (props) => {
219
263
  React.createElement(Title, { title: title, subtitle: description, className: b('header', { 'no-description': !description }) }),
220
264
  React.createElement(AnimateBlock, { className: b('animate-slides'), animate: animated }, renderSlider()))));
221
265
  };
266
+ function getSlideId(sliderId, index) {
267
+ return `slider-${sliderId}-child-${index}`;
268
+ }
222
269
  // TODO remove this and rework PriceDetailed CLOUDFRONT-12230
223
- function discloseAllNestedChildren(children) {
270
+ function discloseAllNestedChildren(children, sliderId) {
224
271
  if (!children) {
225
272
  return [];
226
273
  }
274
+ let childIndex = 0;
275
+ const wrapped = (child) => {
276
+ const id = getSlideId(sliderId, childIndex++);
277
+ return (React.createElement("div", { key: id, id: id }, child));
278
+ };
227
279
  return React.Children.map(children, (child) => {
228
280
  var _a;
229
281
  if (child) {
230
282
  // TODO: if child has 'items' then 'items' determinate like nested children for Slider.
231
283
  const nestedChildren = (_a = child.props.data) === null || _a === void 0 ? void 0 : _a.items;
232
284
  if (nestedChildren) {
233
- return nestedChildren.map((nestedChild) => React.cloneElement(child, {
234
- data: Object.assign(Object.assign({}, child.props.data), { items: [nestedChild] }),
235
- }));
285
+ return nestedChildren.map((nestedChild) => {
286
+ return wrapped(React.cloneElement(child, {
287
+ data: Object.assign(Object.assign({}, child.props.data), { items: [nestedChild] }),
288
+ }));
289
+ });
236
290
  }
237
291
  }
238
- return child;
292
+ return child && wrapped(child);
239
293
  }).filter(Boolean);
240
294
  }
241
295
  export default SliderBlock;
@@ -1,4 +1,6 @@
1
1
  {
2
2
  "arrow-right": "Next",
3
- "arrow-left": "Previous"
3
+ "arrow-left": "Previous",
4
+ "dot-label": "Page {{index}} of {{count}}",
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}} из {{count}}",
5
+ "pagination-label": "Страницы"
4
6
  }
@@ -10,6 +10,7 @@ export interface GetSlidesToShowParams {
10
10
  breakpoints?: SlidesToShow;
11
11
  mobileFullscreen?: boolean;
12
12
  }
13
+ export declare const isFocusable: (element: Element) => boolean;
13
14
  export declare function getSlidesToShowWithDefaults({ contentLength, breakpoints, mobileFullscreen, }: GetSlidesToShowParams): {
14
15
  sm: number;
15
16
  xl: number;
@@ -24,3 +25,12 @@ export declare function getSliderResponsiveParams(breakpoints: SliderBreakpointP
24
25
  }[];
25
26
  export declare function getSlidesCountByBreakpoint(breakpoint: number, breakpoints: SliderBreakpointParams): number;
26
27
  export declare function getSlidesToShowCount(breakpoints: SliderBreakpointParams): number;
28
+ export declare function useRovingTabIndex(props: {
29
+ itemCount: number;
30
+ activeIndex: number;
31
+ firstIndex?: number;
32
+ uniqId: string;
33
+ }): {
34
+ getRovingItemProps: (index: number) => Pick<React.HTMLAttributes<HTMLElement>, 'id' | 'tabIndex' | 'onFocus'>;
35
+ rovingListProps: import("react").HTMLAttributes<HTMLElement>;
36
+ };
@@ -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,3 +1,4 @@
1
+ import React from 'react';
1
2
  import { ClassNameProps } from '../../../models';
2
3
  import './Arrow.css';
3
4
  export type ArrowType = 'left' | 'right';
@@ -6,6 +7,7 @@ export interface ArrowProps {
6
7
  transparent?: boolean;
7
8
  onClick?: () => void;
8
9
  size?: number;
10
+ extraProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;
9
11
  }
10
- declare const Arrow: ({ type, transparent, onClick, className, size }: ArrowProps & ClassNameProps) => JSX.Element;
12
+ declare const Arrow: ({ type, transparent, onClick, className, size, extraProps, }: ArrowProps & ClassNameProps) => JSX.Element;
11
13
  export default Arrow;
@@ -4,8 +4,8 @@ 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, transparent, onClick, className, size = 16 }) => (React.createElement("div", { className: b(null, className) },
8
- React.createElement("button", { className: b('button'), onClick: onClick, "aria-label": i18n(`arrow-${type}`) },
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
9
  React.createElement("div", { className: b('inner', { type, transparent }) },
10
10
  React.createElement("span", { className: b('icon-wrapper') },
11
11
  React.createElement(ToggleArrow, { size: size, type: 'horizontal', iconType: "navigation", className: b('icon') }))))));
@@ -805,7 +805,7 @@ unpredictable css rules order in build */
805
805
  }
806
806
  }
807
807
  .pc-SliderNewBlock_type_fullscreen-card .pc-SliderNewBlock__slider {
808
- padding: 40px 0;
808
+ padding: 24px 0 40px;
809
809
  height: 100vh;
810
810
  margin: 0;
811
811
  }
@@ -867,6 +867,9 @@ unpredictable css rules order in build */
867
867
  }
868
868
  @media (max-width: 577px) {
869
869
  .pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) {
870
+ margin-left: -24px;
871
+ padding-left: 24px;
872
+ width: calc(100% + 48px);
870
873
  overflow-x: auto;
871
874
  }
872
875
  .pc-SliderNewBlock:not(.pc-SliderNewBlock_one-slide) .pc-SliderNewBlock__slider {