@transferwise/components 0.0.0-experimental-2fa5e3f → 0.0.0-experimental-c09cb11

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 (75) 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 +34 -7
  6. package/build/field/Field.js.map +1 -1
  7. package/build/field/Field.mjs +34 -7
  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/inlineAlert/InlineAlert.js +13 -6
  15. package/build/inlineAlert/InlineAlert.js.map +1 -1
  16. package/build/inlineAlert/InlineAlert.mjs +13 -6
  17. package/build/inlineAlert/InlineAlert.mjs.map +1 -1
  18. package/build/label/Label.js +49 -5
  19. package/build/label/Label.js.map +1 -1
  20. package/build/label/Label.messages.js +12 -0
  21. package/build/label/Label.messages.js.map +1 -0
  22. package/build/label/Label.messages.mjs +10 -0
  23. package/build/label/Label.messages.mjs.map +1 -0
  24. package/build/label/Label.mjs +50 -6
  25. package/build/label/Label.mjs.map +1 -1
  26. package/build/main.css +4 -8
  27. package/build/styles/dateLookup/dateTrigger/DateTrigger.css +0 -8
  28. package/build/styles/field/Field.css +4 -0
  29. package/build/styles/main.css +4 -8
  30. package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts.map +1 -1
  31. package/build/types/field/Field.d.ts +4 -2
  32. package/build/types/field/Field.d.ts.map +1 -1
  33. package/build/types/index.d.ts +1 -1
  34. package/build/types/index.d.ts.map +1 -1
  35. package/build/types/inlineAlert/InlineAlert.d.ts +9 -0
  36. package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
  37. package/build/types/label/Label.d.ts +39 -3
  38. package/build/types/label/Label.d.ts.map +1 -1
  39. package/build/types/label/Label.messages.d.ts +8 -0
  40. package/build/types/label/Label.messages.d.ts.map +1 -0
  41. package/build/types/label/index.d.ts +3 -0
  42. package/build/types/label/index.d.ts.map +1 -0
  43. package/package.json +3 -3
  44. package/src/dateInput/DateInput.tests.story.tsx +6 -41
  45. package/src/dateLookup/DateLookup.rtl.spec.tsx +1 -1
  46. package/src/dateLookup/dateTrigger/DateTrigger.css +0 -8
  47. package/src/dateLookup/dateTrigger/DateTrigger.less +0 -8
  48. package/src/dateLookup/dateTrigger/DateTrigger.spec.js +1 -1
  49. package/src/dateLookup/dateTrigger/DateTrigger.tsx +9 -4
  50. package/src/field/Field.css +4 -0
  51. package/src/field/Field.less +5 -0
  52. package/src/field/Field.spec.tsx +41 -5
  53. package/src/field/Field.story.tsx +105 -7
  54. package/src/field/Field.tsx +33 -9
  55. package/src/i18n/en.json +1 -0
  56. package/src/index.ts +1 -1
  57. package/src/inlineAlert/InlineAlert.story.tsx +7 -72
  58. package/src/inlineAlert/InlineAlert.tsx +14 -3
  59. package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.js +5 -10
  60. package/src/inputs/InputGroup.spec.tsx +1 -1
  61. package/src/inputs/SearchInput.spec.tsx +1 -1
  62. package/src/inputs/SelectInput.spec.tsx +1 -1
  63. package/src/label/Label.messages.tsx +8 -0
  64. package/src/label/Label.spec.tsx +42 -7
  65. package/src/label/Label.story.tsx +30 -25
  66. package/src/label/Label.tsx +66 -8
  67. package/src/label/index.ts +2 -0
  68. package/src/main.css +4 -8
  69. package/src/main.less +1 -0
  70. package/src/moneyInput/MoneyInput.story.tsx +11 -11
  71. package/src/radioGroup/RadioGroup.rtl.spec.tsx +1 -1
  72. package/src/select/Select.rtl.spec.tsx +1 -1
  73. package/src/switch/Switch.spec.tsx +1 -1
  74. package/src/switch/Switch.story.tsx +19 -21
  75. package/src/field/Field.tests.story.tsx +0 -33
@@ -1,20 +1,78 @@
1
1
  import { clsx } from 'clsx';
2
+ import messages from './Label.messages';
3
+ import { useIntl } from 'react-intl';
4
+ import Body from '../body';
5
+ import { CommonProps } from '../common';
6
+ import { PropsWithChildren } from 'react';
2
7
 
3
8
  export type LabelProps = {
4
- id?: string;
5
- htmlFor?: string;
6
9
  className?: string;
7
10
  children?: React.ReactNode;
8
11
  };
9
12
 
10
- export const Label = ({ id, htmlFor, className, children }: LabelProps) => {
13
+ /**
14
+ * Avoid using `<Label>` component directly
15
+ * it's for edge cases when `<Field />` isn't suitable for some reasons.
16
+ *
17
+ * Example:
18
+ * ```
19
+ * <Field label={..} description={..} required={..}>..</Field>
20
+ * ```
21
+ */
22
+ const Label = ({ className, children }: LabelProps) => {
23
+ return <div className={clsx('np-label d-flex flex-column', className)}>{children}</div>;
24
+ };
25
+
26
+ export type LabelOptionalProps = PropsWithChildren<CommonProps> & {
27
+ id?: string;
28
+ required?: boolean;
29
+ /**
30
+ * Connect label with form control via `htmlFor` prop, or `id` + `aria-labelledby`
31
+ */
32
+ htmlFor?: string | undefined;
33
+ };
34
+
35
+ /**
36
+ * Avoid wrapping form control with `<Label.Text >`, always connect label and control via `htmlFor` + `id` props
37
+ *
38
+ * Example:
39
+ * ```
40
+ * <Label>
41
+ * <Label.Text htmlFor="foo">Money input with label</Label.Text>
42
+ * <CustomComponent id="foo" />
43
+ * </Label>
44
+ * ```
45
+ */
46
+ // eslint-disable-next-line functional/immutable-data
47
+ Label.Text = function Text({
48
+ id,
49
+ children,
50
+ required = false,
51
+ htmlFor,
52
+ className,
53
+ }: LabelOptionalProps) {
54
+ const { formatMessage } = useIntl();
11
55
  return (
12
- <label
13
- id={id}
14
- htmlFor={htmlFor}
15
- className={clsx('control-label d-flex flex-column gap-y-1 m-b-0', className)}
16
- >
56
+ <label id={id} htmlFor={htmlFor} className="np-text-body-default-bold text-primary m-b-0">
17
57
  {children}
58
+ {required ? null : (
59
+ <Body as="span" className={clsx('text-secondary', 'm-l-1', className)}>
60
+ {formatMessage(messages.optionalLabel)}
61
+ </Body>
62
+ )}
18
63
  </label>
19
64
  );
20
65
  };
66
+
67
+ export type LabelDescriptionProps = PropsWithChildren<CommonProps> & { id?: string };
68
+
69
+ // eslint-disable-next-line functional/immutable-data
70
+ Label.Description = function Description({ id, children, className }: LabelDescriptionProps) {
71
+ return children ? (
72
+ <Body id={id} className={clsx('text-secondary', className)}>
73
+ {children}
74
+ </Body>
75
+ ) : null;
76
+ };
77
+
78
+ export { Label };
@@ -0,0 +1,2 @@
1
+ export { Label } from './Label';
2
+ export type { LabelProps, LabelOptionalProps, LabelDescriptionProps } from './Label';
package/src/main.css CHANGED
@@ -1719,18 +1719,10 @@ button.np-option {
1719
1719
  white-space: nowrap;
1720
1720
  width: 100%;
1721
1721
  }
1722
- .np-date-trigger .control-label {
1723
- font-weight: 400;
1724
- font-weight: var(--font-weight-regular);
1725
- }
1726
1722
  .np-theme-personal .np-date-trigger {
1727
1723
  padding-left: 16px;
1728
1724
  padding-left: var(--size-16);
1729
1725
  }
1730
- .np-theme-personal .np-date-trigger .control-label + span {
1731
- font-weight: 400;
1732
- font-weight: var(--font-weight-regular);
1733
- }
1734
1726
  .clear-btn {
1735
1727
  transition: color 0.15s ease-in-out;
1736
1728
  color: #c9cbce;
@@ -2385,6 +2377,10 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
2385
2377
  border-radius: 9999px !important;
2386
2378
  border-radius: var(--radius-full) !important;
2387
2379
  }
2380
+ .np-field-control {
2381
+ margin-top: 4px;
2382
+ margin-top: var(--size-4);
2383
+ }
2388
2384
  .np-input-group {
2389
2385
  display: inline-grid;
2390
2386
  width: 100%;
package/src/main.less CHANGED
@@ -32,6 +32,7 @@
32
32
  @import "./image/Image.less";
33
33
  @import "./info/Info.less";
34
34
  @import "./inputs/Input.less";
35
+ @import "./field/Field.less";
35
36
  @import "./inputs/InputGroup.less";
36
37
  @import "./inputs/SelectInput.less";
37
38
  @import "./inputs/TextArea.less";
@@ -4,8 +4,7 @@ import { Lock } from '@transferwise/icons';
4
4
  import { useState } from 'react';
5
5
 
6
6
  import MoneyInput, { CurrencyOptionItem } from '.';
7
- import Provider from '../provider/Provider';
8
- import translations from '../i18n';
7
+ import { Field } from '../field/Field';
9
8
 
10
9
  export default {
11
10
  component: MoneyInput,
@@ -17,14 +16,13 @@ export default {
17
16
  const handleOnCurrencyChange = (value: CurrencyOptionItem) => setSelectedCurrency(value);
18
17
 
19
18
  return (
20
- <>
21
- <label htmlFor={args.id}>Editable money input label</label>
19
+ <Field id={args.id} label="Editable money input label" required>
22
20
  <MoneyInput
23
21
  {...args}
24
22
  selectedCurrency={selectedCurrency}
25
23
  onCurrencyChange={handleOnCurrencyChange}
26
24
  />
27
- </>
25
+ </Field>
28
26
  );
29
27
  },
30
28
  args: {
@@ -161,17 +159,19 @@ export const SmallInput: Story = {
161
159
  render: (args) => {
162
160
  return (
163
161
  <>
164
- <label htmlFor={args.id}>Money inputs</label>
165
- <MoneyInput {...args} {...SingleCurrency.args} />
162
+ <Field id={args.id} label="Money inputs" required>
163
+ <MoneyInput {...args} {...SingleCurrency.args} />
164
+ </Field>
166
165
  <br />
167
166
  <MoneyInput {...args} {...MultipleCurrencies.args} />
168
167
  <hr />
169
- <div className="has-error">
170
- <label htmlFor={args.id}>Error states</label>
168
+ <Field id={args.id} label="Error states" sentiment="negative" required>
171
169
  <MoneyInput {...args} {...SingleCurrency.args} />
172
- <br />
170
+ </Field>
171
+ <br />
172
+ <Field sentiment="negative">
173
173
  <MoneyInput {...args} {...MultipleCurrencies.args} />
174
- </div>
174
+ </Field>
175
175
  </>
176
176
  );
177
177
  },
@@ -1,4 +1,4 @@
1
- import { render, screen } from '@testing-library/react';
1
+ import { render, screen } from '../test-utils';
2
2
 
3
3
  import RadioGroup from '.';
4
4
  import { Field } from '../field/Field';
@@ -12,6 +12,6 @@ describe('Select', () => {
12
12
  <Select options={options} selected={options[0]} onChange={() => {}} />
13
13
  </Field>,
14
14
  );
15
- expect(screen.getByLabelText('Currency')).toHaveTextContent('USD');
15
+ expect(screen.getByLabelText(/Currency/)).toHaveTextContent('USD');
16
16
  });
17
17
  });
@@ -89,6 +89,6 @@ describe('Switch', () => {
89
89
  <Switch checked onClick={props.onClick} />
90
90
  </Field>,
91
91
  );
92
- expect(screen.getByLabelText('Dark mode')).toHaveAttribute('role', 'switch');
92
+ expect(screen.getByLabelText(/Dark mode/)).toHaveAttribute('role', 'switch');
93
93
  });
94
94
  });
@@ -1,6 +1,7 @@
1
1
  import { useState } from 'react';
2
2
 
3
3
  import Switch from './Switch';
4
+ import { Field } from '../field/Field';
4
5
 
5
6
  export default {
6
7
  component: Switch,
@@ -13,16 +14,14 @@ export const Basic = () => {
13
14
 
14
15
  return (
15
16
  <div className="d-flex flex-column">
16
- <label id="labelID" htmlFor="switchId">
17
- A switch with a label
18
- </label>
19
- <Switch
20
- checked={checked1}
21
- className="a-class-name"
22
- aria-labelledby="labelID"
23
- id="switchId"
24
- onClick={() => setCheck1(!checked1)}
25
- />
17
+ <Field id="switchId" label="A switch with a label" required>
18
+ <Switch
19
+ checked={checked1}
20
+ className="a-class-name"
21
+ id="switchId"
22
+ onClick={() => setCheck1(!checked1)}
23
+ />
24
+ </Field>
26
25
 
27
26
  <Switch
28
27
  checked={checked2}
@@ -39,17 +38,16 @@ export const Disabled = () => {
39
38
 
40
39
  return (
41
40
  <div className="d-flex flex-column">
42
- <label id="labelID" htmlFor="switchId">
43
- A switch with a label
44
- </label>
45
- <Switch
46
- checked={checked}
47
- disabled
48
- className="a-class-name"
49
- aria-labelledby="labelID"
50
- id="switchId"
51
- onClick={() => setCheck(!checked)}
52
- />
41
+ <Field id="switchId" label="A switch with a label" required>
42
+ <Switch
43
+ checked={checked}
44
+ disabled
45
+ className="a-class-name"
46
+ aria-labelledby="labelID"
47
+ id="switchId"
48
+ onClick={() => setCheck(!checked)}
49
+ />
50
+ </Field>
53
51
 
54
52
  <Switch
55
53
  checked={!checked}
@@ -1,33 +0,0 @@
1
- import { useState } from 'react';
2
-
3
- import { Input } from '../inputs/Input';
4
- import { Field } from './Field';
5
- import { Sentiment } from '../common';
6
-
7
- export default {
8
- component: Field,
9
- title: 'Field/Tests',
10
- };
11
-
12
- export const WithHelpAndErrorOnBlur = () => {
13
- const [value, setValue] = useState('This is some text');
14
- const [error, setError] = useState<string | undefined>(undefined);
15
- return (
16
- <Field
17
- label="Phone number"
18
- sentiment={error ? Sentiment.NEGATIVE : Sentiment.NEUTRAL}
19
- message={error || 'Please include country code'}
20
- >
21
- <Input
22
- value={value}
23
- onChange={({ target }) => {
24
- setValue(target.value);
25
- setError(undefined);
26
- }}
27
- onBlur={() => {
28
- setError('Something went wrong');
29
- }}
30
- />
31
- </Field>
32
- );
33
- };