@transferwise/components 46.67.2 → 46.68.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 (73) hide show
  1. package/build/button/Button.js +22 -6
  2. package/build/button/Button.js.map +1 -1
  3. package/build/button/Button.mjs +22 -6
  4. package/build/button/Button.mjs.map +1 -1
  5. package/build/main.css +212 -210
  6. package/build/styles/button/Button.css +3 -0
  7. package/build/styles/main.css +212 -210
  8. package/build/styles/uploadInput/UploadInput.css +13 -81
  9. package/build/styles/uploadInput/uploadButton/UploadButton.css +77 -31
  10. package/build/styles/uploadInput/uploadItem/UploadItem.css +130 -109
  11. package/build/typeahead/Typeahead.js +22 -8
  12. package/build/typeahead/Typeahead.js.map +1 -1
  13. package/build/typeahead/Typeahead.mjs +22 -9
  14. package/build/typeahead/Typeahead.mjs.map +1 -1
  15. package/build/typeahead/typeaheadInput/TypeaheadInput.js +5 -2
  16. package/build/typeahead/typeaheadInput/TypeaheadInput.js.map +1 -1
  17. package/build/typeahead/typeaheadInput/TypeaheadInput.mjs +5 -2
  18. package/build/typeahead/typeaheadInput/TypeaheadInput.mjs.map +1 -1
  19. package/build/typeahead/typeaheadOption/TypeaheadOption.js +9 -6
  20. package/build/typeahead/typeaheadOption/TypeaheadOption.js.map +1 -1
  21. package/build/typeahead/typeaheadOption/TypeaheadOption.mjs +9 -6
  22. package/build/typeahead/typeaheadOption/TypeaheadOption.mjs.map +1 -1
  23. package/build/types/button/Button.d.ts.map +1 -1
  24. package/build/types/typeahead/Typeahead.d.ts +1 -1
  25. package/build/types/typeahead/Typeahead.d.ts.map +1 -1
  26. package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts +2 -0
  27. package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts.map +1 -1
  28. package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts +2 -1
  29. package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts.map +1 -1
  30. package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
  31. package/build/types/uploadInput/uploadButton/UploadButton.d.ts +5 -0
  32. package/build/types/uploadInput/uploadButton/UploadButton.d.ts.map +1 -1
  33. package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
  34. package/build/uploadInput/UploadInput.js +30 -20
  35. package/build/uploadInput/UploadInput.js.map +1 -1
  36. package/build/uploadInput/UploadInput.mjs +30 -20
  37. package/build/uploadInput/UploadInput.mjs.map +1 -1
  38. package/build/uploadInput/uploadButton/UploadButton.js +25 -32
  39. package/build/uploadInput/uploadButton/UploadButton.js.map +1 -1
  40. package/build/uploadInput/uploadButton/UploadButton.mjs +25 -32
  41. package/build/uploadInput/uploadButton/UploadButton.mjs.map +1 -1
  42. package/build/uploadInput/uploadItem/UploadItem.js +32 -38
  43. package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
  44. package/build/uploadInput/uploadItem/UploadItem.mjs +33 -39
  45. package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
  46. package/build/uploadInput/uploadItem/UploadItemLink.js +2 -1
  47. package/build/uploadInput/uploadItem/UploadItemLink.js.map +1 -1
  48. package/build/uploadInput/uploadItem/UploadItemLink.mjs +2 -1
  49. package/build/uploadInput/uploadItem/UploadItemLink.mjs.map +1 -1
  50. package/package.json +4 -4
  51. package/src/button/Button.css +3 -0
  52. package/src/button/Button.less +6 -0
  53. package/src/button/Button.spec.js +81 -45
  54. package/src/button/Button.story.tsx +54 -20
  55. package/src/button/Button.tsx +32 -7
  56. package/src/button/__snapshots__/Button.spec.js.snap +56 -12
  57. package/src/main.css +212 -210
  58. package/src/typeahead/Typeahead.spec.js +8 -0
  59. package/src/typeahead/Typeahead.tsx +29 -13
  60. package/src/typeahead/typeaheadInput/TypeaheadInput.tsx +9 -0
  61. package/src/typeahead/typeaheadOption/TypeaheadOption.spec.js +8 -0
  62. package/src/typeahead/typeaheadOption/TypeaheadOption.tsx +9 -6
  63. package/src/uploadInput/UploadInput.css +13 -81
  64. package/src/uploadInput/UploadInput.less +18 -80
  65. package/src/uploadInput/UploadInput.tests.story.tsx +5 -5
  66. package/src/uploadInput/UploadInput.tsx +43 -32
  67. package/src/uploadInput/uploadButton/UploadButton.css +77 -31
  68. package/src/uploadInput/uploadButton/UploadButton.less +77 -35
  69. package/src/uploadInput/uploadButton/UploadButton.tsx +37 -26
  70. package/src/uploadInput/uploadItem/UploadItem.css +130 -109
  71. package/src/uploadInput/uploadItem/UploadItem.less +130 -118
  72. package/src/uploadInput/uploadItem/UploadItem.tsx +26 -28
  73. package/src/uploadInput/uploadItem/UploadItemLink.tsx +3 -3
package/src/main.css CHANGED
@@ -543,6 +543,9 @@ div.critical-comms .critical-comms-body {
543
543
  .np-btn.np-btn-xs.btn-block > span.btn-loader {
544
544
  top: 0;
545
545
  }
546
+ .np-btn.disabled[class] {
547
+ pointer-events: auto;
548
+ }
546
549
  .np-card {
547
550
  overflow: hidden;
548
551
  transition-property: transform, box-shadow;
@@ -5458,280 +5461,279 @@ html:not([dir="rtl"]) .np-navigation-option {
5458
5461
  .upload-error-message .alert {
5459
5462
  min-width: 100px;
5460
5463
  }
5461
- .np-upload-button-container {
5462
- border-style: solid;
5463
- }
5464
- .np-upload-button-container .droppable-card-content {
5464
+ .np-upload-input__upload-button {
5465
+ position: relative;
5466
+ padding: 16px;
5467
+ padding: var(--size-16);
5465
5468
  display: flex;
5469
+ align-items: center;
5470
+ margin: 0;
5471
+ border-bottom-left-radius: 10px;
5472
+ border-bottom-left-radius: var(--radius-small);
5473
+ border-bottom-right-radius: 10px;
5474
+ border-bottom-right-radius: var(--radius-small);
5475
+ border: var(--outerBorder);
5476
+ cursor: pointer;
5477
+ }
5478
+ .np-upload-input__upload-button .np-upload-input__title {
5479
+ color: var(--color-content-link);
5480
+ -webkit-text-decoration: underline;
5481
+ text-decoration: underline;
5482
+ text-underline-offset: 0.3em;
5466
5483
  }
5467
- .np-upload-button-container.droppable-dropping {
5468
- border-color: #c9cbce !important;
5469
- border-color: var(--color-interactive-secondary) !important;
5484
+ .np-upload-input__upload-button .np-upload-input__title + .np-upload-input__text {
5485
+ margin-top: 4px;
5486
+ margin-top: var(--size-4);
5470
5487
  }
5471
- .np-upload-button-container.droppable-dropping:before {
5472
- z-index: 2;
5488
+ .np-upload-input__upload-button .np-upload-input__icon {
5489
+ padding-right: 16px;
5490
+ padding-right: var(--size-16);
5491
+ color: var(--color-interactive-primary);
5473
5492
  }
5474
- .np-upload-button-container input[type="file"] {
5493
+ .np-upload-input__upload-button.is-dropping .np-upload-input__icon,
5494
+ .np-upload-input__upload-button.is-dropping .np-upload-input__item-content {
5495
+ display: none;
5496
+ }
5497
+ .np-upload-input__upload-button:focus-within,
5498
+ .np-upload-input__upload-button:focus-visible {
5499
+ outline: var(--ring-outline-color) solid 3px;
5500
+ outline-offset: -3px;
5501
+ }
5502
+ .np-upload-input__upload-button-input {
5503
+ position: absolute;
5475
5504
  opacity: 0;
5476
5505
  z-index: -1;
5506
+ }
5507
+ .np-upload-input__upload-button-input:focus {
5508
+ outline: none;
5509
+ }
5510
+ .np-upload-input__upload-button .np-upload-input__drop-file-overlay {
5511
+ display: flex;
5512
+ flex: 1;
5513
+ padding: 13px 0 !important;
5514
+ background-color: transparent;
5515
+ transition: transform 0.3s ease;
5516
+ position: relative;
5517
+ }
5518
+ .np-upload-input__upload-button--with-entries {
5519
+ border-top-width: 0;
5520
+ }
5521
+ .np-upload-input__upload-button--with-entries:before {
5522
+ display: block;
5477
5523
  position: absolute;
5524
+ height: 1px;
5525
+ background-color: rgba(0,0,0,0.10196);
5526
+ background-color: var(--color-border-neutral);
5527
+ content: " ";
5528
+ left: 16px;
5529
+ left: var(--size-16);
5530
+ width: calc(100% - 2 * 16px);
5531
+ width: calc(100% - 2 * var(--size-16));
5532
+ top: 0;
5478
5533
  }
5479
- .np-upload-button-container .np-upload-button {
5480
- border: none;
5534
+ .np-upload-input__upload-button--without-entries {
5535
+ border-top: var(--outerBorder);
5536
+ border-radius: 10px;
5537
+ border-radius: var(--radius-small);
5538
+ }
5539
+ .np-upload-input__upload-button--enabled.is-dropping,
5540
+ .np-upload-input__upload-button--enabled:hover,
5541
+ .np-upload-input__upload-button--enabled:active {
5542
+ background: rgba(134,167,189,0.10196);
5543
+ background: var(--color-background-neutral);
5481
5544
  }
5482
- .np-upload-button {
5545
+ .np-upload-input__upload-button--enabled.is-dropping:before,
5546
+ .np-upload-input__upload-button--enabled:hover:before,
5547
+ .np-upload-input__upload-button--enabled:active:before {
5483
5548
  width: 100%;
5484
- border-top: 1px solid transparent;
5485
- padding: 16px;
5486
- padding: var(--padding-small);
5487
- border-radius: 0;
5549
+ left: 0;
5488
5550
  }
5489
- label.np-upload-button:not(.disabled):hover,
5490
- label.np-upload-button:not(.disabled):active {
5491
- background-color: var(--color-background-screen-hover);
5551
+ .np-upload-input__upload-button--disabled {
5552
+ cursor: inherit;
5492
5553
  }
5493
- .disabled label.np-upload-button:not(.disabled):hover,
5494
- .disabled label.np-upload-button:not(.disabled):active {
5495
- background-color: transparent;
5554
+ .np-upload-input {
5555
+ --outerBorder: 1px solid var(--color-interactive-secondary);
5556
+ border-radius: 10px;
5557
+ border-radius: var(--radius-small);
5496
5558
  }
5497
- .np-upload-button .media {
5498
- align-items: flex-start;
5559
+ .np-upload-input .np-upload-input__section {
5560
+ margin: 0;
5499
5561
  }
5500
- @media (max-width: 320px) {
5501
- .np-upload-icon {
5502
- padding-left: 0;
5503
- }
5562
+ .np-upload-input .np-upload-input__section:only-child .np-upload-input__item {
5563
+ border-radius: 10px;
5564
+ border-radius: var(--radius-small);
5565
+ border-bottom: var(--outerBorder);
5504
5566
  }
5505
- .np-upload-input.form-control {
5506
- height: auto;
5507
- padding: 0;
5508
- padding: initial;
5567
+ .np-upload-input .np-upload-input__section:has(.np-upload-input__item:last-child.is-interactive:hover):not(:has(.np-upload-input__item-button:hover)) + .np-upload-input__section--uploader .np-upload-input__upload-button::before {
5568
+ left: 0;
5569
+ width: 100%;
5570
+ top: 0;
5571
+ }
5572
+ .np-upload-input__item {
5573
+ position: relative;
5574
+ padding: 16px;
5575
+ padding: var(--size-16);
5576
+ display: flex;
5577
+ align-items: flex-start;
5578
+ border-left: var(--outerBorder);
5579
+ border-right: var(--outerBorder);
5509
5580
  }
5510
- .np-upload-input > div:first-child,
5511
- .np-upload-input > div:first-child .np-upload-item--single-file,
5512
- .np-upload-input > div:first-child .np-upload-item--link {
5581
+ .np-upload-input__item:first-child {
5582
+ border-top: var(--outerBorder);
5513
5583
  border-top-left-radius: 10px;
5514
5584
  border-top-left-radius: var(--radius-small);
5515
5585
  border-top-right-radius: 10px;
5516
5586
  border-top-right-radius: var(--radius-small);
5517
5587
  }
5518
- .np-upload-input > div:last-child {
5519
- border-bottom-left-radius: 10px;
5520
- border-bottom-left-radius: var(--radius-small);
5521
- border-bottom-right-radius: 10px;
5522
- border-bottom-right-radius: var(--radius-small);
5523
- }
5524
- .np-theme-personal .np-upload-input.disabled .btn {
5525
- cursor: inherit;
5526
- }
5527
- .np-theme-personal .np-upload-input .np-upload-icon {
5528
- color: var(--color-interactive-primary);
5588
+ .np-upload-input__item + .np-upload-input__item:before {
5589
+ content: " ";
5590
+ display: block;
5591
+ position: absolute;
5592
+ height: 1px;
5593
+ left: 16px;
5594
+ left: var(--size-16);
5595
+ width: calc(100% - 2 * 16px);
5596
+ width: calc(100% - 2 * var(--size-16));
5597
+ top: 0;
5598
+ background: rgba(0,0,0,0.10196);
5599
+ background: var(--color-border-neutral);
5529
5600
  }
5530
- .np-theme-personal .np-upload-input .media-body {
5601
+ .np-upload-input__item .np-upload-input__item-content {
5531
5602
  padding-right: 32px;
5532
5603
  padding-right: var(--size-32);
5533
- color: var(--color-content-link);
5534
- white-space: break-spaces;
5604
+ flex: 1;
5535
5605
  }
5536
5606
  @media (max-width: 320px) {
5537
- .np-theme-personal .np-upload-input .media-body {
5607
+ .np-upload-input__item .np-upload-input__item-content {
5538
5608
  padding-right: 64px;
5539
5609
  padding-right: var(--size-64);
5540
5610
  }
5541
5611
  }
5542
- .np-theme-personal .np-upload-input .media-body .np-text-body-large-bold {
5543
- -webkit-text-decoration: underline;
5544
- text-decoration: underline;
5545
- text-underline-offset: 0.3em;
5546
- }
5547
- .np-theme-personal .np-upload-input .media-body .np-text-body-default,
5548
- .np-theme-personal .np-upload-input .media-body .np-upload-description,
5549
- .np-theme-personal .np-upload-input .media-body .text-positive {
5550
- color: #5d7079 !important;
5551
- color: var(--color-content-secondary) !important;
5552
- }
5553
- .np-theme-personal .np-upload-input .media-body .text-negative {
5554
- color: var(--color-sentiment-negative) !important;
5612
+ .np-upload-input__item .np-upload-input__title,
5613
+ .np-upload-input__item .np-upload-input__text {
5614
+ margin: 0;
5615
+ -moz-text-align-last: left;
5616
+ text-align-last: left;
5617
+ color: #5d7079;
5618
+ color: var(--color-content-secondary);
5555
5619
  }
5556
- .np-theme-personal .np-upload-input-errors {
5557
- list-style: none;
5558
- padding-left: 0;
5620
+ .np-upload-input__item .np-upload-input__title + .np-upload-input__text {
5621
+ margin-top: 4px;
5622
+ margin-top: var(--size-4);
5559
5623
  }
5560
- .np-theme-personal .np-upload-input-errors li {
5561
- position: relative;
5562
- padding-left: 16px;
5563
- padding-left: var(--size-16);
5624
+ .np-upload-input__item .np-upload-input__icon {
5625
+ padding-right: 16px;
5626
+ padding-right: var(--size-16);
5564
5627
  }
5565
- @media (max-width: 320px) {
5566
- .np-theme-personal .np-upload-input-errors li {
5567
- padding-left: 32px;
5568
- padding-left: var(--size-32);
5569
- }
5628
+ .np-upload-input__item .np-upload-input__item-link,
5629
+ .np-upload-input__item .np-upload-input__item-container {
5630
+ align-items: flex-start;
5631
+ display: flex;
5632
+ width: 100%;
5570
5633
  }
5571
- .np-theme-personal .np-upload-input-errors li:before {
5572
- content: '•';
5634
+ .np-upload-input__item .np-upload-input__item-action {
5635
+ --iconSize: var(--size-24);
5636
+ --clickAreaSize: 44px;
5637
+ --buttonTopRightOffset: var(--size-16);
5638
+ --clickAreaTopRightOffset: calc((var(--clickAreaSize) - var(--iconSize)) * -0.5);
5573
5639
  position: absolute;
5574
- display: block;
5575
- left: 0;
5576
- }
5577
- .np-theme-personal .np-upload-input .status-circle {
5578
- width: 24px;
5579
- width: var(--size-x-small);
5580
- height: 24px;
5581
- height: var(--size-x-small);
5640
+ right: 16px;
5641
+ right: var(--buttonTopRightOffset);
5642
+ top: 16px;
5643
+ top: var(--buttonTopRightOffset);
5582
5644
  }
5583
5645
  @media (max-width: 320px) {
5584
- .np-theme-personal .np-upload-input .status-circle {
5585
- width: 48px;
5586
- width: var(--size-large);
5587
- height: 48px;
5588
- height: var(--size-large);
5646
+ .np-upload-input__item .np-upload-input__item-action {
5647
+ --iconSize: var(--size-48);
5648
+ --clickAreaTopRightOffset: calc(-1 * var(--buttonTopRightOffset));
5589
5649
  }
5590
5650
  }
5591
- .np-upload-item {
5592
- border: 1px solid #c9cbce;
5593
- border: 1px solid var(--color-interactive-secondary);
5594
- position: relative;
5651
+ .np-upload-input__item .np-upload-input__item-action .np-upload-input__item-button {
5652
+ -webkit-appearance: none;
5653
+ -moz-appearance: none;
5654
+ appearance: none;
5655
+ height: var(--iconSize);
5656
+ width: var(--iconSize);
5657
+ padding: 0 4px;
5658
+ padding: 0 var(--size-4);
5659
+ border-radius: 50%;
5660
+ border: 0;
5661
+ background-color: rgba(134,167,189,0.10196);
5662
+ background-color: var(--color-background-neutral);
5663
+ color: var(--color-interactive-primary);
5664
+ transition: color, background-color 0.15s ease-in-out;
5665
+ outline-offset: 0;
5666
+ display: flex;
5667
+ align-items: center;
5668
+ justify-content: center;
5595
5669
  }
5596
- .np-upload-item:first-child ~ div:not(.np-upload-item--link):before,
5597
- .np-upload-item:not(:first-child).np-upload-item--link .np-upload-item__link:before,
5598
- .np-upload-item.np-upload-item--link:hover .np-upload-item__link:after {
5670
+ .np-upload-input__item .np-upload-input__item-action .np-upload-input__item-button:before {
5671
+ content: '';
5599
5672
  display: block;
5673
+ width: var(--clickAreaSize);
5674
+ height: var(--clickAreaSize);
5675
+ border-radius: 50%;
5600
5676
  position: absolute;
5601
- height: 1px;
5602
- background-color: rgba(0,0,0,0.10196);
5603
- background-color: var(--color-border-neutral);
5604
- content: " ";
5605
- left: 16px;
5606
- left: var(--size-16);
5607
- width: calc(100% - 2 * 16px);
5608
- width: calc(100% - 2 * var(--size-16));
5609
- }
5610
- .np-upload-item:first-child ~ div:not(.np-upload-item--link):before,
5611
- .np-upload-item:not(:first-child).np-upload-item--link .np-upload-item__link:before {
5612
- top: 0;
5613
- }
5614
- .np-upload-item.np-upload-item--link:hover .np-upload-item__link:after {
5615
- bottom: -1px;
5616
- }
5617
- .np-upload-item:first-child ~ div {
5618
- border-top: 1px;
5619
- }
5620
- .np-upload-item:not(:first-child) .np-upload-item__link:hover {
5621
- border-top-color: rgba(0,0,0,0.10196);
5622
- border-top-color: var(--color-border-neutral);
5677
+ top: var(--clickAreaTopRightOffset);
5678
+ right: var(--clickAreaTopRightOffset);
5623
5679
  }
5624
- .np-upload-item:not(:last-child) {
5625
- border-bottom: 0;
5626
- }
5627
- .np-upload-item.np-upload-item--link:hover + .np-upload-item:before,
5628
- .np-upload-item.np-upload-item--link:hover + .np-upload-button-container:before,
5629
- .np-upload-item.np-upload-item--link:hover + .np-upload-item .np-upload-item__link:before,
5630
- .np-upload-item.np-upload-item--link:hover + .np-upload-button-container .np-upload-item__link:before {
5631
- display: none;
5680
+ .np-upload-input__item .np-upload-input__item-action .np-upload-input__item-button:hover {
5681
+ background-color: var(--color-sentiment-negative);
5682
+ color: var(--color-contrast-overlay) !important;
5632
5683
  }
5633
- .np-upload-button-container:hover:before,
5634
- .np-upload-button-container.droppable-dropping:before {
5635
- left: 0 !important;
5636
- width: 100% !important;
5684
+ .np-upload-input__item .np-upload-input__item-action .np-upload-input__item-button:active {
5685
+ background-color: var(--color-background-neutral-active);
5637
5686
  }
5638
- .np-upload-button-container:has(:focus-visible) {
5639
- outline: var(--ring-outline-color) solid var(--ring-outline-width);
5640
- outline-offset: var(--ring-outline-offset);
5641
- border-color: transparent;
5642
- outline-offset: -3px;
5687
+ .np-upload-input__item.is-interactive {
5688
+ padding: 0;
5643
5689
  }
5644
- .np-upload-item--single-file:focus-visible,
5645
- .np-upload-item__link:focus-visible,
5646
- .np-upload-button-container:has(:focus-visible) {
5647
- outline-width: 3px;
5690
+ .np-upload-input__item.is-interactive:hover:not(:has(.np-upload-input__item-button:hover)):before,
5691
+ .np-upload-input__item.is-interactive:hover:not(:has(.np-upload-input__item-button:hover)) + .np-upload-input__item:before {
5692
+ width: 100%;
5693
+ left: 0;
5648
5694
  }
5649
- .np-upload-item--link a {
5650
- flex: 1;
5695
+ .np-upload-input__item.is-interactive .np-upload-input__item-link {
5696
+ padding: 16px;
5697
+ padding: var(--size-16);
5651
5698
  -webkit-text-decoration: none;
5652
5699
  text-decoration: none;
5653
- border-top: 1px solid transparent;
5654
5700
  border-radius: inherit;
5701
+ border-top: 1px solid transparent;
5702
+ background-clip: padding-box;
5655
5703
  }
5656
- .np-upload-item--link a:focus-visible {
5704
+ .np-upload-input__item.is-interactive .np-upload-input__item-link:focus-visible {
5657
5705
  outline-offset: -2px;
5706
+ outline-width: 3px;
5658
5707
  }
5659
- .np-upload-item--link a:hover:before {
5660
- display: none !important;
5661
- }
5662
- .np-upload-item--link a:hover:after {
5663
- left: 0 !important;
5664
- width: 100% !important;
5665
- }
5666
- .np-upload-item--link a:hover,
5667
- .np-upload-item--link a:active {
5668
- -webkit-text-decoration: none;
5669
- text-decoration: none;
5670
- }
5671
- .np-upload-item--link a:hover .np-upload-button,
5672
- .np-upload-item--link a:active .np-upload-button {
5708
+ .np-upload-input__item.is-interactive .np-upload-input__item-link:hover,
5709
+ .np-upload-input__item.is-interactive .np-upload-input__item-link:active {
5673
5710
  background-color: rgba(134,167,189,0.10196);
5674
5711
  background-color: var(--color-background-neutral);
5675
- border-radius: inherit;
5676
5712
  }
5677
- .np-upload-item--link:first-of-type a {
5678
- border-top: 0;
5713
+ .np-upload-input__item.is-interactive:first-child .np-upload-input__item-link {
5714
+ border-top-width: 0;
5679
5715
  }
5680
- .np-upload-item__body {
5681
- display: flex;
5682
- align-items: center;
5683
- justify-content: space-between;
5716
+ .np-upload-input__item .np-upload-input-errors {
5717
+ padding-left: 0;
5718
+ list-style-type: "";
5719
+ }
5720
+ .np-upload-input__item .np-upload-input-errors > li {
5684
5721
  position: relative;
5685
- border-radius: inherit;
5722
+ padding-left: 16px;
5723
+ padding-left: var(--size-16);
5686
5724
  }
5687
- .np-upload-item__remove-button {
5688
- display: flex;
5689
- align-items: center;
5690
- justify-content: center;
5691
- align-self: flex-start;
5725
+ .np-upload-input__item .np-upload-input-errors > li::before {
5726
+ content: '•';
5692
5727
  position: absolute;
5693
- height: 24px;
5694
- height: var(--size-24);
5695
- min-height: 0;
5696
- width: 24px;
5697
- width: var(--size-24);
5698
- padding: 0;
5699
- border-radius: 50% !important;
5700
- outline-offset: 0 !important;
5701
- background-color: rgba(134,167,189,0.10196);
5702
- background-color: var(--color-background-neutral);
5703
- border: none;
5704
- color: var(--color-interactive-primary);
5705
- right: 16px;
5706
- right: var(--size-16);
5707
- top: 16px;
5708
- top: var(--size-16);
5709
- transition: color, background-color 0.15s ease-in-out;
5728
+ display: block;
5729
+ left: 0;
5710
5730
  }
5711
5731
  @media (max-width: 320px) {
5712
- .np-upload-item__remove-button {
5713
- top: 16px;
5714
- top: var(--size-16);
5715
- right: 16px;
5716
- right: var(--size-16);
5717
- height: 48px;
5718
- height: var(--size-48);
5719
- width: 48px;
5720
- width: var(--size-48);
5732
+ .np-upload-input__item .np-upload-input-errors > li {
5733
+ padding-left: 32px;
5734
+ padding-left: var(--size-32);
5721
5735
  }
5722
5736
  }
5723
- .np-upload-item__remove-button:hover {
5724
- background-color: var(--color-sentiment-negative);
5725
- color: var(--color-contrast-overlay) !important;
5726
- }
5727
- .np-upload-item__remove-button:before {
5728
- display: block;
5729
- width: 44px;
5730
- height: 44px;
5731
- content: '';
5732
- border-radius: 50%;
5733
- position: absolute;
5734
- }
5735
5737
  .np-progress {
5736
5738
  border-radius: 10px;
5737
5739
  border-radius: var(--radius-small);
@@ -258,6 +258,14 @@ describe('Typeahead', () => {
258
258
  expect(event.preventDefault).toHaveBeenCalledTimes(1);
259
259
  });
260
260
 
261
+ it('sets aria-activedescendant correctly based on focus', () => {
262
+ const inputElement = input().getDOMNode();
263
+
264
+ doTimes(3, () => input().simulate('keyDown', fakeKeyDownEventForKey('ArrowDown')));
265
+
266
+ expect(inputElement).toHaveAttribute('aria-activedescendant', 'menu-test option-Test2');
267
+ });
268
+
261
269
  it('displays alert when alert is provided and chips are valid or alert type is error', () => {
262
270
  const event = {
263
271
  key: 'Enter',
@@ -3,7 +3,7 @@ import { clsx } from 'clsx';
3
3
  import { DebouncedFunc } from 'lodash';
4
4
  import clamp from 'lodash.clamp';
5
5
  import debounce from 'lodash.debounce';
6
- import { Component, ReactNode } from 'react';
6
+ import React, { Component, ReactNode } from 'react';
7
7
  import { injectIntl, WrappedComponentProps } from 'react-intl';
8
8
 
9
9
  import Chip from '../chips/Chip';
@@ -101,6 +101,7 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
101
101
  size: Size.MEDIUM,
102
102
  validateChip: () => true,
103
103
  } satisfies Partial<TypeaheadProps<unknown>>;
104
+ optionRefs: (React.RefObject<HTMLLIElement> | null)[];
104
105
 
105
106
  constructor(props: TypeaheadPropsWithInputAttributes<T>) {
106
107
  super(props);
@@ -115,6 +116,7 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
115
116
  optionsShown: false,
116
117
  isFocused: false,
117
118
  };
119
+ this.optionRefs = [] as (React.RefObject<HTMLLIElement> | null)[];
118
120
  }
119
121
 
120
122
  handleSearchDebounced: DebouncedFunc<Typeahead<T>['handleSearch']>;
@@ -228,7 +230,6 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
228
230
  }
229
231
  }
230
232
  };
231
-
232
233
  moveFocusedOption(offset: number) {
233
234
  this.setState((previousState) => {
234
235
  const { keyboardFocusedOptionIndex } = previousState;
@@ -237,6 +238,10 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
237
238
  if (keyboardFocusedOptionIndex !== null) {
238
239
  index = clamp(keyboardFocusedOptionIndex + offset, 0, options.length - 1);
239
240
  }
241
+ const optionRef = this.optionRefs[index];
242
+ if (optionRef?.current) {
243
+ optionRef.current.focus(); // Set focus on the option element
244
+ }
240
245
  return {
241
246
  keyboardFocusedOptionIndex: index,
242
247
  };
@@ -403,17 +408,23 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
403
408
  >
404
409
  {!!optionsToRender.length && (
405
410
  <ul className="dropdown-menu" role="menu">
406
- {optionsToRender.map((option, idx) => (
407
- <TypeaheadOption
408
- key={`${option.label}${idx.toString()}`}
409
- query={query}
410
- option={option}
411
- selected={keyboardFocusedOptionIndex === idx}
412
- onClick={(event) => {
413
- this.onOptionSelected(event, option);
414
- }}
415
- />
416
- ))}
411
+ {optionsToRender.map((option, idx) => {
412
+ const ref = React.createRef<HTMLLIElement>();
413
+ this.optionRefs[idx] = ref;
414
+ return (
415
+ <TypeaheadOption
416
+ key={`${option.label}${idx.toString()}`}
417
+ ref={ref}
418
+ query={query}
419
+ option={option}
420
+ selected={keyboardFocusedOptionIndex === idx}
421
+ id={String(option.label.replace(/\s+/g, '-'))}
422
+ onClick={(event) => {
423
+ this.onOptionSelected(event, option);
424
+ }}
425
+ />
426
+ )
427
+ })}
417
428
  {footer}
418
429
  </ul>
419
430
  )}
@@ -509,6 +520,11 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
509
520
  typeaheadId={id}
510
521
  renderChip={this.renderChip}
511
522
  autoComplete={inputAutoComplete}
523
+ ariaActivedescendant={
524
+ keyboardFocusedOptionIndex !== null && options[keyboardFocusedOptionIndex]
525
+ ? `option-${options[keyboardFocusedOptionIndex].label.replace(/\s+/g, '-')}`
526
+ : undefined
527
+ }
512
528
  onChange={this.handleOnChange}
513
529
  onKeyDown={this.handleOnKeyDown}
514
530
  onFocus={this.handleOnFocus}
@@ -20,10 +20,12 @@ export type TypeaheadInputProps<T> = {
20
20
  onFocus: () => void;
21
21
  onPaste: React.ClipboardEventHandler<HTMLInputElement>;
22
22
  renderChip: (chip: TypeaheadOption<T>, index: number) => ReactNode;
23
+ ariaActivedescendant?: string;
23
24
  } & Pick<TypeaheadProps<T>, 'id' | 'name' | 'autoFocus' | 'multiple' | 'placeholder' | 'maxHeight'>;
24
25
 
25
26
  type TypeaheadInputState = {
26
27
  inputWidth: number;
28
+ keyboardFocusedOptionIndex: number | null;
27
29
  };
28
30
 
29
31
  export default class TypeaheadInput<T> extends Component<
@@ -37,6 +39,7 @@ export default class TypeaheadInput<T> extends Component<
37
39
  super(props);
38
40
  this.state = {
39
41
  inputWidth: DEFAULT_INPUT_MIN_WIDTH,
42
+ keyboardFocusedOptionIndex: null,
40
43
  };
41
44
  }
42
45
 
@@ -76,6 +79,7 @@ export default class TypeaheadInput<T> extends Component<
76
79
  onFocus,
77
80
  onPaste,
78
81
  autoComplete,
82
+ ariaActivedescendant, // Declare the ariaActivedescendant variable
79
83
  } = this.props;
80
84
  const { inputWidth } = this.state;
81
85
 
@@ -86,6 +90,11 @@ export default class TypeaheadInput<T> extends Component<
86
90
  className={clsx(multiple && 'typeahead__input')}
87
91
  name={name}
88
92
  id={`input-${typeaheadId}`}
93
+ aria-activedescendant={
94
+ ariaActivedescendant
95
+ ? `menu-${typeaheadId} ${ariaActivedescendant}`
96
+ : `menu-${typeaheadId}`
97
+ }
89
98
  autoFocus={autoFocus}
90
99
  placeholder={hasPlaceholder ? placeholder : ''}
91
100
  aria-autocomplete="list"
@@ -51,6 +51,14 @@ describe('Typeahead Option', () => {
51
51
  expect(component.is('.tw-dropdown-item--focused')).toBe(true);
52
52
  });
53
53
 
54
+ it('expect aria-selected to be true', () => {
55
+ component.setProps({
56
+ selected: true,
57
+ });
58
+
59
+ expect(component.prop('aria-selected')).toBe('true');
60
+ });
61
+
54
62
  it('calls onClick when clicked', () => {
55
63
  const onClick = jest.fn();
56
64
  component.setProps({