@transferwise/components 46.119.5 → 46.120.1

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 (140) hide show
  1. package/build/alert/Alert.js +1 -1
  2. package/build/alert/Alert.js.map +1 -1
  3. package/build/alert/Alert.mjs +1 -1
  4. package/build/alert/Alert.mjs.map +1 -1
  5. package/build/checkbox/Checkbox.js +1 -1
  6. package/build/checkbox/Checkbox.js.map +1 -1
  7. package/build/checkbox/Checkbox.mjs +1 -1
  8. package/build/checkbox/Checkbox.mjs.map +1 -1
  9. package/build/common/initials.js +17 -7
  10. package/build/common/initials.js.map +1 -1
  11. package/build/common/initials.mjs +17 -7
  12. package/build/common/initials.mjs.map +1 -1
  13. package/build/field/Field.js +8 -4
  14. package/build/field/Field.js.map +1 -1
  15. package/build/field/Field.mjs +8 -4
  16. package/build/field/Field.mjs.map +1 -1
  17. package/build/inlineAlert/InlineAlert.js +1 -7
  18. package/build/inlineAlert/InlineAlert.js.map +1 -1
  19. package/build/inlineAlert/InlineAlert.mjs +1 -7
  20. package/build/inlineAlert/InlineAlert.mjs.map +1 -1
  21. package/build/main.css +20 -1
  22. package/build/prompt/InlinePrompt/InlinePrompt.js +2 -0
  23. package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
  24. package/build/prompt/InlinePrompt/InlinePrompt.mjs +2 -0
  25. package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
  26. package/build/radioGroup/RadioGroup.js +1 -0
  27. package/build/radioGroup/RadioGroup.js.map +1 -1
  28. package/build/radioGroup/RadioGroup.mjs +1 -0
  29. package/build/radioGroup/RadioGroup.mjs.map +1 -1
  30. package/build/styles/field/Field.css +10 -1
  31. package/build/styles/main.css +20 -1
  32. package/build/styles/prompt/InlinePrompt/InlinePrompt.css +3 -0
  33. package/build/styles/radioGroup/RadioGroup.css +3 -0
  34. package/build/styles/typeahead/Typeahead.css +4 -0
  35. package/build/typeahead/Typeahead.js +20 -7
  36. package/build/typeahead/Typeahead.js.map +1 -1
  37. package/build/typeahead/Typeahead.mjs +20 -7
  38. package/build/typeahead/Typeahead.mjs.map +1 -1
  39. package/build/types/alert/Alert.d.ts +1 -1
  40. package/build/types/alert/Alert.d.ts.map +1 -1
  41. package/build/types/common/initials.d.ts.map +1 -1
  42. package/build/types/field/Field.d.ts +8 -4
  43. package/build/types/field/Field.d.ts.map +1 -1
  44. package/build/types/inlineAlert/InlineAlert.d.ts +1 -7
  45. package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
  46. package/build/types/listItem/_stories/variants/helpers.d.ts +7 -4
  47. package/build/types/listItem/_stories/variants/helpers.d.ts.map +1 -1
  48. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts +6 -1
  49. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -1
  50. package/build/types/radioGroup/RadioGroup.d.ts.map +1 -1
  51. package/build/types/test-utils/index.d.ts +0 -1
  52. package/build/types/test-utils/index.d.ts.map +1 -1
  53. package/build/types/typeahead/Typeahead.d.ts +8 -4
  54. package/build/types/typeahead/Typeahead.d.ts.map +1 -1
  55. package/build/types/upload/Upload.d.ts +1 -1
  56. package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts.map +1 -1
  57. package/build/upload/Upload.js.map +1 -1
  58. package/build/upload/Upload.mjs.map +1 -1
  59. package/build/upload/steps/uploadImageStep/uploadImageStep.js +5 -4
  60. package/build/upload/steps/uploadImageStep/uploadImageStep.js.map +1 -1
  61. package/build/upload/steps/uploadImageStep/uploadImageStep.mjs +5 -4
  62. package/build/upload/steps/uploadImageStep/uploadImageStep.mjs.map +1 -1
  63. package/package.json +9 -8
  64. package/src/DisabledComponents.story.tsx +1 -3
  65. package/src/actionButton/ActionButton.story.tsx +42 -45
  66. package/src/alert/Alert.spec.tsx +1 -1
  67. package/src/alert/Alert.tsx +2 -2
  68. package/src/avatar/Avatar.story.tsx +192 -188
  69. package/src/button/_stories/Button.tests.story.tsx +122 -119
  70. package/src/carousel/Carousel.story.tsx +4 -7
  71. package/src/checkbox/Checkbox.story.tsx +42 -21
  72. package/src/checkbox/Checkbox.tsx +1 -1
  73. package/src/checkbox/__snapshots__/Checkbox.spec.tsx.snap +1 -1
  74. package/src/circularButton/CircularButton.story.tsx +10 -2
  75. package/src/common/bottomSheet/BottomSheet.story.tsx +48 -14
  76. package/src/common/circle/Circle.story.tsx +62 -55
  77. package/src/common/initials.spec.tsx +31 -0
  78. package/src/common/initials.ts +19 -8
  79. package/src/criticalBanner/CriticalCommsBanner.story.tsx +30 -19
  80. package/src/dateInput/DateInput.tests.story.tsx +101 -74
  81. package/src/dateLookup/DateLookup.story.tsx +69 -59
  82. package/src/field/Field.css +10 -1
  83. package/src/field/Field.less +13 -2
  84. package/src/field/Field.spec.tsx +19 -3
  85. package/src/field/Field.story.tsx +18 -0
  86. package/src/field/Field.tsx +17 -5
  87. package/src/header/Header.story.tsx +5 -16
  88. package/src/header/Header.tests.story.tsx +95 -69
  89. package/src/info/Info.story.tsx +27 -11
  90. package/src/inlineAlert/InlineAlert.story.tsx +4 -0
  91. package/src/inlineAlert/InlineAlert.tsx +1 -7
  92. package/src/instructionsList/InstructionsList.story.tsx +0 -1
  93. package/src/listItem/_stories/ListItem.layout.test.story.tsx +1 -3
  94. package/src/listItem/_stories/variants/ListItem.brightGreen.test.story.tsx +77 -35
  95. package/src/listItem/_stories/variants/ListItem.dark.test.story.tsx +65 -29
  96. package/src/listItem/_stories/variants/ListItem.forestGreen.test.story.tsx +77 -35
  97. package/src/listItem/_stories/variants/ListItem.medium.test.story.tsx +38 -18
  98. package/src/listItem/_stories/variants/ListItem.neutral.test.story.tsx +0 -1
  99. package/src/listItem/_stories/variants/ListItem.personal.test.story.tsx +38 -18
  100. package/src/listItem/_stories/variants/ListItem.rtl.test.story.tsx +77 -29
  101. package/src/listItem/_stories/variants/ListItem.small.test.story.tsx +65 -18
  102. package/src/listItem/_stories/variants/helpers.tsx +136 -133
  103. package/src/main.css +20 -1
  104. package/src/main.less +1 -0
  105. package/src/modal/Modal.story.tsx +47 -8
  106. package/src/moneyInput/MoneyInput.story.tsx +2 -2
  107. package/src/primitives/PrimitiveAnchor/stories/PrimitiveAnchor.story.tsx +1 -0
  108. package/src/primitives/PrimitiveAnchor/stories/PrimitiveAnchor.tests.story.tsx +1 -0
  109. package/src/primitives/PrimitiveButton/stories/PrimitiveButton.story.tsx +1 -0
  110. package/src/primitives/PrimitiveButton/stories/PrimitiveButton.tests.story.tsx +1 -0
  111. package/src/prompt/InlinePrompt/InlinePrompt.css +3 -0
  112. package/src/prompt/InlinePrompt/InlinePrompt.less +5 -1
  113. package/src/prompt/InlinePrompt/InlinePrompt.spec.tsx +17 -0
  114. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +35 -0
  115. package/src/prompt/InlinePrompt/InlinePrompt.tsx +7 -0
  116. package/src/provider/theme/ThemeProvider.story.tsx +1 -0
  117. package/src/radioGroup/RadioGroup.css +3 -0
  118. package/src/radioGroup/RadioGroup.less +3 -0
  119. package/src/radioGroup/RadioGroup.story.tsx +2 -0
  120. package/src/radioGroup/RadioGroup.test.story.tsx +62 -0
  121. package/src/radioGroup/RadioGroup.tsx +6 -1
  122. package/src/segmentedControl/SegmentedControl.story.tsx +71 -67
  123. package/src/snackbar/Snackbar.tests.story.tsx +116 -114
  124. package/src/statusIcon/StatusIcon.story.tsx +41 -38
  125. package/src/test-utils/index.tsx +0 -2
  126. package/src/tokens/tokens.story.tsx +1 -1
  127. package/src/tooltip/Tooltip.story.tsx +10 -2
  128. package/src/typeahead/Typeahead.css +4 -0
  129. package/src/typeahead/Typeahead.less +5 -1
  130. package/src/typeahead/Typeahead.spec.tsx +1 -1
  131. package/src/typeahead/Typeahead.story.tsx +151 -3
  132. package/src/typeahead/Typeahead.tsx +33 -9
  133. package/src/upload/Upload.story.tsx +1 -1
  134. package/src/upload/Upload.tests.story.tsx +36 -1
  135. package/src/upload/Upload.tsx +1 -1
  136. package/src/upload/steps/uploadImageStep/uploadImageStep.tsx +7 -3
  137. package/src/withId/withId.story.tsx +1 -1
  138. package/build/types/test-utils/story-config.d.ts +0 -64
  139. package/build/types/test-utils/story-config.d.ts.map +0 -1
  140. package/src/test-utils/story-config.ts +0 -95
@@ -2,10 +2,11 @@ import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { userEvent, within, fn } from 'storybook/test';
3
3
 
4
4
  import { DateInput, Field } from '..';
5
- import { lorem10, storyConfig } from '../test-utils';
5
+ import { lorem10 } from '../test-utils';
6
6
 
7
7
  import Provider from '../provider/Provider';
8
8
  import translations from '../i18n';
9
+ import { allModes } from '../../.storybook/modes';
9
10
 
10
11
  const meta: Meta<typeof DateInput> = {
11
12
  component: DateInput,
@@ -78,64 +79,72 @@ export const CustomPlaceholders: Story = {
78
79
  },
79
80
  };
80
81
 
81
- export const SingleZero = storyConfig(Basic, {});
82
- SingleZero.play = async ({ canvasElement, step }) => {
83
- const canvas = within(canvasElement);
84
- await step('can enter leading zero on day field', async () => {
85
- const dayInput = await canvas.findByRole('textbox', { name: /day/i });
86
- await userEvent.click(dayInput);
87
- await userEvent.type(dayInput, '0');
88
- });
89
- await step('can enter 1 leading zero on year field', async () => {
90
- const yearInput = await canvas.findByRole('textbox', { name: /year/i });
91
- await userEvent.click(yearInput);
92
- await userEvent.type(yearInput, '0');
93
- });
94
- };
95
-
96
- export const ZeroesAsValue = storyConfig(Basic, {});
97
- ZeroesAsValue.play = async ({ canvasElement, step }) => {
98
- const canvas = within(canvasElement);
99
- await step('can enter 2 leading zeroes on day field', async () => {
100
- const dayInput = await canvas.findByRole('textbox', { name: /day/i });
101
- await userEvent.click(dayInput);
102
- await userEvent.type(dayInput, '00');
103
- });
104
- await step('can enter 4 leading zeroes on year field', async () => {
105
- const yearInput = await canvas.findByRole('textbox', { name: /year/i });
106
- await userEvent.click(yearInput);
107
- await userEvent.type(yearInput, '0000');
108
- });
109
- };
110
-
111
- export const ZeroesBeforeValue = storyConfig(Basic, {});
112
- ZeroesBeforeValue.play = async ({ canvasElement, step }) => {
113
- const canvas = within(canvasElement);
114
- await step('can enter leading zeroes on day followed by day', async () => {
115
- const dayInput = await canvas.findByRole('textbox', { name: /day/i });
116
- await userEvent.click(dayInput);
117
- await userEvent.type(dayInput, '01');
118
- });
119
- await step('can enter leading zeroes on year followed by year', async () => {
120
- const yearInput = await canvas.findByRole('textbox', { name: /year/i });
121
- await userEvent.click(yearInput);
122
- await userEvent.type(yearInput, '0001');
123
- });
124
- };
125
-
126
- export const MaxLengthRespected = storyConfig(Basic, {});
127
- MaxLengthRespected.play = async ({ canvasElement, step }) => {
128
- const canvas = within(canvasElement);
129
- await step('can only enter 4 digits in the year field', async () => {
130
- const yearInput = await canvas.findByRole('textbox', { name: /year/i });
131
- await userEvent.click(yearInput);
132
- await userEvent.type(yearInput, '11111111');
133
- });
134
- await step('can only enter 2 digits in the day field', async () => {
135
- const dayInput = await canvas.findByRole('textbox', { name: /day/i });
136
- await userEvent.click(dayInput);
137
- await userEvent.type(dayInput, '11111111');
138
- });
82
+ export const SingleZero: Story = {
83
+ ...Basic,
84
+ play: async ({ canvasElement, step }) => {
85
+ const canvas = within(canvasElement);
86
+ await step('can enter leading zero on day field', async () => {
87
+ const dayInput = await canvas.findByRole('textbox', { name: /day/i });
88
+ await userEvent.click(dayInput);
89
+ await userEvent.type(dayInput, '0');
90
+ });
91
+ await step('can enter 1 leading zero on year field', async () => {
92
+ const yearInput = await canvas.findByRole('textbox', { name: /year/i });
93
+ await userEvent.click(yearInput);
94
+ await userEvent.type(yearInput, '0');
95
+ });
96
+ },
97
+ };
98
+
99
+ export const ZeroesAsValue: Story = {
100
+ ...Basic,
101
+ play: async ({ canvasElement, step }) => {
102
+ const canvas = within(canvasElement);
103
+ await step('can enter 2 leading zeroes on day field', async () => {
104
+ const dayInput = await canvas.findByRole('textbox', { name: /day/i });
105
+ await userEvent.click(dayInput);
106
+ await userEvent.type(dayInput, '00');
107
+ });
108
+ await step('can enter 4 leading zeroes on year field', async () => {
109
+ const yearInput = await canvas.findByRole('textbox', { name: /year/i });
110
+ await userEvent.click(yearInput);
111
+ await userEvent.type(yearInput, '0000');
112
+ });
113
+ },
114
+ };
115
+
116
+ export const ZeroesBeforeValue: Story = {
117
+ ...Basic,
118
+ play: async ({ canvasElement, step }) => {
119
+ const canvas = within(canvasElement);
120
+ await step('can enter leading zeroes on day followed by day', async () => {
121
+ const dayInput = await canvas.findByRole('textbox', { name: /day/i });
122
+ await userEvent.click(dayInput);
123
+ await userEvent.type(dayInput, '01');
124
+ });
125
+ await step('can enter leading zeroes on year followed by year', async () => {
126
+ const yearInput = await canvas.findByRole('textbox', { name: /year/i });
127
+ await userEvent.click(yearInput);
128
+ await userEvent.type(yearInput, '0001');
129
+ });
130
+ },
131
+ };
132
+
133
+ export const MaxLengthRespected: Story = {
134
+ ...Basic,
135
+ play: async ({ canvasElement, step }) => {
136
+ const canvas = within(canvasElement);
137
+ await step('can only enter 4 digits in the year field', async () => {
138
+ const yearInput = await canvas.findByRole('textbox', { name: /year/i });
139
+ await userEvent.click(yearInput);
140
+ await userEvent.type(yearInput, '11111111');
141
+ });
142
+ await step('can only enter 2 digits in the day field', async () => {
143
+ const dayInput = await canvas.findByRole('textbox', { name: /day/i });
144
+ await userEvent.click(dayInput);
145
+ await userEvent.type(dayInput, '11111111');
146
+ });
147
+ },
139
148
  };
140
149
 
141
150
  export const LocalizationWorks: Story = {
@@ -194,21 +203,39 @@ export const DayFirst: Story = {
194
203
  ],
195
204
  };
196
205
 
197
- export const NoNonDigitsAllowed = storyConfig(Basic, {});
198
- NoNonDigitsAllowed.play = async ({ canvasElement, step }) => {
199
- const canvas = within(canvasElement);
200
- await step('can only enter digits in the day field', async () => {
201
- const dayInput = await canvas.findByRole('textbox', { name: /day/i });
202
- await userEvent.click(dayInput);
203
- await userEvent.type(dayInput, 'abcd1');
204
- });
205
- await step('can only enter digits in the year field', async () => {
206
- const yearInput = await canvas.findByRole('textbox', { name: /year/i });
207
- await userEvent.click(yearInput);
208
- await userEvent.type(yearInput, 'abcd2');
209
- });
206
+ export const NoNonDigitsAllowed: Story = {
207
+ ...Basic,
208
+ play: async ({ canvasElement, step }) => {
209
+ const canvas = within(canvasElement);
210
+ await step('can only enter digits in the day field', async () => {
211
+ const dayInput = await canvas.findByRole('textbox', { name: /day/i });
212
+ await userEvent.click(dayInput);
213
+ await userEvent.type(dayInput, 'abcd1');
214
+ });
215
+ await step('can only enter digits in the year field', async () => {
216
+ const yearInput = await canvas.findByRole('textbox', { name: /year/i });
217
+ await userEvent.click(yearInput);
218
+ await userEvent.type(yearInput, 'abcd2');
219
+ });
220
+ },
210
221
  };
211
222
 
212
- export const BasicMobile = storyConfig(Basic, { variants: ['mobile'] });
223
+ export const BasicMobile: Story = {
224
+ ...Basic,
225
+ parameters: {
226
+ variants: ['mobile'],
227
+ chromatic: {
228
+ mobile: allModes.largeMobile,
229
+ },
230
+ },
231
+ };
213
232
 
214
- export const InputErrorMobile = storyConfig(InputError, { variants: ['mobile'] });
233
+ export const InputErrorMobile: Story = {
234
+ ...InputError,
235
+ parameters: {
236
+ variants: ['mobile'],
237
+ chromatic: {
238
+ mobile: allModes.largeMobile,
239
+ },
240
+ },
241
+ };
@@ -1,9 +1,10 @@
1
1
  import { useState } from 'react';
2
2
  import { userEvent } from 'storybook/test';
3
+ import { StoryObj } from '@storybook/react-webpack5';
3
4
  import { Field } from '..';
4
5
  import { Size } from '../common';
5
- import { storyConfig } from '../test-utils';
6
6
  import DateLookup, { type DateLookupProps } from './DateLookup';
7
+ import { allModes } from '../../.storybook/modes';
7
8
 
8
9
  export default {
9
10
  component: DateLookup,
@@ -21,53 +22,18 @@ export default {
21
22
  },
22
23
  };
23
24
 
25
+ type Story = StoryObj<typeof DateLookup>;
26
+
24
27
  const epoch = new Date('2011-01-01');
25
28
  const theFuture = new Date(epoch);
26
29
  theFuture.setUTCDate(epoch.getUTCDate() + 10);
27
30
  const thePast = new Date(epoch);
28
31
  thePast.setUTCDate(epoch.getUTCDate() - 10);
29
32
 
30
- export const Basic = (args: DateLookupProps) => {
31
- const [value, setValue] = useState<Date | null>(epoch);
32
- return (
33
- <DateLookup
34
- {...args}
35
- min={args.min ? new Date(args.min) : thePast}
36
- max={args.max ? new Date(args.max) : theFuture}
37
- value={value}
38
- onChange={(v) => setValue(v)}
39
- />
40
- );
41
- };
42
- Basic.args = {
43
- size: Size.MEDIUM,
44
- disabled: false,
45
- label: 'label',
46
- monthFormat: 'long',
47
- placeholder: 'placeholder',
48
- id: 'date-lookup',
49
- clearable: true,
50
- min: thePast,
51
- max: theFuture,
52
- };
53
- Basic.play = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
54
- await userEvent.tab();
55
- await userEvent.keyboard(' ');
56
- };
57
-
58
- export const Basic400Zoom = storyConfig(
59
- {
60
- render: Basic,
61
- play: Basic.play,
62
- parameters: { chromatic: { delay: 2000 } },
63
- },
64
- { variants: ['400%'] },
65
- );
66
-
67
- export const WithField = (args: DateLookupProps) => {
68
- const [value, setValue] = useState<Date | null>(epoch);
69
- return (
70
- <Field label="Date lookup">
33
+ export const Basic: Story = {
34
+ render: (args: DateLookupProps) => {
35
+ const [value, setValue] = useState<Date | null>(epoch);
36
+ return (
71
37
  <DateLookup
72
38
  {...args}
73
39
  min={args.min ? new Date(args.min) : thePast}
@@ -75,31 +41,75 @@ export const WithField = (args: DateLookupProps) => {
75
41
  value={value}
76
42
  onChange={(v) => setValue(v)}
77
43
  />
78
- </Field>
79
- );
44
+ );
45
+ },
46
+ args: {
47
+ size: Size.MEDIUM,
48
+ disabled: false,
49
+ label: 'label',
50
+ monthFormat: 'long',
51
+ placeholder: 'placeholder',
52
+ id: 'date-lookup',
53
+ clearable: true,
54
+ min: thePast,
55
+ max: theFuture,
56
+ },
57
+ play: async () => {
58
+ await userEvent.tab();
59
+ await userEvent.keyboard(' ');
60
+ },
61
+ };
62
+ export const Basic400Zoom: Story = {
63
+ ...Basic,
64
+ parameters: {
65
+ chromatic: {
66
+ delay: 2000,
67
+ zoom400: allModes.zoom400,
68
+ },
69
+ variants: ['400%'],
70
+ },
80
71
  };
81
72
 
82
- export const RightAligned = (args: DateLookupProps) => {
83
- const [value, setValue] = useState<Date | null>(epoch);
84
- return (
85
- <div className="row">
86
- <div className="col-xs-6">
87
- <p>
88
- This example demonstrates the automatic right alignment behaviour of the calendar. If,
89
- when the calendar is opened, it is cut off on the right, the component will align the
90
- calendar to the rightmost edge of the lookup input.
91
- </p>
92
- </div>
93
- <div className="col-xs-6">
73
+ export const WithField: Story = {
74
+ render: (args: DateLookupProps) => {
75
+ const [value, setValue] = useState<Date | null>(epoch);
76
+ return (
77
+ <Field label="Date lookup">
94
78
  <DateLookup
95
79
  {...args}
96
- id="right-aligned"
97
80
  min={args.min ? new Date(args.min) : thePast}
98
81
  max={args.max ? new Date(args.max) : theFuture}
99
82
  value={value}
100
83
  onChange={(v) => setValue(v)}
101
84
  />
85
+ </Field>
86
+ );
87
+ },
88
+ };
89
+
90
+ export const RightAligned: Story = {
91
+ render: (args: DateLookupProps) => {
92
+ const [value, setValue] = useState<Date | null>(epoch);
93
+ return (
94
+ <div className="row">
95
+ <div className="col-xs-6">
96
+ <p>
97
+ This example demonstrates the automatic right alignment behaviour of the calendar. If,
98
+ when the calendar is opened, it is cut off on the right, the component will align the
99
+ calendar to the rightmost edge of the lookup input.
100
+ </p>
101
+ </div>
102
+ <div className="col-xs-6">
103
+ <DateLookup
104
+ {...args}
105
+ id="right-aligned"
106
+ min={args.min ? new Date(args.min) : thePast}
107
+ max={args.max ? new Date(args.max) : theFuture}
108
+ value={value}
109
+ onChange={(v) => setValue(v)}
110
+ />
111
+ </div>
102
112
  </div>
103
- </div>
104
- );
113
+ );
114
+ },
105
115
  };
@@ -1,4 +1,13 @@
1
- .np-field-control {
1
+ .np-field-control,
2
+ .np-field__prompt {
2
3
  margin-top: 4px;
3
4
  margin-top: var(--size-4);
4
5
  }
6
+ .np-field .form-group--typeahead[class],
7
+ .np-field .np-checkbox-label[class] {
8
+ margin-bottom: 0;
9
+ }
10
+ .np-field:has(.wds-radio-group) .np-field__prompt {
11
+ margin-top: 12px;
12
+ margin-top: var(--size-12);
13
+ }
@@ -1,5 +1,16 @@
1
1
  .np-field {
2
- &-control {
3
- margin-top: var(--size-4);
2
+ &-control,
3
+ &__prompt {
4
+ margin-top: var(--size-4);
5
+ }
6
+
7
+ // @FIXME space between individual fields should be 24px, while some older inputs
8
+ // inject extraneous space.
9
+ .form-group--typeahead[class],
10
+ .np-checkbox-label[class] {
11
+ margin-bottom: 0;
12
+ }
13
+ &:has(.wds-radio-group) &__prompt {
14
+ margin-top: var(--size-12);
4
15
  }
5
16
  }
@@ -71,7 +71,7 @@ describe('Field', () => {
71
71
  expect(screen.getByLabelText(/Phone number/)).toHaveAttribute('aria-describedby');
72
72
  });
73
73
 
74
- it("should allow for InlineAlert's StatusIcon override via `messageIconLabel` prop", () => {
74
+ it("should allow for InlinePrompt's StatusIcon override via `messageIconLabel` prop", () => {
75
75
  const customIconLabel = 'My custom icon label';
76
76
 
77
77
  render(
@@ -86,8 +86,8 @@ describe('Field', () => {
86
86
  </Field>,
87
87
  );
88
88
 
89
- expect(screen.queryByRole('graphics-symbol', { name: 'Error.' })).not.toBeInTheDocument();
90
- expect(screen.getByRole('graphics-symbol', { name: customIconLabel })).toBeInTheDocument();
89
+ expect(screen.queryByLabelText('Error:')).not.toBeInTheDocument();
90
+ expect(screen.getByLabelText(customIconLabel)).toBeInTheDocument();
91
91
  });
92
92
 
93
93
  it('should show or hide (Optional) suffix depending on required prop', () => {
@@ -147,4 +147,20 @@ describe('Field', () => {
147
147
  const label = screen.getByText('Phone number');
148
148
  await userEvent.click(label);
149
149
  });
150
+
151
+ it('should show loading spinner when messageLoading is true', () => {
152
+ render(
153
+ <Field
154
+ label="Phone number"
155
+ message="Processing your request"
156
+ sentiment="neutral"
157
+ messageLoading
158
+ >
159
+ <Input />
160
+ </Field>,
161
+ );
162
+
163
+ expect(screen.getByTestId('InlinePrompt_ProcessIndicator')).toBeInTheDocument();
164
+ expect(screen.getByText('Processing your request')).toBeInTheDocument();
165
+ });
150
166
  });
@@ -46,6 +46,7 @@ export const Basic = (args: FieldProps) => {
46
46
  sentiment={Sentiment.NEGATIVE}
47
47
  message="Validation error, please take a look"
48
48
  messageIconLabel={args.messageIconLabel}
49
+ messageLoading={args.messageLoading}
49
50
  >
50
51
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
51
52
  </Field>
@@ -81,6 +82,7 @@ export const Basic = (args: FieldProps) => {
81
82
  message={lorem10}
82
83
  sentiment="negative"
83
84
  messageIconLabel={args.messageIconLabel}
85
+ messageLoading={args.messageLoading}
84
86
  >
85
87
  <TextArea />
86
88
  </Field>
@@ -109,6 +111,17 @@ export const WithStatusMessages = (args: FieldProps) => {
109
111
  sentiment={Sentiment.POSITIVE}
110
112
  message="Positive message"
111
113
  messageIconLabel={args.messageIconLabel}
114
+ messageLoading={args.messageLoading}
115
+ >
116
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
117
+ </Field>
118
+
119
+ <Field
120
+ label="Text Input with Proposition Message"
121
+ sentiment="proposition"
122
+ message="Proposition message"
123
+ messageIconLabel={args.messageIconLabel}
124
+ messageLoading={args.messageLoading}
112
125
  >
113
126
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
114
127
  </Field>
@@ -118,6 +131,7 @@ export const WithStatusMessages = (args: FieldProps) => {
118
131
  sentiment={Sentiment.WARNING}
119
132
  message="Warning message"
120
133
  messageIconLabel={args.messageIconLabel}
134
+ messageLoading={args.messageLoading}
121
135
  >
122
136
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
123
137
  </Field>
@@ -127,6 +141,7 @@ export const WithStatusMessages = (args: FieldProps) => {
127
141
  sentiment={Sentiment.NEGATIVE}
128
142
  message="This is a required field"
129
143
  messageIconLabel={args.messageIconLabel}
144
+ messageLoading={args.messageLoading}
130
145
  >
131
146
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
132
147
  </Field>
@@ -138,6 +153,7 @@ export const WithStatusMessages = (args: FieldProps) => {
138
153
  sentiment={Sentiment.NEGATIVE}
139
154
  message="Validation error, please take a look"
140
155
  messageIconLabel={args.messageIconLabel}
156
+ messageLoading={args.messageLoading}
141
157
  >
142
158
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
143
159
  </Field>
@@ -148,6 +164,7 @@ export const WithStatusMessages = (args: FieldProps) => {
148
164
  hint="This is a helpful message"
149
165
  error="Validation error, please take a look"
150
166
  messageIconLabel={args.messageIconLabel}
167
+ messageLoading={args.messageLoading}
151
168
  >
152
169
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
153
170
  </Field>
@@ -157,6 +174,7 @@ export const WithStatusMessages = (args: FieldProps) => {
157
174
  label="Text Input with Info under the field"
158
175
  message="This is a helpful message"
159
176
  messageIconLabel={args.messageIconLabel}
177
+ messageLoading={args.messageLoading}
160
178
  >
161
179
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
162
180
  </Field>
@@ -2,7 +2,7 @@ import { clsx } from 'clsx';
2
2
  import { useId, useRef } from 'react';
3
3
 
4
4
  import { Sentiment } from '../common';
5
- import InlineAlert from '../inlineAlert/InlineAlert';
5
+ import { InlinePrompt, type InlinePromptProps } from '../prompt';
6
6
  import {
7
7
  FieldLabelContextProvider,
8
8
  InputDescribedByProvider,
@@ -21,14 +21,18 @@ export type FieldProps = {
21
21
  hint?: React.ReactNode;
22
22
  message?: React.ReactNode;
23
23
  /**
24
- * Override for the [InlineAlert icon's default, accessible name](/?path=/docs/other-statusicon-accessibility--docs)
24
+ * Override for the [InlinePrompt icon's default, accessible name](/?path=/docs/other-statusicon-accessibility--docs)
25
25
  * announced by the screen readers
26
26
  * */
27
27
  messageIconLabel?: string;
28
+ /**
29
+ * If true, shows a loading spinner in place of the message icon of the InlinePrompt
30
+ */
31
+ messageLoading?: boolean;
28
32
  description?: React.ReactNode;
29
33
  /** @deprecated use `message` and `type={Sentiment.NEGATIVE}` prop instead */
30
34
  error?: React.ReactNode;
31
- sentiment?: `${Sentiment.NEGATIVE | Sentiment.NEUTRAL | Sentiment.POSITIVE | Sentiment.WARNING}`;
35
+ sentiment?: InlinePromptProps['sentiment'];
32
36
  className?: string;
33
37
  children?: React.ReactNode;
34
38
  };
@@ -39,6 +43,7 @@ export const Field = ({
39
43
  required = true,
40
44
  message: propMessage,
41
45
  messageIconLabel,
46
+ messageLoading,
42
47
  hint,
43
48
  description = hint,
44
49
  sentiment: propType = Sentiment.NEUTRAL,
@@ -104,9 +109,16 @@ export const Field = ({
104
109
  )}
105
110
 
106
111
  {message && (
107
- <InlineAlert type={sentiment} id={messageId} iconLabel={messageIconLabel}>
112
+ <InlinePrompt
113
+ sentiment={sentiment}
114
+ id={messageId}
115
+ mediaLabel={messageIconLabel}
116
+ className="np-field__prompt"
117
+ loading={messageLoading}
118
+ width="full"
119
+ >
108
120
  {message}
109
- </InlineAlert>
121
+ </InlinePrompt>
110
122
  )}
111
123
  </div>
112
124
  </InputInvalidProvider>
@@ -13,20 +13,6 @@ const withContainer = (Story: any) => (
13
13
  const hideControls = (args: string[]) =>
14
14
  Object.fromEntries(args.map((item) => [item, { table: { disable: true } }]));
15
15
 
16
- /**
17
- * Reusable render logic for wrapping `Header` in a `<fieldset>` if `as` is `legend`.
18
- */
19
- const renderHeader = (args: HeaderProps) => {
20
- if (args.as === 'legend') {
21
- return (
22
- <fieldset style={{ width: '100%' }}>
23
- <Header {...args} />
24
- </fieldset>
25
- );
26
- }
27
- return <Header {...args} />;
28
- };
29
-
30
16
  /**
31
17
  * The stories below document the `Header` component, which is used to structure content and convey hierarchy. <br />
32
18
  * For more details, refer to the [design documentation](https://wise.design/components/section-header).
@@ -89,7 +75,6 @@ export default meta;
89
75
  type Story = StoryObj<typeof Header>;
90
76
 
91
77
  export const Playground: Story = {
92
- render: renderHeader,
93
78
  args: {
94
79
  title: 'Playground Header',
95
80
  level: 'group',
@@ -151,7 +136,11 @@ export const DisabledAction: Story = {
151
136
  * Demonstrates a `Header` rendered as a custom HTML element.
152
137
  */
153
138
  export const CustomElement: Story = {
154
- render: renderHeader,
139
+ render: (args) => (
140
+ <fieldset style={{ width: '100%' }}>
141
+ <Header {...args} />
142
+ </fieldset>
143
+ ),
155
144
  args: {
156
145
  title: 'Legend Header',
157
146
  as: 'legend',