@dnanpm/styleguide 3.9.8 → 3.9.9

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 (27) hide show
  1. package/build/cjs/components/Carousel/Carousel.d.ts +188 -0
  2. package/build/cjs/components/Carousel/Carousel.js +23 -10
  3. package/build/cjs/components/Divider/Divider.d.ts +4 -0
  4. package/build/cjs/components/Divider/Divider.js +2 -1
  5. package/build/cjs/components/InfoDialog/InfoDialog.d.ts +4 -0
  6. package/build/cjs/components/InfoDialog/InfoDialog.js +1 -1
  7. package/build/cjs/components/Input/Input.js +1 -2
  8. package/build/cjs/components/LabelText/LabelText.d.ts +5 -3
  9. package/build/cjs/components/LabelText/LabelText.js +1 -1
  10. package/build/cjs/components/ProgressIndicator/ProgressIndicator.d.ts +2 -2
  11. package/build/cjs/components/ProgressIndicator/ProgressIndicator.js +13 -6
  12. package/build/cjs/components/ReadMore/ReadMore.d.ts +4 -0
  13. package/build/cjs/components/ReadMore/ReadMore.js +30 -3
  14. package/build/es/components/Carousel/Carousel.d.ts +188 -0
  15. package/build/es/components/Carousel/Carousel.js +23 -11
  16. package/build/es/components/Divider/Divider.d.ts +4 -0
  17. package/build/es/components/Divider/Divider.js +2 -1
  18. package/build/es/components/InfoDialog/InfoDialog.d.ts +4 -0
  19. package/build/es/components/InfoDialog/InfoDialog.js +1 -1
  20. package/build/es/components/Input/Input.js +1 -2
  21. package/build/es/components/LabelText/LabelText.d.ts +5 -3
  22. package/build/es/components/LabelText/LabelText.js +1 -1
  23. package/build/es/components/ProgressIndicator/ProgressIndicator.d.ts +2 -2
  24. package/build/es/components/ProgressIndicator/ProgressIndicator.js +13 -6
  25. package/build/es/components/ReadMore/ReadMore.d.ts +4 -0
  26. package/build/es/components/ReadMore/ReadMore.js +31 -4
  27. package/package.json +5 -5
@@ -54,8 +54,196 @@ interface Props {
54
54
  * If not provided, visibleItems property will be used
55
55
  */
56
56
  responsive?: Partial<Responsive>;
57
+ /**
58
+ * Allows to pass a screen reader label for the pagination item next to the current slide number
59
+ */
60
+ paginationAriaLabel?: string;
61
+ /**
62
+ * Allows to pass a screen reader label for the next arrow button
63
+ */
64
+ nextAriaLabel?: string;
65
+ /**
66
+ * Allows to pass a screen reader label for the previous arrow button
67
+ */
68
+ previousAriaLabel?: string;
69
+ /**
70
+ * Number of items to move when navigating the carousel
71
+ *
72
+ * @default 1
73
+ */
74
+ swipeStep?: number;
57
75
  }
76
+ declare const SlideItem: import("styled-components").StyledComponent<"div", {
77
+ base: {
78
+ baseHeight: {
79
+ value: number;
80
+ unit: string;
81
+ };
82
+ baseWidth: {
83
+ value: number;
84
+ unit: string;
85
+ };
86
+ };
87
+ breakpoints: import("../../themes/themeComponents/breakpoints").ViewBreakpoints;
88
+ color: {
89
+ default: {
90
+ pink: string;
91
+ plum: string;
92
+ white: string;
93
+ black: string;
94
+ };
95
+ accent: {
96
+ lemon: string;
97
+ sky: string;
98
+ orange: string;
99
+ };
100
+ active: {
101
+ pink: string;
102
+ };
103
+ hover: {
104
+ pink: string;
105
+ };
106
+ text: {
107
+ gray: string;
108
+ pink: string;
109
+ plum: string;
110
+ white: string;
111
+ black: string;
112
+ };
113
+ line: {
114
+ L01: string;
115
+ L02: string;
116
+ L03: string;
117
+ L04: string;
118
+ };
119
+ notification: {
120
+ info: string;
121
+ success: string;
122
+ warning: string;
123
+ error: string;
124
+ };
125
+ background: {
126
+ sand: {
127
+ default: string;
128
+ E01: string;
129
+ E02: string;
130
+ };
131
+ pink: {
132
+ default: string;
133
+ E01: string;
134
+ E02: string;
135
+ };
136
+ plum: {
137
+ default: string;
138
+ E01: string;
139
+ E02: string;
140
+ };
141
+ lemon: {
142
+ default: string;
143
+ E01: string;
144
+ E02: string;
145
+ };
146
+ sky: {
147
+ default: string;
148
+ E01: string;
149
+ E02: string;
150
+ };
151
+ orange: {
152
+ default: string;
153
+ E01: string;
154
+ E02: string;
155
+ };
156
+ white: {
157
+ default: string;
158
+ };
159
+ };
160
+ focus: {
161
+ dark: string;
162
+ light: string;
163
+ };
164
+ transparency: {
165
+ T0: string;
166
+ T10: string;
167
+ T20: string;
168
+ T30: string;
169
+ T40: string;
170
+ T50: string;
171
+ T60: string;
172
+ T70: string;
173
+ T80: string;
174
+ T90: string;
175
+ T100: string;
176
+ };
177
+ };
178
+ fontFamily: {
179
+ default: string;
180
+ heading: string;
181
+ numerals: string;
182
+ };
183
+ fontSize: {
184
+ default: string;
185
+ xl: string;
186
+ l: string;
187
+ s: string;
188
+ xs: string;
189
+ h1XL: string;
190
+ h1L: string;
191
+ h1M: string;
192
+ h1S: string;
193
+ h2M: string;
194
+ h2S: string;
195
+ h3: string;
196
+ h4: string;
197
+ h5: string;
198
+ h1: string;
199
+ h2: string;
200
+ };
201
+ fontWeight: {
202
+ book: number;
203
+ medium: number;
204
+ bold: number;
205
+ black: number;
206
+ };
207
+ form: {
208
+ smallSelectWidth: string;
209
+ smallSelectHeight: string;
210
+ };
211
+ grid: {
212
+ gutter: string;
213
+ };
214
+ lineHeight: {
215
+ default: string;
216
+ xl: string;
217
+ s: string;
218
+ xs: string;
219
+ xxs: string;
220
+ auto: string;
221
+ h1XL: string;
222
+ h1L: string;
223
+ h1M: string;
224
+ h1S: string;
225
+ h2M: string;
226
+ h2S: string;
227
+ h3: string;
228
+ h4: string;
229
+ h5: string;
230
+ h1: string;
231
+ h2: string;
232
+ };
233
+ media: Record<string | number, (l: TemplateStringsArray, ...p: (string | number)[]) => string>;
234
+ radius: {
235
+ default: string;
236
+ s: string;
237
+ xs: string;
238
+ circle: string;
239
+ pill: string;
240
+ };
241
+ }, Required<Pick<Props, "visibleItems">> & {
242
+ itemWidthCorrection: number;
243
+ isSwiping: boolean;
244
+ }, never>;
58
245
  /** @visibleName Carousel */
59
246
  declare const Carousel: ({ "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
60
247
  /** @component */
61
248
  export default Carousel;
249
+ export { SlideItem };
@@ -146,6 +146,7 @@ const Counter = styled.default.span `
146
146
  `;
147
147
  /** @visibleName Carousel */
148
148
  const Carousel = (_a) => {
149
+ var _b;
149
150
  var { 'data-testid': dataTestId } = _a, props = tslib.__rest(_a, ['data-testid']);
150
151
  const slidesWrapperRef = React.useRef(null);
151
152
  const scrollbarRef = React.useRef(null);
@@ -175,9 +176,18 @@ const Carousel = (_a) => {
175
176
  }, 100);
176
177
  return () => clearTimeout(timeoutId);
177
178
  }, [width, isMobile, props.responsive, props.visibleItems, props.children]);
179
+ const getStep = (step, visibleItems) => {
180
+ if (step > visibleItems) {
181
+ return Math.floor(visibleItems);
182
+ }
183
+ return Math.floor(step);
184
+ };
178
185
  const visibleItems = props.visibleItems || calculatedItems;
179
186
  const slidesWrapperGapSizePx = 20;
180
187
  const slideScreensCount = React.Children.count(props.children) - Math.floor(visibleItems) + 1;
188
+ const step = getStep((_b = props.swipeStep) !== null && _b !== void 0 ? _b : 1, visibleItems);
189
+ const currentStepIndex = Math.ceil(currentIndex / step);
190
+ const totalSwipeSteps = Math.ceil(slideScreensCount / step + ((slideScreensCount - 1) % step !== 0 ? 1 : 0));
181
191
  const itemWidthCorrectionRatio = (slidesWrapperGapSizePx * visibleItems) % Math.floor(visibleItems) === 0
182
192
  ? (visibleItems - 1) / visibleItems
183
193
  : Math.floor(visibleItems) / visibleItems;
@@ -224,14 +234,15 @@ const Carousel = (_a) => {
224
234
  }
225
235
  };
226
236
  const handleNavigationButtonPreviousClick = () => {
227
- handleSetCurrentIndex(currentIndex - 1);
237
+ handleSetCurrentIndex(currentIndex - step);
228
238
  };
229
239
  const handleNavigationButtonNextClick = () => {
230
- handleSetCurrentIndex(currentIndex + 1);
240
+ handleSetCurrentIndex(currentIndex + step);
231
241
  };
232
242
  const handlePaginationItemClick = (e) => {
233
243
  if (e.currentTarget.parentElement) {
234
- handleSetCurrentIndex([...e.currentTarget.parentElement.children].indexOf(e.currentTarget));
244
+ const index = [...e.currentTarget.parentElement.children].indexOf(e.currentTarget);
245
+ handleSetCurrentIndex(index * step);
235
246
  }
236
247
  };
237
248
  const handlePointerMove = (e) => {
@@ -272,14 +283,14 @@ const Carousel = (_a) => {
272
283
  if (endTime - data.startTime > 300) {
273
284
  const swipeRatio = Math.abs(data.currentTransform - data.startTransform) / data.itemWidth;
274
285
  if (swipeRatio >= 0.5) {
275
- handleSetCurrentIndex(currentIndex + Math.round(data.direction > 0 ? swipeRatio : -swipeRatio));
286
+ handleSetCurrentIndex(currentIndex + Math.round(data.direction > 0 ? swipeRatio : -swipeRatio) * step);
276
287
  }
277
288
  else {
278
289
  handleSetCurrentIndex(currentIndex);
279
290
  }
280
291
  }
281
292
  else {
282
- handleSetCurrentIndex(currentIndex + data.direction);
293
+ handleSetCurrentIndex(currentIndex + data.direction * step);
283
294
  }
284
295
  if (data.scrollbarNavigation && data.direction === 0) {
285
296
  if (knobRef.current) {
@@ -341,19 +352,21 @@ const Carousel = (_a) => {
341
352
  props.title && React__default.default.createElement(Title, null, props.title),
342
353
  React__default.default.createElement(Navigation, null,
343
354
  props.hasCounter && (React__default.default.createElement(Counter, null,
344
- slideScreensCount === 0 ? 0 : currentIndex + 1,
355
+ slideScreensCount === 0 ? 0 : currentStepIndex + 1,
345
356
  "/",
346
- slideScreensCount)),
347
- React__default.default.createElement(ButtonArrow.default, { direction: "left", "aria-label": "Previous", onClick: handleNavigationButtonPreviousClick, disabled: currentIndex <= 0 }),
348
- React__default.default.createElement(ButtonArrow.default, { direction: "right", "aria-label": "Next", onClick: handleNavigationButtonNextClick, disabled: currentIndex + visibleItems >= React.Children.count(props.children) }))),
357
+ totalSwipeSteps)),
358
+ React__default.default.createElement(ButtonArrow.default, { direction: "left", "aria-label": props.previousAriaLabel, onClick: handleNavigationButtonPreviousClick, disabled: currentIndex <= 0, type: "button" }),
359
+ React__default.default.createElement(ButtonArrow.default, { direction: "right", "aria-label": props.nextAriaLabel, onClick: handleNavigationButtonNextClick, disabled: currentIndex + visibleItems >= React.Children.count(props.children), type: "button" }))),
349
360
  React__default.default.createElement(Content, { "data-testid": dataTestId && `${dataTestId}-content` },
350
361
  React__default.default.createElement(SlidesWrapper, { ref: slidesWrapperRef, onPointerDown: handleSlidesPointerDown, gap: slidesWrapperGapSizePx / 16 }, React.Children.map(props.children, child => (React__default.default.createElement(SlideItem, { visibleItems: visibleItems, itemWidthCorrection: itemWidthCorrection, isSwiping: isSwiping, onPointerDown: handlePointerDown }, child))))),
351
362
  React__default.default.createElement(Footer, { "data-testid": dataTestId && `${dataTestId}-footer` },
352
- React__default.default.createElement(Pagination, null, [...Array(slideScreensCount).keys()].map((value, index) => (React__default.default.createElement(PaginationItem, { key: value, "aria-label": `Move to step ${index + 1}`, "aria-current": index === currentIndex, isActive: index === currentIndex, onClick: handlePaginationItemClick })))),
363
+ React__default.default.createElement(Pagination, null, [...Array(totalSwipeSteps).keys()].map((value, index) => (React__default.default.createElement(PaginationItem, { key: value, "aria-label": props.paginationAriaLabel &&
364
+ `${props.paginationAriaLabel} ${index + 1}`, "aria-current": Math.ceil(currentIndex / step) === index, isActive: Math.ceil(currentIndex / step) === index, onClick: handlePaginationItemClick, type: "button" })))),
353
365
  React__default.default.createElement(Scrollbar, { ref: scrollbarRef, onPointerDown: handleScrollbarPointerDown },
354
366
  React__default.default.createElement(Knob, { ref: knobRef, knobSize: slideScreensCount })),
355
367
  props.footerButton && (React__default.default.createElement(FooterButton, null,
356
368
  React__default.default.createElement(ButtonIcon.default, { icon: icons.ArrowRight, onClick: props.onFooterButtonClick }, props.footerButton))))));
357
369
  };
358
370
 
371
+ exports.SlideItem = SlideItem;
359
372
  exports.default = Carousel;
@@ -29,6 +29,10 @@ interface Props {
29
29
  * Allows to pass a custom className
30
30
  */
31
31
  className?: string;
32
+ /**
33
+ * An aria-label to the focusable separator should be included if there is more than one focusable separator
34
+ */
35
+ ariaLabelFocusableSeparator?: string;
32
36
  }
33
37
  declare const Divider: ({ "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
34
38
  /** @component */
@@ -26,7 +26,8 @@ const DividerWrapper = styled__default.default.div `
26
26
  `;
27
27
  const Divider = (_a) => {
28
28
  var { 'data-testid': dataTestId } = _a, props = tslib.__rest(_a, ['data-testid']);
29
- return (React__default.default.createElement(DividerWrapper, { id: props.id, margin: props.margin, padding: props.padding, className: props.className, "data-testid": dataTestId }, props.children));
29
+ const isFocusableSeparator = Boolean(props.children);
30
+ return (React__default.default.createElement(DividerWrapper, { id: props.id, margin: props.margin, padding: props.padding, className: props.className, "data-testid": dataTestId, as: isFocusableSeparator ? 'div' : 'hr', role: isFocusableSeparator ? 'separator' : undefined, "aria-orientation": "horizontal", "aria-label": props.ariaLabelFocusableSeparator, "aria-hidden": !isFocusableSeparator, tabIndex: isFocusableSeparator ? 0 : -1 }, props.children));
30
31
  };
31
32
 
32
33
  exports.default = Divider;
@@ -37,6 +37,10 @@ interface Props {
37
37
  * Allows to pass testid string for testing purposes
38
38
  */
39
39
  'data-testid'?: string;
40
+ /**
41
+ * Allows to pass a screen reader label to the component
42
+ */
43
+ ariaLabel?: string;
40
44
  }
41
45
  /** @visibleName Info Dialog */
42
46
  declare const InfoDialog: ({ position, type, "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
@@ -62,7 +62,7 @@ const InfoDialogContainer = styled.default.div `
62
62
  /** @visibleName Info Dialog */
63
63
  const InfoDialog = (_a) => {
64
64
  var { position = 'middle', type = 'default', 'data-testid': dataTestId } = _a, props = tslib.__rest(_a, ["position", "type", 'data-testid']);
65
- return (React__default.default.createElement(InfoDialogContainer, { id: props.id, "data-testid": dataTestId, className: props.className, position: position, type: type }, props.children));
65
+ return (React__default.default.createElement(InfoDialogContainer, { id: props.id, "data-testid": dataTestId, className: props.className, position: position, type: type, role: "region", "aria-label": props.ariaLabel }, props.children));
66
66
  };
67
67
 
68
68
  exports.default = InfoDialog;
@@ -166,8 +166,7 @@ const Input = (_a) => {
166
166
  return (React__default.default.createElement(FieldContainer, { className: props.className },
167
167
  props.label && (React__default.default.createElement(LabelText.default, { htmlFor: props.id, "data-testid": dataTestId && `${dataTestId}-label`, status: props.status === 'error' ? props.status : undefined, isMandatory: props.required }, props.label)),
168
168
  React__default.default.createElement(FieldWrapper, { status: props.status, "$type": type, "$disabled": props.disabled },
169
- React__default.default.createElement(StyledInput, { id: props.id, name: props.name, type: props.readonly ? 'hidden' : type, value: props.value, placeholder: props.placeholder, onChange: handleChange, onBlur: handleOnBlur, onFocus: props.onFocus, onClick: onClick, onKeyDown: props.onKeyDown, onKeyPress: props.onKeyPress, required: props.required, disabled: props.disabled, autoComplete: props.autocomplete, "aria-disabled": props.disabled, "aria-label": !props.label ? (_b = props.ariaLabel) !== null && _b !== void 0 ? _b : props.id : undefined, ref: inputRef, tabIndex: props.tabIndex, "aria-describedby": getDescribedBy(), "data-testid": dataTestId, readOnly: props.readonly }),
170
- props.readonly && React__default.default.createElement("div", null, props.value),
169
+ React__default.default.createElement(StyledInput, { id: props.id, name: props.name, type: type, value: props.value, placeholder: props.placeholder, onChange: handleChange, onBlur: handleOnBlur, onFocus: props.onFocus, onClick: onClick, onKeyDown: props.onKeyDown, onKeyPress: props.onKeyPress, required: props.required, disabled: props.disabled, autoComplete: props.autocomplete, "aria-disabled": props.disabled, "aria-label": !props.label ? (_b = props.ariaLabel) !== null && _b !== void 0 ? _b : props.id : undefined, ref: inputRef, tabIndex: props.tabIndex, "aria-describedby": getDescribedBy(), "data-testid": dataTestId, readOnly: props.readonly }),
171
170
  ((props.status && props.status !== 'comment') ||
172
171
  props.showPasswordToggle ||
173
172
  props.disabled ||
@@ -18,10 +18,12 @@ interface Props {
18
18
  * Styling of `label` element changes depending on the passed status
19
19
  *
20
20
  * @param {LabelTextStatus} undefined Default styling
21
- * @param {LabelTextStatus} info Changes color to `theme.color.notification.info`
22
- * @param {LabelTextStatus} success Changes color to `theme.color.notification.success`
23
- * @param {LabelTextStatus} warning Changes color to `theme.color.notification.warning`
21
+ * @param {LabelTextStatus} info Changes color to default color (this type will be deprecated in the future)
22
+ * @param {LabelTextStatus} success Changes color to default color (this type will be deprecated in the future)
23
+ * @param {LabelTextStatus} warning Changes color to default color (this type will be deprecated in the future)
24
24
  * @param {LabelTextStatus} error Changes color to `theme.color.notification.error`
25
+ *
26
+ * @deprecated info, success and warning are deprecated, please switch to default or error status
25
27
  */
26
28
  status?: LabelTextStatus;
27
29
  /**
@@ -14,7 +14,7 @@ var React__default = /*#__PURE__*/_interopDefaultCompat(React);
14
14
 
15
15
  const Label = styled.default.label `
16
16
  display: block;
17
- color: ${({ status }) => (status ? theme.default.color.notification[status] : theme.default.color.text.gray)};
17
+ color: ${({ status }) => status === 'error' ? theme.default.color.notification.error : theme.default.color.text.gray};
18
18
  font-weight: ${theme.default.fontWeight.medium};
19
19
  font-size: ${theme.default.fontSize.default};
20
20
  line-height: ${theme.default.lineHeight.default};
@@ -1,4 +1,4 @@
1
- import type { MouseEvent } from 'react';
1
+ import type { MouseEvent, KeyboardEvent } from 'react';
2
2
  import React from 'react';
3
3
  type ProgressIndicatorStatus = 'error';
4
4
  interface Props {
@@ -15,7 +15,7 @@ interface Props {
15
15
  * On Progress Indicator Item label or number click callback
16
16
  * Use `e.currentTarget.parentElement` to get Progress Indicator Item element
17
17
  */
18
- onStepClick?: (stepIndex: number, e: MouseEvent<HTMLElement>) => void;
18
+ onStepClick?: (stepIndex: number, e: MouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>) => void;
19
19
  /**
20
20
  * Allows to change version of component to small
21
21
  */
@@ -126,14 +126,21 @@ const ProgressIndicator = (_a) => {
126
126
  props.onStepClick(index, e);
127
127
  }
128
128
  };
129
- return (React__default.default.createElement(ProgressIndicatorItem, { key: id, small: props.small, "aria-current": isActive ? 'step' : 'false' },
129
+ const handleKeyDown = (e) => {
130
+ if ((e.key === 'Enter' || e.key === ' ') && props.onStepClick) {
131
+ e.preventDefault();
132
+ props.onStepClick(index, e);
133
+ }
134
+ };
135
+ const isClickable = isCompleted && Boolean(props.onStepClick);
136
+ return (React__default.default.createElement(ProgressIndicatorItem, { key: id, small: props.small },
130
137
  index > 0 && (React__default.default.createElement(ProgressIndicatorItemConnector, { small: props.small, isActive: isActive, isCompleted: isCompleted })),
131
- React__default.default.createElement(ProgressIndicatorItemNumber, { small: props.small, onClick: handleClick, isActive: isActive, isCompleted: isCompleted, isError: isError, isClickable: isCompleted && Boolean(props.onStepClick) }, isCompleted || isError ? (React__default.default.createElement(React__default.default.Fragment, null,
132
- isCompleted && props.completedStepLabel && (React__default.default.createElement("span", { className: "visually-hidden" }, props.completedStepLabel)),
133
- React__default.default.createElement(Icon.default, { icon: isError ? icons.Warning : icons.Check, color: isError ? theme.default.color.text.white : theme.default.color.text.pink, size: "1rem" }))) : (stepNumber)),
134
- label && (React__default.default.createElement(ProgressIndicatorItemLabel, { small: props.small, onClick: handleClick, isActive: isActive, className: "visually-hidden" }, label))));
138
+ React__default.default.createElement(ProgressIndicatorItemNumber, { small: props.small, onClick: handleClick, isActive: isActive, isCompleted: isCompleted, isError: isError, onKeyDown: handleKeyDown, tabIndex: isClickable || isActive ? 0 : -1, isClickable: isClickable, role: "tab", "aria-current": isActive ? 'step' : 'false', "aria-label": isCompleted && props.completedStepLabel
139
+ ? `${label}, ${props.completedStepLabel}`
140
+ : label }, isCompleted || isError ? (React__default.default.createElement(Icon.default, { icon: isError ? icons.Warning : icons.Check, color: isError ? theme.default.color.text.white : theme.default.color.text.pink, size: "1rem", "aria-hidden": true })) : (stepNumber)),
141
+ label && (React__default.default.createElement(ProgressIndicatorItemLabel, { "aria-hidden": true, small: props.small, onClick: handleClick, isActive: isActive, className: "visually-hidden" }, label))));
135
142
  });
136
- return (React__default.default.createElement(ProgressIndicatorWrapper, { className: props.className, "data-testid": dataTestId, "aria-label": props.ariaLabel, role: "list" }, progressIndicatorItems));
143
+ return (React__default.default.createElement(ProgressIndicatorWrapper, { className: props.className, "data-testid": dataTestId, "aria-label": props.ariaLabel, role: "tablist" }, progressIndicatorItems));
137
144
  };
138
145
 
139
146
  exports.default = ProgressIndicator;
@@ -68,6 +68,10 @@ interface Props {
68
68
  * Allows to pass testid string for testing purposes
69
69
  */
70
70
  'data-testid'?: string;
71
+ /**
72
+ * Allows to pass an accessible label for the component, enhancing screen reader support.
73
+ */
74
+ ariaLabel?: string;
71
75
  }
72
76
  /** @visibleName Read More */
73
77
  declare const ReadMore: ({ collapsedSize, "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
@@ -45,6 +45,9 @@ const StyledButtonIcon = styled.default(ButtonIcon.default) `
45
45
  const ReadMore = (_a) => {
46
46
  var { collapsedSize = '10rem', 'data-testid': dataTestId } = _a, props = tslib.__rest(_a, ["collapsedSize", 'data-testid']);
47
47
  const [expanded, setExpanded] = React.useState(props.seoInitExpanded === true || false);
48
+ const contentRef = React.useRef(null);
49
+ const buttonRef = React.useRef(null);
50
+ const userInteractedRef = React.useRef(false);
48
51
  // TODO: Remove once https://jira.dna.fi/browse/STYLE-662 is done
49
52
  const temporaryIsStatelessFlag = typeof props.isExpanded !== 'undefined';
50
53
  const temporaryStateManagement = temporaryIsStatelessFlag ? props.isExpanded : expanded;
@@ -56,16 +59,40 @@ const ReadMore = (_a) => {
56
59
  if (!temporaryIsStatelessFlag) {
57
60
  setExpanded(!expanded);
58
61
  }
62
+ userInteractedRef.current = true;
59
63
  };
60
64
  React.useEffect(() => {
61
65
  if (props.seoInitExpanded) {
62
66
  setExpanded(false);
63
67
  }
64
68
  }, [props.seoInitExpanded]);
65
- return (React__default.default.createElement(Container, { id: props.id, className: props.className, "data-testid": dataTestId },
66
- React__default.default.createElement(Content, { isExpanded: temporaryStateManagement, collapsedSize: collapsedSize, "data-testid": dataTestId && `${dataTestId}-content` }, props.children),
69
+ React.useEffect(() => {
70
+ var _a, _b;
71
+ if (userInteractedRef.current) {
72
+ if (temporaryStateManagement) {
73
+ (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.focus();
74
+ }
75
+ else {
76
+ (_b = buttonRef.current) === null || _b === void 0 ? void 0 : _b.focus();
77
+ }
78
+ }
79
+ }, [temporaryStateManagement]);
80
+ // Function to apply tabIndex to all links elements of children (since we don't control what is passed as children)
81
+ const forceTabIndexOnTextLinks = (child) => {
82
+ if (!React.isValidElement(child)) {
83
+ return child;
84
+ }
85
+ if (child.type === 'a') {
86
+ return React.cloneElement(child, {
87
+ tabIndex: temporaryStateManagement ? 0 : -1,
88
+ });
89
+ }
90
+ return child;
91
+ };
92
+ return (React__default.default.createElement(Container, { id: props.id, className: props.className, "data-testid": dataTestId, "aria-label": props.ariaLabel, role: "region" },
93
+ React__default.default.createElement(Content, { ref: contentRef, isExpanded: temporaryStateManagement, collapsedSize: collapsedSize, "data-testid": dataTestId && `${dataTestId}-content`, "aria-hidden": temporaryStateManagement ? 'false' : 'true', tabIndex: temporaryStateManagement ? 0 : -1 }, React.Children.map(props.children, forceTabIndexOnTextLinks)),
67
94
  React__default.default.createElement(ButtonWrapper, { buttonPosition: props.buttonPosition },
68
- React__default.default.createElement(StyledButtonIcon, { icon: temporaryStateManagement ? icons.ChevronUp : icons.ChevronDown, onClick: handleOnClick }, temporaryButtonLabel || props.buttonLabel))));
95
+ React__default.default.createElement(StyledButtonIcon, { ref: buttonRef, icon: temporaryStateManagement ? icons.ChevronUp : icons.ChevronDown, onClick: handleOnClick, ariaHidden: true, "aria-expanded": temporaryStateManagement }, temporaryButtonLabel || props.buttonLabel))));
69
96
  };
70
97
 
71
98
  exports.default = ReadMore;
@@ -54,8 +54,196 @@ interface Props {
54
54
  * If not provided, visibleItems property will be used
55
55
  */
56
56
  responsive?: Partial<Responsive>;
57
+ /**
58
+ * Allows to pass a screen reader label for the pagination item next to the current slide number
59
+ */
60
+ paginationAriaLabel?: string;
61
+ /**
62
+ * Allows to pass a screen reader label for the next arrow button
63
+ */
64
+ nextAriaLabel?: string;
65
+ /**
66
+ * Allows to pass a screen reader label for the previous arrow button
67
+ */
68
+ previousAriaLabel?: string;
69
+ /**
70
+ * Number of items to move when navigating the carousel
71
+ *
72
+ * @default 1
73
+ */
74
+ swipeStep?: number;
57
75
  }
76
+ declare const SlideItem: import("styled-components").StyledComponent<"div", {
77
+ base: {
78
+ baseHeight: {
79
+ value: number;
80
+ unit: string;
81
+ };
82
+ baseWidth: {
83
+ value: number;
84
+ unit: string;
85
+ };
86
+ };
87
+ breakpoints: import("../../themes/themeComponents/breakpoints").ViewBreakpoints;
88
+ color: {
89
+ default: {
90
+ pink: string;
91
+ plum: string;
92
+ white: string;
93
+ black: string;
94
+ };
95
+ accent: {
96
+ lemon: string;
97
+ sky: string;
98
+ orange: string;
99
+ };
100
+ active: {
101
+ pink: string;
102
+ };
103
+ hover: {
104
+ pink: string;
105
+ };
106
+ text: {
107
+ gray: string;
108
+ pink: string;
109
+ plum: string;
110
+ white: string;
111
+ black: string;
112
+ };
113
+ line: {
114
+ L01: string;
115
+ L02: string;
116
+ L03: string;
117
+ L04: string;
118
+ };
119
+ notification: {
120
+ info: string;
121
+ success: string;
122
+ warning: string;
123
+ error: string;
124
+ };
125
+ background: {
126
+ sand: {
127
+ default: string;
128
+ E01: string;
129
+ E02: string;
130
+ };
131
+ pink: {
132
+ default: string;
133
+ E01: string;
134
+ E02: string;
135
+ };
136
+ plum: {
137
+ default: string;
138
+ E01: string;
139
+ E02: string;
140
+ };
141
+ lemon: {
142
+ default: string;
143
+ E01: string;
144
+ E02: string;
145
+ };
146
+ sky: {
147
+ default: string;
148
+ E01: string;
149
+ E02: string;
150
+ };
151
+ orange: {
152
+ default: string;
153
+ E01: string;
154
+ E02: string;
155
+ };
156
+ white: {
157
+ default: string;
158
+ };
159
+ };
160
+ focus: {
161
+ dark: string;
162
+ light: string;
163
+ };
164
+ transparency: {
165
+ T0: string;
166
+ T10: string;
167
+ T20: string;
168
+ T30: string;
169
+ T40: string;
170
+ T50: string;
171
+ T60: string;
172
+ T70: string;
173
+ T80: string;
174
+ T90: string;
175
+ T100: string;
176
+ };
177
+ };
178
+ fontFamily: {
179
+ default: string;
180
+ heading: string;
181
+ numerals: string;
182
+ };
183
+ fontSize: {
184
+ default: string;
185
+ xl: string;
186
+ l: string;
187
+ s: string;
188
+ xs: string;
189
+ h1XL: string;
190
+ h1L: string;
191
+ h1M: string;
192
+ h1S: string;
193
+ h2M: string;
194
+ h2S: string;
195
+ h3: string;
196
+ h4: string;
197
+ h5: string;
198
+ h1: string;
199
+ h2: string;
200
+ };
201
+ fontWeight: {
202
+ book: number;
203
+ medium: number;
204
+ bold: number;
205
+ black: number;
206
+ };
207
+ form: {
208
+ smallSelectWidth: string;
209
+ smallSelectHeight: string;
210
+ };
211
+ grid: {
212
+ gutter: string;
213
+ };
214
+ lineHeight: {
215
+ default: string;
216
+ xl: string;
217
+ s: string;
218
+ xs: string;
219
+ xxs: string;
220
+ auto: string;
221
+ h1XL: string;
222
+ h1L: string;
223
+ h1M: string;
224
+ h1S: string;
225
+ h2M: string;
226
+ h2S: string;
227
+ h3: string;
228
+ h4: string;
229
+ h5: string;
230
+ h1: string;
231
+ h2: string;
232
+ };
233
+ media: Record<string | number, (l: TemplateStringsArray, ...p: (string | number)[]) => string>;
234
+ radius: {
235
+ default: string;
236
+ s: string;
237
+ xs: string;
238
+ circle: string;
239
+ pill: string;
240
+ };
241
+ }, Required<Pick<Props, "visibleItems">> & {
242
+ itemWidthCorrection: number;
243
+ isSwiping: boolean;
244
+ }, never>;
58
245
  /** @visibleName Carousel */
59
246
  declare const Carousel: ({ "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
60
247
  /** @component */
61
248
  export default Carousel;
249
+ export { SlideItem };
@@ -138,6 +138,7 @@ const Counter = styled.span `
138
138
  `;
139
139
  /** @visibleName Carousel */
140
140
  const Carousel = (_a) => {
141
+ var _b;
141
142
  var { 'data-testid': dataTestId } = _a, props = __rest(_a, ['data-testid']);
142
143
  const slidesWrapperRef = useRef(null);
143
144
  const scrollbarRef = useRef(null);
@@ -167,9 +168,18 @@ const Carousel = (_a) => {
167
168
  }, 100);
168
169
  return () => clearTimeout(timeoutId);
169
170
  }, [width, isMobile, props.responsive, props.visibleItems, props.children]);
171
+ const getStep = (step, visibleItems) => {
172
+ if (step > visibleItems) {
173
+ return Math.floor(visibleItems);
174
+ }
175
+ return Math.floor(step);
176
+ };
170
177
  const visibleItems = props.visibleItems || calculatedItems;
171
178
  const slidesWrapperGapSizePx = 20;
172
179
  const slideScreensCount = Children.count(props.children) - Math.floor(visibleItems) + 1;
180
+ const step = getStep((_b = props.swipeStep) !== null && _b !== void 0 ? _b : 1, visibleItems);
181
+ const currentStepIndex = Math.ceil(currentIndex / step);
182
+ const totalSwipeSteps = Math.ceil(slideScreensCount / step + ((slideScreensCount - 1) % step !== 0 ? 1 : 0));
173
183
  const itemWidthCorrectionRatio = (slidesWrapperGapSizePx * visibleItems) % Math.floor(visibleItems) === 0
174
184
  ? (visibleItems - 1) / visibleItems
175
185
  : Math.floor(visibleItems) / visibleItems;
@@ -216,14 +226,15 @@ const Carousel = (_a) => {
216
226
  }
217
227
  };
218
228
  const handleNavigationButtonPreviousClick = () => {
219
- handleSetCurrentIndex(currentIndex - 1);
229
+ handleSetCurrentIndex(currentIndex - step);
220
230
  };
221
231
  const handleNavigationButtonNextClick = () => {
222
- handleSetCurrentIndex(currentIndex + 1);
232
+ handleSetCurrentIndex(currentIndex + step);
223
233
  };
224
234
  const handlePaginationItemClick = (e) => {
225
235
  if (e.currentTarget.parentElement) {
226
- handleSetCurrentIndex([...e.currentTarget.parentElement.children].indexOf(e.currentTarget));
236
+ const index = [...e.currentTarget.parentElement.children].indexOf(e.currentTarget);
237
+ handleSetCurrentIndex(index * step);
227
238
  }
228
239
  };
229
240
  const handlePointerMove = (e) => {
@@ -264,14 +275,14 @@ const Carousel = (_a) => {
264
275
  if (endTime - data.startTime > 300) {
265
276
  const swipeRatio = Math.abs(data.currentTransform - data.startTransform) / data.itemWidth;
266
277
  if (swipeRatio >= 0.5) {
267
- handleSetCurrentIndex(currentIndex + Math.round(data.direction > 0 ? swipeRatio : -swipeRatio));
278
+ handleSetCurrentIndex(currentIndex + Math.round(data.direction > 0 ? swipeRatio : -swipeRatio) * step);
268
279
  }
269
280
  else {
270
281
  handleSetCurrentIndex(currentIndex);
271
282
  }
272
283
  }
273
284
  else {
274
- handleSetCurrentIndex(currentIndex + data.direction);
285
+ handleSetCurrentIndex(currentIndex + data.direction * step);
275
286
  }
276
287
  if (data.scrollbarNavigation && data.direction === 0) {
277
288
  if (knobRef.current) {
@@ -333,19 +344,20 @@ const Carousel = (_a) => {
333
344
  props.title && React__default.createElement(Title, null, props.title),
334
345
  React__default.createElement(Navigation, null,
335
346
  props.hasCounter && (React__default.createElement(Counter, null,
336
- slideScreensCount === 0 ? 0 : currentIndex + 1,
347
+ slideScreensCount === 0 ? 0 : currentStepIndex + 1,
337
348
  "/",
338
- slideScreensCount)),
339
- React__default.createElement(ButtonArrow, { direction: "left", "aria-label": "Previous", onClick: handleNavigationButtonPreviousClick, disabled: currentIndex <= 0 }),
340
- React__default.createElement(ButtonArrow, { direction: "right", "aria-label": "Next", onClick: handleNavigationButtonNextClick, disabled: currentIndex + visibleItems >= Children.count(props.children) }))),
349
+ totalSwipeSteps)),
350
+ React__default.createElement(ButtonArrow, { direction: "left", "aria-label": props.previousAriaLabel, onClick: handleNavigationButtonPreviousClick, disabled: currentIndex <= 0, type: "button" }),
351
+ React__default.createElement(ButtonArrow, { direction: "right", "aria-label": props.nextAriaLabel, onClick: handleNavigationButtonNextClick, disabled: currentIndex + visibleItems >= Children.count(props.children), type: "button" }))),
341
352
  React__default.createElement(Content, { "data-testid": dataTestId && `${dataTestId}-content` },
342
353
  React__default.createElement(SlidesWrapper, { ref: slidesWrapperRef, onPointerDown: handleSlidesPointerDown, gap: slidesWrapperGapSizePx / 16 }, Children.map(props.children, child => (React__default.createElement(SlideItem, { visibleItems: visibleItems, itemWidthCorrection: itemWidthCorrection, isSwiping: isSwiping, onPointerDown: handlePointerDown }, child))))),
343
354
  React__default.createElement(Footer, { "data-testid": dataTestId && `${dataTestId}-footer` },
344
- React__default.createElement(Pagination, null, [...Array(slideScreensCount).keys()].map((value, index) => (React__default.createElement(PaginationItem, { key: value, "aria-label": `Move to step ${index + 1}`, "aria-current": index === currentIndex, isActive: index === currentIndex, onClick: handlePaginationItemClick })))),
355
+ React__default.createElement(Pagination, null, [...Array(totalSwipeSteps).keys()].map((value, index) => (React__default.createElement(PaginationItem, { key: value, "aria-label": props.paginationAriaLabel &&
356
+ `${props.paginationAriaLabel} ${index + 1}`, "aria-current": Math.ceil(currentIndex / step) === index, isActive: Math.ceil(currentIndex / step) === index, onClick: handlePaginationItemClick, type: "button" })))),
345
357
  React__default.createElement(Scrollbar, { ref: scrollbarRef, onPointerDown: handleScrollbarPointerDown },
346
358
  React__default.createElement(Knob, { ref: knobRef, knobSize: slideScreensCount })),
347
359
  props.footerButton && (React__default.createElement(FooterButton, null,
348
360
  React__default.createElement(ButtonIcon, { icon: ArrowRight, onClick: props.onFooterButtonClick }, props.footerButton))))));
349
361
  };
350
362
 
351
- export { Carousel as default };
363
+ export { SlideItem, Carousel as default };
@@ -29,6 +29,10 @@ interface Props {
29
29
  * Allows to pass a custom className
30
30
  */
31
31
  className?: string;
32
+ /**
33
+ * An aria-label to the focusable separator should be included if there is more than one focusable separator
34
+ */
35
+ ariaLabelFocusableSeparator?: string;
32
36
  }
33
37
  declare const Divider: ({ "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
34
38
  /** @component */
@@ -17,7 +17,8 @@ const DividerWrapper = styled__default.div `
17
17
  `;
18
18
  const Divider = (_a) => {
19
19
  var { 'data-testid': dataTestId } = _a, props = __rest(_a, ['data-testid']);
20
- return (React__default.createElement(DividerWrapper, { id: props.id, margin: props.margin, padding: props.padding, className: props.className, "data-testid": dataTestId }, props.children));
20
+ const isFocusableSeparator = Boolean(props.children);
21
+ return (React__default.createElement(DividerWrapper, { id: props.id, margin: props.margin, padding: props.padding, className: props.className, "data-testid": dataTestId, as: isFocusableSeparator ? 'div' : 'hr', role: isFocusableSeparator ? 'separator' : undefined, "aria-orientation": "horizontal", "aria-label": props.ariaLabelFocusableSeparator, "aria-hidden": !isFocusableSeparator, tabIndex: isFocusableSeparator ? 0 : -1 }, props.children));
21
22
  };
22
23
 
23
24
  export { Divider as default };
@@ -37,6 +37,10 @@ interface Props {
37
37
  * Allows to pass testid string for testing purposes
38
38
  */
39
39
  'data-testid'?: string;
40
+ /**
41
+ * Allows to pass a screen reader label to the component
42
+ */
43
+ ariaLabel?: string;
40
44
  }
41
45
  /** @visibleName Info Dialog */
42
46
  declare const InfoDialog: ({ position, type, "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
@@ -54,7 +54,7 @@ const InfoDialogContainer = styled.div `
54
54
  /** @visibleName Info Dialog */
55
55
  const InfoDialog = (_a) => {
56
56
  var { position = 'middle', type = 'default', 'data-testid': dataTestId } = _a, props = __rest(_a, ["position", "type", 'data-testid']);
57
- return (React__default.createElement(InfoDialogContainer, { id: props.id, "data-testid": dataTestId, className: props.className, position: position, type: type }, props.children));
57
+ return (React__default.createElement(InfoDialogContainer, { id: props.id, "data-testid": dataTestId, className: props.className, position: position, type: type, role: "region", "aria-label": props.ariaLabel }, props.children));
58
58
  };
59
59
 
60
60
  export { InfoDialog as default };
@@ -158,8 +158,7 @@ const Input = (_a) => {
158
158
  return (React__default.createElement(FieldContainer, { className: props.className },
159
159
  props.label && (React__default.createElement(LabelText, { htmlFor: props.id, "data-testid": dataTestId && `${dataTestId}-label`, status: props.status === 'error' ? props.status : undefined, isMandatory: props.required }, props.label)),
160
160
  React__default.createElement(FieldWrapper, { status: props.status, "$type": type, "$disabled": props.disabled },
161
- React__default.createElement(StyledInput, { id: props.id, name: props.name, type: props.readonly ? 'hidden' : type, value: props.value, placeholder: props.placeholder, onChange: handleChange, onBlur: handleOnBlur, onFocus: props.onFocus, onClick: onClick, onKeyDown: props.onKeyDown, onKeyPress: props.onKeyPress, required: props.required, disabled: props.disabled, autoComplete: props.autocomplete, "aria-disabled": props.disabled, "aria-label": !props.label ? (_b = props.ariaLabel) !== null && _b !== void 0 ? _b : props.id : undefined, ref: inputRef, tabIndex: props.tabIndex, "aria-describedby": getDescribedBy(), "data-testid": dataTestId, readOnly: props.readonly }),
162
- props.readonly && React__default.createElement("div", null, props.value),
161
+ React__default.createElement(StyledInput, { id: props.id, name: props.name, type: type, value: props.value, placeholder: props.placeholder, onChange: handleChange, onBlur: handleOnBlur, onFocus: props.onFocus, onClick: onClick, onKeyDown: props.onKeyDown, onKeyPress: props.onKeyPress, required: props.required, disabled: props.disabled, autoComplete: props.autocomplete, "aria-disabled": props.disabled, "aria-label": !props.label ? (_b = props.ariaLabel) !== null && _b !== void 0 ? _b : props.id : undefined, ref: inputRef, tabIndex: props.tabIndex, "aria-describedby": getDescribedBy(), "data-testid": dataTestId, readOnly: props.readonly }),
163
162
  ((props.status && props.status !== 'comment') ||
164
163
  props.showPasswordToggle ||
165
164
  props.disabled ||
@@ -18,10 +18,12 @@ interface Props {
18
18
  * Styling of `label` element changes depending on the passed status
19
19
  *
20
20
  * @param {LabelTextStatus} undefined Default styling
21
- * @param {LabelTextStatus} info Changes color to `theme.color.notification.info`
22
- * @param {LabelTextStatus} success Changes color to `theme.color.notification.success`
23
- * @param {LabelTextStatus} warning Changes color to `theme.color.notification.warning`
21
+ * @param {LabelTextStatus} info Changes color to default color (this type will be deprecated in the future)
22
+ * @param {LabelTextStatus} success Changes color to default color (this type will be deprecated in the future)
23
+ * @param {LabelTextStatus} warning Changes color to default color (this type will be deprecated in the future)
24
24
  * @param {LabelTextStatus} error Changes color to `theme.color.notification.error`
25
+ *
26
+ * @deprecated info, success and warning are deprecated, please switch to default or error status
25
27
  */
26
28
  status?: LabelTextStatus;
27
29
  /**
@@ -6,7 +6,7 @@ import { getDividedSize } from '../../utils/styledUtils.js';
6
6
 
7
7
  const Label = styled.label `
8
8
  display: block;
9
- color: ${({ status }) => (status ? theme.color.notification[status] : theme.color.text.gray)};
9
+ color: ${({ status }) => status === 'error' ? theme.color.notification.error : theme.color.text.gray};
10
10
  font-weight: ${theme.fontWeight.medium};
11
11
  font-size: ${theme.fontSize.default};
12
12
  line-height: ${theme.lineHeight.default};
@@ -1,4 +1,4 @@
1
- import type { MouseEvent } from 'react';
1
+ import type { MouseEvent, KeyboardEvent } from 'react';
2
2
  import React from 'react';
3
3
  type ProgressIndicatorStatus = 'error';
4
4
  interface Props {
@@ -15,7 +15,7 @@ interface Props {
15
15
  * On Progress Indicator Item label or number click callback
16
16
  * Use `e.currentTarget.parentElement` to get Progress Indicator Item element
17
17
  */
18
- onStepClick?: (stepIndex: number, e: MouseEvent<HTMLElement>) => void;
18
+ onStepClick?: (stepIndex: number, e: MouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>) => void;
19
19
  /**
20
20
  * Allows to change version of component to small
21
21
  */
@@ -118,14 +118,21 @@ const ProgressIndicator = (_a) => {
118
118
  props.onStepClick(index, e);
119
119
  }
120
120
  };
121
- return (React__default.createElement(ProgressIndicatorItem, { key: id, small: props.small, "aria-current": isActive ? 'step' : 'false' },
121
+ const handleKeyDown = (e) => {
122
+ if ((e.key === 'Enter' || e.key === ' ') && props.onStepClick) {
123
+ e.preventDefault();
124
+ props.onStepClick(index, e);
125
+ }
126
+ };
127
+ const isClickable = isCompleted && Boolean(props.onStepClick);
128
+ return (React__default.createElement(ProgressIndicatorItem, { key: id, small: props.small },
122
129
  index > 0 && (React__default.createElement(ProgressIndicatorItemConnector, { small: props.small, isActive: isActive, isCompleted: isCompleted })),
123
- React__default.createElement(ProgressIndicatorItemNumber, { small: props.small, onClick: handleClick, isActive: isActive, isCompleted: isCompleted, isError: isError, isClickable: isCompleted && Boolean(props.onStepClick) }, isCompleted || isError ? (React__default.createElement(React__default.Fragment, null,
124
- isCompleted && props.completedStepLabel && (React__default.createElement("span", { className: "visually-hidden" }, props.completedStepLabel)),
125
- React__default.createElement(Icon, { icon: isError ? Warning : Check, color: isError ? theme.color.text.white : theme.color.text.pink, size: "1rem" }))) : (stepNumber)),
126
- label && (React__default.createElement(ProgressIndicatorItemLabel, { small: props.small, onClick: handleClick, isActive: isActive, className: "visually-hidden" }, label))));
130
+ React__default.createElement(ProgressIndicatorItemNumber, { small: props.small, onClick: handleClick, isActive: isActive, isCompleted: isCompleted, isError: isError, onKeyDown: handleKeyDown, tabIndex: isClickable || isActive ? 0 : -1, isClickable: isClickable, role: "tab", "aria-current": isActive ? 'step' : 'false', "aria-label": isCompleted && props.completedStepLabel
131
+ ? `${label}, ${props.completedStepLabel}`
132
+ : label }, isCompleted || isError ? (React__default.createElement(Icon, { icon: isError ? Warning : Check, color: isError ? theme.color.text.white : theme.color.text.pink, size: "1rem", "aria-hidden": true })) : (stepNumber)),
133
+ label && (React__default.createElement(ProgressIndicatorItemLabel, { "aria-hidden": true, small: props.small, onClick: handleClick, isActive: isActive, className: "visually-hidden" }, label))));
127
134
  });
128
- return (React__default.createElement(ProgressIndicatorWrapper, { className: props.className, "data-testid": dataTestId, "aria-label": props.ariaLabel, role: "list" }, progressIndicatorItems));
135
+ return (React__default.createElement(ProgressIndicatorWrapper, { className: props.className, "data-testid": dataTestId, "aria-label": props.ariaLabel, role: "tablist" }, progressIndicatorItems));
129
136
  };
130
137
 
131
138
  export { ProgressIndicator as default };
@@ -68,6 +68,10 @@ interface Props {
68
68
  * Allows to pass testid string for testing purposes
69
69
  */
70
70
  'data-testid'?: string;
71
+ /**
72
+ * Allows to pass an accessible label for the component, enhancing screen reader support.
73
+ */
74
+ ariaLabel?: string;
71
75
  }
72
76
  /** @visibleName Read More */
73
77
  declare const ReadMore: ({ collapsedSize, "data-testid": dataTestId, ...props }: Props) => React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { __rest } from 'tslib';
2
2
  import { ChevronUp, ChevronDown } from '@dnanpm/icons';
3
- import React__default, { useState, useEffect } from 'react';
3
+ import React__default, { useState, useRef, useEffect, Children, isValidElement, cloneElement } from 'react';
4
4
  import styled from '../../themes/styled.js';
5
5
  import theme from '../../themes/theme.js';
6
6
  import ButtonIcon from '../ButtonIcon/ButtonIcon.js';
@@ -37,6 +37,9 @@ const StyledButtonIcon = styled(ButtonIcon) `
37
37
  const ReadMore = (_a) => {
38
38
  var { collapsedSize = '10rem', 'data-testid': dataTestId } = _a, props = __rest(_a, ["collapsedSize", 'data-testid']);
39
39
  const [expanded, setExpanded] = useState(props.seoInitExpanded === true || false);
40
+ const contentRef = useRef(null);
41
+ const buttonRef = useRef(null);
42
+ const userInteractedRef = useRef(false);
40
43
  // TODO: Remove once https://jira.dna.fi/browse/STYLE-662 is done
41
44
  const temporaryIsStatelessFlag = typeof props.isExpanded !== 'undefined';
42
45
  const temporaryStateManagement = temporaryIsStatelessFlag ? props.isExpanded : expanded;
@@ -48,16 +51,40 @@ const ReadMore = (_a) => {
48
51
  if (!temporaryIsStatelessFlag) {
49
52
  setExpanded(!expanded);
50
53
  }
54
+ userInteractedRef.current = true;
51
55
  };
52
56
  useEffect(() => {
53
57
  if (props.seoInitExpanded) {
54
58
  setExpanded(false);
55
59
  }
56
60
  }, [props.seoInitExpanded]);
57
- return (React__default.createElement(Container, { id: props.id, className: props.className, "data-testid": dataTestId },
58
- React__default.createElement(Content, { isExpanded: temporaryStateManagement, collapsedSize: collapsedSize, "data-testid": dataTestId && `${dataTestId}-content` }, props.children),
61
+ useEffect(() => {
62
+ var _a, _b;
63
+ if (userInteractedRef.current) {
64
+ if (temporaryStateManagement) {
65
+ (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.focus();
66
+ }
67
+ else {
68
+ (_b = buttonRef.current) === null || _b === void 0 ? void 0 : _b.focus();
69
+ }
70
+ }
71
+ }, [temporaryStateManagement]);
72
+ // Function to apply tabIndex to all links elements of children (since we don't control what is passed as children)
73
+ const forceTabIndexOnTextLinks = (child) => {
74
+ if (!isValidElement(child)) {
75
+ return child;
76
+ }
77
+ if (child.type === 'a') {
78
+ return cloneElement(child, {
79
+ tabIndex: temporaryStateManagement ? 0 : -1,
80
+ });
81
+ }
82
+ return child;
83
+ };
84
+ return (React__default.createElement(Container, { id: props.id, className: props.className, "data-testid": dataTestId, "aria-label": props.ariaLabel, role: "region" },
85
+ React__default.createElement(Content, { ref: contentRef, isExpanded: temporaryStateManagement, collapsedSize: collapsedSize, "data-testid": dataTestId && `${dataTestId}-content`, "aria-hidden": temporaryStateManagement ? 'false' : 'true', tabIndex: temporaryStateManagement ? 0 : -1 }, Children.map(props.children, forceTabIndexOnTextLinks)),
59
86
  React__default.createElement(ButtonWrapper, { buttonPosition: props.buttonPosition },
60
- React__default.createElement(StyledButtonIcon, { icon: temporaryStateManagement ? ChevronUp : ChevronDown, onClick: handleOnClick }, temporaryButtonLabel || props.buttonLabel))));
87
+ React__default.createElement(StyledButtonIcon, { ref: buttonRef, icon: temporaryStateManagement ? ChevronUp : ChevronDown, onClick: handleOnClick, ariaHidden: true, "aria-expanded": temporaryStateManagement }, temporaryButtonLabel || props.buttonLabel))));
61
88
  };
62
89
 
63
90
  export { ReadMore as default };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dnanpm/styleguide",
3
3
  "sideEffects": false,
4
- "version": "v3.9.8",
4
+ "version": "v3.9.9",
5
5
  "main": "build/cjs/index.js",
6
6
  "module": "build/es/index.js",
7
7
  "jsnext:main": "build/es/index.js",
@@ -41,14 +41,14 @@
41
41
  "not op_mini all"
42
42
  ],
43
43
  "devDependencies": {
44
- "@babel/core": "^7.26.0",
44
+ "@babel/core": "^7.26.10",
45
45
  "@babel/preset-env": "^7.26.0",
46
46
  "@babel/preset-react": "^7.26.3",
47
47
  "@babel/preset-typescript": "^7.27.0",
48
48
  "@dnanpm/icons": "2.0.7",
49
- "@rollup/plugin-commonjs": "^28.0.1",
49
+ "@rollup/plugin-commonjs": "^28.0.3",
50
50
  "@rollup/plugin-node-resolve": "^15.3.0",
51
- "@rollup/plugin-typescript": "^12.1.1",
51
+ "@rollup/plugin-typescript": "^12.1.2",
52
52
  "@testing-library/jest-dom": "^6.6.3",
53
53
  "@testing-library/react": "^14.3.1",
54
54
  "@testing-library/user-event": "^14.5.2",
@@ -94,7 +94,7 @@
94
94
  "ts-node": "^10.9.2",
95
95
  "tslib": "^2.8.1",
96
96
  "typescript": "^5.1.6",
97
- "webpack": "^5.95.0"
97
+ "webpack": "^5.99.6"
98
98
  },
99
99
  "dependencies": {
100
100
  "ramda": "^0.27.1",