@indico-data/design-system 3.18.0 → 3.19.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 (93) hide show
  1. package/lib/components/forms/date/datePicker/types.d.ts +7 -0
  2. package/lib/components/forms/date/iconTriggerDatePicker/IconTriggerDatePicker.d.ts +3 -0
  3. package/lib/components/forms/date/iconTriggerDatePicker/types.d.ts +5 -0
  4. package/lib/components/forms/date/inputDatePicker/SingleInputDatePicker.d.ts +2 -1
  5. package/lib/components/forms/date/inputDateRangePicker/InputDateRangePicker.d.ts +3 -0
  6. package/lib/components/forms/date/inputDateRangePicker/types.d.ts +7 -0
  7. package/lib/components/forms/date/inputDateTimePicker/SingleInputDateTimePicker.d.ts +2 -1
  8. package/lib/components/forms/select/Select.d.ts +3 -1
  9. package/lib/components/forms/select/types.d.ts +10 -0
  10. package/lib/components/forms/subcomponents/Label.d.ts +4 -0
  11. package/lib/components/forms/subcomponents/types.d.ts +5 -0
  12. package/lib/components/forms/timePicker/TimePicker.d.ts +4 -1
  13. package/lib/components/forms/timePicker/types.d.ts +5 -0
  14. package/lib/components/modal/ConfirmationModal.d.ts +1 -1
  15. package/lib/components/modal/Modal.d.ts +1 -1
  16. package/lib/components/modal/Modal.stories.d.ts +4 -0
  17. package/lib/components/modal/types.d.ts +19 -5
  18. package/lib/components/pagination/Pagination.d.ts +1 -1
  19. package/lib/components/pagination/index.d.ts +1 -0
  20. package/lib/components/pagination/types.d.ts +13 -0
  21. package/lib/components/stepper/Stepper.d.ts +1 -1
  22. package/lib/components/stepper/components/BackNavigation.d.ts +2 -1
  23. package/lib/components/stepper/components/NextNavigation.d.ts +3 -1
  24. package/lib/components/stepper/types.d.ts +11 -0
  25. package/lib/components/table/LoadingComponent.d.ts +5 -1
  26. package/lib/components/table/components/HorizontalStickyHeader.d.ts +4 -1
  27. package/lib/components/table/hooks/usePinnedColumnsManager.d.ts +2 -2
  28. package/lib/components/table/types.d.ts +18 -0
  29. package/lib/components/table/utils/processColumns.d.ts +2 -2
  30. package/lib/components/tanstackTable/TankstackTable.types.d.ts +19 -2
  31. package/lib/components/tanstackTable/TanstackTable.d.ts +1 -1
  32. package/lib/components/tanstackTable/components/NoResults/NoResults.d.ts +2 -1
  33. package/lib/components/tanstackTable/components/TablePagination/TablePagination.d.ts +3 -1
  34. package/lib/index.d.ts +143 -23
  35. package/lib/index.esm.js +130 -60
  36. package/lib/index.esm.js.map +1 -1
  37. package/lib/index.js +130 -60
  38. package/lib/index.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/components/button/Button.tsx +4 -18
  41. package/src/components/button/__tests__/Button.test.tsx +30 -28
  42. package/src/components/forms/date/datePicker/DatePicker.stories.tsx +10 -0
  43. package/src/components/forms/date/datePicker/DatePicker.tsx +9 -2
  44. package/src/components/forms/date/datePicker/types.ts +8 -0
  45. package/src/components/forms/date/iconTriggerDatePicker/IconTriggerDatePicker.stories.tsx +10 -0
  46. package/src/components/forms/date/iconTriggerDatePicker/IconTriggerDatePicker.tsx +12 -1
  47. package/src/components/forms/date/iconTriggerDatePicker/types.ts +5 -0
  48. package/src/components/forms/date/inputDatePicker/SingleInputDatePicker.tsx +4 -3
  49. package/src/components/forms/date/inputDatePicker/__tests__/SingleInputDatePicker.test.tsx +2 -0
  50. package/src/components/forms/date/inputDateRangePicker/InputDateRangePicker.stories.tsx +10 -0
  51. package/src/components/forms/date/inputDateRangePicker/InputDateRangePicker.tsx +14 -2
  52. package/src/components/forms/date/inputDateRangePicker/types.ts +7 -0
  53. package/src/components/forms/date/inputDateTimePicker/SingleInputDateTimePicker.tsx +3 -2
  54. package/src/components/forms/input/Input.tsx +1 -0
  55. package/src/components/forms/numberInput/NumberInput.tsx +1 -0
  56. package/src/components/forms/passwordInput/PasswordInput.tsx +7 -1
  57. package/src/components/forms/select/Select.stories.tsx +6 -5
  58. package/src/components/forms/select/Select.tsx +15 -1
  59. package/src/components/forms/select/types.ts +11 -0
  60. package/src/components/forms/subcomponents/Label.tsx +20 -3
  61. package/src/components/forms/subcomponents/types.ts +5 -0
  62. package/src/components/forms/textarea/Textarea.tsx +1 -0
  63. package/src/components/forms/timePicker/TimePicker.stories.tsx +10 -0
  64. package/src/components/forms/timePicker/TimePicker.tsx +10 -1
  65. package/src/components/forms/timePicker/types.ts +5 -0
  66. package/src/components/modal/ConfirmationModal.tsx +19 -14
  67. package/src/components/modal/Modal.stories.tsx +53 -22
  68. package/src/components/modal/Modal.tsx +8 -2
  69. package/src/components/modal/types.ts +21 -5
  70. package/src/components/pagination/Pagination.stories.tsx +11 -0
  71. package/src/components/pagination/Pagination.tsx +14 -5
  72. package/src/components/pagination/index.ts +1 -0
  73. package/src/components/pagination/types.ts +14 -0
  74. package/src/components/stepper/Stepper.stories.tsx +11 -0
  75. package/src/components/stepper/Stepper.tsx +16 -2
  76. package/src/components/stepper/components/BackNavigation.tsx +5 -3
  77. package/src/components/stepper/components/NextNavigation.tsx +15 -5
  78. package/src/components/stepper/types.ts +12 -0
  79. package/src/components/table/LoadingComponent.tsx +6 -2
  80. package/src/components/table/Table.stories.tsx +10 -0
  81. package/src/components/table/Table.tsx +12 -2
  82. package/src/components/table/components/HorizontalStickyHeader.tsx +12 -1
  83. package/src/components/table/hooks/usePinnedColumnsManager.ts +3 -2
  84. package/src/components/table/types.ts +20 -0
  85. package/src/components/table/utils/processColumns.tsx +3 -1
  86. package/src/components/tanstackTable/TankstackTable.types.ts +20 -2
  87. package/src/components/tanstackTable/TanstackTable.stories.tsx +8 -6
  88. package/src/components/tanstackTable/TanstackTable.tsx +21 -11
  89. package/src/components/tanstackTable/components/NoResults/NoResults.tsx +9 -3
  90. package/src/components/tanstackTable/components/TablePagination/TablePagination.tsx +4 -1
  91. package/src/index.ts +1 -1
  92. package/src/storybook/formArgTypes.ts +10 -0
  93. package/src/storybookDocs/Permafrost.mdx +8 -0
@@ -1,10 +1,19 @@
1
1
  import React, { forwardRef } from 'react';
2
+ import { FormLabelText } from './types';
3
+
4
+ export type { FormLabelText } from './types';
5
+
6
+ const DEFAULT_TEXT: Required<FormLabelText> = {
7
+ required: '(required)',
8
+ };
2
9
 
3
10
  export interface LabelProps {
4
11
  label?: string;
5
12
  name: string;
6
13
  isRequired?: boolean;
7
14
  hasHiddenLabel?: boolean;
15
+ /** Customizable display text. */
16
+ text?: FormLabelText;
8
17
  }
9
18
 
10
19
  export const Label = ({ label, name, isRequired }: LabelProps) => {
@@ -21,17 +30,25 @@ export const Label = ({ label, name, isRequired }: LabelProps) => {
21
30
  // HOC to add common label functionality to components
22
31
  export function withLabel<P extends object>(WrappedComponent: React.ComponentType<P>) {
23
32
  const WithLabelComponent = (
24
- { label, hasHiddenLabel = false, name, isRequired, ...rest }: P & LabelProps,
33
+ { label, hasHiddenLabel = false, name, isRequired, text: textProp, ...rest }: P & LabelProps,
25
34
  ref: React.Ref<any>,
26
35
  ) => {
36
+ const text = { ...DEFAULT_TEXT, ...textProp };
27
37
  const ariaLabel = hasHiddenLabel
28
- ? { 'aria-label': isRequired ? `${label} (required)` : label }
38
+ ? { 'aria-label': isRequired ? `${label} ${text.required}` : label }
29
39
  : {};
30
40
 
31
41
  return (
32
42
  <div className="form-control">
33
43
  {!hasHiddenLabel && <Label label={label} name={name} isRequired={isRequired} />}
34
- <WrappedComponent {...(rest as P)} id={name} name={name} {...ariaLabel} ref={ref} />
44
+ <WrappedComponent
45
+ {...(rest as P)}
46
+ id={name}
47
+ name={name}
48
+ {...ariaLabel}
49
+ text={textProp}
50
+ ref={ref}
51
+ />
35
52
  </div>
36
53
  );
37
54
  };
@@ -0,0 +1,5 @@
1
+ /** Customizable text for form Label. */
2
+ export interface FormLabelText {
3
+ /** Text appended to aria-label for required fields. Default: "(required)" */
4
+ required?: string;
5
+ }
@@ -53,6 +53,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
53
53
  autofocus,
54
54
  defaultValue,
55
55
  tabIndex,
56
+ text: _text,
56
57
  ...rest
57
58
  },
58
59
  ref,
@@ -44,6 +44,16 @@ const meta: Meta<typeof TimePicker> = {
44
44
  control: 'text',
45
45
  defaultValue: 'Time Picker',
46
46
  },
47
+ text: {
48
+ control: 'object',
49
+ description: 'Customizable text.',
50
+ table: {
51
+ category: 'i18n Text',
52
+ type: {
53
+ summary: '{ validationError?: string }',
54
+ },
55
+ },
56
+ },
47
57
  },
48
58
  decorators: [
49
59
  (Story: React.ComponentType) => (
@@ -3,6 +3,11 @@ import { Input } from '../input/Input';
3
3
  import { FloatUI } from '../../floatUI/FloatUI';
4
4
  import { formatTimeValue, validateInputValue } from './helpers';
5
5
  import { offset, flip, shift } from '@floating-ui/react';
6
+ import { TimePickerText } from './types';
7
+
8
+ const DEFAULT_TEXT: Required<TimePickerText> = {
9
+ validationError: 'Time validation error',
10
+ };
6
11
 
7
12
  interface TimePickerProps {
8
13
  ref?: React.LegacyRef<HTMLInputElement>;
@@ -20,6 +25,8 @@ interface TimePickerProps {
20
25
  isReadOnly?: boolean;
21
26
  isDisabled?: boolean;
22
27
  tabIndex?: number;
28
+ /** Customizable display text. */
29
+ text?: TimePickerText;
23
30
  [key: string]: unknown;
24
31
  }
25
32
 
@@ -34,8 +41,10 @@ export const TimePicker = ({
34
41
  isDisabled,
35
42
  isReadOnly,
36
43
  tabIndex,
44
+ text: textProp,
37
45
  ...rest
38
46
  }: TimePickerProps) => {
47
+ const text = { ...DEFAULT_TEXT, ...textProp };
39
48
  const [validationError, setValidationError] = useState('');
40
49
  const [inputValue, setInputValue] = useState(timeValue);
41
50
 
@@ -82,7 +91,7 @@ export const TimePicker = ({
82
91
  />
83
92
  {/* This is a temporary work around to address a validation issue in cenote*/}
84
93
  <FloatUI
85
- ariaLabel="Time validation error"
94
+ ariaLabel={text.validationError}
86
95
  isOpen={!!validationError}
87
96
  setIsOpen={() => {}} // Prevent click-to-open behavior
88
97
  isPortal
@@ -0,0 +1,5 @@
1
+ /** Customizable text for TimePicker. */
2
+ export interface TimePickerText {
3
+ /** Aria label for the validation error tooltip. Default: "Time validation error" */
4
+ validationError?: string;
5
+ }
@@ -4,16 +4,22 @@ import { Checkbox } from '../forms/checkbox/Checkbox';
4
4
  import { Col, Row } from '../grid';
5
5
  import { Icon } from '../icons/Icon';
6
6
  import { Modal } from './Modal';
7
- import { ConfirmationModalProps } from './types';
7
+ import { ConfirmationModalProps, ConfirmationModalText } from './types';
8
8
  import classNames from 'classnames';
9
9
  import { useState } from 'react';
10
10
 
11
+ const DEFAULT_TEXT: Required<ConfirmationModalText> = {
12
+ closeButton: 'Close',
13
+ dontShowAgain: "Don't display this again.",
14
+ confirm: 'Confirm',
15
+ cancel: 'Cancel',
16
+ };
17
+
11
18
  const defaultFooter = ({
12
19
  onCancelRequest,
13
20
  onConfirmRequest,
14
- confirmationButtonText,
21
+ text,
15
22
  confirmationButtonVariant,
16
- cancelButtonText,
17
23
  hasDontShowAgainCheckbox,
18
24
  isChecked,
19
25
  onDontShowAgainChange,
@@ -24,9 +30,8 @@ const defaultFooter = ({
24
30
  }: {
25
31
  dontShowAgain?: boolean;
26
32
  }) => void | Promise<void> | Promise<boolean>;
27
- confirmationButtonText?: string;
33
+ text: Required<ConfirmationModalText>;
28
34
  confirmationButtonVariant?: ButtonVariants;
29
- cancelButtonText?: string;
30
35
  hasDontShowAgainCheckbox?: boolean;
31
36
  isChecked?: boolean;
32
37
  onDontShowAgainChange?: (checked: boolean) => void;
@@ -35,7 +40,7 @@ const defaultFooter = ({
35
40
  {hasDontShowAgainCheckbox && (
36
41
  <Col>
37
42
  <Checkbox
38
- label="Don't display this again."
43
+ label={text.dontShowAgain}
39
44
  onChange={(e) => onDontShowAgainChange?.(e.target.checked)}
40
45
  isChecked={isChecked}
41
46
  id="dont-show-again"
@@ -44,17 +49,17 @@ const defaultFooter = ({
44
49
  </Col>
45
50
  )}
46
51
  <Col xs="content">
47
- <Button onClick={onCancelRequest} ariaLabel={cancelButtonText || 'Cancel'} variant="outline">
48
- {cancelButtonText}
52
+ <Button onClick={onCancelRequest} ariaLabel={text.cancel} variant="outline">
53
+ {text.cancel}
49
54
  </Button>
50
55
  </Col>
51
56
  <Col xs="content">
52
57
  <Button
53
58
  onClick={() => onConfirmRequest?.({ dontShowAgain: isChecked })}
54
- ariaLabel={confirmationButtonText || 'Confirm'}
59
+ ariaLabel={text.confirm}
55
60
  variant={confirmationButtonVariant}
56
61
  >
57
- {confirmationButtonText}
62
+ {text.confirm}
58
63
  </Button>
59
64
  </Col>
60
65
  </Row>
@@ -77,15 +82,15 @@ export const ConfirmationModal = ({
77
82
  children,
78
83
  onConfirmRequest,
79
84
  onCancelRequest,
80
- confirmationButtonText = 'Confirm',
81
- cancelButtonText = 'Cancel',
82
85
  confirmationButtonVariant = 'solid',
83
86
  icon,
84
87
  title,
85
88
  status = 'info',
86
89
  maxWidthInPixels,
87
90
  hasDontShowAgainCheckbox,
91
+ text: textProp,
88
92
  }: ConfirmationModalProps) => {
93
+ const text = { ...DEFAULT_TEXT, ...textProp };
89
94
  const [dontShowAgain, setDontShowAgain] = useState(false);
90
95
 
91
96
  const modalFooter =
@@ -93,8 +98,7 @@ export const ConfirmationModal = ({
93
98
  defaultFooter({
94
99
  onCancelRequest,
95
100
  onConfirmRequest,
96
- confirmationButtonText,
97
- cancelButtonText,
101
+ text,
98
102
  confirmationButtonVariant,
99
103
  hasDontShowAgainCheckbox,
100
104
  isChecked: dontShowAgain,
@@ -117,6 +121,7 @@ export const ConfirmationModal = ({
117
121
  overlayElement={overlayElement}
118
122
  footer={modalFooter}
119
123
  maxWidthInPixels={maxWidthInPixels}
124
+ text={{ closeButton: text.closeButton }}
120
125
  >
121
126
  {icon && (
122
127
  <Icon
@@ -173,15 +173,6 @@ const meta: Meta = {
173
173
  },
174
174
  },
175
175
  },
176
- confirmationButtonText: {
177
- control: 'text',
178
- table: {
179
- category: 'Confirmation Modal',
180
- type: {
181
- summary: 'string',
182
- },
183
- },
184
- },
185
176
  confirmationButtonVariant: {
186
177
  control: 'select',
187
178
  options: ['solid', 'outline', 'link', 'action', 'destructive', 'soft'],
@@ -192,15 +183,6 @@ const meta: Meta = {
192
183
  },
193
184
  },
194
185
  },
195
- cancelButtonText: {
196
- control: 'text',
197
- table: {
198
- category: 'Confirmation Modal',
199
- type: {
200
- summary: 'string',
201
- },
202
- },
203
- },
204
186
  status: {
205
187
  control: 'select',
206
188
  options: ['info', 'success', 'error'],
@@ -230,6 +212,17 @@ const meta: Meta = {
230
212
  },
231
213
  },
232
214
  },
215
+ text: {
216
+ control: 'object',
217
+ table: {
218
+ category: 'i18n Text',
219
+ type: {
220
+ summary:
221
+ '{ closeButton?: string; dontShowAgain?: string; confirm?: string; cancel?: string }',
222
+ },
223
+ },
224
+ description: 'Customizable text.',
225
+ },
233
226
  },
234
227
  };
235
228
 
@@ -320,9 +313,8 @@ export const ConfirmationModalStory: StoryObj<typeof ConfirmationModal> = {
320
313
  console.log('closed');
321
314
  },
322
315
  title: 'Disable User',
323
- confirmationButtonText: 'Delete',
324
316
  confirmationButtonVariant: 'destructive',
325
- cancelButtonText: 'Cancel',
317
+ text: { confirm: 'Delete', cancel: 'Cancel' },
326
318
  shouldCloseOnOverlayClick: true,
327
319
  subtitle: '',
328
320
  icon: 'trash',
@@ -371,9 +363,8 @@ export const ConfirmationModalStoryWithCheckbox: StoryObj<typeof ConfirmationMod
371
363
  console.log('closed');
372
364
  },
373
365
  title: 'Disable User',
374
- confirmationButtonText: 'Delete',
375
366
  confirmationButtonVariant: 'destructive',
376
- cancelButtonText: 'Cancel',
367
+ text: { confirm: 'Delete', cancel: 'Cancel' },
377
368
  shouldCloseOnOverlayClick: true,
378
369
  icon: 'trash',
379
370
  status: 'error',
@@ -420,3 +411,43 @@ export const ConfirmationModalStoryWithCheckbox: StoryObj<typeof ConfirmationMod
420
411
  );
421
412
  },
422
413
  };
414
+
415
+ /**
416
+ * Use the `text` prop to customize displayed text.
417
+ */
418
+ export const WithText: StoryObj<typeof ConfirmationModal> = {
419
+ args: {
420
+ title: 'Désactiver utilisateur',
421
+ confirmationButtonVariant: 'destructive',
422
+ icon: 'trash',
423
+ status: 'error',
424
+ maxWidthInPixels: 600,
425
+ hasDontShowAgainCheckbox: true,
426
+ parentSelector: () => document.body,
427
+ text: {
428
+ confirm: 'Supprimer',
429
+ cancel: 'Annuler',
430
+ closeButton: 'Fermer',
431
+ dontShowAgain: 'Ne plus afficher ce message',
432
+ },
433
+ },
434
+
435
+ render: (args) => {
436
+ const [isOpen, setIsOpen] = useState<boolean>(false);
437
+
438
+ return (
439
+ <Container>
440
+ <Row>
441
+ <Col sm={4}>
442
+ <ConfirmationModal {...args} isOpen={isOpen} onRequestClose={() => setIsOpen(false)}>
443
+ <p>French example with custom text.</p>
444
+ </ConfirmationModal>
445
+ <Button ariaLabel="open modal" onClick={() => setIsOpen(true)}>
446
+ Open French Modal
447
+ </Button>
448
+ </Col>
449
+ </Row>
450
+ </Container>
451
+ );
452
+ },
453
+ };
@@ -2,7 +2,11 @@ import classNames from 'classnames';
2
2
  import ReactModal from 'react-modal';
3
3
  import { Button } from '../button/Button';
4
4
  import { Col, Row } from '../grid';
5
- import { ModalProps } from './types';
5
+ import { ModalProps, ModalText } from './types';
6
+
7
+ const DEFAULT_TEXT: Required<ModalText> = {
8
+ closeButton: 'Close',
9
+ };
6
10
 
7
11
  export const Modal = ({
8
12
  className = '',
@@ -25,8 +29,10 @@ export const Modal = ({
25
29
  subtitle,
26
30
  footer,
27
31
  maxWidthInPixels,
32
+ text: textProp,
28
33
  ...rest
29
34
  }: ModalProps) => {
35
+ const text = { ...DEFAULT_TEXT, ...textProp };
30
36
  const modalClasses = classNames('modal', `modal--${position}`, className);
31
37
  const overlayClasses = classNames('modal-overlay', overlayClassName);
32
38
 
@@ -55,7 +61,7 @@ export const Modal = ({
55
61
  variant="link"
56
62
  size="md"
57
63
  iconLeft="x-close"
58
- ariaLabel="Close"
64
+ ariaLabel={text.closeButton}
59
65
  />
60
66
  {hasHeader && (
61
67
  <div className="modal-header">
@@ -1,6 +1,12 @@
1
1
  import { ButtonVariants } from '../button/types';
2
2
  import { IconName } from '../icons/types';
3
3
 
4
+ /** Customizable text for Modal. */
5
+ export interface ModalText {
6
+ /** Aria label for the close button. Default: "Close" */
7
+ closeButton?: string;
8
+ }
9
+
4
10
  export interface ModalProps {
5
11
  /** Additional classes for the badge component */
6
12
  className?: string;
@@ -36,9 +42,21 @@ export interface ModalProps {
36
42
  footer?: React.ReactNode;
37
43
  /** The maximum width of the modal in pixels */
38
44
  maxWidthInPixels?: number;
45
+ /** Customizable display text. */
46
+ text?: ModalText;
47
+ }
48
+
49
+ /** Customizable text for ConfirmationModal. Extends ModalText. */
50
+ export interface ConfirmationModalText extends ModalText {
51
+ /** Label for the "Don't show again" checkbox. Default: "Don't display this again." */
52
+ dontShowAgain?: string;
53
+ /** Text for the confirm button. Default: "Confirm" */
54
+ confirm?: string;
55
+ /** Text for the cancel button. Default: "Cancel" */
56
+ cancel?: string;
39
57
  }
40
58
 
41
- export interface ConfirmationModalProps extends ModalProps {
59
+ export interface ConfirmationModalProps extends Omit<ModalProps, 'text'> {
42
60
  onConfirmRequest?: ({
43
61
  dontShowAgain,
44
62
  }: {
@@ -49,12 +67,10 @@ export interface ConfirmationModalProps extends ModalProps {
49
67
  hasDontShowAgainCheckbox?: boolean;
50
68
  /** The variant of the confirmation button. */
51
69
  confirmationButtonVariant?: ButtonVariants;
52
- /** The text of the confirmation button */
53
- confirmationButtonText?: string;
54
- /** The text of the cancel button */
55
- cancelButtonText?: string;
56
70
  /** The icon of the modal */
57
71
  icon?: IconName;
58
72
  /** The status of the modal. This will determine the color of the icon. */
59
73
  status?: 'info' | 'success' | 'error';
74
+ /** Customizable display text. */
75
+ text?: ConfirmationModalText;
60
76
  }
@@ -43,6 +43,17 @@ const meta: Meta = {
43
43
  },
44
44
  },
45
45
  },
46
+ text: {
47
+ control: 'object',
48
+ description: 'Customizable text.',
49
+ table: {
50
+ category: 'i18n Text',
51
+ type: {
52
+ summary:
53
+ '{ previousPage?: string; nextPage?: string; currentPage?: string; of?: string }',
54
+ },
55
+ },
56
+ },
46
57
  },
47
58
  };
48
59
 
@@ -1,19 +1,28 @@
1
1
  import { useState, useEffect } from 'react';
2
2
  import classNames from 'classnames';
3
- import { PaginationProps } from './types';
3
+ import { PaginationProps, PaginationText } from './types';
4
4
  import { Container, Row, Col } from '../grid';
5
5
  import { Input } from '../forms/input';
6
6
  import { Button } from '../button';
7
7
 
8
+ const DEFAULT_TEXT: Required<PaginationText> = {
9
+ previousPage: 'Previous Page',
10
+ nextPage: 'Next Page',
11
+ currentPage: 'Current Page',
12
+ of: 'of',
13
+ };
14
+
8
15
  export const Pagination = ({
9
16
  totalPages,
10
17
  currentPage = 1,
11
18
  onChange,
12
19
  className,
20
+ text: textProp,
13
21
  ...rest
14
22
  }: PaginationProps) => {
23
+ const text = { ...DEFAULT_TEXT, ...textProp };
15
24
  const [inputValue, setInputValue] = useState(currentPage.toString());
16
- const totalPagesText = `of ${totalPages}`;
25
+ const totalPagesText = `${text.of} ${totalPages}`;
17
26
  const classes = classNames('pagination', className);
18
27
 
19
28
  useEffect(() => {
@@ -60,7 +69,7 @@ export const Pagination = ({
60
69
  <div className="pagination__previous">
61
70
  <Button
62
71
  data-testid="pagination-previous-button"
63
- ariaLabel="Previous Page"
72
+ ariaLabel={text.previousPage}
64
73
  variant="link"
65
74
  onClick={handlePreviousPage}
66
75
  iconLeft="chevron-left"
@@ -78,7 +87,7 @@ export const Pagination = ({
78
87
  })}
79
88
  value={totalPages === 0 ? '0' : inputValue}
80
89
  name="currentPage"
81
- label="Current Page"
90
+ label={text.currentPage}
82
91
  hasHiddenLabel
83
92
  onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
84
93
  if (e.key === 'Enter') {
@@ -103,7 +112,7 @@ export const Pagination = ({
103
112
  <div className="pagination__next">
104
113
  <Button
105
114
  data-testid="pagination-next-button"
106
- ariaLabel="Next Page"
115
+ ariaLabel={text.nextPage}
107
116
  variant="link"
108
117
  onClick={handleNextPage}
109
118
  iconLeft="chevron-right"
@@ -1 +1,2 @@
1
1
  export { Pagination } from './Pagination';
2
+ export type { PaginationText } from './types';
@@ -1,3 +1,15 @@
1
+ /** Customizable text for Pagination. */
2
+ export interface PaginationText {
3
+ /** Aria label for previous page button. Default: "Previous Page" */
4
+ previousPage?: string;
5
+ /** Aria label for next page button. Default: "Next Page" */
6
+ nextPage?: string;
7
+ /** Label for current page input. Default: "Current Page" */
8
+ currentPage?: string;
9
+ /** Text between current page and total (e.g., "of"). Default: "of" */
10
+ of?: string;
11
+ }
12
+
1
13
  export interface PaginationProps {
2
14
  /** The total number of pages to be displayed */
3
15
  totalPages: number;
@@ -7,4 +19,6 @@ export interface PaginationProps {
7
19
  className?: string;
8
20
  /** The callback function that is called when the page changes. */
9
21
  onChange?: (value: number) => void;
22
+ /** Customizable display text. */
23
+ text?: PaginationText;
10
24
  }
@@ -146,6 +146,17 @@ const meta: Meta = {
146
146
  },
147
147
  },
148
148
  },
149
+ text: {
150
+ control: 'object',
151
+ description: 'Customizable text.',
152
+ table: {
153
+ category: 'i18n Text',
154
+ type: {
155
+ summary:
156
+ '{ previousStep?: string; previousStepAriaLabel?: string; nextStep?: string; nextStepAriaLabel?: string; finish?: string; finishAriaLabel?: string }',
157
+ },
158
+ },
159
+ },
149
160
  },
150
161
  };
151
162
 
@@ -2,7 +2,13 @@ import { useState, Children } from 'react';
2
2
  import { Legend } from './components/Legend';
3
3
  import { BackNavigation } from './components/BackNavigation';
4
4
  import { NextNavigation } from './components/NextNavigation';
5
- import { StepperProps } from './types';
5
+ import { StepperProps, StepperText } from './types';
6
+
7
+ const DEFAULT_TEXT: Required<StepperText> = {
8
+ previousStep: 'Previous Step',
9
+ nextStep: 'Next Step',
10
+ finish: 'Finish',
11
+ };
6
12
 
7
13
  export const Stepper = ({
8
14
  currentStep: externalCurrentStep,
@@ -14,7 +20,9 @@ export const Stepper = ({
14
20
  onFinishClick,
15
21
  children,
16
22
  onStepClick,
23
+ text: textProp,
17
24
  }: StepperProps) => {
25
+ const text = { ...DEFAULT_TEXT, ...textProp };
18
26
  const [internalCurrentStep, setInternalCurrentStep] = useState(0);
19
27
 
20
28
  const currentStep = externalCurrentStep !== undefined ? externalCurrentStep : internalCurrentStep;
@@ -71,12 +79,18 @@ export const Stepper = ({
71
79
  <div className="stepper-steps">{childrenArray[currentStep]}</div>
72
80
  </div>
73
81
  <div className="stepper-actions">
74
- <BackNavigation isDisabled={isFirstStep} onBackClick={handleBackClick} />
82
+ <BackNavigation
83
+ isDisabled={isFirstStep}
84
+ onBackClick={handleBackClick}
85
+ label={text.previousStep}
86
+ />
75
87
  <NextNavigation
76
88
  isLastStep={isLastStep}
77
89
  onNextClick={handleNextClick}
78
90
  onFinishClick={handleFinishClick}
79
91
  isDisabled={disableNextButton(currentStep)}
92
+ nextLabel={text.nextStep}
93
+ finishLabel={text.finish}
80
94
  />
81
95
  </div>
82
96
  </div>
@@ -1,21 +1,23 @@
1
1
  import { Button } from '../../button';
2
+
2
3
  type Props = {
3
4
  isDisabled: boolean;
4
5
  onBackClick: () => void;
6
+ label: string;
5
7
  };
6
8
 
7
- export const BackNavigation = ({ isDisabled, onBackClick }: Props) => {
9
+ export const BackNavigation = ({ isDisabled, onBackClick, label }: Props) => {
8
10
  return (
9
11
  <div className="stepper-navigation-back">
10
12
  <Button
11
13
  data-testid="stepper-back-button"
12
- ariaLabel="Previous Step"
14
+ ariaLabel={label}
13
15
  iconLeft="fa-arrow-left"
14
16
  onClick={onBackClick}
15
17
  variant="outline"
16
18
  isDisabled={isDisabled}
17
19
  >
18
- Previous Step
20
+ {label}
19
21
  </Button>
20
22
  </div>
21
23
  );
@@ -1,12 +1,22 @@
1
1
  import { Button } from '../../button';
2
+
2
3
  type Props = {
3
4
  isLastStep: boolean;
4
5
  onNextClick: () => void;
5
6
  onFinishClick: () => void;
6
7
  isDisabled: boolean;
8
+ nextLabel: string;
9
+ finishLabel: string;
7
10
  };
8
11
 
9
- export const NextNavigation = ({ isLastStep, onNextClick, onFinishClick, isDisabled }: Props) => {
12
+ export const NextNavigation = ({
13
+ isLastStep,
14
+ onNextClick,
15
+ onFinishClick,
16
+ isDisabled,
17
+ nextLabel,
18
+ finishLabel,
19
+ }: Props) => {
10
20
  return (
11
21
  <div className="stepper-navigation">
12
22
  {!isLastStep ? (
@@ -14,22 +24,22 @@ export const NextNavigation = ({ isLastStep, onNextClick, onFinishClick, isDisab
14
24
  <Button
15
25
  data-testid="stepper-next-button"
16
26
  iconRight="fa-arrow-right"
17
- ariaLabel="Next Step"
27
+ ariaLabel={nextLabel}
18
28
  onClick={onNextClick}
19
29
  isDisabled={isDisabled}
20
30
  >
21
- Next Step
31
+ {nextLabel}
22
32
  </Button>
23
33
  </div>
24
34
  ) : (
25
35
  <div className="stepper-navigation-finish">
26
36
  <Button
27
37
  data-testid="stepper-finish-button"
28
- ariaLabel="Finish"
38
+ ariaLabel={finishLabel}
29
39
  onClick={onFinishClick}
30
40
  isDisabled={isDisabled}
31
41
  >
32
- Finish
42
+ {finishLabel}
33
43
  </Button>
34
44
  </div>
35
45
  )}