@transferwise/components 46.107.0 → 46.108.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 (82) hide show
  1. package/build/header/Header.js +1 -0
  2. package/build/header/Header.js.map +1 -1
  3. package/build/header/Header.mjs +1 -0
  4. package/build/header/Header.mjs.map +1 -1
  5. package/build/link/Link.js +6 -2
  6. package/build/link/Link.js.map +1 -1
  7. package/build/link/Link.mjs +6 -2
  8. package/build/link/Link.mjs.map +1 -1
  9. package/build/listItem/ListItem.js +20 -8
  10. package/build/listItem/ListItem.js.map +1 -1
  11. package/build/listItem/ListItem.mjs +20 -8
  12. package/build/listItem/ListItem.mjs.map +1 -1
  13. package/build/listItem/ListItemContext.js.map +1 -1
  14. package/build/listItem/ListItemContext.mjs.map +1 -1
  15. package/build/listItem/Navigation/ListItemNavigation.js +1 -3
  16. package/build/listItem/Navigation/ListItemNavigation.js.map +1 -1
  17. package/build/listItem/Navigation/ListItemNavigation.mjs +2 -4
  18. package/build/listItem/Navigation/ListItemNavigation.mjs.map +1 -1
  19. package/build/listItem/Prompt/InlinePrompt/InlinePrompt.js +74 -0
  20. package/build/listItem/Prompt/InlinePrompt/InlinePrompt.js.map +1 -0
  21. package/build/listItem/Prompt/InlinePrompt/InlinePrompt.mjs +72 -0
  22. package/build/listItem/Prompt/InlinePrompt/InlinePrompt.mjs.map +1 -0
  23. package/build/listItem/Prompt/ListItemPrompt.js +10 -15
  24. package/build/listItem/Prompt/ListItemPrompt.js.map +1 -1
  25. package/build/listItem/Prompt/ListItemPrompt.mjs +11 -16
  26. package/build/listItem/Prompt/ListItemPrompt.mjs.map +1 -1
  27. package/build/main.css +94 -74
  28. package/build/styles/link/Link.css +7 -0
  29. package/build/styles/listItem/ListItem.css +87 -74
  30. package/build/styles/listItem/Prompt/InlinePrompt/InlinePrompt.css +153 -0
  31. package/build/styles/listItem/Prompt/ListItemPrompt.css +72 -72
  32. package/build/styles/main.css +94 -74
  33. package/build/types/header/Header.d.ts +1 -0
  34. package/build/types/header/Header.d.ts.map +1 -1
  35. package/build/types/link/Link.d.ts +1 -1
  36. package/build/types/link/Link.d.ts.map +1 -1
  37. package/build/types/listItem/ListItem.d.ts +10 -1
  38. package/build/types/listItem/ListItem.d.ts.map +1 -1
  39. package/build/types/listItem/ListItemContext.d.ts +2 -1
  40. package/build/types/listItem/ListItemContext.d.ts.map +1 -1
  41. package/build/types/listItem/Navigation/ListItemNavigation.d.ts.map +1 -1
  42. package/build/types/listItem/Prompt/InlinePrompt/InlinePrompt.d.ts +15 -0
  43. package/build/types/listItem/Prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -0
  44. package/build/types/listItem/Prompt/InlinePrompt/index.d.ts +3 -0
  45. package/build/types/listItem/Prompt/InlinePrompt/index.d.ts.map +1 -0
  46. package/build/types/listItem/Prompt/ListItemPrompt.d.ts +4 -6
  47. package/build/types/listItem/Prompt/ListItemPrompt.d.ts.map +1 -1
  48. package/build/types/listItem/_stories/helpers.d.ts.map +1 -1
  49. package/build/types/listItem/_stories/subcomponents.d.ts +1 -0
  50. package/build/types/listItem/_stories/subcomponents.d.ts.map +1 -1
  51. package/build/types/listItem/useListItemControl.d.ts +1 -1
  52. package/package.json +4 -4
  53. package/src/header/Header.story.tsx +14 -0
  54. package/src/header/Header.tsx +2 -0
  55. package/src/link/Link.css +7 -0
  56. package/src/link/Link.less +8 -0
  57. package/src/link/Link.spec.tsx +28 -0
  58. package/src/link/Link.story.tsx +72 -16
  59. package/src/link/Link.tsx +5 -1
  60. package/src/listItem/ListItem.css +87 -74
  61. package/src/listItem/ListItem.less +19 -4
  62. package/src/listItem/ListItem.spec.tsx +33 -0
  63. package/src/listItem/ListItem.tsx +38 -12
  64. package/src/listItem/ListItemContext.tsx +2 -1
  65. package/src/listItem/Navigation/ListItemNavigation.spec.tsx +1 -10
  66. package/src/listItem/Navigation/ListItemNavigation.story.tsx +0 -22
  67. package/src/listItem/Navigation/ListItemNavigation.tsx +2 -3
  68. package/src/listItem/Prompt/InlinePrompt/InlinePrompt.css +153 -0
  69. package/src/listItem/Prompt/InlinePrompt/InlinePrompt.less +162 -0
  70. package/src/listItem/Prompt/InlinePrompt/InlinePrompt.spec.tsx +66 -0
  71. package/src/listItem/Prompt/InlinePrompt/InlinePrompt.tsx +56 -0
  72. package/src/listItem/Prompt/InlinePrompt/index.ts +2 -0
  73. package/src/listItem/Prompt/ListItemPrompt.css +72 -72
  74. package/src/listItem/Prompt/ListItemPrompt.less +2 -130
  75. package/src/listItem/Prompt/ListItemPrompt.spec.tsx +36 -0
  76. package/src/listItem/Prompt/ListItemPrompt.story.tsx +4 -2
  77. package/src/listItem/Prompt/ListItemPrompt.tsx +14 -14
  78. package/src/listItem/_stories/ListItem.disabled.story.tsx +433 -0
  79. package/src/listItem/_stories/ListItem.story.tsx +1 -177
  80. package/src/listItem/_stories/helpers.tsx +1 -0
  81. package/src/listItem/_stories/subcomponents.tsx +5 -0
  82. package/src/main.css +94 -74
@@ -382,10 +382,8 @@
382
382
  margin-top: var(--size-4);
383
383
  }
384
384
  }
385
- .wds-list-item-prompt {
386
- grid-area: prompt;
385
+ .wds-inline-prompt {
387
386
  display: inline-flex;
388
- justify-self: start;
389
387
  text-align: left;
390
388
  padding-top: calc(8px / 2);
391
389
  padding-top: calc(var(--padding-x-small) / 2);
@@ -400,33 +398,27 @@
400
398
  word-break: break-word;
401
399
  word-wrap: break-word;
402
400
  }
403
- .wds-list-item-prompt:has(a),
404
- .wds-list-item-prompt:has(button) {
401
+ .wds-inline-prompt:has(a),
402
+ .wds-inline-prompt:has(button) {
405
403
  position: relative;
406
404
  z-index: 1;
407
405
  }
408
- .wds-list-item-prompt a,
409
- .wds-list-item-prompt button {
406
+ .wds-inline-prompt--muted {
407
+ opacity: 0.93;
408
+ filter: grayscale(1);
409
+ }
410
+ .wds-inline-prompt a,
411
+ .wds-inline-prompt button {
410
412
  text-underline-offset: calc(4px / 2);
411
413
  text-underline-offset: calc(var(--size-4) / 2);
412
414
  }
413
- .wds-list-item-prompt a:first-of-type:before,
414
- .wds-list-item-prompt button:first-of-type:before {
415
+ .wds-inline-prompt a:first-of-type:before,
416
+ .wds-inline-prompt button:first-of-type:before {
415
417
  content: '';
416
418
  position: absolute;
417
419
  inset: 0;
418
420
  }
419
- .wds-list-item-prompt.np-prompt-icon {
420
- padding-left: calc(8px - 1px);
421
- padding-left: calc(var(--padding-x-small) - 1px);
422
- padding-right: 8px;
423
- padding-right: var(--padding-x-small);
424
- display: inline-flex;
425
- align-items: center;
426
- gap: 4px;
427
- gap: var(--size-4);
428
- }
429
- .wds-list-item-prompt .np-prompt-icon {
421
+ .wds-inline-prompt__media-wrapper {
430
422
  padding-right: calc(12px / 2);
431
423
  padding-right: calc(var(--size-12) / 2);
432
424
  padding-top: calc(4px - 1px);
@@ -434,111 +426,119 @@
434
426
  padding-bottom: calc(4px - 1px);
435
427
  padding-bottom: calc(var(--size-4) - 1px);
436
428
  }
437
- .wds-list-item-prompt .np-prompt-icon .tw-icon-tags,
438
- .wds-list-item-prompt .np-prompt-icon .tw-icon-confetti {
429
+ .wds-inline-prompt__media-wrapper .tw-icon-tags,
430
+ .wds-inline-prompt__media-wrapper .tw-icon-confetti {
439
431
  color: var(--color-sentiment-positive-primary);
440
432
  }
441
- .wds-list-item-prompt.negative {
433
+ .wds-inline-prompt--negative {
442
434
  background-color: var(--color-sentiment-negative-secondary);
443
435
  color: var(--color-sentiment-negative-primary);
444
436
  }
445
- .wds-list-item-prompt.negative a,
446
- .wds-list-item-prompt.negative button {
437
+ .wds-inline-prompt--negative a,
438
+ .wds-inline-prompt--negative button {
447
439
  color: var(--color-sentiment-negative-primary);
448
440
  }
449
- .wds-list-item-prompt.negative a:hover,
450
- .wds-list-item-prompt.negative button:hover {
441
+ .wds-inline-prompt--negative a:hover,
442
+ .wds-inline-prompt--negative button:hover {
451
443
  color: var(--color-sentiment-negative-primary-hover);
452
444
  }
453
- .wds-list-item-prompt.negative a:active,
454
- .wds-list-item-prompt.negative button:active {
445
+ .wds-inline-prompt--negative a:active,
446
+ .wds-inline-prompt--negative button:active {
455
447
  color: var(--color-sentiment-negative-primary-active);
456
448
  }
457
- .wds-list-item-prompt.wds-list-item-prompt.negative:has(a, button):hover {
449
+ .wds-inline-prompt.wds-inline-prompt--negative:has(a, button):hover {
458
450
  background-color: var(--color-sentiment-negative-secondary-hover);
459
451
  }
460
- .wds-list-item-prompt.wds-list-item-prompt.negative:has(a, button):active {
452
+ .wds-inline-prompt.wds-inline-prompt--negative:has(a, button):active {
461
453
  background-color: var(--color-sentiment-negative-secondary-active);
462
454
  }
463
- .wds-list-item-prompt.positive,
464
- .wds-list-item-prompt.discount,
465
- .wds-list-item-prompt.savings {
455
+ .wds-inline-prompt--positive {
456
+ background-color: var(--color-sentiment-positive-secondary);
457
+ color: var(--color-sentiment-positive-primary);
458
+ }
459
+ .wds-inline-prompt--positive a,
460
+ .wds-inline-prompt--positive button {
461
+ color: var(--color-sentiment-positive-primary);
462
+ }
463
+ .wds-inline-prompt--positive a:hover,
464
+ .wds-inline-prompt--positive button:hover {
465
+ color: var(--color-sentiment-positive-primary-hover);
466
+ }
467
+ .wds-inline-prompt--positive a:active,
468
+ .wds-inline-prompt--positive button:active {
469
+ color: var(--color-sentiment-positive-primary-active);
470
+ }
471
+ .wds-inline-prompt.wds-inline-prompt--positive:has(a, button):hover {
472
+ background-color: var(--color-sentiment-positive-secondary-hover);
473
+ }
474
+ .wds-inline-prompt.wds-inline-prompt--positive:has(a, button):active {
475
+ background-color: var(--color-sentiment-positive-secondary-active);
476
+ }
477
+ .wds-inline-prompt--proposition {
466
478
  background-color: var(--color-sentiment-positive-secondary);
467
479
  color: var(--color-sentiment-positive-primary);
468
480
  }
469
- .wds-list-item-prompt.positive a,
470
- .wds-list-item-prompt.discount a,
471
- .wds-list-item-prompt.savings a,
472
- .wds-list-item-prompt.positive button,
473
- .wds-list-item-prompt.discount button,
474
- .wds-list-item-prompt.savings button {
481
+ .wds-inline-prompt--proposition a,
482
+ .wds-inline-prompt--proposition button {
475
483
  color: var(--color-sentiment-positive-primary);
476
484
  }
477
- .wds-list-item-prompt.positive a:hover,
478
- .wds-list-item-prompt.discount a:hover,
479
- .wds-list-item-prompt.savings a:hover,
480
- .wds-list-item-prompt.positive button:hover,
481
- .wds-list-item-prompt.discount button:hover,
482
- .wds-list-item-prompt.savings button:hover {
485
+ .wds-inline-prompt--proposition a:hover,
486
+ .wds-inline-prompt--proposition button:hover {
483
487
  color: var(--color-sentiment-positive-primary-hover);
484
488
  }
485
- .wds-list-item-prompt.positive a:active,
486
- .wds-list-item-prompt.discount a:active,
487
- .wds-list-item-prompt.savings a:active,
488
- .wds-list-item-prompt.positive button:active,
489
- .wds-list-item-prompt.discount button:active,
490
- .wds-list-item-prompt.savings button:active {
489
+ .wds-inline-prompt--proposition a:active,
490
+ .wds-inline-prompt--proposition button:active {
491
491
  color: var(--color-sentiment-positive-primary-active);
492
492
  }
493
- .wds-list-item-prompt.wds-list-item-prompt.positive:has(a, button):hover,
494
- .wds-list-item-prompt.wds-list-item-prompt.discount:has(a, button):hover,
495
- .wds-list-item-prompt.wds-list-item-prompt.savings:has(a, button):hover {
493
+ .wds-inline-prompt.wds-inline-prompt--proposition:has(a, button):hover {
496
494
  background-color: var(--color-sentiment-positive-secondary-hover);
497
495
  }
498
- .wds-list-item-prompt.wds-list-item-prompt.positive:has(a, button):active,
499
- .wds-list-item-prompt.wds-list-item-prompt.discount:has(a, button):active,
500
- .wds-list-item-prompt.wds-list-item-prompt.savings:has(a, button):active {
496
+ .wds-inline-prompt.wds-inline-prompt--proposition:has(a, button):active {
501
497
  background-color: var(--color-sentiment-positive-secondary-active);
502
498
  }
503
- .wds-list-item-prompt.neutral {
499
+ .wds-inline-prompt--neutral {
504
500
  background-color: rgba(134,167,189,0.10196);
505
501
  background-color: var(--color-background-neutral);
506
502
  color: #37517e;
507
503
  color: var(--color-content-primary);
508
504
  }
509
- .wds-list-item-prompt.neutral a,
510
- .wds-list-item-prompt.neutral button {
505
+ .wds-inline-prompt--neutral a,
506
+ .wds-inline-prompt--neutral button {
511
507
  color: #37517e;
512
508
  color: var(--color-content-primary);
513
509
  }
514
- .wds-list-item-prompt.wds-list-item-prompt.neutral:has(a, button):hover {
510
+ .wds-inline-prompt.wds-inline-prompt--neutral:has(a, button):hover {
515
511
  background-color: var(--color-background-neutral-hover);
516
512
  }
517
- .wds-list-item-prompt.wds-list-item-prompt.neutral:has(a, button):active {
513
+ .wds-inline-prompt.wds-inline-prompt--neutral:has(a, button):active {
518
514
  background-color: var(--color-background-neutral-active);
519
515
  }
520
- .wds-list-item-prompt.warning {
516
+ .wds-inline-prompt--warning {
521
517
  background-color: var(--color-sentiment-warning-secondary);
522
518
  color: var(--color-sentiment-warning-content);
523
519
  }
524
- .wds-list-item-prompt.warning a,
525
- .wds-list-item-prompt.warning button {
520
+ .wds-inline-prompt--warning a,
521
+ .wds-inline-prompt--warning button {
526
522
  color: var(--color-sentiment-warning-content);
527
523
  }
528
- .wds-list-item-prompt.warning a:hover,
529
- .wds-list-item-prompt.warning button:hover {
524
+ .wds-inline-prompt--warning a:hover,
525
+ .wds-inline-prompt--warning button:hover {
530
526
  color: var(--color-sentiment-warning-content-hover);
531
527
  }
532
- .wds-list-item-prompt.warning a:active,
533
- .wds-list-item-prompt.warning button:active {
528
+ .wds-inline-prompt--warning a:active,
529
+ .wds-inline-prompt--warning button:active {
534
530
  color: var(--color-sentiment-warning-content-active);
535
531
  }
536
- .wds-list-item-prompt.wds-list-item-prompt.warning:has(a, button):hover {
532
+ .wds-inline-prompt.wds-inline-prompt--warning:has(a, button):hover {
537
533
  background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 92%, var(--color-sentiment-warning-primary));
538
534
  }
539
- .wds-list-item-prompt.wds-list-item-prompt.warning:has(a, button):active {
535
+ .wds-inline-prompt.wds-inline-prompt--warning:has(a, button):active {
540
536
  background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 84%, var(--color-sentiment-warning-primary));
541
537
  }
538
+ .wds-list-item-prompt {
539
+ grid-area: prompt;
540
+ justify-self: start;
541
+ }
542
542
  .wds-list-item {
543
543
  list-style: none;
544
544
  width: 100%;
@@ -720,16 +720,29 @@
720
720
  flex: 0 0 auto;
721
721
  }
722
722
  .wds-list-item.disabled {
723
- filter: none;
724
723
  opacity: 1;
724
+ opacity: initial;
725
725
  }
726
+ .wds-list-item.disabled,
726
727
  .wds-list-item.disabled label {
727
728
  cursor: not-allowed;
728
729
  }
729
- .wds-list-item.disabled .tw-icon-backslash-circle {
730
+ .wds-list-item.disabled .wds-list-item-title,
731
+ .wds-list-item.disabled .wds-list-item-title-value,
732
+ .wds-list-item.disabled .wds-list-item-subtitle,
733
+ .wds-list-item.disabled .wds-list-item-subtitle-value,
734
+ .wds-list-item.disabled .wds-list-item-additional-info {
730
735
  color: #768e9c;
731
736
  color: var(--color-content-tertiary);
732
737
  }
738
+ .wds-list-item.disabled .wds-list-item-media,
739
+ .wds-list-item.disabled .wds-list-item-body,
740
+ .wds-list-item.disabled .wds-list-item-additional-info {
741
+ opacity: 0.93;
742
+ }
743
+ .wds-list-item.disabled--has-prompt-reason .wds-list-item-prompt {
744
+ opacity: 0.93;
745
+ }
733
746
  .wds-list-item-spotlight {
734
747
  padding-left: 12px;
735
748
  padding-left: var(--size-12);
@@ -223,16 +223,31 @@
223
223
  }
224
224
 
225
225
  &.disabled {
226
- filter: none;
227
- opacity: 1;
226
+ opacity: unset;
228
227
 
229
- label {
228
+ &, label {
230
229
  cursor: not-allowed;
231
230
  }
232
231
 
233
- .tw-icon-backslash-circle {
232
+ .wds-list-item-title,
233
+ .wds-list-item-title-value,
234
+ .wds-list-item-subtitle,
235
+ .wds-list-item-subtitle-value,
236
+ .wds-list-item-additional-info {
234
237
  color: var(--color-content-tertiary);
235
238
  }
239
+
240
+ .wds-list-item-media,
241
+ .wds-list-item-body,
242
+ .wds-list-item-additional-info {
243
+ opacity: .93;
244
+ }
245
+ }
246
+
247
+ &.disabled--has-prompt-reason {
248
+ .wds-list-item-prompt{
249
+ opacity: .93;
250
+ }
236
251
  }
237
252
 
238
253
  &-spotlight {
@@ -14,6 +14,7 @@ describe('ListItem', () => {
14
14
  const additionalInfo = '__additionalInfo__';
15
15
  const additionalInfoAction = '__infoAction__';
16
16
  const prompt = '__prompt__';
17
+ const disabledPromptMessage = '__disabledPromptMessage__';
17
18
  const promptAction = '__promptAction__';
18
19
  const promptWithLink = (
19
20
  <>
@@ -1511,4 +1512,36 @@ describe('ListItem', () => {
1511
1512
  expect(listItem.querySelector('.wds-list-item-spotlight__border')).not.toBeInTheDocument();
1512
1513
  });
1513
1514
  });
1515
+
1516
+ describe('disable states', () => {
1517
+ describe('short-lived', () => {
1518
+ it('should override existing prompt if disabled and disabledPromptMessage are set', () => {
1519
+ render(
1520
+ <ListItem
1521
+ title="Test Title"
1522
+ prompt={<ListItem.Prompt>{prompt}</ListItem.Prompt>}
1523
+ disabled
1524
+ disabledPromptMessage={disabledPromptMessage}
1525
+ />,
1526
+ );
1527
+ expect(screen.queryByText(prompt)).not.toBeInTheDocument();
1528
+ expect(screen.getByText(disabledPromptMessage)).toBeInTheDocument();
1529
+ expect(screen.getByTestId('InlinePrompt_Muted').parentNode?.parentNode).toHaveAttribute(
1530
+ 'id',
1531
+ expect.stringMatching(/_prompt$/),
1532
+ );
1533
+ });
1534
+
1535
+ it('should render muted prompt if disabled and disabledPromptMessage are set', () => {
1536
+ render(
1537
+ <ListItem title="Test Title" disabled disabledPromptMessage={disabledPromptMessage} />,
1538
+ );
1539
+ expect(screen.getByText(disabledPromptMessage)).toBeInTheDocument();
1540
+ expect(screen.getByTestId('InlinePrompt_Muted').parentNode?.parentNode).toHaveAttribute(
1541
+ 'id',
1542
+ expect.stringMatching(/_prompt$/),
1543
+ );
1544
+ });
1545
+ });
1546
+ });
1514
1547
  });
@@ -6,7 +6,7 @@ import {
6
6
  type PropsWithChildren,
7
7
  type ReactNode,
8
8
  } from 'react';
9
- import { Typography } from '../common';
9
+ import { Sentiment, Typography } from '../common';
10
10
  import Body from '../body';
11
11
  import { AdditionalInfo } from './AdditionalInfo';
12
12
  import { IconButton, type ListItemIconButtonProps } from './IconButton';
@@ -50,7 +50,16 @@ export type ListItemProps = {
50
50
  * Swaps vertical hierarchy of title and subtitle and their corresponding right values.
51
51
  */
52
52
  inverted?: boolean;
53
+ /**
54
+ * Disables the control and renders the ListItem in greyscale and with slightly decreased opacity.
55
+ */
53
56
  disabled?: boolean;
57
+ /**
58
+ * If set, it'll extend the `disabled` state, overriding existing or injecting uniquely styled prompt with the message provided via this prop. <br />
59
+ * **NB:** This message cannot house more than **1** link or inline button.<br />
60
+ * **NB:** It must be used together with `disabled` prop and will be disregarded otherwise.
61
+ */
62
+ disabledPromptMessage?: ReactNode;
54
63
  /**
55
64
  * Highlights the list item as an action to be taken or already taken. <br />
56
65
  */
@@ -111,6 +120,7 @@ export const ListItem = ({
111
120
  valueSubtitle,
112
121
  control = null,
113
122
  disabled,
123
+ disabledPromptMessage,
114
124
  className,
115
125
  valueColumnWidth,
116
126
  id,
@@ -126,7 +136,7 @@ export const ListItem = ({
126
136
  ...(valueTitle ? { valueTitle: `${idPrefix}_value-title` } : {}),
127
137
  ...(valueSubtitle ? { valueSubtitle: `${idPrefix}_value-subtitle` } : {}),
128
138
  control: `${idPrefix}_control`,
129
- ...(prompt ? { prompt: `${idPrefix}_prompt` } : {}),
139
+ ...(prompt || (disabled && disabledPromptMessage) ? { prompt: `${idPrefix}_prompt` } : {}),
130
140
  ...(additionalInfo ? { additionalInfo: `${idPrefix}_additional-info` } : {}),
131
141
  };
132
142
 
@@ -159,8 +169,9 @@ export const ListItem = ({
159
169
  setControlProps,
160
170
  setMediaSize,
161
171
  ids,
162
- props: { disabled, inverted },
172
+ props: { disabled, inverted, disabledPromptMessage },
163
173
  mediaSize,
174
+ isPartiallyInteractive,
164
175
  describedByIds,
165
176
  }),
166
177
  [describedByIds, mediaSize],
@@ -175,7 +186,7 @@ export const ListItem = ({
175
186
  const hasMedia = Boolean(media);
176
187
  const hasControl = Boolean(control);
177
188
  const hasInfo = Boolean(additionalInfo);
178
- const hasPrompt = Boolean(prompt);
189
+ const hasPrompt = Boolean(prompt) || (disabled && Boolean(disabledPromptMessage));
179
190
 
180
191
  /* eslint-disable functional/immutable-data */
181
192
  if (hasMedia && hasControl) {
@@ -223,7 +234,8 @@ export const ListItem = ({
223
234
  'wds-list-item-partially-interactive': isPartiallyInteractive,
224
235
  [`wds-list-item-spotlight wds-list-item-spotlight-${spotlight}`]:
225
236
  isFullyInteractive && !!spotlight,
226
- disabled,
237
+ disabled: disabled && !isPartiallyInteractive,
238
+ 'disabled--has-prompt-reason': !disabledPromptMessage && disabled && !isPartiallyInteractive,
227
239
  },
228
240
  className,
229
241
  )}
@@ -247,6 +259,7 @@ export const ListItem = ({
247
259
  subtitle,
248
260
  additionalInfo,
249
261
  disabled,
262
+ disabledPromptMessage,
250
263
  prompt,
251
264
  controlType,
252
265
  controlProps,
@@ -348,13 +361,17 @@ type ViewProps = PropsWithChildren<{
348
361
  controlType?: ListItemTypes;
349
362
  controlProps?: ListItemControlProps;
350
363
  }> &
351
- Pick<ListItemProps, 'subtitle' | 'additionalInfo' | 'disabled' | 'prompt' | 'className'>;
364
+ Pick<
365
+ ListItemProps,
366
+ 'subtitle' | 'additionalInfo' | 'prompt' | 'disabled' | 'disabledPromptMessage' | 'className'
367
+ >;
352
368
 
353
369
  function View({
354
370
  children,
355
371
  additionalInfo,
356
372
  prompt,
357
373
  disabled,
374
+ disabledPromptMessage,
358
375
  isPartiallyInteractive,
359
376
  controlType = 'non-interactive',
360
377
  controlProps,
@@ -365,12 +382,21 @@ function View({
365
382
 
366
383
  const isHrefProvided = isLinkControl && !!(controlProps as ListItemNavigationProps)?.href;
367
384
 
368
- const renderExtras = () => (
369
- <>
370
- {additionalInfo}
371
- {prompt}
372
- </>
373
- );
385
+ const renderExtras = () => {
386
+ const resolvedPrompt =
387
+ disabled && disabledPromptMessage && !prompt ? (
388
+ <Prompt sentiment={Sentiment.NEUTRAL}>{disabledPromptMessage}</Prompt>
389
+ ) : (
390
+ prompt
391
+ );
392
+
393
+ return (
394
+ <>
395
+ {additionalInfo}
396
+ {resolvedPrompt}
397
+ </>
398
+ );
399
+ };
374
400
 
375
401
  if (isLinkControl && isHrefProvided) {
376
402
  return (
@@ -16,8 +16,9 @@ export type ListItemContextData = {
16
16
  control: string;
17
17
  prompt?: string;
18
18
  };
19
- props: Pick<ListItemProps, 'disabled' | 'inverted'>;
19
+ props: Pick<ListItemProps, 'disabled' | 'inverted' | 'disabledPromptMessage'>;
20
20
  mediaSize?: ListItemMediaSize;
21
+ isPartiallyInteractive?: boolean;
21
22
  describedByIds: string;
22
23
  };
23
24
 
@@ -25,8 +25,7 @@ describe('ListItem.Navigation', () => {
25
25
  disabled: true,
26
26
  control: <ListItem.Navigation onClick={jest.fn()} />,
27
27
  });
28
- expect(screen.getByTestId('backslash-circle-icon')).toBeInTheDocument();
29
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
28
+ expect(screen.queryByRole('button')).toBeDisabled();
30
29
  expect(screen.queryByRole('link')).not.toBeInTheDocument();
31
30
  });
32
31
  });
@@ -48,14 +47,6 @@ describe('ListItem.Navigation', () => {
48
47
  expect(link).toHaveAttribute('rel', 'noopener noreferrer');
49
48
  });
50
49
 
51
- it('renders disabled icon when ListItem is disabled', () => {
52
- renderWith({
53
- disabled: true,
54
- control: <ListItem.Navigation href="wise.com" />,
55
- });
56
- expect(screen.getByTestId('backslash-circle-icon')).toBeInTheDocument();
57
- });
58
-
59
50
  it('handles onClick events', async () => {
60
51
  const handleClick = jest.fn();
61
52
  renderWith({ control: <ListItem.Navigation href="#target" onClick={handleClick} /> });
@@ -90,25 +90,3 @@ export const AsButton: Story = {
90
90
  );
91
91
  },
92
92
  };
93
-
94
- /**
95
- * Unlike other controls, the Navigation control has a custom disabled state
96
- * for improved discoverability, accessibility and overall UX.
97
- */
98
- export const Disabled: Story = {
99
- render: (args) => {
100
- return (
101
- <List>
102
- <ListItem
103
- disabled
104
- control={<ListItem.Navigation {...args} />}
105
- title="This option is disabled"
106
- subtitle={lorem10}
107
- additionalInfo={INFO.nonInteractive}
108
- prompt={PROMPTS.interactive}
109
- media={MEDIA.avatarSingle}
110
- />
111
- </List>
112
- );
113
- },
114
- };
@@ -1,4 +1,4 @@
1
- import { ChevronRight, BackslashCircle } from '@transferwise/icons';
1
+ import { ChevronRight } from '@transferwise/icons';
2
2
  import type { ButtonProps } from '../../button/Button.types';
3
3
  import { useListItemControl } from '../useListItemControl';
4
4
  import { PrimitiveButton } from '../../primitives';
@@ -20,12 +20,11 @@ export const Navigation = function Navigation({ href, ...props }: ListItemNaviga
20
20
  const { ids, describedByIds } = useContext(ListItemContext);
21
21
  const icon = <ChevronRight size={16} />;
22
22
 
23
- if (baseItemProps.disabled) return <BackslashCircle size={24} />;
24
-
25
23
  return href ? (
26
24
  <>{icon}</>
27
25
  ) : (
28
26
  <PrimitiveButton
27
+ disabled={baseItemProps.disabled}
29
28
  aria-describedby={describedByIds}
30
29
  id={ids.control}
31
30
  className="btn-unstyled wds-list-item-control"