@transferwise/components 46.117.1 → 46.119.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 (95) hide show
  1. package/build/dateLookup/dayCalendar/DayCalendar.js +4 -4
  2. package/build/dateLookup/dayCalendar/DayCalendar.js.map +1 -1
  3. package/build/dateLookup/dayCalendar/table/DayCalendarTable.js +4 -4
  4. package/build/dateLookup/dayCalendar/table/DayCalendarTable.js.map +1 -1
  5. package/build/dateLookup/monthCalendar/MonthCalendar.js +4 -4
  6. package/build/dateLookup/monthCalendar/MonthCalendar.js.map +1 -1
  7. package/build/dateLookup/yearCalendar/YearCalendar.js +4 -4
  8. package/build/dateLookup/yearCalendar/YearCalendar.js.map +1 -1
  9. package/build/dimmer/Dimmer.js +4 -4
  10. package/build/dimmer/Dimmer.js.map +1 -1
  11. package/build/index.js +4 -0
  12. package/build/index.js.map +1 -1
  13. package/build/index.mjs +2 -0
  14. package/build/index.mjs.map +1 -1
  15. package/build/inputs/SelectInput.js +4 -4
  16. package/build/inputs/SelectInput.js.map +1 -1
  17. package/build/inputs/SelectInput.mjs +4 -4
  18. package/build/inputs/SelectInput.mjs.map +1 -1
  19. package/build/listItem/Prompt/ListItemPrompt.js +2 -0
  20. package/build/listItem/Prompt/ListItemPrompt.js.map +1 -1
  21. package/build/listItem/Prompt/ListItemPrompt.mjs +2 -0
  22. package/build/listItem/Prompt/ListItemPrompt.mjs.map +1 -1
  23. package/build/moneyInput/MoneyInput.js +2 -2
  24. package/build/moneyInput/MoneyInput.js.map +1 -1
  25. package/build/moneyInput/MoneyInput.mjs +2 -2
  26. package/build/moneyInput/MoneyInput.mjs.map +1 -1
  27. package/build/promoCard/PromoCard.js +3 -3
  28. package/build/promoCard/PromoCard.js.map +1 -1
  29. package/build/promoCard/PromoCardGroup.js +2 -2
  30. package/build/promoCard/PromoCardGroup.js.map +1 -1
  31. package/build/promoCard/PromoCardGroup.mjs +2 -2
  32. package/build/promoCard/PromoCardGroup.mjs.map +1 -1
  33. package/build/prompt/InlinePrompt/InlinePrompt.js +8 -3
  34. package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
  35. package/build/prompt/InlinePrompt/InlinePrompt.mjs +8 -3
  36. package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
  37. package/build/typeahead/Typeahead.js +2 -2
  38. package/build/typeahead/Typeahead.js.map +1 -1
  39. package/build/typeahead/Typeahead.mjs +2 -2
  40. package/build/typeahead/Typeahead.mjs.map +1 -1
  41. package/build/types/index.d.ts +4 -0
  42. package/build/types/index.d.ts.map +1 -1
  43. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  44. package/build/types/listItem/ListItem.d.ts +1 -1
  45. package/build/types/listItem/Prompt/ListItemPrompt.d.ts +2 -2
  46. package/build/types/listItem/Prompt/ListItemPrompt.d.ts.map +1 -1
  47. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts +9 -2
  48. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -1
  49. package/build/upload/Upload.js +2 -2
  50. package/build/upload/Upload.js.map +1 -1
  51. package/build/upload/Upload.mjs +2 -2
  52. package/build/upload/Upload.mjs.map +1 -1
  53. package/package.json +37 -37
  54. package/src/accordion/AccordionItem/__snapshots__/AccordionItem.spec.js.snap +1 -1
  55. package/src/accordion/__snapshots__/Accordion.spec.js.snap +1 -1
  56. package/src/actionButton/__snapshots__/ActionButton.spec.tsx.snap +1 -1
  57. package/src/alert/Alert.story.tsx +1 -1
  58. package/src/alert/Alert.tests.story.tsx +1 -1
  59. package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +1 -1
  60. package/src/button/Button.vars.less +28 -7
  61. package/src/checkbox/__snapshots__/Checkbox.spec.tsx.snap +1 -1
  62. package/src/chevron/__snapshots__/Chevron.spec.tsx.snap +1 -1
  63. package/src/chips/__snapshots__/Chips.spec.tsx.snap +1 -1
  64. package/src/common/RadioButton/__snapshots__/RadioButton.spec.tsx.snap +1 -1
  65. package/src/common/bottomSheet/__snapshots__/BottomSheet.spec.tsx.snap +1 -1
  66. package/src/common/card/__snapshots__/Card.spec.tsx.snap +1 -1
  67. package/src/common/closeButton/__snapshots__/CloseButton.spec.tsx.snap +1 -1
  68. package/src/common/flowHeader/__snapshots__/FlowHeader.spec.tsx.snap +1 -1
  69. package/src/common/panel/__snapshots__/Panel.spec.tsx.snap +1 -1
  70. package/src/criticalBanner/CriticalCommsBanner.story.tsx +1 -1
  71. package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +1 -1
  72. package/src/iconButton/IconButton.story.tsx +2 -2
  73. package/src/index.ts +4 -0
  74. package/src/inlineAlert/InlineAlert.story.tsx +1 -1
  75. package/src/inputs/SelectInput.tsx +21 -19
  76. package/src/link/Link.story.tsx +2 -2
  77. package/src/listItem/Prompt/ListItemPrompt.spec.tsx +48 -0
  78. package/src/listItem/Prompt/ListItemPrompt.story.tsx +1 -0
  79. package/src/listItem/Prompt/ListItemPrompt.tsx +7 -2
  80. package/src/logo/__snapshots__/Logo.spec.tsx.snap +1 -1
  81. package/src/nudge/Nudge.story.tsx +1 -1
  82. package/src/overlayHeader/__snapshots__/OverlayHeader.spec.tsx.snap +1 -1
  83. package/src/popover/__snapshots__/Popover.spec.tsx.snap +1 -1
  84. package/src/promoCard/__snapshots__/PromoCard.spec.tsx.snap +1 -1
  85. package/src/promoCard/__snapshots__/PromoCardGroup.spec.tsx.snap +1 -1
  86. package/src/prompt/InlinePrompt/InlinePrompt.spec.tsx +29 -1
  87. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +45 -4
  88. package/src/prompt/InlinePrompt/InlinePrompt.tsx +12 -4
  89. package/src/provider/theme/ThemeProvider.story.tsx +1 -1
  90. package/src/sentimentSurface/SentimentSurface.story.tsx +163 -102
  91. package/src/sentimentSurface/SentimentSurface.tests.story.tsx +6 -2
  92. package/src/tile/__snapshots__/Tile.spec.tsx.snap +1 -1
  93. package/src/{neptune-css/NeptuneCSS.story.tsx → tokens/tokens.story.tsx} +2 -2
  94. package/src/tooltip/__snapshots__/Tooltip.spec.tsx.snap +1 -1
  95. package/src/withId/withId.story.tsx +1 -0
package/src/index.ts CHANGED
@@ -35,6 +35,7 @@ export type { HeaderProps } from './header';
35
35
  export type { EmphasisProps } from './emphasis';
36
36
  export type { FieldProps } from './field/Field';
37
37
  export type { InfoProps } from './info';
38
+ export type { InlinePromptProps } from './prompt';
38
39
  export type { InputWithDisplayFormatProps } from './inputWithDisplayFormat';
39
40
  export type { InputProps } from './inputs/Input';
40
41
  export type { InputGroupProps } from './inputs/InputGroup';
@@ -89,6 +90,7 @@ export type { SnackbarContextType } from './snackbar/SnackbarContext';
89
90
  export type { StatusIconProps } from './statusIcon';
90
91
  export type { StickyProps } from './sticky';
91
92
  export type { SummaryProps } from './summary';
93
+ export type { SentimentSurfaceProps } from './sentimentSurface';
92
94
  export type { SwitchProps } from './switch';
93
95
  export type { SwitchOptionProps } from './switchOption';
94
96
  export type { TabItem, TabsProps } from './tabs';
@@ -169,6 +171,7 @@ export { default as Header } from './header';
169
171
  export { default as Image } from './image';
170
172
  export { default as Info } from './info';
171
173
  export { default as InlineAlert } from './inlineAlert';
174
+ export { InlinePrompt } from './prompt';
172
175
  export { default as InputWithDisplayFormat } from './inputWithDisplayFormat';
173
176
  export { Input } from './inputs/Input';
174
177
  export { InputGroup } from './inputs/InputGroup';
@@ -209,6 +212,7 @@ export { default as ResponsivePanel } from './common/responsivePanel';
209
212
  export { default as Section } from './section';
210
213
  export { default as SegmentedControl } from './segmentedControl';
211
214
  export { default as Select } from './select';
215
+ export { default as SentimentSurface } from './sentimentSurface';
212
216
  export { default as SlidingPanel } from './slidingPanel';
213
217
  export { default as SnackbarPortal } from './snackbar/Snackbar';
214
218
  export { SnackbarConsumer, SnackbarContext } from './snackbar/SnackbarContext';
@@ -6,7 +6,7 @@ import Link from '../link';
6
6
 
7
7
  export default {
8
8
  component: InlineAlert,
9
- title: 'Forms/InlineAlert',
9
+ title: 'Prompts/InlineAlert',
10
10
  } as Meta<InlineAlertProps>;
11
11
 
12
12
  export const Basic = () => {
@@ -250,8 +250,10 @@ const defaultRenderTrigger = (({ content, placeholderShown, clear, disabled, siz
250
250
  </InputGroup>
251
251
  )) satisfies SelectInputProps['renderTrigger'];
252
252
 
253
- interface SelectInputClearButtonProps
254
- extends Pick<React.ComponentPropsWithoutRef<'button'>, 'className' | 'onClick'> {}
253
+ interface SelectInputClearButtonProps extends Pick<
254
+ React.ComponentPropsWithoutRef<'button'>,
255
+ 'className' | 'onClick'
256
+ > {}
255
257
 
256
258
  function SelectInputClearButton({ className, onClick }: SelectInputClearButtonProps) {
257
259
  const intl = useIntl();
@@ -576,17 +578,10 @@ const SelectInputOptionsContainer = forwardRef(function SelectInputOptionsContai
576
578
  );
577
579
  });
578
580
 
579
- interface SelectInputOptionsProps<T = string>
580
- extends Pick<
581
- SelectInputProps<T>,
582
- | 'items'
583
- | 'renderValue'
584
- | 'renderFooter'
585
- | 'filterable'
586
- | 'filterPlaceholder'
587
- | 'id'
588
- | 'parentId'
589
- > {
581
+ interface SelectInputOptionsProps<T = string> extends Pick<
582
+ SelectInputProps<T>,
583
+ 'items' | 'renderValue' | 'renderFooter' | 'filterable' | 'filterPlaceholder' | 'id' | 'parentId'
584
+ > {
590
585
  searchInputRef: React.MutableRefObject<HTMLInputElement | null>;
591
586
  listboxRef: React.MutableRefObject<HTMLDivElement | null>;
592
587
  filterQuery: string;
@@ -828,14 +823,19 @@ function SelectInputOptions<T = string>({
828
823
  <Virtualizer
829
824
  ref={virtualiserHandlerRef}
830
825
  key={needle}
831
- count={filteredItems.length}
826
+ data={filteredItems}
832
827
  keepMounted={mountedIndexes}
833
828
  scrollRef={listboxRef} // `VList` doesn't expose this
834
829
  onScroll={async () => {
835
830
  if (!virtualiserHandlerRef.current) return;
836
831
 
837
- const startIndex = virtualiserHandlerRef.current.findStartIndex();
838
- const endIndex = virtualiserHandlerRef.current.findStartIndex();
832
+ const startIndex = virtualiserHandlerRef.current.findItemIndex(
833
+ virtualiserHandlerRef.current.scrollOffset,
834
+ );
835
+ const endIndex = virtualiserHandlerRef.current.findItemIndex(
836
+ virtualiserHandlerRef.current.scrollOffset +
837
+ virtualiserHandlerRef.current.viewportSize,
838
+ );
839
839
 
840
840
  setMountedIndexes((prevMountedIndexes) => {
841
841
  const indexes = new Set(prevMountedIndexes);
@@ -848,7 +848,7 @@ function SelectInputOptions<T = string>({
848
848
  });
849
849
  }}
850
850
  >
851
- {(index) => (
851
+ {(item, index) => (
852
852
  // The position of each item can't be inferred by browsers when
853
853
  // virtualizing, as some of the items may not be in the DOM
854
854
  <SelectInputItemsCountContext.Provider value={filteredItems.length}>
@@ -924,8 +924,10 @@ function SelectInputItemView<T = string>({
924
924
  return null;
925
925
  }
926
926
 
927
- interface SelectInputGroupItemViewProps<T = string>
928
- extends SelectInputItemViewProps<T, SelectInputGroupItem<T | undefined>> {}
927
+ interface SelectInputGroupItemViewProps<T = string> extends SelectInputItemViewProps<
928
+ T,
929
+ SelectInputGroupItem<T | undefined>
930
+ > {}
929
931
 
930
932
  function SelectInputGroupItemView<T = string>({
931
933
  item,
@@ -161,8 +161,8 @@ export const Basic = () => {
161
161
  };
162
162
 
163
163
  /**
164
- * `Link` is sentiment-aware and will automatically adjust its
165
- * colours if wrapped inside the [SentimentSurface](/?path=/docs/content-sentimentsurface--docs) component
164
+ * `Link` is sentiment-aware and will automatically adjust its colours if wrapped inside
165
+ * the [SentimentSurface](?path=/docs/foundations-sentimentsurface--docs) component
166
166
  */
167
167
  export const SentimentAwareness = function Render() {
168
168
  return (['success', 'warning', 'negative'] as const).map((sentiment) => (
@@ -69,4 +69,52 @@ describe('ListItem.Prompt', () => {
69
69
  expect(screen.getByTestId('InlinePrompt_Muted')).toBeInTheDocument();
70
70
  });
71
71
  });
72
+
73
+ [
74
+ { sentiment: Sentiment.NEGATIVE as const, iconLabel: 'Error:' },
75
+ { sentiment: Sentiment.WARNING as const, iconLabel: 'Warning:' },
76
+ { sentiment: Sentiment.NEUTRAL as const, iconLabel: 'Information:' },
77
+ { sentiment: Sentiment.POSITIVE as const, iconLabel: 'Success:' },
78
+ { sentiment: 'proposition' as const, iconLabel: '' },
79
+ ].forEach(({ sentiment, iconLabel }) => {
80
+ describe(sentiment, () => {
81
+ const customLabel = 'Custom icon label';
82
+
83
+ if (!iconLabel) {
84
+ it('should not have accessible name for the icon', () => {
85
+ const { container } = render(
86
+ <ListItem
87
+ title="Test Title"
88
+ prompt={<ListItem.Prompt sentiment={sentiment}>Message</ListItem.Prompt>}
89
+ />,
90
+ );
91
+ expect(container.querySelector('svg')).not.toHaveAccessibleName();
92
+ });
93
+ } else {
94
+ it('should use default aria label', () => {
95
+ render(
96
+ <ListItem
97
+ title="Test Title"
98
+ prompt={<ListItem.Prompt sentiment={sentiment}>Message</ListItem.Prompt>}
99
+ />,
100
+ );
101
+ expect(screen.getByLabelText(iconLabel)).toBeInTheDocument();
102
+ });
103
+ }
104
+
105
+ it('should allow for customisation of aria label', () => {
106
+ render(
107
+ <ListItem
108
+ title="Test Title"
109
+ prompt={
110
+ <ListItem.Prompt sentiment={sentiment} iconLabel={customLabel}>
111
+ Message
112
+ </ListItem.Prompt>
113
+ }
114
+ />,
115
+ );
116
+ expect(screen.getByLabelText(customLabel)).toBeInTheDocument();
117
+ });
118
+ });
119
+ });
72
120
  });
@@ -23,6 +23,7 @@ const meta: Meta<ListItemPromptProps> = {
23
23
  decorators: [withoutKey],
24
24
  args: {
25
25
  sentiment: undefined,
26
+ iconLabel: undefined,
26
27
  children: 'You have done a terrible thing',
27
28
  },
28
29
  argTypes: {
@@ -4,7 +4,7 @@ import { Sentiment } from '../../common';
4
4
  import { ListItemContext, type ListItemContextData } from '../ListItemContext';
5
5
  import { InlinePrompt, type InlinePromptProps } from '../../prompt';
6
6
 
7
- export type ListItemPromptProps = Pick<InlinePromptProps, 'children' | 'sentiment' | 'muted'>;
7
+ export type ListItemPromptProps = Pick<InlinePromptProps, 'children' | 'sentiment' | 'iconLabel'>;
8
8
 
9
9
  /**
10
10
  * This component allows for rendering an Inline Prompt. <br />
@@ -12,7 +12,11 @@ export type ListItemPromptProps = Pick<InlinePromptProps, 'children' | 'sentimen
12
12
  *
13
13
  * Please refer to the [Design documentation](https://wise.design/components/list-item#prompt) for details.
14
14
  */
15
- export const Prompt = ({ sentiment = Sentiment.NEUTRAL, children }: ListItemPromptProps) => {
15
+ export const Prompt = ({
16
+ sentiment = Sentiment.NEUTRAL,
17
+ iconLabel,
18
+ children,
19
+ }: ListItemPromptProps) => {
16
20
  const { ids, props } = useContext<ListItemContextData>(ListItemContext);
17
21
  const isLongLivedMuted = props.disabled && Boolean(props.disabledPromptMessage);
18
22
 
@@ -20,6 +24,7 @@ export const Prompt = ({ sentiment = Sentiment.NEUTRAL, children }: ListItemProm
20
24
  <InlinePrompt
21
25
  id={ids.prompt}
22
26
  sentiment={sentiment}
27
+ iconLabel={iconLabel}
23
28
  muted={isLongLivedMuted}
24
29
  className="wds-list-item-prompt"
25
30
  >
@@ -1,4 +1,4 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
2
 
3
3
  exports[`Logo on mobile renders only fast flag 1`] = `
4
4
  <div>
@@ -5,7 +5,7 @@ import { Nudge } from '..';
5
5
 
6
6
  export default {
7
7
  component: Nudge,
8
- title: 'Feedback/Nudge',
8
+ title: 'Prompts/Nudge',
9
9
  };
10
10
 
11
11
  export const Default = () => {
@@ -1,4 +1,4 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
2
 
3
3
  exports[`OverlayHeader renders as expected 1`] = `
4
4
  <div>
@@ -1,4 +1,4 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
2
 
3
3
  exports[`Popover on desktop renders when is open 1`] = `
4
4
  <div
@@ -1,4 +1,4 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
2
 
3
3
  exports[`PromoCard matches snapshot 1`] = `
4
4
  <div
@@ -1,4 +1,4 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
2
 
3
3
  exports[`PromoCardGroup matches snapshot 1`] = `
4
4
  <div
@@ -26,7 +26,7 @@ describe('InlinePrompt', () => {
26
26
  { sentiment: Sentiment.NEGATIVE as const, acceptsMedia: false, statusIconLabel: 'Error:' },
27
27
  { sentiment: Sentiment.WARNING as const, acceptsMedia: false, statusIconLabel: 'Warning:' },
28
28
  { sentiment: Sentiment.NEUTRAL as const, acceptsMedia: false, statusIconLabel: 'Information:' },
29
- { sentiment: Sentiment.POSITIVE as const, acceptsMedia: true, statusIconLabel: '' },
29
+ { sentiment: Sentiment.POSITIVE as const, acceptsMedia: true, statusIconLabel: 'Success:' },
30
30
  { sentiment: 'proposition' as const, acceptsMedia: true, statusIconLabel: '' },
31
31
  ].forEach(({ sentiment, statusIconLabel, acceptsMedia }) => {
32
32
  describe(sentiment, () => {
@@ -90,6 +90,34 @@ describe('InlinePrompt', () => {
90
90
  });
91
91
  }
92
92
  });
93
+
94
+ describe('iconLabel', () => {
95
+ const iconLabel = 'Custom icon label';
96
+
97
+ if (!statusIconLabel) {
98
+ it('should not have accessible name for the icon', () => {
99
+ const { container } = render(<InlinePrompt {...defaultProps} sentiment={sentiment} />);
100
+ expect(container.querySelector('svg')).not.toHaveAccessibleName();
101
+ });
102
+ } else {
103
+ it('should use default aria label', () => {
104
+ render(<InlinePrompt {...defaultProps} sentiment={sentiment} />);
105
+ expect(screen.getByLabelText(statusIconLabel)).toBeInTheDocument();
106
+ });
107
+ }
108
+
109
+ it('should allow for customisation of aria label', () => {
110
+ render(<InlinePrompt {...defaultProps} sentiment={sentiment} iconLabel={iconLabel} />);
111
+ expect(screen.getByLabelText(iconLabel)).toBeInTheDocument();
112
+ });
113
+
114
+ it('should retain custom label while muted', () => {
115
+ render(
116
+ <InlinePrompt {...defaultProps} sentiment={sentiment} iconLabel={iconLabel} muted />,
117
+ );
118
+ expect(screen.getByLabelText(iconLabel)).toBeInTheDocument();
119
+ });
120
+ });
93
121
  });
94
122
  });
95
123
 
@@ -1,5 +1,6 @@
1
1
  import type { ReactElement } from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
3
+ import { action } from 'storybook/actions';
3
4
  import { Taxi, Travel } from '@transferwise/icons';
4
5
  import { lorem5 } from '../../test-utils';
5
6
  import Link from '../../link';
@@ -22,8 +23,9 @@ const withComponentGrid =
22
23
  );
23
24
 
24
25
  export default {
25
- title: 'Internal/InlinePrompt',
26
+ title: 'Prompts/InlinePrompt',
26
27
  component: InlinePrompt,
28
+ tags: ['new'],
27
29
  args: {
28
30
  loading: false,
29
31
  muted: false,
@@ -158,6 +160,39 @@ export const Loading: StoryObj<PreviewStoryArgs> = {
158
160
  },
159
161
  };
160
162
 
163
+ /**
164
+ * `InlinePrompt` can include a single instance of the `Link` component, which can be rendered as
165
+ * either HTML anchor or button. That element will spread across the whole surface of the Prompt
166
+ * so it's more accessible for motor–impaired and touch devices users.
167
+ *
168
+ * > ⚠️ For that reason it's crucial to only include **one** interactive element inside a prompt.
169
+ */
170
+ export const Interactivity: StoryObj<PreviewStoryArgs> = {
171
+ argTypes: previewArgTypes,
172
+ args: {
173
+ muted: true,
174
+ previewMedia: false,
175
+ },
176
+ render: (args: PreviewStoryArgs) => (
177
+ <>
178
+ <InlinePrompt sentiment={args.sentiment}>
179
+ This prompt includes a{' '}
180
+ <Link href="https://wise.com" target="_blank" rel="noreferrer">
181
+ link to some resource
182
+ </Link>{' '}
183
+ to help the user in their journey.
184
+ </InlinePrompt>
185
+
186
+ <InlinePrompt sentiment={args.sentiment}>
187
+ {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
188
+ This prompt includes an <Link onClick={action('inline button')}>inline button</Link> than
189
+ can e.g. trigger a modal.
190
+ </InlinePrompt>
191
+ </>
192
+ ),
193
+ decorators: [withComponentGrid()],
194
+ };
195
+
161
196
  /**
162
197
  * Inline prompt is usually associated with a different component, such as `Input` or `ListItem`.
163
198
  * When those components are disabled, the prompt is often used to communicate to the user why they
@@ -174,14 +209,20 @@ export const Muted: StoryObj<PreviewStoryArgs> = {
174
209
  },
175
210
  render: (args: PreviewStoryArgs) => {
176
211
  const [props, previewProps] = getPropsForPreview(args);
177
- return <InlinePrompt {...props} {...previewProps} />;
212
+ return (
213
+ <InlinePrompt {...props} {...previewProps}>
214
+ Please <Link href="#">confirm your residential address</Link> to activate this feature.
215
+ </InlinePrompt>
216
+ );
178
217
  },
179
218
  };
180
219
 
181
220
  /**
182
221
  * While main sentiments (`warning`, `negative`, `neutral`) must retain their associated
183
222
  * `StatusIcons`, the `positive` and `proposition` ones allow for Icon overrides to bring it
184
- * closer to the prompt's content.
223
+ * closer to the prompt's content. <br /><br />
224
+ * It's also possible to override the default icon's accessible name announced by screen readers
225
+ * via `iconLabel` prop, which is especially useful for the `proposition` sentiment.
185
226
  */
186
227
  export const IconOverrides: StoryObj<PreviewStoryArgs> = {
187
228
  render: (args: PreviewStoryArgs) => {
@@ -190,7 +231,7 @@ export const IconOverrides: StoryObj<PreviewStoryArgs> = {
190
231
  <InlinePrompt {...args} media={<Travel />} sentiment="positive">
191
232
  Your travel account is set up and ready to use.
192
233
  </InlinePrompt>
193
- <InlinePrompt {...args} media={<Taxi />} sentiment="proposition">
234
+ <InlinePrompt {...args} media={<Taxi />} sentiment="proposition" iconLabel="Taxi addon: ">
194
235
  Connect Wise with your taxi app to get exclusive discounts.
195
236
  </InlinePrompt>
196
237
  <InlinePrompt {...args} media={<Taxi />} sentiment="negative">
@@ -28,6 +28,11 @@ export type InlinePromptProps = {
28
28
  * Icon override for `proposition` and `positive` sentiments. Unsupported for remaining ones.
29
29
  */
30
30
  media?: React.ReactNode;
31
+ /**
32
+ * Override for the sentiment's-derived, default, accessible name announced by the screen readers.
33
+ * To be used primarily for `proposition` sentiment.
34
+ */
35
+ iconLabel?: string;
31
36
  id?: string;
32
37
  className?: string;
33
38
  'data-testid'?: string;
@@ -36,7 +41,9 @@ export type InlinePromptProps = {
36
41
 
37
42
  /**
38
43
  * Inline prompts appear alongside a specific component on the screen. They help the user stay
39
- * informed, fix something, or get more out of what they're doing.
44
+ * informed, fix something, or get more out of what they're doing. <br />
45
+ *
46
+ * **NB:** It should be used in favour of `InlineAlert` which will be soon deprecated.
40
47
  */
41
48
  export const InlinePrompt = ({
42
49
  sentiment = Sentiment.POSITIVE,
@@ -45,6 +52,7 @@ export const InlinePrompt = ({
45
52
  className,
46
53
  children,
47
54
  media = null,
55
+ iconLabel,
48
56
  'data-testid': dataTestId,
49
57
  ...rest
50
58
  }: InlinePromptProps) => {
@@ -52,7 +60,7 @@ export const InlinePrompt = ({
52
60
 
53
61
  const renderMedia = () => {
54
62
  if (muted) {
55
- return <BackslashCircle size={16} data-testid="InlinePrompt_Muted" />;
63
+ return <BackslashCircle size={16} data-testid="InlinePrompt_Muted" title={iconLabel} />;
56
64
  }
57
65
  if (loading) {
58
66
  return (
@@ -69,10 +77,10 @@ export const InlinePrompt = ({
69
77
  }
70
78
 
71
79
  if (sentiment === 'proposition') {
72
- return media || <GiftBox />;
80
+ return media || <GiftBox title={iconLabel} />;
73
81
  }
74
82
 
75
- return <StatusIcon size={16} sentiment={sentiment} />;
83
+ return <StatusIcon size={16} sentiment={sentiment} iconLabel={iconLabel} />;
76
84
  };
77
85
 
78
86
  return (
@@ -22,7 +22,7 @@ function ThemeProvider(props: ThemeProviderProps) {
22
22
 
23
23
  export default {
24
24
  component: ThemeProvider,
25
- title: 'Other/ThemeProvider',
25
+ title: 'Foundations/ThemeProvider',
26
26
  } satisfies Meta<typeof ThemeProvider>;
27
27
 
28
28
  type Story = StoryObj<typeof ThemeProvider>;