@ethlete/components 1.0.0-next.78 → 1.0.0-next.80

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 (270) hide show
  1. package/CHANGELOG.md +139 -0
  2. package/design/accordion.ts +73 -0
  3. package/design/anchored-dialog.ts +92 -0
  4. package/design/avatar.ts +90 -0
  5. package/design/badge.ts +48 -0
  6. package/design/banner.ts +77 -0
  7. package/design/bracket.ts +457 -0
  8. package/design/breadcrumb.ts +145 -0
  9. package/design/button.ts +62 -1
  10. package/design/calendar.ts +306 -0
  11. package/design/card.ts +92 -0
  12. package/design/carousel.ts +240 -0
  13. package/design/chart.ts +512 -0
  14. package/design/checkbox.ts +275 -0
  15. package/design/chip.ts +64 -0
  16. package/design/config.json +8 -0
  17. package/design/control.ts +19 -0
  18. package/design/copy-button.ts +59 -0
  19. package/design/description-list.ts +41 -0
  20. package/design/dialog.ts +216 -0
  21. package/design/divider.ts +27 -0
  22. package/design/empty-state.ts +45 -0
  23. package/design/floating-action.ts +55 -0
  24. package/design/form-field.ts +3 -0
  25. package/design/grid.ts +148 -0
  26. package/design/input.ts +86 -0
  27. package/design/kbd.ts +19 -0
  28. package/design/loader.ts +152 -0
  29. package/design/masonry.ts +115 -0
  30. package/design/match.ts +131 -0
  31. package/design/menu.ts +147 -0
  32. package/design/notification.ts +133 -0
  33. package/design/otp-input.ts +107 -0
  34. package/design/pagination.ts +120 -0
  35. package/design/picture.ts +80 -0
  36. package/design/progress-steps.ts +79 -0
  37. package/design/query-error.ts +60 -0
  38. package/design/radio-group.ts +132 -0
  39. package/design/scheduler.ts +369 -0
  40. package/design/scrollable.ts +218 -0
  41. package/design/scrollbar.ts +47 -0
  42. package/design/sdk/assets/fallback.svg +1 -0
  43. package/design/sdk/assets/tall.svg +1 -0
  44. package/design/sdk/assets/wide.svg +1 -0
  45. package/design/sdk/components/accent-on-light/accent-on-light.css +35 -0
  46. package/design/sdk/components/accent-on-light/accent-on-light.ts +10 -0
  47. package/design/sdk/components/accent-on-light/shared/controls.ts +46 -0
  48. package/design/sdk/components/accordion/accordion.css +17 -0
  49. package/design/sdk/components/accordion/accordion.ts +68 -0
  50. package/design/sdk/components/anchored-dialog/anchored-dialog.css +63 -0
  51. package/design/sdk/components/anchored-dialog/anchored-dialog.ts +65 -0
  52. package/design/sdk/components/avatar/avatar.css +14 -0
  53. package/design/sdk/components/avatar/avatar.ts +79 -0
  54. package/design/sdk/components/badge/badge.css +13 -0
  55. package/design/sdk/components/badge/badge.ts +53 -0
  56. package/design/sdk/components/banner/banner.css +18 -0
  57. package/design/sdk/components/banner/banner.ts +88 -0
  58. package/design/sdk/components/bracket/bracket.css +59 -0
  59. package/design/sdk/components/bracket/bracket.ts +144 -0
  60. package/design/sdk/components/breadcrumb/breadcrumb.css +25 -0
  61. package/design/sdk/components/breadcrumb/breadcrumb.ts +82 -0
  62. package/design/sdk/components/button/button.css +41 -0
  63. package/design/sdk/components/button/button.ts +59 -7
  64. package/design/sdk/components/calendar/calendar.css +33 -0
  65. package/design/sdk/components/calendar/calendar.ts +97 -0
  66. package/design/sdk/components/card/card.css +19 -0
  67. package/design/sdk/components/card/card.ts +62 -0
  68. package/design/sdk/components/carousel/carousel.css +44 -0
  69. package/design/sdk/components/carousel/carousel.ts +75 -0
  70. package/design/sdk/components/chart/chart.css +56 -0
  71. package/design/sdk/components/chart/chart.ts +99 -0
  72. package/design/sdk/components/checkbox/checkbox.css +65 -0
  73. package/design/sdk/components/checkbox/checkbox.ts +180 -0
  74. package/design/sdk/components/chip/chip.css +18 -0
  75. package/design/sdk/components/chip/chip.ts +77 -0
  76. package/design/sdk/components/copy-button/copy-button.css +14 -0
  77. package/design/sdk/components/copy-button/copy-button.ts +60 -0
  78. package/design/sdk/components/description-list/description-list.css +7 -0
  79. package/design/sdk/components/description-list/description-list.ts +54 -0
  80. package/design/sdk/components/dialog/dialog.css +29 -0
  81. package/design/sdk/components/dialog/dialog.ts +79 -0
  82. package/design/sdk/components/divider/divider.css +26 -0
  83. package/design/sdk/components/divider/divider.ts +44 -0
  84. package/design/sdk/components/empty-state/empty-state.css +15 -0
  85. package/design/sdk/components/empty-state/empty-state.ts +57 -0
  86. package/design/sdk/components/floating-action/floating-action.css +51 -0
  87. package/design/sdk/components/floating-action/floating-action.ts +63 -0
  88. package/design/sdk/components/form-field/form-field.ts +23 -5
  89. package/design/sdk/components/grid/grid.css +17 -0
  90. package/design/sdk/components/grid/grid.ts +81 -0
  91. package/design/sdk/components/input/input.css +75 -0
  92. package/design/sdk/components/input/input.ts +80 -0
  93. package/design/sdk/components/kbd/kbd.css +25 -0
  94. package/design/sdk/components/kbd/kbd.ts +58 -0
  95. package/design/sdk/components/loader/loader.css +37 -0
  96. package/design/sdk/components/loader/loader.ts +69 -0
  97. package/design/sdk/components/masonry/masonry.css +7 -0
  98. package/design/sdk/components/masonry/masonry.ts +43 -0
  99. package/design/sdk/components/match/match.css +25 -0
  100. package/design/sdk/components/match/match.ts +77 -0
  101. package/design/sdk/components/menu/menu.css +22 -0
  102. package/design/sdk/components/menu/menu.ts +103 -0
  103. package/design/sdk/components/notification/notification.css +32 -0
  104. package/design/sdk/components/notification/notification.ts +107 -0
  105. package/design/sdk/components/otp-input/otp-input.css +35 -0
  106. package/design/sdk/components/otp-input/otp-input.ts +65 -0
  107. package/design/sdk/components/pagination/pagination.css +14 -0
  108. package/design/sdk/components/pagination/pagination.ts +76 -0
  109. package/design/sdk/components/picture/picture.css +37 -0
  110. package/design/sdk/components/picture/picture.ts +97 -0
  111. package/design/sdk/components/progress-steps/progress-steps.css +37 -0
  112. package/design/sdk/components/progress-steps/progress-steps.ts +92 -0
  113. package/design/sdk/components/query-error/query-error.css +33 -0
  114. package/design/sdk/components/query-error/query-error.ts +121 -0
  115. package/design/sdk/components/radio-group/radio-group.css +46 -0
  116. package/design/sdk/components/radio-group/radio-group.ts +167 -0
  117. package/design/sdk/components/scheduler/scheduler.css +55 -0
  118. package/design/sdk/components/scheduler/scheduler.ts +240 -0
  119. package/design/sdk/components/scrollable/scrollable.css +58 -0
  120. package/design/sdk/components/scrollable/scrollable.ts +133 -0
  121. package/design/sdk/components/scrollbar/scrollbar.css +78 -0
  122. package/design/sdk/components/scrollbar/scrollbar.ts +124 -0
  123. package/design/sdk/components/select/select.ts +1 -1
  124. package/design/sdk/components/select/shared/select-part.ts +25 -3
  125. package/design/sdk/components/select-panel/select-panel.css +3 -0
  126. package/design/sdk/components/select-panel/select-panel.ts +125 -0
  127. package/design/sdk/components/skeleton/skeleton.css +22 -0
  128. package/design/sdk/components/skeleton/skeleton.ts +51 -0
  129. package/design/sdk/components/slider/slider.css +52 -0
  130. package/design/sdk/components/slider/slider.ts +87 -0
  131. package/design/sdk/components/standings/standings.css +33 -0
  132. package/design/sdk/components/standings/standings.ts +131 -0
  133. package/design/sdk/components/stat-tile/stat-tile.css +15 -0
  134. package/design/sdk/components/stat-tile/stat-tile.ts +85 -0
  135. package/design/sdk/components/stream/stream.css +48 -0
  136. package/design/sdk/components/stream/stream.ts +43 -0
  137. package/design/sdk/components/switch/switch.css +37 -0
  138. package/design/sdk/components/switch/switch.ts +63 -0
  139. package/design/sdk/components/table/table.css +67 -0
  140. package/design/sdk/components/table/table.ts +161 -0
  141. package/design/sdk/components/tabs/tabs.css +13 -0
  142. package/design/sdk/components/tabs/tabs.ts +74 -0
  143. package/design/sdk/components/textarea/textarea.css +116 -0
  144. package/design/sdk/components/textarea/textarea.ts +65 -0
  145. package/design/sdk/components/timeline/timeline.css +30 -0
  146. package/design/sdk/components/timeline/timeline.ts +87 -0
  147. package/design/sdk/components/toolbar/toolbar.css +24 -0
  148. package/design/sdk/components/toolbar/toolbar.ts +88 -0
  149. package/design/sdk/components/tooltip/tooltip.css +15 -0
  150. package/design/sdk/components/tooltip/tooltip.ts +28 -0
  151. package/design/sdk/components/tree/selected-tint.css +15 -0
  152. package/design/sdk/components/tree/tree.ts +70 -0
  153. package/design/sdk/foundations/colors/colors.css +124 -4
  154. package/design/sdk/foundations/colors/colors.ts +1 -1
  155. package/design/sdk/foundations/colors/shared/contrast.ts +1 -1
  156. package/design/sdk/foundations/elevation/elevation.css +6 -0
  157. package/design/sdk/foundations/elevation/elevation.ts +11 -0
  158. package/design/sdk/foundations/elevation/shared/elevation/scene.css +101 -0
  159. package/design/sdk/foundations/elevation/shared/elevation/scene.ts +74 -0
  160. package/design/sdk/foundations/icons/icons.ts +119 -0
  161. package/design/sdk/pictures.json +1183 -0
  162. package/design/select.ts +5 -4
  163. package/design/skeleton.ts +67 -0
  164. package/design/slider.ts +155 -0
  165. package/design/standings.ts +161 -0
  166. package/design/stat-tile.ts +109 -0
  167. package/design/stream.ts +92 -0
  168. package/design/switch.ts +83 -0
  169. package/design/table.ts +302 -0
  170. package/design/tabs.ts +75 -0
  171. package/design/textarea.ts +94 -0
  172. package/design/timeline.ts +52 -0
  173. package/design/toolbar.ts +95 -0
  174. package/design/tooltip.ts +87 -0
  175. package/fesm2022/ethlete-components.mjs +1440 -1209
  176. package/fesm2022/ethlete-components.mjs.map +1 -1
  177. package/generators/generators.json +2 -0
  178. package/package.json +1 -1
  179. package/src/lib/accordion/accordion.component.css +2 -1
  180. package/src/lib/avatar/avatar.component.css +10 -0
  181. package/src/lib/badge/badge.component.css +2 -2
  182. package/src/lib/banner/banner.component.css +3 -1
  183. package/src/lib/breadcrumb/breadcrumb-outlet.component.css +5 -0
  184. package/src/lib/breadcrumb/breadcrumb.component.css +5 -1
  185. package/src/lib/button/button-properties-styles.component.css +6 -6
  186. package/src/lib/button/button.component.css +27 -4
  187. package/src/lib/button/button.types.ts +33 -0
  188. package/src/lib/button/icon-button.component.css +21 -22
  189. package/src/lib/button/split-button.component.css +5 -1
  190. package/src/lib/button/window-control-button.component.css +43 -3
  191. package/src/lib/calendar/calendar.component.css +15 -5
  192. package/src/lib/card/card.component.css +4 -0
  193. package/src/lib/carousel/carousel-autoplay-styles.component.css +1 -1
  194. package/src/lib/carousel/carousel.component.css +2 -2
  195. package/src/lib/chart/chart-axis.component.css +3 -3
  196. package/src/lib/chip/chip.component.css +12 -6
  197. package/src/lib/description-list/description-list.component.css +2 -1
  198. package/src/lib/empty-state/empty-state.component.css +4 -0
  199. package/src/lib/floating-action/floating-action-styles.component.css +27 -0
  200. package/src/lib/focus-ring/focus-ring-styles.component.css +4 -1
  201. package/src/lib/forms/checkbox/checkbox.component.css +31 -5
  202. package/src/lib/forms/color-input/color-input.component.css +3 -1
  203. package/src/lib/forms/color-input/color-picker-panel.component.css +6 -2
  204. package/src/lib/forms/date-time/date-input/date-input.component.css +1 -1
  205. package/src/lib/forms/date-time/date-time-input/date-time-input.component.css +1 -1
  206. package/src/lib/forms/date-time/duration-input/duration-input.component.css +1 -1
  207. package/src/lib/forms/date-time/range-input-shell-styles.component.css +1 -1
  208. package/src/lib/forms/date-time/time-input/time-input.component.css +1 -1
  209. package/src/lib/forms/description/description.component.css +7 -0
  210. package/src/lib/forms/dropzone/dropzone.component.css +26 -0
  211. package/src/lib/forms/form-field/form-field-control-suffix-styles.component.css +4 -2
  212. package/src/lib/forms/form-field/form-field-text-shell-styles.component.css +54 -5
  213. package/src/lib/forms/form-field/form-field-textarea-styles.component.css +62 -0
  214. package/src/lib/forms/form-field/form-field.component.css +6 -0
  215. package/src/lib/forms/form-field/headless/label.directive.css +1 -1
  216. package/src/lib/forms/input/input.component.css +6 -2
  217. package/src/lib/forms/input/number-input.component.css +2 -2
  218. package/src/lib/forms/input/password-input.component.css +4 -3
  219. package/src/lib/forms/otp-input/otp-input.component.css +23 -4
  220. package/src/lib/forms/phone-input/phone-input.component.css +4 -3
  221. package/src/lib/forms/rating/rating.component.css +2 -1
  222. package/src/lib/forms/rich-text-editor/rich-text-editor.component.css +1 -1
  223. package/src/lib/forms/selection-card-styles.component.css +3 -2
  224. package/src/lib/forms/selection-list/checkbox-group/checkbox-group-select-all.component.css +4 -2
  225. package/src/lib/forms/selection-list/checkbox-group/checkbox-option.component.css +4 -2
  226. package/src/lib/forms/selection-list/radio-group/radio.component.css +5 -2
  227. package/src/lib/forms/selection-list/segmented-button-group/segmented-button.component.css +2 -1
  228. package/src/lib/forms/slider/range-slider.component.css +98 -6
  229. package/src/lib/forms/slider/slider.component.css +96 -4
  230. package/src/lib/forms/switch/switch.component.css +45 -15
  231. package/src/lib/forms/tag-input/tag-input.component.css +2 -2
  232. package/src/lib/forms/textarea/textarea-autosize-styles.component.css +2 -3
  233. package/src/lib/forms/textarea/textarea.component.css +7 -2
  234. package/src/lib/grid/grid-item-toolbar.component.css +10 -0
  235. package/src/lib/grid/grid-item.component.css +6 -1
  236. package/src/lib/kbd/kbd.component.css +1 -1
  237. package/src/lib/loader/brand-loader/brand-loader.component.css +4 -1
  238. package/src/lib/loader/progress-bar/progress-bar.component.css +1 -1
  239. package/src/lib/loader/spinner/spinner-styles.component.css +1 -1
  240. package/src/lib/match/match-card.component.css +9 -3
  241. package/src/lib/match/match-score.component.css +4 -1
  242. package/src/lib/menu/menu-selection-item.component.css +1 -1
  243. package/src/lib/menu/menu.component.css +6 -1
  244. package/src/lib/notification/notification.component.css +3 -3
  245. package/src/lib/overlay/overlay-container.component.css +4 -0
  246. package/src/lib/pagination/pagination.component.css +4 -0
  247. package/src/lib/progress-steps/progress-step.component.css +4 -4
  248. package/src/lib/query-error/query-error.component.css +4 -0
  249. package/src/lib/scheduler/scheduler-appointment-styles.component.css +21 -5
  250. package/src/lib/scheduler/scheduler-month-view.component.css +4 -2
  251. package/src/lib/scheduler/scheduler-time-grid-view.component.css +8 -2
  252. package/src/lib/scrollable/headless/scrollable-navigation.component.css +1 -1
  253. package/src/lib/standings/standings-pick.component.css +1 -1
  254. package/src/lib/standings/standings.component.css +10 -10
  255. package/src/lib/stat-tile/stat-tile-sparkline.component.css +1 -1
  256. package/src/lib/stream/consent/stream-consent.component.css +99 -0
  257. package/src/lib/stream/error/stream-player-error.component.css +100 -0
  258. package/src/lib/stream/loading/stream-player-loading.component.css +16 -0
  259. package/src/lib/stream/pip/pip-slot-placeholder.component.css +68 -0
  260. package/src/lib/stream/stream-player-slot-styles.component.css +4 -0
  261. package/src/lib/table/table-resize-grip.component.css +2 -1
  262. package/src/lib/table/table-select-cell.component.css +45 -15
  263. package/src/lib/table/table.component.css +15 -5
  264. package/src/lib/tabs/tab-bar-styles.component.css +1 -1
  265. package/src/lib/tabs/tabs/tab-group.component.css +111 -0
  266. package/src/lib/time-picker/time-picker.component.css +2 -1
  267. package/src/lib/timeline/timeline-item.component.css +5 -1
  268. package/src/lib/toolbar/toolbar.component.css +4 -0
  269. package/src/lib/tooltip/tooltip.component.css +14 -0
  270. package/types/ethlete-components.d.ts +156 -128
@@ -0,0 +1,240 @@
1
+ import iconButtonBase from '../src/lib/button/icon-button.component.css?inline';
2
+ import autoplayBase from '../src/lib/carousel/carousel-autoplay-styles.component.css?inline';
3
+ import carouselBase from '../src/lib/carousel/carousel.component.css?inline';
4
+ import { CHEVRON_ICON } from '../src/lib/icon/headless/chevron-icon';
5
+ import iconBase from '../src/lib/icon/headless/icon-styles.component.css?inline';
6
+ import { PAUSE_ICON } from '../src/lib/icon/headless/pause-icon';
7
+ import { PLAY_ICON } from '../src/lib/icon/headless/play-icon';
8
+ import scrollableBase from '../src/lib/scrollable/scrollable.component.css?inline';
9
+ import { buttonStyles } from './button';
10
+ import { iconMarkup } from './icon';
11
+ import { scrollable } from './scrollable';
12
+
13
+ export type CarouselMockSlide = {
14
+ /** The slide's inner HTML, as the consumer's slide template renders it. */
15
+ content: string;
16
+ };
17
+
18
+ export type CarouselMockOptions = {
19
+ slides: CarouselMockSlide[];
20
+ /** The index of the active slide. Left out, 0. */
21
+ active?: number;
22
+ /** Left out, `full`: one slide at a time. */
23
+ itemSize?: 'full' | 'half' | 'third';
24
+ /** Left out, true, as the `loop` input defaults to. Looping draws the clones and never disables the arrows. */
25
+ loop?: boolean;
26
+ slideAlign?: 'start' | 'center';
27
+ /** The gap between the slides in px, set as `--et-carousel-slide-gap`. Left out, 0. */
28
+ slideGap?: number;
29
+ /** Left out, true. */
30
+ showControls?: boolean;
31
+ /** Left out, true. */
32
+ showDots?: boolean;
33
+ /** Draws the play toggle and the countdown ring. */
34
+ autoplay?: boolean;
35
+ /** Whether autoplay runs: the toggle shows pause and the active dot counts down. Left out, true while `autoplay` is on. */
36
+ playing?: boolean;
37
+ /** The slide's autoplay time in ms. Left out, 5000. */
38
+ autoplayTime?: number;
39
+ /** Where the countdown ring is held, as a fraction of the slide's time. Left out, 0.4. */
40
+ autoplayProgress?: number;
41
+ /** Extra attributes on the previous button, e.g. design markers. */
42
+ previousAttributes?: string;
43
+ /** Extra attributes on the next button, e.g. design markers. */
44
+ nextAttributes?: string;
45
+ /** Extra attributes on the play toggle, e.g. design markers. */
46
+ playToggleAttributes?: string;
47
+ /** Extra attributes on a dot, by index, e.g. design markers. */
48
+ dotAttributes?: Record<number, string>;
49
+ /** A color theme name the app registers. Left out, the carousel takes the color theme around it. */
50
+ color?: string;
51
+ /** Extra attributes on the host, e.g. a style or design markers. */
52
+ attributes?: string;
53
+ /** Extra attributes on the track's scroll container, e.g. design markers. */
54
+ trackAttributes?: string;
55
+ };
56
+
57
+ const PER_VIEW = { full: 1, half: 2, third: 3 };
58
+
59
+ /** The stylesheets `carousel()` draws with: the real carousel, autoplay, scrollable and icon-button CSS, plus the rules that draw the countdown at one point without its animation. */
60
+ export const carouselStyles = /* @__PURE__ */ [
61
+ buttonStyles,
62
+ iconBase,
63
+ iconButtonBase,
64
+ scrollableBase,
65
+ carouselBase,
66
+ autoplayBase,
67
+ `.et-carousel .et-carousel-dot[data-et-frozen-at] .et-carousel-dot-progress-half::before {
68
+ --_sweep: clamp(0, var(--et-carousel-frozen-at) * 2, 1);
69
+ animation: none;
70
+ opacity: 1;
71
+ rotate: calc(-180deg + var(--_sweep) * 180deg);
72
+ }
73
+ .et-carousel .et-carousel-dot[data-et-frozen-at] .et-carousel-dot-progress-half:last-child::before {
74
+ --_sweep: clamp(0, var(--et-carousel-frozen-at) * 2 - 1, 1);
75
+ opacity: clamp(0, var(--_sweep) * 1000, 1);
76
+ }`,
77
+ ].join('\n');
78
+
79
+ type ControlOptions = { classes: string[]; label: string; disabled: boolean; icons: string; attributes?: string };
80
+
81
+ const control = ({ classes, label, disabled, icons, attributes }: ControlOptions) => {
82
+ const hostClasses = [
83
+ 'et-carousel-control',
84
+ ...classes,
85
+ 'et-icon-button',
86
+ 'et-color-interactive',
87
+ 'et-focus-ring',
88
+ 'et-color--inherited',
89
+ ];
90
+ const host = [
91
+ attributes,
92
+ `class="${hostClasses.join(' ')}"`,
93
+ 'type="button"',
94
+ `aria-label="${label}"`,
95
+ disabled && 'aria-disabled="true"',
96
+ 'data-variant="transparent"',
97
+ 'data-size="sm"',
98
+ ].filter(Boolean);
99
+
100
+ return `<button ${host.join(' ')}><div class="et-icon-button-icon">${icons}</div></button>`;
101
+ };
102
+
103
+ /**
104
+ * Draws `<et-carousel>` as HTML: the scrollable track with its slides (and the clones a looping carousel adds), the
105
+ * previous and next buttons, the dots and the autoplay toggle with its countdown ring. The active slide is brought
106
+ * into view by translating the slides statically.
107
+ */
108
+ export const carousel = (options: CarouselMockOptions) => {
109
+ const count = options.slides.length;
110
+ const active = Math.min(Math.max(options.active ?? 0, 0), Math.max(count - 1, 0));
111
+ const itemSize = options.itemSize ?? 'full';
112
+ const perView = PER_VIEW[itemSize];
113
+ const loop = options.loop ?? true;
114
+ const slideAlign = options.slideAlign ?? 'start';
115
+ const gap = options.slideGap ?? 0;
116
+ const autoplay = options.autoplay ?? false;
117
+ const playing = autoplay && (options.playing ?? true);
118
+ const autoplayTime = options.autoplayTime ?? 5000;
119
+ const cloneCount = loop && count > perView ? Math.min(count, perView + 1) : 0;
120
+ const looping = cloneCount > 0;
121
+ const firstInView = looping ? cloneCount + active : Math.min(active, Math.max(count - perView, 0));
122
+ const shift = slideAlign === 'center' && itemSize !== 'full' ? cloneCount + active - (perView - 1) / 2 : firstInView;
123
+ const atStart = !looping && firstInView === 0;
124
+ const atEnd = !looping && firstInView >= count - perView;
125
+ const canGoPrevious = count > 1 && (loop || !atStart);
126
+ const canGoNext = count > 1 && (loop || !atEnd);
127
+
128
+ const slideItem = (index: number, isClone: boolean) => {
129
+ const attributes = [
130
+ 'class="et-carousel-item"',
131
+ 'role="group"',
132
+ 'aria-roledescription="slide"',
133
+ `aria-label="${index + 1} of ${count}"`,
134
+ isClone && 'aria-hidden="true" inert="" data-clone=""',
135
+ !isClone && index === active && 'data-active=""',
136
+ shift !== 0 && `style="translate: calc(${-shift} * (100% + ${gap}px)) 0"`,
137
+ ].filter(Boolean);
138
+
139
+ return {
140
+ attributes: attributes.join(' '),
141
+ content: `<div class="et-carousel-slide-content">${options.slides[index]?.content ?? ''}</div>`,
142
+ };
143
+ };
144
+
145
+ const items = [
146
+ ...Array.from({ length: cloneCount }, (_, offset) => slideItem(count - cloneCount + offset, true)),
147
+ ...Array.from({ length: count }, (_, index) => slideItem(index, false)),
148
+ ...Array.from({ length: cloneCount }, (_, index) => slideItem(index, true)),
149
+ ];
150
+
151
+ const track = scrollable({
152
+ items,
153
+ canScroll: count > perView,
154
+ position: atStart ? 'start' : atEnd ? 'end' : 'middle',
155
+ renderMasks: false,
156
+ snap: true,
157
+ itemSize,
158
+ itemGap: gap,
159
+ class: 'et-carousel-track',
160
+ containerAttributes: options.trackAttributes,
161
+ });
162
+
163
+ const progressAttributes = [
164
+ 'class="et-carousel-dot-progress"',
165
+ 'aria-hidden="true"',
166
+ `style="--_et-carousel-autoplay-duration: ${autoplayTime}ms"`,
167
+ ];
168
+ const progress = autoplay
169
+ ? `<span ${progressAttributes.join(' ')}>` +
170
+ `<span class="et-carousel-dot-progress-half"></span><span class="et-carousel-dot-progress-half"></span></span>`
171
+ : '';
172
+
173
+ const dots = Array.from({ length: count }, (_, index) => {
174
+ const isActive = index === active;
175
+ const counting = isActive && playing;
176
+ const attributes = [
177
+ options.dotAttributes?.[index],
178
+ 'class="et-carousel-dot et-focus-ring"',
179
+ 'type="button"',
180
+ `aria-label="Go to slide ${index + 1}"`,
181
+ isActive && 'aria-current="true" data-active=""',
182
+ counting && 'data-counting=""',
183
+ counting && `data-et-frozen-at="" style="--et-carousel-frozen-at: ${options.autoplayProgress ?? 0.4}"`,
184
+ ].filter(Boolean);
185
+
186
+ return `<button ${attributes.join(' ')}>${progress}</button>`;
187
+ }).join('');
188
+
189
+ const showControls = options.showControls ?? true;
190
+ const showDots = options.showDots ?? true;
191
+
192
+ const controls = [
193
+ showControls &&
194
+ control({
195
+ classes: [],
196
+ label: 'Previous slide',
197
+ disabled: !canGoPrevious,
198
+ icons: iconMarkup(CHEVRON_ICON, 'et-carousel-control-icon et-carousel-control-icon--previous'),
199
+ attributes: options.previousAttributes,
200
+ }),
201
+ showDots && `<div class="et-carousel-dots">${dots}</div>`,
202
+ autoplay &&
203
+ control({
204
+ classes: ['et-carousel-play-toggle'],
205
+ label: playing ? 'Pause automatic slide show' : 'Start automatic slide show',
206
+ disabled: false,
207
+ icons:
208
+ iconMarkup(PLAY_ICON, 'et-carousel-control-icon et-carousel-play-toggle-icon') +
209
+ iconMarkup(PAUSE_ICON, 'et-carousel-control-icon et-carousel-play-toggle-icon'),
210
+ attributes: [options.playToggleAttributes, playing && 'data-playing=""'].filter(Boolean).join(' '),
211
+ }),
212
+ showControls &&
213
+ control({
214
+ classes: [],
215
+ label: 'Next slide',
216
+ disabled: !canGoNext,
217
+ icons: iconMarkup(CHEVRON_ICON, 'et-carousel-control-icon et-carousel-control-icon--next'),
218
+ attributes: options.nextAttributes,
219
+ }),
220
+ ].filter(Boolean);
221
+
222
+ const host = [
223
+ options.attributes,
224
+ `class="${['et-carousel', options.color && `et-color--${options.color}`].filter(Boolean).join(' ')}"`,
225
+ 'role="region"',
226
+ 'aria-roledescription="carousel"',
227
+ 'aria-label="Carousel"',
228
+ `data-slide-align="${slideAlign}"`,
229
+ 'data-transition="none"',
230
+ looping && 'data-looping=""',
231
+ playing && 'data-autoplaying=""',
232
+ gap && `style="--et-carousel-slide-gap: ${gap}px"`,
233
+ ].filter(Boolean);
234
+
235
+ return (
236
+ `<et-carousel ${host.join(' ')}>${track}` +
237
+ (controls.length ? `<div class="et-carousel-controls">${controls.join('')}</div>` : '') +
238
+ `</et-carousel>`
239
+ );
240
+ };