@transferwise/components 46.52.3 → 46.53.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 (121) hide show
  1. package/build/dateLookup/dateTrigger/DateTrigger.js +8 -4
  2. package/build/dateLookup/dateTrigger/DateTrigger.js.map +1 -1
  3. package/build/dateLookup/dateTrigger/DateTrigger.mjs +8 -4
  4. package/build/dateLookup/dateTrigger/DateTrigger.mjs.map +1 -1
  5. package/build/field/Field.js +36 -8
  6. package/build/field/Field.js.map +1 -1
  7. package/build/field/Field.mjs +37 -9
  8. package/build/field/Field.mjs.map +1 -1
  9. package/build/i18n/en.json +1 -0
  10. package/build/i18n/en.json.js +1 -0
  11. package/build/i18n/en.json.js.map +1 -1
  12. package/build/i18n/en.json.mjs +1 -0
  13. package/build/i18n/en.json.mjs.map +1 -1
  14. package/build/index.js +2 -2
  15. package/build/index.mjs +1 -1
  16. package/build/inlineAlert/InlineAlert.js +13 -6
  17. package/build/inlineAlert/InlineAlert.js.map +1 -1
  18. package/build/inlineAlert/InlineAlert.mjs +13 -6
  19. package/build/inlineAlert/InlineAlert.mjs.map +1 -1
  20. package/build/label/Label.js +35 -4
  21. package/build/label/Label.js.map +1 -1
  22. package/build/label/Label.messages.js +12 -0
  23. package/build/label/Label.messages.js.map +1 -0
  24. package/build/label/Label.messages.mjs +10 -0
  25. package/build/label/Label.messages.mjs.map +1 -0
  26. package/build/label/Label.mjs +36 -5
  27. package/build/label/Label.mjs.map +1 -1
  28. package/build/main.css +4 -8
  29. package/build/styles/dateLookup/dateTrigger/DateTrigger.css +0 -8
  30. package/build/styles/field/Field.css +4 -0
  31. package/build/styles/main.css +4 -8
  32. package/build/tabs/Tab.js +13 -38
  33. package/build/tabs/Tab.js.map +1 -1
  34. package/build/tabs/Tab.mjs +13 -34
  35. package/build/tabs/Tab.mjs.map +1 -1
  36. package/build/tabs/TabList.js +3 -11
  37. package/build/tabs/TabList.js.map +1 -1
  38. package/build/tabs/TabList.mjs +3 -7
  39. package/build/tabs/TabList.mjs.map +1 -1
  40. package/build/tabs/TabPanel.js +3 -16
  41. package/build/tabs/TabPanel.js.map +1 -1
  42. package/build/tabs/TabPanel.mjs +3 -12
  43. package/build/tabs/TabPanel.mjs.map +1 -1
  44. package/build/tabs/Tabs.js +24 -48
  45. package/build/tabs/Tabs.js.map +1 -1
  46. package/build/tabs/Tabs.mjs +24 -47
  47. package/build/tabs/Tabs.mjs.map +1 -1
  48. package/build/tabs/utils.js +0 -1
  49. package/build/tabs/utils.js.map +1 -1
  50. package/build/tabs/utils.mjs +0 -1
  51. package/build/tabs/utils.mjs.map +1 -1
  52. package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts.map +1 -1
  53. package/build/types/field/Field.d.ts +4 -2
  54. package/build/types/field/Field.d.ts.map +1 -1
  55. package/build/types/index.d.ts +2 -1
  56. package/build/types/index.d.ts.map +1 -1
  57. package/build/types/inlineAlert/InlineAlert.d.ts +9 -0
  58. package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
  59. package/build/types/label/Label.d.ts +21 -1
  60. package/build/types/label/Label.d.ts.map +1 -1
  61. package/build/types/label/Label.messages.d.ts +8 -0
  62. package/build/types/label/Label.messages.d.ts.map +1 -0
  63. package/build/types/label/index.d.ts +3 -0
  64. package/build/types/label/index.d.ts.map +1 -0
  65. package/build/types/tabs/Tab.d.ts +12 -1
  66. package/build/types/tabs/Tab.d.ts.map +1 -1
  67. package/build/types/tabs/TabList.d.ts +3 -8
  68. package/build/types/tabs/TabList.d.ts.map +1 -1
  69. package/build/types/tabs/TabPanel.d.ts +6 -14
  70. package/build/types/tabs/TabPanel.d.ts.map +1 -1
  71. package/build/types/tabs/Tabs.d.ts +83 -30
  72. package/build/types/tabs/Tabs.d.ts.map +1 -1
  73. package/build/types/tabs/index.d.ts +2 -1
  74. package/build/types/tabs/index.d.ts.map +1 -1
  75. package/build/types/tabs/utils.d.ts +12 -7
  76. package/build/types/tabs/utils.d.ts.map +1 -1
  77. package/package.json +2 -2
  78. package/src/dateInput/DateInput.tests.story.tsx +6 -42
  79. package/src/dateLookup/DateLookup.rtl.spec.tsx +1 -1
  80. package/src/dateLookup/dateTrigger/DateTrigger.css +0 -8
  81. package/src/dateLookup/dateTrigger/DateTrigger.less +0 -8
  82. package/src/dateLookup/dateTrigger/DateTrigger.spec.js +1 -1
  83. package/src/dateLookup/dateTrigger/DateTrigger.tsx +9 -4
  84. package/src/field/Field.css +4 -0
  85. package/src/field/Field.less +5 -0
  86. package/src/field/Field.spec.tsx +41 -5
  87. package/src/field/Field.story.tsx +105 -7
  88. package/src/field/Field.tsx +34 -10
  89. package/src/i18n/en.json +1 -0
  90. package/src/index.ts +2 -1
  91. package/src/inlineAlert/InlineAlert.story.tsx +7 -72
  92. package/src/inlineAlert/InlineAlert.tsx +14 -3
  93. package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.js +5 -10
  94. package/src/inputs/InputGroup.spec.tsx +1 -1
  95. package/src/inputs/SearchInput.spec.tsx +1 -1
  96. package/src/inputs/SelectInput.spec.tsx +1 -1
  97. package/src/label/Label.messages.tsx +8 -0
  98. package/src/label/Label.spec.tsx +53 -4
  99. package/src/label/Label.story.tsx +32 -26
  100. package/src/label/Label.tsx +47 -2
  101. package/src/label/index.ts +2 -0
  102. package/src/main.css +4 -8
  103. package/src/main.less +1 -0
  104. package/src/moneyInput/MoneyInput.story.tsx +11 -11
  105. package/src/radioGroup/RadioGroup.rtl.spec.tsx +1 -1
  106. package/src/select/Select.rtl.spec.tsx +1 -1
  107. package/src/switch/Switch.spec.tsx +1 -1
  108. package/src/switch/Switch.story.tsx +19 -21
  109. package/src/tabs/Tab.tsx +72 -0
  110. package/src/tabs/TabList.tsx +11 -0
  111. package/src/tabs/TabPanel.tsx +14 -0
  112. package/src/tabs/{Tabs.story.js → Tabs.story.tsx} +1 -1
  113. package/src/tabs/{Tabs.js → Tabs.tsx} +111 -74
  114. package/src/tabs/index.ts +2 -0
  115. package/src/tabs/{utils.spec.js → utils.spec.ts} +24 -21
  116. package/src/tabs/{utils.js → utils.ts} +15 -9
  117. package/src/field/Field.tests.story.tsx +0 -33
  118. package/src/tabs/Tab.js +0 -71
  119. package/src/tabs/TabList.js +0 -15
  120. package/src/tabs/TabPanel.js +0 -20
  121. package/src/tabs/index.js +0 -1
@@ -1,30 +1,83 @@
1
- import * as React from 'react';
2
-
3
- export interface TabsTabs {
4
- title: string;
5
- content: React.ReactNode;
6
- disabled: boolean;
7
- }
8
-
9
- export type TabsTransitionSpacing = "default" | "xs" | "sm" | "md" | "lg";
10
-
11
- export type TabsHeaderWidth = "auto" | "block";
12
-
13
- export interface TabsProps {
14
- tabs: TabsTabs[];
15
- selected: number;
16
- name: string;
17
- animatePanelsOnClick?: boolean;
18
- changeTabOnSwipe?: boolean;
19
- className?: string;
20
- transitionSpacing?: TabsTransitionSpacing;
21
- headerWidth?: TabsHeaderWidth;
22
- id?: string;
23
- onTabSelect: (...args: any[])=>any;
24
- }
25
-
26
- export default class Tabs extends React.Component<TabsProps, any> {
27
- render(): JSX.Element;
28
-
29
- }
30
-
1
+ import { Component } from 'react';
2
+ import { Size, Width } from '../common';
3
+ import { Swipe } from './utils';
4
+ export interface TabItem {
5
+ title: string;
6
+ content: React.ReactNode;
7
+ disabled: boolean;
8
+ }
9
+ type TabsTransitionSpacing = 'default' | `${Size.EXTRA_SMALL | Size.SMALL | Size.MEDIUM | Size.LARGE}`;
10
+ export interface TabsProps {
11
+ tabs: TabItem[];
12
+ selected: number;
13
+ name: string;
14
+ animatePanelsOnClick?: boolean;
15
+ changeTabOnSwipe?: boolean;
16
+ className?: string;
17
+ transitionSpacing?: TabsTransitionSpacing;
18
+ headerWidth?: `${Width}`;
19
+ id?: string;
20
+ onTabSelect: (index: number) => void;
21
+ }
22
+ interface TabsState {
23
+ start: Swipe | null;
24
+ translateX: number;
25
+ translateFrom: number;
26
+ translateTo: number;
27
+ translateLineX: string | null;
28
+ isAnimating: boolean;
29
+ isSwiping: boolean;
30
+ isScrolling: boolean;
31
+ lastSwipeVelocity: number;
32
+ fullWidthTabs: boolean;
33
+ currentSwipe: Swipe[];
34
+ selectedTabIndex: number;
35
+ }
36
+ export default class Tabs extends Component<TabsProps, TabsState> {
37
+ props: TabsProps & Required<Pick<TabsProps, keyof typeof Tabs.defaultProps>>;
38
+ static defaultProps: {
39
+ changeTabOnSwipe: true;
40
+ transitionSpacing: "default";
41
+ headerWidth: Width.BLOCK;
42
+ };
43
+ containerReference: import("react").RefObject<HTMLDivElement>;
44
+ constructor(props: Tabs['props']);
45
+ container: HTMLDivElement | null;
46
+ containerWidth: number;
47
+ tabRefs: (HTMLLIElement | null)[];
48
+ get filteredTabsLength(): number;
49
+ get MAX_INDEX(): number;
50
+ componentDidMount(): void;
51
+ componentDidUpdate(previousProps: TabsProps, previousState: TabsState): void;
52
+ componentWillUnmount(): void;
53
+ handleResize: () => void;
54
+ setContainerRefAndWidth: (node: HTMLDivElement | null) => void;
55
+ setContainerWidth: (node: HTMLDivElement | null) => void;
56
+ isTabDisabled: (index: number) => boolean;
57
+ getAllTabsWidth: () => number;
58
+ getDistanceToSelectedTab: (selectedTabIndex: number) => number;
59
+ setTabWidth: () => void;
60
+ getTabLineWidth: () => string;
61
+ getTabToSelect: (selected: number, start: Swipe, end: Swipe) => number;
62
+ swipedOverHalfOfContainer: (difference: number) => boolean;
63
+ calculateApplicableDragDifference: ({ currentSelected, nextSelected, start, end, }: {
64
+ currentSelected: number;
65
+ nextSelected: number;
66
+ start: Swipe;
67
+ end: Swipe;
68
+ }) => number | false;
69
+ switchTab: (index: number) => void;
70
+ getTabIndexWithoutDisabledTabs(index: number): number;
71
+ animateToTab: (index: number, instant?: boolean) => void;
72
+ animateLine: (index: number) => void;
73
+ animatePanel: (index: number, instant?: boolean) => void;
74
+ disableScroll: (event: Event) => void;
75
+ handleTabClick: (index: number) => () => void;
76
+ onKeyDown: (index: number) => (event: React.KeyboardEvent<HTMLLIElement>) => void;
77
+ handleTouchStart: React.TouchEventHandler<HTMLDivElement>;
78
+ handleTouchMove: React.TouchEventHandler<HTMLDivElement>;
79
+ handleTouchEnd: React.TouchEventHandler<HTMLDivElement>;
80
+ render(): import("react").JSX.Element;
81
+ }
82
+ export {};
83
+ //# sourceMappingURL=Tabs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/tabs/Tabs.js"],"names":[],"mappings":";AA4BA;IAIE,wBAcC;IAjBD,qDAAqD;IACrD,oBADW,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAChB;IAI/B;;;;;;;;;;;MAWC;IAGH,gBAAiB;IAEjB,uBAAmB;IAEnB,eAAa;IAEb,8BAEC;IAED,wBAEC;IAED,0BASC;IAED,iEAiCC;IAED,6BAIC;IAED,yBAME;IAEF,6CAGE;IAEF,uCAQE;IAEF,mCAIE;IAEF,2BAME;IAEF,yDAKE;IAEF,wBAeE;IAEF,8BAWE;IAMF,6DA4BE;IAEF,wDAAoF;IAEpF;;;;;yBAkBE;IAEF,gCAGE;IAEF,mDAEC;IAED,iDAIE;IAEF,kCAME;IAGF,sDAYE;IAEF,oCAME;IAEF,2CAEE;IAEF,gDAIE;IAEF,uCAYE;IAEF,sCAiDE;IAEF,qCAoCE;IAEF,sCAiKC;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAhjB8C,OAAO;AAkjBtD;;;;;;;EAAiD;sBAhjBV,WAAW;qBAAX,WAAW"}
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/tabs/Tabs.tsx"],"names":[],"mappings":"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"}
@@ -1,2 +1,3 @@
1
- export { default } from "./Tabs";
1
+ export { default } from './Tabs';
2
+ export type { TabItem, TabsProps } from './Tabs';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tabs/index.js"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tabs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
@@ -1,8 +1,13 @@
1
- export function getVelocity(coords: any): number;
2
- export function getSwipeVelocity(start: any, end: any): number;
3
- export function getSwipeDifference(start: any, end: any, axis?: string): number;
4
- export function swipedLeftToRight(start: any, end: any): boolean;
5
- export function swipedRightToLeft(start: any, end: any): boolean;
6
- export function swipeShouldChangeTab(start: any, end: any): boolean;
7
- export function getElasticDragDifference(difference: any): number;
1
+ export interface Swipe {
2
+ x: number;
3
+ y: number;
4
+ time: number;
5
+ }
6
+ export declare const getSwipeVelocity: (start: Swipe, end: Swipe) => number;
7
+ export declare const getSwipeDifference: (start: Swipe, end: Swipe, axis?: "x" | "y") => number;
8
+ export declare const swipedLeftToRight: (start: Swipe, end: Swipe) => boolean;
9
+ export declare const swipedRightToLeft: (start: Swipe, end: Swipe) => boolean;
10
+ export declare const swipeShouldChangeTab: (start: Swipe, end: Swipe) => boolean;
11
+ export declare function getVelocity(coords: Swipe[]): number;
12
+ export declare const getElasticDragDifference: (difference: number) => number;
8
13
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/tabs/utils.js"],"names":[],"mappings":"AAgCA,iDAUC;AAnCM,+DAIN;AAEM,gFAEN;AAEM,iEAEN;AAEM,iEAEN;AAEM,oEAKN;AAmBM,kEACuE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/tabs/utils.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,gBAAgB,UAAW,KAAK,OAAO,KAAK,WAIxD,CAAC;AAEF,eAAO,MAAM,kBAAkB,UAAW,KAAK,OAAO,KAAK,SAAQ,GAAG,GAAG,GAAG,WAE3E,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAW,KAAK,OAAO,KAAK,YAEzD,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAW,KAAK,OAAO,KAAK,YAEzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,UAAW,KAAK,OAAO,KAAK,YAK5D,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,UAU1C;AAOD,eAAO,MAAM,wBAAwB,eAAgB,MAAM,WACmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "46.52.3",
3
+ "version": "46.53.0",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -92,8 +92,8 @@
92
92
  "rollup": "^4.18.1",
93
93
  "rollup-preserve-directives": "^1.1.1",
94
94
  "storybook": "^8.2.2",
95
- "@transferwise/neptune-css": "14.12.1",
96
95
  "@transferwise/less-config": "3.1.0",
96
+ "@transferwise/neptune-css": "14.13.0",
97
97
  "@wise/components-theming": "1.5.0"
98
98
  },
99
99
  "peerDependencies": {
@@ -1,7 +1,7 @@
1
1
  import { Meta, StoryObj } from '@storybook/react';
2
2
  import { userEvent, within, fn } from '@storybook/test';
3
3
 
4
- import { DateInput, DateMode, Info, InlineAlert, Title, Typography } from '..';
4
+ import { DateInput, Field } from '..';
5
5
  import { lorem10, storyConfig } from '../test-utils';
6
6
 
7
7
  import Provider from '../provider/Provider';
@@ -38,45 +38,10 @@ export const WithLabel = {
38
38
  onChange: fn(),
39
39
  },
40
40
  render: (args) => {
41
- const id1 = 'date-input-group-label-1';
42
- const label = 'Date of Birth';
43
-
44
41
  return (
45
- <>
46
- <Title type={Typography.TITLE_SUBSECTION}>
47
- label (as <code>div</code> element) is linked with <code>DateInput</code> via{' '}
48
- <code>aria-labelledby</code> prop
49
- </Title>
50
- <div className="control-label" id={id1}>
51
- Date of Delivery
52
- </div>
53
- <DateInput {...args} aria-labelledby={id1} />
54
-
55
- <br />
56
-
57
- <Title type={Typography.TITLE_SUBSECTION}>
58
- label (as <code>div</code> element) is detached but <code>DateInput</code> has same label
59
- via <code>aria-label</code> attribute
60
- </Title>
61
- <div className="control-label">
62
- {label}{' '}
63
- <Info aria-label="Fast transfer hint" title="Fast transfer hint" content={lorem10} />
64
- </div>
65
- <DateInput {...args} aria-label={label} />
66
-
67
- <br />
68
-
69
- <Title type={Typography.TITLE_SUBSECTION}>
70
- <code>DateInput</code> wrapped in <code>fieldset</code> + using <code>legend</code> as
71
- label (rare use case)
72
- </Title>
73
- <fieldset>
74
- <legend className="control-label">
75
- Expiry Date for Credit Card (example of MONTH_YEAR mode)
76
- </legend>
77
- <DateInput {...args} mode={DateMode.MONTH_YEAR} />
78
- </fieldset>
79
- </>
42
+ <Field label="Date of Delivery">
43
+ <DateInput {...args} />
44
+ </Field>
80
45
  );
81
46
  },
82
47
  } satisfies Story;
@@ -84,10 +49,9 @@ export const WithLabel = {
84
49
  export const InputError = {
85
50
  ...Basic,
86
51
  render: (args) => (
87
- <div className="form-group has-error">
52
+ <Field sentiment="negative" message={lorem10}>
88
53
  <DateInput {...args} value={new Date('2010-04-05')} />
89
- <InlineAlert type="error">{lorem10}</InlineAlert>
90
- </div>
54
+ </Field>
91
55
  ),
92
56
  } satisfies Story;
93
57
 
@@ -28,7 +28,7 @@ describe('DateLookup', () => {
28
28
  </Field>,
29
29
  );
30
30
  // TODO: Replace with `.toHaveAttribute('aria-haspopup')`
31
- expect(screen.getByLabelText('Date of birth')).toHaveTextContent(
31
+ expect(screen.getByLabelText(/Date of birth/)).toHaveTextContent(
32
32
  initialValue.getFullYear().toString(),
33
33
  );
34
34
  });
@@ -4,18 +4,10 @@
4
4
  white-space: nowrap;
5
5
  width: 100%;
6
6
  }
7
- .np-date-trigger .control-label {
8
- font-weight: 400;
9
- font-weight: var(--font-weight-regular);
10
- }
11
7
  .np-theme-personal .np-date-trigger {
12
8
  padding-left: 16px;
13
9
  padding-left: var(--size-16);
14
10
  }
15
- .np-theme-personal .np-date-trigger .control-label + span {
16
- font-weight: 400;
17
- font-weight: var(--font-weight-regular);
18
- }
19
11
  .clear-btn {
20
12
  transition: color 0.15s ease-in-out;
21
13
  color: #c9cbce;
@@ -7,16 +7,8 @@
7
7
  white-space: nowrap;
8
8
  width: 100%;
9
9
 
10
- .control-label {
11
- font-weight: var(--font-weight-regular);
12
- }
13
-
14
10
  .np-theme-personal & {
15
11
  padding-left: var(--size-16);
16
-
17
- .control-label + span {
18
- font-weight: var(--font-weight-regular);
19
- }
20
12
  }
21
13
  }
22
14
 
@@ -119,5 +119,5 @@ describe('DateTrigger', () => {
119
119
  const button = () => component.find('.np-date-trigger');
120
120
  const clearButton = () => component.find('.clear-btn');
121
121
  const chevron = () => component.find(Chevron);
122
- const label = () => component.find('.control-label');
122
+ const label = () => component.find('.np-date-trigger-label');
123
123
  });
@@ -2,12 +2,13 @@ import { formatDate } from '@transferwise/formatting';
2
2
  import { useIntl } from 'react-intl';
3
3
 
4
4
  import Chevron from '../../chevron';
5
- import { Size, Position, SizeSmall, SizeMedium, SizeLarge } from '../../common';
5
+ import { Size, Position, SizeSmall, SizeMedium, SizeLarge, Typography } from '../../common';
6
6
  import { CloseButton } from '../../common/closeButton/CloseButton';
7
7
 
8
8
  import messages from './DateTrigger.messages';
9
9
  import { useContext } from 'react';
10
10
  import { OverlayIdContext } from '../../provider/overlay/OverlayIdProvider';
11
+ import Body from '../../body';
11
12
 
12
13
  interface DateTriggerProps {
13
14
  selectedDate: Date | null;
@@ -45,15 +46,19 @@ const DateTrigger: React.FC<DateTriggerProps> = ({
45
46
  type="button"
46
47
  onClick={onClick}
47
48
  >
48
- {label && <span className="control-label small m-r-1">{label}</span>}
49
+ {label && (
50
+ <Body as="span" className="np-date-trigger-label m-r-1">
51
+ {label}
52
+ </Body>
53
+ )}
49
54
  {selectedDate ? (
50
- <span className="font-weight-normal">
55
+ <Body as="span" type={Typography.BODY_LARGE}>
51
56
  {formatDate(selectedDate, locale, {
52
57
  day: 'numeric',
53
58
  month: monthFormat,
54
59
  year: 'numeric',
55
60
  })}
56
- </span>
61
+ </Body>
57
62
  ) : (
58
63
  <span
59
64
  className="form-control-placeholder visible-xs-inline visible-sm-inline
@@ -0,0 +1,4 @@
1
+ .np-field-control {
2
+ margin-top: 4px;
3
+ margin-top: var(--size-4);
4
+ }
@@ -0,0 +1,5 @@
1
+ .np-field {
2
+ &-control {
3
+ margin-top: var(--size-4);
4
+ }
5
+ }
@@ -14,7 +14,7 @@ describe('Field', () => {
14
14
  </Field>,
15
15
  );
16
16
 
17
- expect(screen.getByLabelText('Phone number')).toBeInTheDocument();
17
+ expect(screen.getByLabelText(/Phone number/)).toBeInTheDocument();
18
18
  expect(screen.getByRole('textbox')).not.toHaveAttribute('aria-describedby');
19
19
  });
20
20
 
@@ -25,7 +25,7 @@ describe('Field', () => {
25
25
  </Field>,
26
26
  );
27
27
 
28
- const textbox = screen.getByRole('textbox', { description: 'This is help text' });
28
+ const textbox = screen.getByRole('textbox', { description: /This is help text/ });
29
29
  expect(textbox).toBeInTheDocument();
30
30
  expect(textbox).not.toBeInvalid();
31
31
  });
@@ -42,15 +42,51 @@ describe('Field', () => {
42
42
  expect(textbox).toBeInvalid();
43
43
  });
44
44
 
45
- it('should prefer error text over help text if both are provided', () => {
45
+ it('should shows error text and help text when both are provided', () => {
46
46
  render(
47
47
  <Field label="Phone number" error="This is error text" hint="This is help text">
48
48
  <Input />
49
49
  </Field>,
50
50
  );
51
51
 
52
- expect(screen.getByRole('textbox', { description: 'This is error text' })).toBeInTheDocument();
53
- expect(screen.queryByText('This is help text')).not.toBeInTheDocument();
52
+ expect(screen.getByRole('textbox', { description: /This is error text/ })).toBeInTheDocument();
53
+ expect(screen.getByText('This is help text')).toBeInTheDocument();
54
+ expect(screen.getByLabelText(/Phone number/)).toHaveAttribute('aria-describedby');
55
+ });
56
+
57
+ it('should shows message and description when both are provided', () => {
58
+ render(
59
+ <Field
60
+ label="Phone number"
61
+ description="This is help text"
62
+ sentiment="negative"
63
+ message="This is error text"
64
+ >
65
+ <Input />
66
+ </Field>,
67
+ );
68
+
69
+ expect(screen.getByRole('textbox', { description: /This is error text/ })).toBeInTheDocument();
70
+ expect(screen.getByText('This is help text')).toBeInTheDocument();
71
+ expect(screen.getByLabelText(/Phone number/)).toHaveAttribute('aria-describedby');
72
+ });
73
+
74
+ it('should show or hide (Optional) suffix depending on required prop', () => {
75
+ render(
76
+ <Field label="Phone number" description="This is help text">
77
+ <Input />
78
+ </Field>,
79
+ );
80
+
81
+ expect(screen.getByText('(Optional)')).toBeInTheDocument();
82
+
83
+ render(
84
+ <Field label="Phone number" description="This is help text" required>
85
+ <Input />
86
+ </Field>,
87
+ );
88
+
89
+ expect(screen.getByLabelText('Phone number')).toBeInTheDocument();
54
90
  });
55
91
 
56
92
  it('avoids triggering button within label inadvertently', async () => {
@@ -3,6 +3,12 @@ import { useState } from 'react';
3
3
  import { Input } from '../inputs/Input';
4
4
  import { Field } from './Field';
5
5
  import { Sentiment } from '../common';
6
+ import DateInput from '../dateInput';
7
+ import { fn } from '@storybook/test';
8
+ import { lorem10, lorem40 } from '../test-utils';
9
+ import { TextArea } from '../inputs/TextArea';
10
+ import { SearchInput } from '../inputs/SearchInput';
11
+ import Info from '../info';
6
12
 
7
13
  export default {
8
14
  component: Field,
@@ -13,9 +19,66 @@ export default {
13
19
  export const Basic = () => {
14
20
  const [value, setValue] = useState<string | undefined>('This is some text');
15
21
  return (
16
- <Field label="Phone number">
17
- <Input value={value} onChange={({ target }) => setValue(target.value)} />
18
- </Field>
22
+ <div className="row">
23
+ <div className="col-md-8 col-md-offset-2">
24
+ <Field label="Required Text Input" required>
25
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
26
+ </Field>
27
+ <Field label="Text Input">
28
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
29
+ </Field>
30
+ <Field label="Text Input with Description" description="This a field Description">
31
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
32
+ </Field>
33
+ <Field
34
+ label="Text Input with Validation Error"
35
+ description="This a field Description"
36
+ sentiment={Sentiment.NEGATIVE}
37
+ message="Validation error, please take a look"
38
+ >
39
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
40
+ </Field>
41
+
42
+ <Field label="Date Of Birth">
43
+ <DateInput onChange={fn} />
44
+ </Field>
45
+
46
+ <Field label="Date Of Birth with Description" description={lorem10}>
47
+ <DateInput onChange={fn} />
48
+ </Field>
49
+
50
+ <Field label="Search business">
51
+ <SearchInput />
52
+ </Field>
53
+
54
+ <Field label="Textarea">
55
+ <TextArea />
56
+ </Field>
57
+
58
+ <Field label="Textarea with Description" description="This a TextArea Description">
59
+ <TextArea />
60
+ </Field>
61
+
62
+ <Field
63
+ label="Textarea with Validation Error"
64
+ description="This a TextArea Description"
65
+ message={lorem10}
66
+ sentiment="negative"
67
+ >
68
+ <TextArea />
69
+ </Field>
70
+
71
+ <Field
72
+ label={
73
+ <>
74
+ Label with Suffix <Info content={lorem40} />
75
+ </>
76
+ }
77
+ >
78
+ <TextArea />
79
+ </Field>
80
+ </div>
81
+ </div>
19
82
  );
20
83
  };
21
84
 
@@ -23,16 +86,51 @@ export const WithStatusMessages = () => {
23
86
  const [value, setValue] = useState<string | undefined>('This is some text');
24
87
  return (
25
88
  <div>
26
- <Field label="Phone number" sentiment={Sentiment.POSITIVE} message="Positive message">
89
+ <Field
90
+ label="Text Input with Positive Message"
91
+ sentiment={Sentiment.POSITIVE}
92
+ message="Positive message"
93
+ >
27
94
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
28
95
  </Field>
29
- <Field label="Phone number" sentiment={Sentiment.WARNING} message="Warning message">
96
+
97
+ <Field
98
+ label="Text Input with Warning Message"
99
+ sentiment={Sentiment.WARNING}
100
+ message="Warning message"
101
+ >
30
102
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
31
103
  </Field>
32
- <Field label="Phone number" sentiment={Sentiment.NEGATIVE} message="This is a required field">
104
+
105
+ <Field
106
+ label="Text Input with Validation Error"
107
+ sentiment={Sentiment.NEGATIVE}
108
+ message="This is a required field"
109
+ >
110
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
111
+ </Field>
112
+
113
+ {/* instance with deprecated `hint` prop */}
114
+ <Field
115
+ label="Text Input with deprecated `hint` prop"
116
+ hint="This is a helpful message"
117
+ sentiment={Sentiment.NEGATIVE}
118
+ message="Validation error, please take a look"
119
+ >
33
120
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
34
121
  </Field>
35
- <Field label="Phone number" message="This is a helpful message">
122
+
123
+ {/* instance with deprecated `error` & `hint` props */}
124
+ <Field
125
+ label="Text Input with deprecated `error` & `hint` props"
126
+ hint="This is a helpful message"
127
+ error="Validation error, please take a look"
128
+ >
129
+ <Input value={value} onChange={({ target }) => setValue(target.value)} />
130
+ </Field>
131
+
132
+ {/* instance of info via `message` property, this is rare case (e.g MoneyInput) */}
133
+ <Field label="Text Input with Info under the field" message="This is a helpful message">
36
134
  <Input value={value} onChange={({ target }) => setValue(target.value)} />
37
135
  </Field>
38
136
  </div>