@transferwise/components 0.0.0-experimental-5125346 → 0.0.0-experimental-3b84ee4

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 (44) hide show
  1. package/build/i18n/en.json +1 -0
  2. package/build/index.js +2442 -2335
  3. package/build/index.js.map +1 -1
  4. package/build/index.mjs +2444 -2338
  5. package/build/index.mjs.map +1 -1
  6. package/build/main.css +54 -65
  7. package/build/styles/main.css +54 -65
  8. package/build/styles/selectOption/SelectOption.css +42 -0
  9. package/build/styles/uploadInput/UploadInput.css +1 -18
  10. package/build/styles/uploadInput/uploadButton/UploadButton.css +0 -4
  11. package/build/styles/uploadInput/uploadItem/UploadItem.css +11 -43
  12. package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
  13. package/build/types/index.d.ts +2 -0
  14. package/build/types/index.d.ts.map +1 -1
  15. package/build/types/inlineAlert/InlineAlert.d.ts +2 -2
  16. package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
  17. package/build/types/selectOption/SelectOption.d.ts +21 -0
  18. package/build/types/selectOption/SelectOption.d.ts.map +1 -0
  19. package/build/types/selectOption/SelectOption.messages.d.ts +8 -0
  20. package/build/types/selectOption/SelectOption.messages.d.ts.map +1 -0
  21. package/build/types/selectOption/index.d.ts +3 -0
  22. package/build/types/selectOption/index.d.ts.map +1 -0
  23. package/package.json +1 -1
  24. package/src/common/responsivePanel/ResponsivePanel.tsx +2 -0
  25. package/src/i18n/en.json +1 -0
  26. package/src/index.ts +2 -0
  27. package/src/inlineAlert/InlineAlert.tsx +1 -1
  28. package/src/main.css +54 -65
  29. package/src/main.less +1 -0
  30. package/src/selectOption/SelectOption.css +42 -0
  31. package/src/selectOption/SelectOption.less +40 -0
  32. package/src/selectOption/SelectOption.messages.ts +8 -0
  33. package/src/selectOption/SelectOption.spec.tsx +101 -0
  34. package/src/selectOption/SelectOption.story.tsx +230 -0
  35. package/src/selectOption/SelectOption.tsx +157 -0
  36. package/src/selectOption/index.ts +2 -0
  37. package/src/ssr.spec.js +1 -0
  38. package/src/uploadInput/UploadInput.css +1 -18
  39. package/src/uploadInput/UploadInput.less +1 -17
  40. package/src/uploadInput/UploadInput.tests.story.tsx +2 -13
  41. package/src/uploadInput/uploadButton/UploadButton.css +0 -4
  42. package/src/uploadInput/uploadButton/UploadButton.less +0 -5
  43. package/src/uploadInput/uploadItem/UploadItem.css +11 -43
  44. package/src/uploadInput/uploadItem/UploadItem.less +17 -61
@@ -0,0 +1,8 @@
1
+ declare const _default: {
2
+ actionLabel: {
3
+ id: string;
4
+ defaultMessage: string;
5
+ };
6
+ };
7
+ export default _default;
8
+ //# sourceMappingURL=SelectOption.messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectOption.messages.d.ts","sourceRoot":"","sources":["../../../src/selectOption/SelectOption.messages.ts"],"names":[],"mappings":";;;;;;AAEA,wBAKG"}
@@ -0,0 +1,3 @@
1
+ export { default } from './SelectOption';
2
+ export type { SelectOptionProps, SelectOptionValue, SelectOptiopsSection } from './SelectOption';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/selectOption/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-5125346",
3
+ "version": "0.0.0-experimental-3b84ee4",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -16,6 +16,7 @@ const ResponsivePanel = forwardRef<HTMLDivElement, PanelProps>(function Responsi
16
16
  onClose,
17
17
  open = false,
18
18
  position = Position.BOTTOM,
19
+ anchorWidth = false,
19
20
  }: PanelProps,
20
21
  reference,
21
22
  ) {
@@ -35,6 +36,7 @@ const ResponsivePanel = forwardRef<HTMLDivElement, PanelProps>(function Responsi
35
36
  arrow={arrow}
36
37
  open={open}
37
38
  position={position}
39
+ anchorWidth={anchorWidth}
38
40
  anchorRef={anchorRef}
39
41
  className={className}
40
42
  onClose={onClose}
package/src/i18n/en.json CHANGED
@@ -23,6 +23,7 @@
23
23
  "neptune.PhoneNumberInput.SelectInput.placeholder": "Select an option...",
24
24
  "neptune.Select.searchPlaceholder": "Search...",
25
25
  "neptune.SelectInput.noResultsFound": "No results found",
26
+ "neptune.SelectOption.action.label": "Choose",
26
27
  "neptune.Summary.statusDone": "Item done",
27
28
  "neptune.Summary.statusNotDone": "Item to do",
28
29
  "neptune.Summary.statusPending": "Item pending",
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  */
4
4
  export type { AccordionItem, AccordionProps } from './accordion';
5
5
  export type { ActionOptionProps } from './actionOption';
6
+ export type { SelectOptionProps, SelectOptionValue, SelectOptiopsSection } from './selectOption';
6
7
  export type { AlertAction, AlertProps, AlertType } from './alert';
7
8
  export type { AvatarProps } from './avatar';
8
9
  export type { BadgeProps } from './badge';
@@ -86,6 +87,7 @@ export type { UploadError, UploadResponse, UploadedFile } from './uploadInput/ty
86
87
  export { default as Accordion } from './accordion';
87
88
  export { default as ActionButton } from './actionButton';
88
89
  export { default as ActionOption } from './actionOption';
90
+ export { default as SelectOption } from './selectOption';
89
91
  export { default as Alert } from './alert';
90
92
  export { default as Avatar } from './avatar';
91
93
  export { default as AvatarWrapper } from './avatarWrapper';
@@ -1,5 +1,5 @@
1
1
  import classNames from 'classnames';
2
- import { ReactNode } from 'react';
2
+ import React, { ReactNode } from 'react';
3
3
 
4
4
  import { Sentiment, Size } from '../common';
5
5
  import StatusIcon from '../statusIcon';
package/src/main.css CHANGED
@@ -1484,6 +1484,48 @@ button.np-option {
1484
1484
  border-radius: var(--radius-small);
1485
1485
  }
1486
1486
  }
1487
+ .np-select-option {
1488
+ border-radius: 10px;
1489
+ border-radius: var(--radius-small);
1490
+ padding: 16px;
1491
+ padding: var(--size-16);
1492
+ }
1493
+ .np-select-option-placeholder {
1494
+ background-color: rgba(134,167,189,0.10196);
1495
+ background-color: var(--color-background-neutral);
1496
+ }
1497
+ .np-select-option-placeholder:hover {
1498
+ background-color: var(--color-background-neutral-hover);
1499
+ }
1500
+ .np-select-option-placeholder:focus,
1501
+ .np-select-option-placeholder:active {
1502
+ background-color: var(--color-background-neutral-active);
1503
+ }
1504
+ .np-select-option-selected {
1505
+ border: 1px solid #c9cbce;
1506
+ border: 1px solid var(--color-interactive-secondary);
1507
+ }
1508
+ .np-select-option-list {
1509
+ max-height: 350px;
1510
+ overflow-y: auto;
1511
+ }
1512
+ .np-select-option-section {
1513
+ margin-top: 0 !important;
1514
+ }
1515
+ .has-error * .np-select-option {
1516
+ --ring-outline-color: var(--color-sentiment-negative);
1517
+ --ring-outline-offset: 0;
1518
+ outline: var(--ring-outline-color) solid var(--ring-outline-width);
1519
+ outline-offset: 0;
1520
+ outline-offset: var(--ring-outline-offset);
1521
+ }
1522
+ .has-error * .np-select-option:focus {
1523
+ outline: none;
1524
+ }
1525
+ .has-error * .np-select-option:focus-visible {
1526
+ outline: var(--ring-outline-color) solid var(--ring-outline-width);
1527
+ outline-offset: var(--ring-outline-offset);
1528
+ }
1487
1529
  .np-panel__content {
1488
1530
  opacity: 0;
1489
1531
  visibility: hidden;
@@ -5402,9 +5444,6 @@ html:not([dir="rtl"]) .np-navigation-option {
5402
5444
  border-color: #c9cbce !important;
5403
5445
  border-color: var(--color-interactive-secondary) !important;
5404
5446
  }
5405
- .np-upload-button-container.droppable-dropping:before {
5406
- z-index: 2;
5407
- }
5408
5447
  .np-upload-button-container input[type="file"] {
5409
5448
  opacity: 0;
5410
5449
  z-index: -1;
@@ -5415,7 +5454,6 @@ html:not([dir="rtl"]) .np-navigation-option {
5415
5454
  }
5416
5455
  .np-upload-button {
5417
5456
  width: 100%;
5418
- border-top: 1px solid transparent;
5419
5457
  padding: 16px;
5420
5458
  padding: var(--padding-small);
5421
5459
  border-radius: 0;
@@ -5483,25 +5521,8 @@ label.np-upload-button:not(.disabled):active {
5483
5521
  color: var(--color-sentiment-negative) !important;
5484
5522
  }
5485
5523
  .np-theme-personal .np-upload-input-errors {
5486
- list-style: none;
5487
5524
  padding-left: 0;
5488
- }
5489
- .np-theme-personal .np-upload-input-errors li {
5490
- position: relative;
5491
- padding-left: 16px;
5492
- padding-left: var(--size-16);
5493
- }
5494
- @media (max-width: 320px) {
5495
- .np-theme-personal .np-upload-input-errors li {
5496
- padding-left: 32px;
5497
- padding-left: var(--size-32);
5498
- }
5499
- }
5500
- .np-theme-personal .np-upload-input-errors li:before {
5501
- content: '•';
5502
- position: absolute;
5503
- display: block;
5504
- left: 0;
5525
+ list-style-position: inside;
5505
5526
  }
5506
5527
  .np-theme-personal .np-upload-input .status-circle {
5507
5528
  width: 24px;
@@ -5520,49 +5541,30 @@ label.np-upload-button:not(.disabled):active {
5520
5541
  .np-upload-item {
5521
5542
  border: 1px solid #c9cbce;
5522
5543
  border: 1px solid var(--color-interactive-secondary);
5523
- position: relative;
5524
5544
  }
5525
- .np-upload-item:first-child ~ div:not(.np-upload-item__link):before,
5526
- .np-upload-item:not(:first-child).np-upload-item__link .np-upload-item--link:before,
5527
- .np-upload-item.np-upload-item__link:hover .np-upload-item--link:after {
5545
+ .np-upload-item:first-child ~ div:before {
5528
5546
  display: block;
5529
- position: absolute;
5547
+ position: relative;
5530
5548
  height: 1px;
5531
5549
  background-color: rgba(0,0,0,0.10196);
5532
5550
  background-color: var(--color-border-neutral);
5533
5551
  content: " ";
5534
- left: 16px;
5535
- left: var(--size-16);
5536
- width: calc(100% - 2 * 16px);
5537
- width: calc(100% - 2 * var(--size-16));
5538
- }
5539
- .np-upload-item:first-child ~ div:not(.np-upload-item__link):before,
5540
- .np-upload-item:not(:first-child).np-upload-item__link .np-upload-item--link:before {
5541
- top: 0;
5542
- }
5543
- .np-upload-item.np-upload-item__link:hover .np-upload-item--link:after {
5544
- bottom: -1px;
5552
+ margin: 0 16px;
5553
+ margin: 0 var(--size-16);
5545
5554
  }
5546
5555
  .np-upload-item:first-child ~ div {
5547
- border-top: 1px;
5548
- }
5549
- .np-upload-item:not(:first-child) .np-upload-item--link:hover {
5550
- border-top-color: rgba(0,0,0,0.10196);
5551
- border-top-color: var(--color-border-neutral);
5556
+ border-top: 0;
5552
5557
  }
5553
5558
  .np-upload-item:not(:last-child) {
5554
5559
  border-bottom: 0;
5555
5560
  }
5556
- .np-upload-item.np-upload-item__link:hover + .np-upload-item:before,
5557
- .np-upload-item.np-upload-item__link:hover + .np-upload-button-container:before,
5558
- .np-upload-item.np-upload-item__link:hover + .np-upload-item .np-upload-item--link:before,
5559
- .np-upload-item.np-upload-item__link:hover + .np-upload-button-container .np-upload-item--link:before {
5560
- display: none;
5561
+ .np-upload-item.np-upload-item__link:hover:before,
5562
+ .np-upload-button-container:hover:before {
5563
+ margin: 0 !important;
5561
5564
  }
5562
- .np-upload-button-container:hover:before,
5563
- .np-upload-button-container.droppable-dropping:before {
5564
- left: 0 !important;
5565
- width: 100% !important;
5565
+ .np-upload-item.np-upload-item__link:hover + div:before,
5566
+ .np-upload-button-container:hover + div:before {
5567
+ margin: 0 !important;
5566
5568
  }
5567
5569
  .np-upload-button-container:has(:focus-visible) {
5568
5570
  outline: var(--ring-outline-color) solid var(--ring-outline-width);
@@ -5579,29 +5581,17 @@ label.np-upload-button:not(.disabled):active {
5579
5581
  flex: 1;
5580
5582
  -webkit-text-decoration: none;
5581
5583
  text-decoration: none;
5582
- border-top: 1px solid transparent;
5583
5584
  border-radius: inherit;
5584
5585
  }
5585
5586
  .np-upload-item__link a:focus-visible {
5586
5587
  outline-offset: -2px;
5587
5588
  }
5588
- .np-upload-item__link a:hover:before {
5589
- display: none !important;
5590
- }
5591
- .np-upload-item__link a:hover:after {
5592
- left: 0 !important;
5593
- width: 100% !important;
5594
- }
5595
5589
  .np-upload-item__link a:hover,
5596
5590
  .np-upload-item__link a:active {
5597
5591
  -webkit-text-decoration: none;
5598
5592
  text-decoration: none;
5599
- }
5600
- .np-upload-item__link a:hover .np-upload-button,
5601
- .np-upload-item__link a:active .np-upload-button {
5602
5593
  background-color: rgba(134,167,189,0.10196);
5603
5594
  background-color: var(--color-background-neutral);
5604
- border-radius: inherit;
5605
5595
  }
5606
5596
  .np-upload-item__body {
5607
5597
  display: flex;
@@ -5626,7 +5616,6 @@ label.np-upload-button:not(.disabled):active {
5626
5616
  outline-offset: 0 !important;
5627
5617
  background-color: rgba(134,167,189,0.10196);
5628
5618
  background-color: var(--color-background-neutral);
5629
- border: none;
5630
5619
  color: var(--color-interactive-primary);
5631
5620
  right: 16px;
5632
5621
  right: var(--size-16);
package/src/main.less CHANGED
@@ -13,6 +13,7 @@
13
13
  @import "./common/card/Card.less";
14
14
  @import "./common/closeButton/CloseButton.less";
15
15
  @import "./common/Option/Option.less";
16
+ @import "./selectOption/SelectOption.less";
16
17
  @import "./common/panel/Panel.less";
17
18
  @import "./common/RadioButton/RadioButton.less";
18
19
  @import "./dateInput/DateInput.less";
@@ -0,0 +1,42 @@
1
+ .np-select-option {
2
+ border-radius: 10px;
3
+ border-radius: var(--radius-small);
4
+ padding: 16px;
5
+ padding: var(--size-16);
6
+ }
7
+ .np-select-option-placeholder {
8
+ background-color: rgba(134,167,189,0.10196);
9
+ background-color: var(--color-background-neutral);
10
+ }
11
+ .np-select-option-placeholder:hover {
12
+ background-color: var(--color-background-neutral-hover);
13
+ }
14
+ .np-select-option-placeholder:focus,
15
+ .np-select-option-placeholder:active {
16
+ background-color: var(--color-background-neutral-active);
17
+ }
18
+ .np-select-option-selected {
19
+ border: 1px solid #c9cbce;
20
+ border: 1px solid var(--color-interactive-secondary);
21
+ }
22
+ .np-select-option-list {
23
+ max-height: 350px;
24
+ overflow-y: auto;
25
+ }
26
+ .np-select-option-section {
27
+ margin-top: 0 !important;
28
+ }
29
+ .has-error * .np-select-option {
30
+ --ring-outline-color: var(--color-sentiment-negative);
31
+ --ring-outline-offset: 0;
32
+ outline: var(--ring-outline-color) solid var(--ring-outline-width);
33
+ outline-offset: 0;
34
+ outline-offset: var(--ring-outline-offset);
35
+ }
36
+ .has-error * .np-select-option:focus {
37
+ outline: none;
38
+ }
39
+ .has-error * .np-select-option:focus-visible {
40
+ outline: var(--ring-outline-color) solid var(--ring-outline-width);
41
+ outline-offset: var(--ring-outline-offset);
42
+ }
@@ -0,0 +1,40 @@
1
+ @import (reference) "../../node_modules/@transferwise/neptune-css/src/less/ring.less";
2
+
3
+ .np-select-option {
4
+ border-radius: var(--radius-small);
5
+ padding: var(--size-16);
6
+
7
+ &-placeholder {
8
+ background-color: var(--color-background-neutral);
9
+
10
+ &:hover {
11
+ background-color: var(--color-background-neutral-hover);
12
+ }
13
+
14
+ &:focus,
15
+ &:active {
16
+ background-color: var(--color-background-neutral-active);
17
+ }
18
+ }
19
+
20
+ &-selected {
21
+ border: 1px solid var(--color-interactive-secondary);
22
+ }
23
+
24
+ &-list {
25
+ max-height: 350px;
26
+ overflow-y: auto;
27
+ }
28
+
29
+ &-section {
30
+ // override large margin in Section & Header
31
+ margin-top: 0 !important;
32
+ }
33
+
34
+ .has-error * & {
35
+ .ring-negative();
36
+ .ring-offset-0();
37
+ .ring();
38
+ .focus-ring();
39
+ }
40
+ }
@@ -0,0 +1,8 @@
1
+ import { defineMessages } from 'react-intl';
2
+
3
+ export default defineMessages({
4
+ actionLabel: {
5
+ id: 'neptune.SelectOption.action.label',
6
+ defaultMessage: 'Choose',
7
+ },
8
+ });
@@ -0,0 +1,101 @@
1
+ import { render, userEvent, screen, within, mockMatchMedia } from '../test-utils';
2
+ import { composeStories } from '@storybook/react';
3
+ import * as stories from './SelectOption.story';
4
+ import { Breakpoint } from '../common';
5
+ import { wait } from '../test-utils/wait';
6
+
7
+ const { Basic: SelectOptionExample } = composeStories(stories);
8
+
9
+ mockMatchMedia();
10
+
11
+ describe('Select Option', () => {
12
+ it('opens dropdown on desktop view', async () => {
13
+ render(<SelectOptionExample />);
14
+
15
+ let dialog = screen.queryByRole('dialog');
16
+ expect(dialog).not.toBeInTheDocument();
17
+
18
+ const button = screen.getByRole('button', {
19
+ name: /choose/i,
20
+ });
21
+
22
+ await userEvent.click(button);
23
+
24
+ dialog = screen.queryByRole('dialog');
25
+ expect(dialog).toBeInTheDocument();
26
+ });
27
+
28
+ it('opens bottom sheet on mobile view', async () => {
29
+ // mock mobile view
30
+ window.innerWidth = Breakpoint.EXTRA_SMALL;
31
+
32
+ render(<SelectOptionExample />);
33
+
34
+ let dialog = screen.queryByRole('dialog');
35
+ expect(dialog).not.toBeInTheDocument();
36
+
37
+ const button = screen.getByRole('button', {
38
+ name: /choose/i,
39
+ });
40
+
41
+ await userEvent.click(button);
42
+
43
+ dialog = screen.queryByRole('dialog');
44
+ expect(dialog).toBeInTheDocument();
45
+ });
46
+
47
+ it('shows options', async () => {
48
+ render(<SelectOptionExample />);
49
+
50
+ const button = screen.getByRole('button', {
51
+ name: /choose/i,
52
+ });
53
+
54
+ await userEvent.click(button);
55
+
56
+ const dialog = screen.getByRole('dialog');
57
+ const sectionHeaders = within(dialog).getAllByRole('heading', { name: /balances|jars/i });
58
+ expect(sectionHeaders).toHaveLength(2);
59
+
60
+ const options = within(dialog).getAllByRole('heading', { level: 4 });
61
+ expect(options).toHaveLength(5);
62
+ });
63
+
64
+ it('choose option', async () => {
65
+ // mock mobile view
66
+ window.innerWidth = Breakpoint.EXTRA_SMALL;
67
+
68
+ const onClickHandler = jest.fn();
69
+ render(
70
+ <SelectOptionExample
71
+ placeholder={{ title: 'Please choose balance', actionLabel: 'Pick' }}
72
+ onChange={onClickHandler}
73
+ />,
74
+ );
75
+
76
+ const button = screen.getByRole('button', {
77
+ name: /pick/i,
78
+ });
79
+
80
+ expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
81
+ await userEvent.click(button);
82
+ expect(screen.getByRole('dialog')).toBeInTheDocument();
83
+
84
+ const pickedOption = within(screen.getByRole('dialog')).getByText('Trip to Mars');
85
+
86
+ expect(onClickHandler).not.toHaveBeenCalled();
87
+ await userEvent.click(pickedOption);
88
+ expect(onClickHandler).toHaveBeenCalledTimes(1);
89
+
90
+ // wait for dialog to close
91
+ await wait(500);
92
+ expect(screen.getByText('Trip to Mars')).toBeInTheDocument();
93
+ expect(
94
+ screen.queryByRole('button', {
95
+ name: /pick/i,
96
+ }),
97
+ ).not.toBeInTheDocument();
98
+ expect(screen.queryAllByTestId('chevron-up-icon')).toHaveLength(1);
99
+ expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
100
+ });
101
+ });