@telefonica/mistica 16.69.0 → 16.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/css/mistica.css +1 -1
  2. package/dist/accordion.css-mistica.js +6 -6
  3. package/dist/align.css-mistica.js +1 -1
  4. package/dist/autocomplete.css-mistica.js +1 -1
  5. package/dist/avatar.css-mistica.js +1 -1
  6. package/dist/badge.css-mistica.js +1 -1
  7. package/dist/box.css-mistica.js +13 -13
  8. package/dist/boxed.css-mistica.js +24 -24
  9. package/dist/button-group.css-mistica.js +1 -1
  10. package/dist/button-layout.css-mistica.js +14 -14
  11. package/dist/button.css-mistica.js +30 -30
  12. package/dist/callout.css-mistica.js +11 -11
  13. package/dist/card-internal.css-mistica.js +15 -15
  14. package/dist/carousel.css-mistica.js +8 -8
  15. package/dist/checkbox.css-mistica.js +11 -11
  16. package/dist/chip.css-mistica.js +15 -15
  17. package/dist/circle.css-mistica.js +1 -1
  18. package/dist/community/advanced-data-card.css-mistica.js +6 -6
  19. package/dist/community/ai-card.css-mistica.js +13 -13
  20. package/dist/community/blocks.css-mistica.js +1 -1
  21. package/dist/community/cyber/example-component.css-mistica.js +1 -1
  22. package/dist/community/example-component.css-mistica.js +2 -2
  23. package/dist/counter.css-mistica.js +1 -1
  24. package/dist/cover-hero.css-mistica.js +2 -2
  25. package/dist/credit-card-number-field.css-mistica.js +3 -3
  26. package/dist/date-field.css-mistica.js +1 -1
  27. package/dist/date-time-picker.css-mistica.js +1 -1
  28. package/dist/dialog.css-mistica.js +4 -4
  29. package/dist/divider.css-mistica.js +5 -5
  30. package/dist/double-field.css-mistica.js +2 -2
  31. package/dist/drawer.css-mistica.js +1 -1
  32. package/dist/drawer.js +70 -79
  33. package/dist/empty-state-card.css-mistica.js +1 -1
  34. package/dist/empty-state.css-mistica.js +5 -5
  35. package/dist/fade-in.css-mistica.js +1 -1
  36. package/dist/feedback.css-mistica.js +1 -1
  37. package/dist/file-upload.css-mistica.js +7 -7
  38. package/dist/fixed-footer-layout.css-mistica.js +2 -2
  39. package/dist/form.css-mistica.js +1 -1
  40. package/dist/grid-layout.css-mistica.js +3 -3
  41. package/dist/grid.css-mistica.js +120 -120
  42. package/dist/header.css-mistica.js +1 -1
  43. package/dist/hero.css-mistica.js +2 -2
  44. package/dist/horizontal-scroll.css-mistica.js +1 -1
  45. package/dist/icon-button.css-mistica.js +53 -53
  46. package/dist/icons/icon-chevron.css-mistica.js +2 -2
  47. package/dist/icons/icon-error.css-mistica.js +1 -1
  48. package/dist/image.css-mistica.js +2 -2
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.js +4 -0
  51. package/dist/inline.css-mistica.js +9 -9
  52. package/dist/list.css-mistica.js +1 -1
  53. package/dist/loading-bar.css-mistica.js +1 -1
  54. package/dist/loading-screen.css-mistica.js +4 -4
  55. package/dist/logo.css-mistica.js +5 -5
  56. package/dist/menu.css-mistica.js +13 -13
  57. package/dist/mosaic.css-mistica.js +1 -1
  58. package/dist/navigation-bar.css-mistica.js +18 -18
  59. package/dist/navigation-breadcrumbs.css-mistica.js +1 -1
  60. package/dist/package-version.js +1 -1
  61. package/dist/pagination.css-mistica.js +67 -0
  62. package/dist/pagination.css.d.ts +12 -0
  63. package/dist/pagination.d.ts +34 -0
  64. package/dist/pagination.js +318 -0
  65. package/dist/pin-field.css-mistica.js +1 -1
  66. package/dist/popover.css-mistica.js +1 -1
  67. package/dist/progress-bar.css-mistica.js +6 -6
  68. package/dist/radio-button.css-mistica.js +19 -19
  69. package/dist/rating.css-mistica.js +2 -2
  70. package/dist/responsive-layout.css-mistica.js +6 -6
  71. package/dist/screen-reader-only.css-mistica.js +1 -1
  72. package/dist/select.css-mistica.js +15 -15
  73. package/dist/select.js +45 -43
  74. package/dist/sheet-action-row.css-mistica.js +1 -1
  75. package/dist/sheet-common.css-mistica.js +1 -1
  76. package/dist/sheet-info.css-mistica.js +1 -1
  77. package/dist/skeletons.css-mistica.js +6 -6
  78. package/dist/skins/skin-contract.css-mistica.js +684 -684
  79. package/dist/skip-link.css-mistica.js +1 -1
  80. package/dist/slider.css-mistica.js +18 -18
  81. package/dist/snackbar.css-mistica.js +4 -4
  82. package/dist/spinner.css-mistica.js +1 -1
  83. package/dist/square.css-mistica.js +1 -1
  84. package/dist/stack.css-mistica.js +5 -5
  85. package/dist/stacking-group.css-mistica.js +1 -1
  86. package/dist/stepper.css-mistica.js +2 -2
  87. package/dist/switch-component.css-mistica.js +35 -35
  88. package/dist/table.css-mistica.js +9 -9
  89. package/dist/tabs.css-mistica.js +17 -17
  90. package/dist/tag.css-mistica.js +1 -1
  91. package/dist/text-field-base.css-mistica.js +15 -15
  92. package/dist/text-field-components.css-mistica.js +3 -3
  93. package/dist/text-link.css-mistica.js +6 -6
  94. package/dist/text-tokens.d.ts +14 -0
  95. package/dist/text-tokens.js +173 -117
  96. package/dist/text.css-mistica.js +6 -6
  97. package/dist/timeline.css-mistica.js +9 -9
  98. package/dist/timer.css-mistica.js +6 -6
  99. package/dist/tooltip.css-mistica.js +1 -1
  100. package/dist/touchable.css-mistica.js +1 -1
  101. package/dist/utils/aspect-ratio-support.css-mistica.js +2 -2
  102. package/dist/video.css-mistica.js +1 -1
  103. package/dist/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
  104. package/dist-es/accordion.css-mistica.js +6 -6
  105. package/dist-es/align.css-mistica.js +1 -1
  106. package/dist-es/autocomplete.css-mistica.js +1 -1
  107. package/dist-es/avatar.css-mistica.js +1 -1
  108. package/dist-es/badge.css-mistica.js +1 -1
  109. package/dist-es/box.css-mistica.js +13 -13
  110. package/dist-es/boxed.css-mistica.js +23 -23
  111. package/dist-es/button-group.css-mistica.js +1 -1
  112. package/dist-es/button-layout.css-mistica.js +14 -14
  113. package/dist-es/button.css-mistica.js +30 -30
  114. package/dist-es/callout.css-mistica.js +11 -11
  115. package/dist-es/card-internal.css-mistica.js +15 -15
  116. package/dist-es/carousel.css-mistica.js +8 -8
  117. package/dist-es/checkbox.css-mistica.js +11 -11
  118. package/dist-es/chip.css-mistica.js +15 -15
  119. package/dist-es/circle.css-mistica.js +1 -1
  120. package/dist-es/community/advanced-data-card.css-mistica.js +6 -6
  121. package/dist-es/community/ai-card.css-mistica.js +4 -4
  122. package/dist-es/community/blocks.css-mistica.js +1 -1
  123. package/dist-es/community/cyber/example-component.css-mistica.js +1 -1
  124. package/dist-es/community/example-component.css-mistica.js +2 -2
  125. package/dist-es/counter.css-mistica.js +1 -1
  126. package/dist-es/cover-hero.css-mistica.js +2 -2
  127. package/dist-es/credit-card-number-field.css-mistica.js +3 -3
  128. package/dist-es/date-field.css-mistica.js +1 -1
  129. package/dist-es/date-time-picker.css-mistica.js +1 -1
  130. package/dist-es/dialog.css-mistica.js +4 -4
  131. package/dist-es/divider.css-mistica.js +5 -5
  132. package/dist-es/double-field.css-mistica.js +2 -2
  133. package/dist-es/drawer.css-mistica.js +1 -1
  134. package/dist-es/drawer.js +87 -96
  135. package/dist-es/empty-state-card.css-mistica.js +1 -1
  136. package/dist-es/empty-state.css-mistica.js +5 -5
  137. package/dist-es/fade-in.css-mistica.js +1 -1
  138. package/dist-es/feedback.css-mistica.js +1 -1
  139. package/dist-es/file-upload.css-mistica.js +7 -7
  140. package/dist-es/fixed-footer-layout.css-mistica.js +2 -2
  141. package/dist-es/form.css-mistica.js +1 -1
  142. package/dist-es/grid-layout.css-mistica.js +3 -3
  143. package/dist-es/grid.css-mistica.js +120 -120
  144. package/dist-es/header.css-mistica.js +1 -1
  145. package/dist-es/hero.css-mistica.js +2 -2
  146. package/dist-es/horizontal-scroll.css-mistica.js +1 -1
  147. package/dist-es/icon-button.css-mistica.js +53 -53
  148. package/dist-es/icons/icon-chevron.css-mistica.js +2 -2
  149. package/dist-es/icons/icon-error.css-mistica.js +1 -1
  150. package/dist-es/image.css-mistica.js +2 -2
  151. package/dist-es/index.js +2290 -2289
  152. package/dist-es/inline.css-mistica.js +9 -9
  153. package/dist-es/list.css-mistica.js +1 -1
  154. package/dist-es/loading-bar.css-mistica.js +1 -1
  155. package/dist-es/loading-screen.css-mistica.js +4 -4
  156. package/dist-es/logo.css-mistica.js +5 -5
  157. package/dist-es/menu.css-mistica.js +13 -13
  158. package/dist-es/mosaic.css-mistica.js +1 -1
  159. package/dist-es/navigation-bar.css-mistica.js +18 -18
  160. package/dist-es/navigation-breadcrumbs.css-mistica.js +1 -1
  161. package/dist-es/package-version.js +1 -1
  162. package/dist-es/pagination.css-mistica.js +20 -0
  163. package/dist-es/pagination.js +252 -0
  164. package/dist-es/pin-field.css-mistica.js +1 -1
  165. package/dist-es/popover.css-mistica.js +1 -1
  166. package/dist-es/progress-bar.css-mistica.js +6 -6
  167. package/dist-es/radio-button.css-mistica.js +19 -19
  168. package/dist-es/rating.css-mistica.js +2 -2
  169. package/dist-es/responsive-layout.css-mistica.js +6 -6
  170. package/dist-es/screen-reader-only.css-mistica.js +1 -1
  171. package/dist-es/select.css-mistica.js +15 -15
  172. package/dist-es/select.js +69 -67
  173. package/dist-es/sheet-action-row.css-mistica.js +1 -1
  174. package/dist-es/sheet-common.css-mistica.js +1 -1
  175. package/dist-es/sheet-info.css-mistica.js +1 -1
  176. package/dist-es/skeletons.css-mistica.js +6 -6
  177. package/dist-es/skins/skin-contract.css-mistica.js +684 -684
  178. package/dist-es/skip-link.css-mistica.js +1 -1
  179. package/dist-es/slider.css-mistica.js +18 -18
  180. package/dist-es/snackbar.css-mistica.js +4 -4
  181. package/dist-es/spinner.css-mistica.js +1 -1
  182. package/dist-es/square.css-mistica.js +1 -1
  183. package/dist-es/stack.css-mistica.js +5 -5
  184. package/dist-es/stacking-group.css-mistica.js +1 -1
  185. package/dist-es/stepper.css-mistica.js +2 -2
  186. package/dist-es/style.css +1 -1
  187. package/dist-es/switch-component.css-mistica.js +35 -35
  188. package/dist-es/table.css-mistica.js +9 -9
  189. package/dist-es/tabs.css-mistica.js +17 -17
  190. package/dist-es/tag.css-mistica.js +1 -1
  191. package/dist-es/text-field-base.css-mistica.js +15 -15
  192. package/dist-es/text-field-components.css-mistica.js +3 -3
  193. package/dist-es/text-link.css-mistica.js +6 -6
  194. package/dist-es/text-tokens.js +94 -59
  195. package/dist-es/text.css-mistica.js +6 -6
  196. package/dist-es/timeline.css-mistica.js +9 -9
  197. package/dist-es/timer.css-mistica.js +6 -6
  198. package/dist-es/tooltip.css-mistica.js +1 -1
  199. package/dist-es/touchable.css-mistica.js +1 -1
  200. package/dist-es/utils/aspect-ratio-support.css-mistica.js +2 -2
  201. package/dist-es/video.css-mistica.js +1 -1
  202. package/dist-es/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
  203. package/doc/components.md +27 -0
  204. package/doc/patterns.md +20 -0
  205. package/package.json +2 -2
  206. package/src/button.css.ts +1 -0
  207. package/src/drawer.tsx +0 -14
  208. package/src/focus-trap.tsx +0 -1
  209. package/src/index.tsx +1 -0
  210. package/src/package-version.tsx +1 -1
  211. package/src/pagination.css.ts +303 -0
  212. package/src/pagination.tsx +376 -0
  213. package/src/select.tsx +2 -1
  214. package/src/test-utils/index.tsx +2 -1
  215. package/src/text-tokens.tsx +56 -0
@@ -0,0 +1,303 @@
1
+ import {style, styleVariants} from '@vanilla-extract/css';
2
+ import {sprinkles} from './sprinkles.css';
3
+ import {vars as skinVars} from './skins/skin-contract.css';
4
+ import * as mq from './media-queries.css';
5
+
6
+ export const container = style([
7
+ sprinkles({
8
+ display: 'inline-flex',
9
+ alignItems: 'center',
10
+ columnGap: {
11
+ mobile: 4,
12
+ desktop: 8,
13
+ },
14
+ paddingY: 8,
15
+ paddingX: {
16
+ mobile: 0,
17
+ desktop: 16,
18
+ },
19
+ maxWidth: '100%',
20
+ }),
21
+ {
22
+ width: 'fit-content',
23
+ boxSizing: 'border-box',
24
+ },
25
+ ]);
26
+
27
+ export const containerNavOnly = style({
28
+ gap: 16,
29
+ });
30
+
31
+ export const pageList = style([
32
+ sprinkles({
33
+ display: 'flex',
34
+ alignItems: 'center',
35
+ columnGap: {
36
+ mobile: 4,
37
+ desktop: 8,
38
+ },
39
+ }),
40
+ {
41
+ margin: 0,
42
+ padding: 0,
43
+ listStyle: 'none',
44
+ },
45
+ ]);
46
+
47
+ export const pageListDesktop = style({
48
+ display: 'none',
49
+
50
+ '@media': {
51
+ [mq.desktopOrBigger]: {
52
+ display: 'flex',
53
+ },
54
+ },
55
+ });
56
+
57
+ export const pageListMobile = style({
58
+ '@media': {
59
+ [mq.desktopOrBigger]: {
60
+ display: 'none',
61
+ },
62
+ },
63
+ });
64
+
65
+ export const pageListItem = style([
66
+ sprinkles({
67
+ display: 'flex',
68
+ alignItems: 'center',
69
+ justifyContent: 'center',
70
+ }),
71
+ {
72
+ minWidth: 48,
73
+ height: 48,
74
+
75
+ '@media': {
76
+ [mq.desktopOrBigger]: {
77
+ minWidth: 32,
78
+ height: 32,
79
+ },
80
+ },
81
+ },
82
+ ]);
83
+
84
+ const interactiveArea = style([
85
+ {
86
+ position: 'relative',
87
+ padding: 0,
88
+ border: 0,
89
+ font: 'inherit',
90
+ background: 'transparent',
91
+ color: skinVars.colors.textPrimary,
92
+ borderRadius: skinVars.borderRadii.button,
93
+ WebkitTapHighlightColor: 'transparent',
94
+ boxSizing: 'border-box',
95
+
96
+ selectors: {
97
+ '&&': {
98
+ display: 'flex',
99
+ alignItems: 'center',
100
+ justifyContent: 'center',
101
+ width: '100%',
102
+ height: '100%',
103
+ },
104
+ },
105
+ },
106
+ ]);
107
+
108
+ const pageElement = style([
109
+ interactiveArea,
110
+ {
111
+ selectors: {
112
+ '&&': {
113
+ width: 'auto',
114
+ minWidth: 48,
115
+ padding: '0 12px',
116
+ },
117
+ },
118
+
119
+ ':before': {
120
+ content: '""',
121
+ position: 'absolute',
122
+ top: '50%',
123
+ left: '50%',
124
+ width: 'max(32px, calc(100% - 16px))',
125
+ height: 32,
126
+ borderRadius: 16,
127
+ transform: 'translate(-50%, -50%) scale(0.8)',
128
+ opacity: 0,
129
+ transition: 'transform 0.2s ease-in-out, opacity 0.2s ease-in-out',
130
+ },
131
+
132
+ '@media': {
133
+ [mq.desktopOrBigger]: {
134
+ selectors: {
135
+ '&&': {
136
+ minWidth: 32,
137
+ padding: '0 4px',
138
+ },
139
+ },
140
+
141
+ ':before': {
142
+ width: '100%',
143
+ },
144
+ },
145
+ },
146
+ },
147
+ ]);
148
+
149
+ export const pageButton = style([
150
+ pageElement,
151
+ {
152
+ cursor: 'pointer',
153
+
154
+ selectors: {
155
+ '&:active:not(:disabled):before': {
156
+ opacity: 1,
157
+ transform: 'translate(-50%, -50%) scale(1)',
158
+ backgroundColor: skinVars.colors.brandLow,
159
+ },
160
+ '&:disabled': {
161
+ cursor: 'default',
162
+ opacity: 0.5,
163
+ },
164
+ },
165
+
166
+ '@media': {
167
+ [mq.supportsHover]: {
168
+ selectors: {
169
+ '&:hover:not(:disabled):before': {
170
+ opacity: 1,
171
+ transform: 'translate(-50%, -50%) scale(1.06)',
172
+ backgroundColor: skinVars.colors.neutralLow,
173
+ },
174
+ '&:active:not(:disabled):before': {
175
+ opacity: 1,
176
+ transform: 'translate(-50%, -50%) scale(1)',
177
+ backgroundColor: skinVars.colors.brandLow,
178
+ },
179
+ },
180
+ },
181
+ [mq.touchableOnly]: {
182
+ ':before': {
183
+ transition: 'none',
184
+ },
185
+ },
186
+ },
187
+ },
188
+ ]);
189
+
190
+ export const pageButtonVariants = styleVariants({
191
+ default: {},
192
+ brand: {
193
+ color: skinVars.colors.textButtonSecondaryBrand,
194
+ selectors: {
195
+ '&:active:not(:disabled)': {
196
+ color: skinVars.colors.textBrand,
197
+ },
198
+ '&:active:not(:disabled):before': {
199
+ backgroundColor: skinVars.colors.brandLow,
200
+ },
201
+ },
202
+ '@media': {
203
+ [mq.supportsHover]: {
204
+ selectors: {
205
+ '&:hover:not(:disabled):before': {
206
+ backgroundColor: skinVars.colors.backgroundContainerBrandHover,
207
+ },
208
+ '&:active:not(:disabled)': {
209
+ color: skinVars.colors.textBrand,
210
+ },
211
+ '&:active:not(:disabled):before': {
212
+ backgroundColor: skinVars.colors.brandLow,
213
+ },
214
+ },
215
+ },
216
+ },
217
+ },
218
+ negative: {
219
+ color: skinVars.colors.textButtonSecondaryNegative,
220
+ selectors: {
221
+ '&:active:not(:disabled)': {
222
+ color: skinVars.colors.textButtonPrimaryNegative,
223
+ },
224
+ '&:active:not(:disabled):before': {
225
+ backgroundColor: skinVars.colors.buttonPrimaryBackgroundNegative,
226
+ },
227
+ },
228
+ '@media': {
229
+ [mq.supportsHover]: {
230
+ selectors: {
231
+ '&:hover:not(:disabled):before': {
232
+ backgroundColor: skinVars.colors.backgroundContainerBrandHover,
233
+ },
234
+ '&:active:not(:disabled)': {
235
+ color: skinVars.colors.textButtonPrimaryNegative,
236
+ },
237
+ '&:active:not(:disabled):before': {
238
+ backgroundColor: skinVars.colors.buttonPrimaryBackgroundNegative,
239
+ },
240
+ },
241
+ },
242
+ },
243
+ },
244
+ alternative: {},
245
+ media: {},
246
+ });
247
+
248
+ export const currentPage = style([
249
+ pageElement,
250
+ {
251
+ cursor: 'default',
252
+ color: skinVars.colors.textActivated,
253
+
254
+ ':before': {
255
+ opacity: 1,
256
+ transform: 'translate(-50%, -50%) scale(1)',
257
+ backgroundColor: skinVars.colors.brandLow,
258
+ },
259
+ },
260
+ ]);
261
+
262
+ export const currentPageVariants = styleVariants({
263
+ default: {},
264
+ brand: {
265
+ color: skinVars.colors.textBrand,
266
+ ':before': {
267
+ backgroundColor: skinVars.colors.brandLow,
268
+ },
269
+ },
270
+ negative: {
271
+ color: skinVars.colors.textButtonPrimaryNegative,
272
+ ':before': {
273
+ backgroundColor: skinVars.colors.buttonPrimaryBackgroundNegative,
274
+ },
275
+ },
276
+ alternative: {},
277
+ media: {},
278
+ });
279
+
280
+ export const pageContent = style({
281
+ position: 'relative',
282
+ zIndex: 1,
283
+ });
284
+
285
+ export const navigationButtonLinkVariants = styleVariants({
286
+ default: {},
287
+ brand: {
288
+ selectors: {
289
+ '&&': {
290
+ color: skinVars.colors.textButtonSecondaryBrand,
291
+ },
292
+ },
293
+ },
294
+ negative: {
295
+ selectors: {
296
+ '&&': {
297
+ color: skinVars.colors.textButtonSecondaryNegative,
298
+ },
299
+ },
300
+ },
301
+ alternative: {},
302
+ media: {},
303
+ });
@@ -0,0 +1,376 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import classnames from 'classnames';
5
+ import * as styles from './pagination.css';
6
+ import {Text3} from './text';
7
+ import Touchable from './touchable';
8
+ import {ButtonLink} from './button';
9
+ import {IconButton} from './icon-button';
10
+ import {useTheme} from './hooks';
11
+ import {useThemeVariant} from './theme-variant-context';
12
+ import IconChevronLeftRegular from './generated/mistica-icons/icon-chevron-left-regular';
13
+ import IconChevronRightRegular from './generated/mistica-icons/icon-chevron-right-regular';
14
+ import {getPrefixedDataAttributes} from './utils/dom';
15
+ import {vars as skinVars} from './skins/skin-contract.css';
16
+ import * as tokens from './text-tokens';
17
+
18
+ import type {ExclusifyUnion} from './utils/utility-types';
19
+ import type {DataAttributes} from './utils/types';
20
+ import type {NonDeprecatedVariant} from './theme-variant-context';
21
+
22
+ export type PaginationProps = {
23
+ totalPages: number;
24
+ currentPage?: number;
25
+ defaultPage?: number;
26
+ onChange?: (page: number) => void;
27
+
28
+ hideNavigationControls?: boolean;
29
+ hidePageList?: boolean;
30
+
31
+ surroundingPageCount?: number;
32
+
33
+ navLeftLabel?: string;
34
+ navRightLabel?: string;
35
+
36
+ mode?: 'default' | 'iconOnly';
37
+ disabled?: boolean;
38
+
39
+ dataAttributes?: DataAttributes;
40
+ 'aria-label'?: string;
41
+ };
42
+
43
+ type PageItem = {type: 'page'; page: number; current: boolean};
44
+ type EllipsisItem = {type: 'ellipsis'};
45
+ type PaginationItem = ExclusifyUnion<PageItem | EllipsisItem>;
46
+
47
+ const DEFAULT_SURROUNDING_PAGE_COUNT = 1;
48
+ const FIRST_PAGE = 1;
49
+
50
+ const clamp = (value: number, min: number, max: number): number => Math.min(Math.max(value, min), max);
51
+
52
+ export const getPaginationItems = ({
53
+ totalPages,
54
+ currentPage,
55
+ surroundingPageCount = DEFAULT_SURROUNDING_PAGE_COUNT,
56
+ includeBoundaryPages = true,
57
+ }: {
58
+ totalPages: number;
59
+ currentPage: number;
60
+ surroundingPageCount?: number;
61
+ includeBoundaryPages?: boolean;
62
+ }): Array<PaginationItem> => {
63
+ if (totalPages <= 1) {
64
+ return [];
65
+ }
66
+
67
+ const activePage = clamp(currentPage, FIRST_PAGE, totalPages);
68
+ const surroundingCount = clamp(Math.floor(surroundingPageCount), 0, totalPages);
69
+ const dynamicPageCount = 2 * surroundingCount + 1;
70
+
71
+ if (totalPages <= dynamicPageCount) {
72
+ return Array.from({length: totalPages}, (_, index) => {
73
+ const page = index + FIRST_PAGE;
74
+ return {type: 'page', page, current: page === activePage};
75
+ });
76
+ }
77
+
78
+ const lastPage = totalPages;
79
+ const createPageItem = (page: number): PaginationItem => ({
80
+ type: 'page',
81
+ page,
82
+ current: page === activePage,
83
+ });
84
+ const createPageRange = (start: number, end: number): Array<PaginationItem> =>
85
+ Array.from({length: Math.max(0, end - start + 1)}, (_, index) => createPageItem(start + index));
86
+
87
+ if (!includeBoundaryPages) {
88
+ const rangeStart = Math.max(
89
+ Math.min(activePage - surroundingCount, lastPage - dynamicPageCount),
90
+ FIRST_PAGE + 1
91
+ );
92
+ const rangeEnd = rangeStart + dynamicPageCount - 1;
93
+ const items: Array<PaginationItem> = [];
94
+
95
+ if (rangeStart > FIRST_PAGE + 1) {
96
+ items.push({type: 'ellipsis'});
97
+ } else {
98
+ items.push(createPageItem(FIRST_PAGE));
99
+ }
100
+
101
+ items.push(...createPageRange(rangeStart, rangeEnd));
102
+
103
+ if (rangeEnd < lastPage - 1) {
104
+ items.push({type: 'ellipsis'});
105
+ } else if (rangeEnd < lastPage) {
106
+ items.push(createPageItem(lastPage));
107
+ }
108
+
109
+ return items;
110
+ }
111
+
112
+ const rangeStart = Math.max(
113
+ Math.min(activePage - surroundingCount, lastPage - dynamicPageCount - 1),
114
+ FIRST_PAGE + 2
115
+ );
116
+ const rangeEnd = Math.min(
117
+ Math.max(activePage + surroundingCount, FIRST_PAGE + dynamicPageCount + 1),
118
+ lastPage - 2
119
+ );
120
+
121
+ const items: Array<PaginationItem> = [createPageItem(FIRST_PAGE)];
122
+
123
+ if (rangeStart > FIRST_PAGE + 2) {
124
+ items.push({type: 'ellipsis'});
125
+ } else {
126
+ items.push(createPageItem(FIRST_PAGE + 1));
127
+ }
128
+
129
+ items.push(...createPageRange(rangeStart, rangeEnd));
130
+
131
+ if (rangeEnd < lastPage - 2) {
132
+ items.push({type: 'ellipsis'});
133
+ } else {
134
+ items.push(createPageItem(lastPage - 1));
135
+ }
136
+
137
+ items.push(createPageItem(lastPage));
138
+
139
+ return items;
140
+ };
141
+
142
+ const PaginationLabel = ({children}: {children: React.ReactNode}): JSX.Element => {
143
+ return (
144
+ <Text3 as="span" medium color="currentColor" wordBreak={false}>
145
+ {children}
146
+ </Text3>
147
+ );
148
+ };
149
+
150
+ const getEllipsisColor = (variant: NonDeprecatedVariant): string => {
151
+ switch (variant) {
152
+ case 'brand':
153
+ return skinVars.colors.textButtonSecondaryBrand;
154
+ case 'negative':
155
+ return skinVars.colors.textButtonSecondaryNegative;
156
+ default:
157
+ return skinVars.colors.textSecondary;
158
+ }
159
+ };
160
+
161
+ type PageListProps = {
162
+ items: Array<PaginationItem>;
163
+ disabled?: boolean;
164
+ className?: string;
165
+ onPageClick: (page: number) => void;
166
+ };
167
+
168
+ const PageList = ({items, disabled, className, onPageClick}: PageListProps): JSX.Element => {
169
+ const {texts, t} = useTheme();
170
+ const variant = useThemeVariant();
171
+ const goToPageLabel = (page: number) =>
172
+ t(texts.paginationGoToPage || tokens.paginationGoToPage, String(page));
173
+ const currentPageLabel = (page: number) =>
174
+ t(texts.paginationCurrentPage || tokens.paginationCurrentPage, String(page));
175
+
176
+ return (
177
+ <ol className={classnames(styles.pageList, className)}>
178
+ {items.map((item, index) => {
179
+ if (item.type === 'ellipsis') {
180
+ return (
181
+ <li key={`ellipsis-${index}`} className={styles.pageListItem} aria-hidden="true">
182
+ <Text3 as="span" medium color={getEllipsisColor(variant)} wordBreak={false}>
183
+ ...
184
+ </Text3>
185
+ </li>
186
+ );
187
+ }
188
+
189
+ if (item.current) {
190
+ return (
191
+ <li key={item.page} className={styles.pageListItem}>
192
+ <Touchable
193
+ className={classnames(
194
+ styles.currentPage,
195
+ styles.currentPageVariants[variant]
196
+ )}
197
+ onPress={() => {}}
198
+ aria-current="page"
199
+ aria-disabled
200
+ aria-label={currentPageLabel(item.page)}
201
+ >
202
+ <span className={styles.pageContent}>
203
+ <PaginationLabel>{item.page}</PaginationLabel>
204
+ </span>
205
+ </Touchable>
206
+ </li>
207
+ );
208
+ }
209
+
210
+ return (
211
+ <li key={item.page} className={styles.pageListItem}>
212
+ <Touchable
213
+ className={classnames(styles.pageButton, styles.pageButtonVariants[variant])}
214
+ disabled={disabled}
215
+ aria-label={goToPageLabel(item.page)}
216
+ onPress={() => onPageClick(item.page)}
217
+ >
218
+ <span className={styles.pageContent}>
219
+ <PaginationLabel>{item.page}</PaginationLabel>
220
+ </span>
221
+ </Touchable>
222
+ </li>
223
+ );
224
+ })}
225
+ </ol>
226
+ );
227
+ };
228
+
229
+ export const Pagination = ({
230
+ totalPages,
231
+ currentPage,
232
+ defaultPage = 1,
233
+ onChange,
234
+ hideNavigationControls = false,
235
+ hidePageList = false,
236
+ surroundingPageCount,
237
+ navLeftLabel,
238
+ navRightLabel,
239
+ mode = 'default',
240
+ disabled = false,
241
+ dataAttributes,
242
+ 'aria-label': ariaLabel,
243
+ }: PaginationProps): JSX.Element | null => {
244
+ const isControlled = currentPage !== undefined;
245
+ const [internalPage, setInternalPage] = React.useState(defaultPage);
246
+ const {texts, t} = useTheme();
247
+ const variant = useThemeVariant();
248
+
249
+ if (totalPages <= 1 || (hideNavigationControls && hidePageList)) {
250
+ return null;
251
+ }
252
+
253
+ const activePage = clamp(isControlled ? currentPage : internalPage, FIRST_PAGE, totalPages);
254
+
255
+ const sectionLabel = t(
256
+ texts.paginationSection || tokens.paginationSection,
257
+ String(activePage),
258
+ String(totalPages)
259
+ );
260
+ const resolvedAriaLabel = ariaLabel ? `${sectionLabel}, ${ariaLabel}` : sectionLabel;
261
+ const resolvedPrevLabel = navLeftLabel || texts.paginationPrevPage || t(tokens.paginationPrevPage);
262
+ const resolvedNextLabel = navRightLabel || texts.paginationNextPage || t(tokens.paginationNextPage);
263
+ const resolvedPrevAriaLabel =
264
+ navLeftLabel || texts.paginationPrevPageAriaLabel || t(tokens.paginationPrevPageAriaLabel);
265
+ const resolvedNextAriaLabel =
266
+ navRightLabel || texts.paginationNextPageAriaLabel || t(tokens.paginationNextPageAriaLabel);
267
+
268
+ const goToPage = (page: number) => {
269
+ const nextPage = clamp(page, FIRST_PAGE, totalPages);
270
+
271
+ if (disabled || nextPage === activePage) {
272
+ return;
273
+ }
274
+
275
+ if (!isControlled) {
276
+ setInternalPage(nextPage);
277
+ }
278
+
279
+ onChange?.(nextPage);
280
+ };
281
+
282
+ const isPrevDisabled = activePage <= 1;
283
+ const isNextDisabled = activePage >= totalPages;
284
+ const desktopItems = getPaginationItems({
285
+ totalPages,
286
+ currentPage: activePage,
287
+ surroundingPageCount,
288
+ includeBoundaryPages: true,
289
+ });
290
+ const mobileItems = getPaginationItems({
291
+ totalPages,
292
+ currentPage: activePage,
293
+ surroundingPageCount,
294
+ includeBoundaryPages: false,
295
+ });
296
+
297
+ return (
298
+ <nav
299
+ aria-label={resolvedAriaLabel}
300
+ className={classnames(styles.container, {
301
+ [styles.containerNavOnly]: hidePageList,
302
+ })}
303
+ {...getPrefixedDataAttributes(dataAttributes, 'Pagination')}
304
+ >
305
+ {!hideNavigationControls &&
306
+ (mode === 'iconOnly' ? (
307
+ <IconButton
308
+ small
309
+ Icon={IconChevronLeftRegular}
310
+ type="brand"
311
+ backgroundType="transparent"
312
+ disabled={disabled || isPrevDisabled}
313
+ aria-label={resolvedPrevAriaLabel}
314
+ onPress={() => goToPage(activePage - 1)}
315
+ bleedLeft
316
+ />
317
+ ) : (
318
+ <ButtonLink
319
+ small
320
+ className={styles.navigationButtonLinkVariants[variant]}
321
+ disabled={disabled || isPrevDisabled}
322
+ aria-label={resolvedPrevAriaLabel}
323
+ onPress={() => goToPage(activePage - 1)}
324
+ bleedLeft
325
+ StartIcon={IconChevronLeftRegular}
326
+ >
327
+ {resolvedPrevLabel}
328
+ </ButtonLink>
329
+ ))}
330
+
331
+ {!hidePageList && (
332
+ <>
333
+ <PageList
334
+ items={desktopItems}
335
+ disabled={disabled}
336
+ className={styles.pageListDesktop}
337
+ onPageClick={goToPage}
338
+ />
339
+ <PageList
340
+ items={mobileItems}
341
+ disabled={disabled}
342
+ className={styles.pageListMobile}
343
+ onPageClick={goToPage}
344
+ />
345
+ </>
346
+ )}
347
+ {!hideNavigationControls &&
348
+ (mode === 'iconOnly' ? (
349
+ <IconButton
350
+ small
351
+ Icon={IconChevronRightRegular}
352
+ type="brand"
353
+ backgroundType="transparent"
354
+ disabled={disabled || isNextDisabled}
355
+ aria-label={resolvedNextAriaLabel}
356
+ onPress={() => goToPage(activePage + 1)}
357
+ bleedRight
358
+ />
359
+ ) : (
360
+ <ButtonLink
361
+ small
362
+ className={styles.navigationButtonLinkVariants[variant]}
363
+ disabled={disabled || isNextDisabled}
364
+ aria-label={resolvedNextAriaLabel}
365
+ onPress={() => goToPage(activePage + 1)}
366
+ bleedRight
367
+ EndIcon={IconChevronRightRegular}
368
+ >
369
+ {resolvedNextLabel}
370
+ </ButtonLink>
371
+ ))}
372
+ </nav>
373
+ );
374
+ };
375
+
376
+ export default Pagination;
package/src/select.tsx CHANGED
@@ -225,11 +225,12 @@ const Select = ({
225
225
  input: inputRef.current,
226
226
  focusableElement: focusableRef.current,
227
227
  label,
228
+ required: !optional,
228
229
  });
229
230
  return () => {
230
231
  register(name, {input: null, focusableElement: null, label: ''});
231
232
  };
232
- }, [name, register, focusableRef, inputRef, focusableElement, inputElement, label]);
233
+ }, [name, register, focusableRef, inputRef, focusableElement, inputElement, label, optional]);
233
234
 
234
235
  React.useEffect(() => {
235
236
  const updateTentativeValueState = (e: KeyboardEvent) => {
@@ -195,7 +195,8 @@ export const openStoryPage = ({
195
195
  | 'Telefonica'
196
196
  | 'Blau'
197
197
  | 'Tu'
198
- | 'Esimflag';
198
+ | 'Esimflag'
199
+ | 'Cyber';
199
200
  args?: StoryArgs;
200
201
  isDarkMode?: boolean;
201
202
  }): Promise<PageApi> =>