@transferwise/components 0.0.0-experimental-e3593b2 → 0.0.0-experimental-a33db42
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.
- package/build/dateLookup/dateTrigger/DateTrigger.js +4 -8
- package/build/dateLookup/dateTrigger/DateTrigger.js.map +1 -1
- package/build/dateLookup/dateTrigger/DateTrigger.mjs +4 -8
- package/build/dateLookup/dateTrigger/DateTrigger.mjs.map +1 -1
- package/build/field/Field.js +2 -9
- package/build/field/Field.js.map +1 -1
- package/build/field/Field.mjs +2 -9
- package/build/field/Field.mjs.map +1 -1
- package/build/i18n/en.json +1 -3
- package/build/i18n/en.json.js +1 -3
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +1 -3
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/label/Label.js +1 -29
- package/build/label/Label.js.map +1 -1
- package/build/label/Label.mjs +2 -30
- package/build/label/Label.mjs.map +1 -1
- package/build/main.css +8 -0
- package/build/moneyInput/MoneyInput.js +11 -29
- package/build/moneyInput/MoneyInput.js.map +1 -1
- package/build/moneyInput/MoneyInput.mjs +11 -29
- package/build/moneyInput/MoneyInput.mjs.map +1 -1
- package/build/styles/dateLookup/dateTrigger/DateTrigger.css +8 -0
- package/build/styles/main.css +8 -0
- package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts.map +1 -1
- package/build/types/field/Field.d.ts +2 -4
- package/build/types/field/Field.d.ts.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/label/Label.d.ts +1 -10
- package/build/types/label/Label.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.d.ts +0 -1
- package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/dateInput/DateInput.tests.story.tsx +32 -8
- package/src/dateLookup/DateLookup.rtl.spec.tsx +1 -1
- package/src/dateLookup/dateTrigger/DateTrigger.css +8 -0
- package/src/dateLookup/dateTrigger/DateTrigger.less +8 -0
- package/src/dateLookup/dateTrigger/DateTrigger.spec.js +1 -1
- package/src/dateLookup/dateTrigger/DateTrigger.tsx +4 -9
- package/src/field/Field.spec.tsx +3 -3
- package/src/field/Field.story.tsx +3 -40
- package/src/field/Field.tests.story.tsx +33 -0
- package/src/field/Field.tsx +6 -12
- package/src/i18n/en.json +1 -3
- package/src/index.ts +1 -1
- package/src/inlineAlert/InlineAlert.story.tsx +21 -8
- package/src/inputs/InputGroup.spec.tsx +1 -1
- package/src/inputs/SearchInput.spec.tsx +1 -1
- package/src/inputs/SelectInput.spec.tsx +1 -1
- package/src/label/Label.story.tsx +21 -37
- package/src/label/Label.tsx +2 -44
- package/src/main.css +8 -0
- package/src/moneyInput/MoneyInput.story.tsx +0 -34
- package/src/moneyInput/MoneyInput.tsx +0 -21
- package/src/radioGroup/RadioGroup.rtl.spec.tsx +1 -1
- package/src/select/Select.rtl.spec.tsx +1 -1
- package/src/switch/Switch.spec.tsx +1 -1
- package/build/label/Label.messages.js +0 -15
- package/build/label/Label.messages.js.map +0 -1
- package/build/label/Label.messages.mjs +0 -13
- package/build/label/Label.messages.mjs.map +0 -1
- package/build/types/label/Label.messages.d.ts +0 -12
- package/build/types/label/Label.messages.d.ts.map +0 -1
- package/build/types/label/index.d.ts +0 -3
- package/build/types/label/index.d.ts.map +0 -1
- package/src/label/Label.messages.tsx +0 -12
- package/src/label/index.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-a33db42",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -93,12 +93,12 @@
|
|
|
93
93
|
"rollup-preserve-directives": "^1.1.1",
|
|
94
94
|
"storybook": "^8.2.2",
|
|
95
95
|
"@transferwise/less-config": "3.1.0",
|
|
96
|
-
"@transferwise/neptune-css": "
|
|
96
|
+
"@transferwise/neptune-css": "14.12.1",
|
|
97
97
|
"@wise/components-theming": "1.4.0"
|
|
98
98
|
},
|
|
99
99
|
"peerDependencies": {
|
|
100
100
|
"@transferwise/icons": "^3.7.0",
|
|
101
|
-
"@transferwise/neptune-css": "
|
|
101
|
+
"@transferwise/neptune-css": "^14.9.6",
|
|
102
102
|
"@wise/art": "^2.7.0",
|
|
103
103
|
"@wise/components-theming": "^1.0.0",
|
|
104
104
|
"react": ">=18",
|
|
@@ -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,
|
|
4
|
+
import { DateInput, DateMode, Info, InlineAlert, Title, Typography } from '..';
|
|
5
5
|
import { lorem10, storyConfig } from '../test-utils';
|
|
6
6
|
|
|
7
7
|
import Provider from '../provider/Provider';
|
|
@@ -39,19 +39,43 @@ export const WithLabel = {
|
|
|
39
39
|
},
|
|
40
40
|
render: (args) => {
|
|
41
41
|
const id1 = 'date-input-group-label-1';
|
|
42
|
+
const label = 'Date of Birth';
|
|
42
43
|
|
|
43
44
|
return (
|
|
44
45
|
<>
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
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} />
|
|
49
54
|
|
|
50
55
|
<br />
|
|
51
56
|
|
|
52
|
-
<
|
|
53
|
-
<DateInput
|
|
54
|
-
|
|
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>
|
|
55
79
|
</>
|
|
56
80
|
);
|
|
57
81
|
},
|
|
@@ -28,7 +28,7 @@ describe('DateLookup', () => {
|
|
|
28
28
|
</Field>,
|
|
29
29
|
);
|
|
30
30
|
// TODO: Replace with `.toHaveAttribute('aria-haspopup')`
|
|
31
|
-
expect(screen.getByLabelText(
|
|
31
|
+
expect(screen.getByLabelText('Date of birth')).toHaveTextContent(
|
|
32
32
|
initialValue.getFullYear().toString(),
|
|
33
33
|
);
|
|
34
34
|
});
|
|
@@ -4,10 +4,18 @@
|
|
|
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
|
+
}
|
|
7
11
|
.np-theme-personal .np-date-trigger {
|
|
8
12
|
padding-left: 16px;
|
|
9
13
|
padding-left: var(--size-16);
|
|
10
14
|
}
|
|
15
|
+
.np-theme-personal .np-date-trigger .control-label + span {
|
|
16
|
+
font-weight: 400;
|
|
17
|
+
font-weight: var(--font-weight-regular);
|
|
18
|
+
}
|
|
11
19
|
.clear-btn {
|
|
12
20
|
transition: color 0.15s ease-in-out;
|
|
13
21
|
color: #c9cbce;
|
|
@@ -7,8 +7,16 @@
|
|
|
7
7
|
white-space: nowrap;
|
|
8
8
|
width: 100%;
|
|
9
9
|
|
|
10
|
+
.control-label {
|
|
11
|
+
font-weight: var(--font-weight-regular);
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
.np-theme-personal & {
|
|
11
15
|
padding-left: var(--size-16);
|
|
16
|
+
|
|
17
|
+
.control-label + span {
|
|
18
|
+
font-weight: var(--font-weight-regular);
|
|
19
|
+
}
|
|
12
20
|
}
|
|
13
21
|
}
|
|
14
22
|
|
|
@@ -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('.
|
|
122
|
+
const label = () => component.find('.control-label');
|
|
123
123
|
});
|
|
@@ -2,13 +2,12 @@ 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
|
|
5
|
+
import { Size, Position, SizeSmall, SizeMedium, SizeLarge } 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';
|
|
12
11
|
|
|
13
12
|
interface DateTriggerProps {
|
|
14
13
|
selectedDate: Date | null;
|
|
@@ -46,19 +45,15 @@ const DateTrigger: React.FC<DateTriggerProps> = ({
|
|
|
46
45
|
type="button"
|
|
47
46
|
onClick={onClick}
|
|
48
47
|
>
|
|
49
|
-
{label &&
|
|
50
|
-
<Body as="span" className="np-date-trigger-label m-r-1">
|
|
51
|
-
{label}
|
|
52
|
-
</Body>
|
|
53
|
-
)}
|
|
48
|
+
{label && <span className="control-label small m-r-1">{label}</span>}
|
|
54
49
|
{selectedDate ? (
|
|
55
|
-
<
|
|
50
|
+
<span className="font-weight-normal">
|
|
56
51
|
{formatDate(selectedDate, locale, {
|
|
57
52
|
day: 'numeric',
|
|
58
53
|
month: monthFormat,
|
|
59
54
|
year: 'numeric',
|
|
60
55
|
})}
|
|
61
|
-
</
|
|
56
|
+
</span>
|
|
62
57
|
) : (
|
|
63
58
|
<span
|
|
64
59
|
className="form-control-placeholder visible-xs-inline visible-sm-inline
|
package/src/field/Field.spec.tsx
CHANGED
|
@@ -14,7 +14,7 @@ describe('Field', () => {
|
|
|
14
14
|
</Field>,
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
expect(screen.getByLabelText(
|
|
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.
|
|
28
|
+
const textbox = screen.getByRole('textbox', { description: 'This is help text' });
|
|
29
29
|
expect(textbox).toBeInTheDocument();
|
|
30
30
|
expect(textbox).not.toBeInvalid();
|
|
31
31
|
});
|
|
@@ -50,7 +50,7 @@ describe('Field', () => {
|
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
expect(screen.getByRole('textbox', { description: 'This is error text' })).toBeInTheDocument();
|
|
53
|
-
expect(screen.
|
|
53
|
+
expect(screen.queryByText('This is help text')).not.toBeInTheDocument();
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('avoids triggering button within label inadvertently', async () => {
|
|
@@ -13,17 +13,9 @@ export default {
|
|
|
13
13
|
export const Basic = () => {
|
|
14
14
|
const [value, setValue] = useState<string | undefined>('This is some text');
|
|
15
15
|
return (
|
|
16
|
-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
</Field>
|
|
20
|
-
<Field label="Phone number">
|
|
21
|
-
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
22
|
-
</Field>
|
|
23
|
-
<Field label="Phone number" description="Please provide you primary phone number">
|
|
24
|
-
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
25
|
-
</Field>
|
|
26
|
-
</>
|
|
16
|
+
<Field label="Phone number">
|
|
17
|
+
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
18
|
+
</Field>
|
|
27
19
|
);
|
|
28
20
|
};
|
|
29
21
|
|
|
@@ -40,35 +32,6 @@ export const WithStatusMessages = () => {
|
|
|
40
32
|
<Field label="Phone number" sentiment={Sentiment.NEGATIVE} message="This is a required field">
|
|
41
33
|
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
42
34
|
</Field>
|
|
43
|
-
|
|
44
|
-
{/* instance with deprecated `hint` prop */}
|
|
45
|
-
<Field
|
|
46
|
-
label="Phone number"
|
|
47
|
-
hint="This is a helpful message"
|
|
48
|
-
sentiment={Sentiment.NEGATIVE}
|
|
49
|
-
message="Validation error, please take a look"
|
|
50
|
-
>
|
|
51
|
-
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
52
|
-
</Field>
|
|
53
|
-
{/* instance with deprecated `error` & `hint` props */}
|
|
54
|
-
<Field
|
|
55
|
-
label="Phone number"
|
|
56
|
-
hint="This is a helpful message"
|
|
57
|
-
error="Validation error, please take a look"
|
|
58
|
-
>
|
|
59
|
-
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
60
|
-
</Field>
|
|
61
|
-
|
|
62
|
-
<Field
|
|
63
|
-
label="Phone number"
|
|
64
|
-
description="This is a helpful message"
|
|
65
|
-
sentiment={Sentiment.NEGATIVE}
|
|
66
|
-
message="Validation error, please take a look"
|
|
67
|
-
>
|
|
68
|
-
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
69
|
-
</Field>
|
|
70
|
-
|
|
71
|
-
{/* instance of info via `message` property, this is rare case (e.g MoneyInput) */}
|
|
72
35
|
<Field label="Phone number" message="This is a helpful message">
|
|
73
36
|
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
74
37
|
</Field>
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
};
|
package/src/field/Field.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import {
|
|
2
|
+
import { useId } from 'react';
|
|
3
3
|
|
|
4
4
|
import { Sentiment } from '../common';
|
|
5
5
|
import InlineAlert from '../inlineAlert/InlineAlert';
|
|
@@ -9,18 +9,16 @@ import {
|
|
|
9
9
|
InputIdContextProvider,
|
|
10
10
|
InputInvalidProvider,
|
|
11
11
|
} from '../inputs/contexts';
|
|
12
|
-
import { Label } from '../label';
|
|
12
|
+
import { Label } from '../label/Label';
|
|
13
13
|
|
|
14
14
|
export type FieldProps = {
|
|
15
15
|
/** `null` disables auto-generating the `id` attribute, falling back to nesting-based label association over setting `htmlFor` explicitly. */
|
|
16
16
|
id?: string | null;
|
|
17
17
|
/** Should be specified unless the wrapped control has its own labeling mechanism, e.g. `Checkbox`. */
|
|
18
18
|
label?: React.ReactNode;
|
|
19
|
-
|
|
20
|
-
/** @deprecated use `description` prop instead */
|
|
19
|
+
/** @deprecated use `message` and `type={Sentiment.NEUTRAL}` prop instead */
|
|
21
20
|
hint?: React.ReactNode;
|
|
22
21
|
message?: React.ReactNode;
|
|
23
|
-
description?: React.ReactNode;
|
|
24
22
|
/** @deprecated use `message` and `type={Sentiment.NEGATIVE}` prop instead */
|
|
25
23
|
error?: React.ReactNode;
|
|
26
24
|
sentiment?: `${Sentiment.NEGATIVE | Sentiment.NEUTRAL | Sentiment.POSITIVE | Sentiment.WARNING}`;
|
|
@@ -31,23 +29,20 @@ export type FieldProps = {
|
|
|
31
29
|
export const Field = ({
|
|
32
30
|
id,
|
|
33
31
|
label,
|
|
34
|
-
required = false,
|
|
35
32
|
message: propMessage,
|
|
36
|
-
hint,
|
|
37
|
-
description = hint,
|
|
38
33
|
sentiment: propType = Sentiment.NEUTRAL,
|
|
39
34
|
className,
|
|
40
35
|
children,
|
|
41
36
|
...props
|
|
42
37
|
}: FieldProps) => {
|
|
43
38
|
const sentiment = props.error ? Sentiment.NEGATIVE : propType;
|
|
44
|
-
const message =
|
|
39
|
+
const message = props.error || props.hint || propMessage;
|
|
45
40
|
const hasError = sentiment === Sentiment.NEGATIVE;
|
|
46
41
|
|
|
47
42
|
const labelId = useId();
|
|
48
43
|
|
|
49
44
|
const fallbackInputId = useId();
|
|
50
|
-
const inputId = id !== null ?
|
|
45
|
+
const inputId = id !== null ? id ?? fallbackInputId : undefined;
|
|
51
46
|
|
|
52
47
|
const descriptionId = useId();
|
|
53
48
|
|
|
@@ -70,8 +65,7 @@ export const Field = ({
|
|
|
70
65
|
>
|
|
71
66
|
{label != null ? (
|
|
72
67
|
<Label id={labelId} htmlFor={inputId}>
|
|
73
|
-
{
|
|
74
|
-
{description && <Label.Description>{description}</Label.Description>}
|
|
68
|
+
{label}
|
|
75
69
|
{children}
|
|
76
70
|
</Label>
|
|
77
71
|
) : (
|
package/src/i18n/en.json
CHANGED
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"neptune.DateLookup.year": "year",
|
|
19
19
|
"neptune.FlowNavigation.back": "back to previous step",
|
|
20
20
|
"neptune.Info.ariaLabel": "More information",
|
|
21
|
-
"neptune.Label.optional": "(Optional)",
|
|
22
21
|
"neptune.Link.opensInNewTab": "(opens in new tab)",
|
|
23
22
|
"neptune.MoneyInput.Select.placeholder": "Select an option...",
|
|
24
23
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "Select an option...",
|
|
@@ -56,6 +55,5 @@
|
|
|
56
55
|
"neptune.UploadItem.uploaded": "Uploaded",
|
|
57
56
|
"neptune.UploadItem.uploadedFile": "Uploaded file",
|
|
58
57
|
"neptune.UploadItem.uploading": "Uploading...",
|
|
59
|
-
"neptune.UploadItem.uploadingFailed": "Uploading failed"
|
|
60
|
-
"neptune.aria.Label.optional": "This field is optional"
|
|
58
|
+
"neptune.UploadItem.uploadingFailed": "Uploading failed"
|
|
61
59
|
}
|
package/src/index.ts
CHANGED
|
@@ -44,7 +44,7 @@ export type {
|
|
|
44
44
|
} from './inputs/SelectInput';
|
|
45
45
|
export type { TextAreaProps } from './inputs/TextArea';
|
|
46
46
|
export type { InstructionsListProps } from './instructionsList';
|
|
47
|
-
export type { LabelProps
|
|
47
|
+
export type { LabelProps } from './label/Label';
|
|
48
48
|
export type { LoaderProps } from './loader';
|
|
49
49
|
export type { MarkdownProps } from './markdown';
|
|
50
50
|
export type { ModalProps } from './modal';
|
|
@@ -5,8 +5,6 @@ import { Sentiment } from '../common';
|
|
|
5
5
|
import { Input } from '../inputs/Input';
|
|
6
6
|
|
|
7
7
|
import InlineAlert, { InlineAlertProps } from './InlineAlert';
|
|
8
|
-
import { Label } from '../label';
|
|
9
|
-
import { lorem40 } from '../test-utils';
|
|
10
8
|
|
|
11
9
|
export default {
|
|
12
10
|
component: InlineAlert,
|
|
@@ -68,26 +66,41 @@ export const Basic = () => {
|
|
|
68
66
|
this manually.
|
|
69
67
|
</p>
|
|
70
68
|
<div className={`form-group ${typeClass}`}>
|
|
71
|
-
<
|
|
69
|
+
<label className="control-label" htmlFor="id0">
|
|
70
|
+
Toggleable
|
|
71
|
+
</label>
|
|
72
72
|
<Input id="id0" value="Neptune is cool" />
|
|
73
73
|
<InlineAlert type={type}>{message}</InlineAlert>
|
|
74
74
|
</div>
|
|
75
75
|
<div className="form-group has-error">
|
|
76
|
-
<
|
|
76
|
+
<label className="control-label" htmlFor="id1">
|
|
77
|
+
Negative
|
|
78
|
+
</label>
|
|
77
79
|
<Input id="id1" value="Neptune is cool" />
|
|
78
80
|
<InlineAlert type="negative">{message}</InlineAlert>
|
|
79
81
|
</div>
|
|
80
82
|
<div className="form-group has-success">
|
|
81
|
-
<
|
|
83
|
+
<label className="control-label" htmlFor="id2">
|
|
84
|
+
Positive
|
|
85
|
+
</label>
|
|
82
86
|
<Input id="id2" value="Neptune is cool" />
|
|
83
|
-
<InlineAlert type="positive">
|
|
87
|
+
<InlineAlert type="positive">
|
|
88
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
|
|
89
|
+
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
|
90
|
+
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
|
91
|
+
</InlineAlert>
|
|
84
92
|
</div>
|
|
85
93
|
<div className="form-group has-neutral">
|
|
86
|
-
<
|
|
94
|
+
<label className="control-label" htmlFor="id3">
|
|
95
|
+
Neutral
|
|
96
|
+
</label>
|
|
87
97
|
<Input id="id3" value="Neptune is cool" />
|
|
98
|
+
<InlineAlert type="neutral">{message}</InlineAlert>
|
|
88
99
|
</div>
|
|
89
100
|
<div className="form-group">
|
|
90
|
-
<label htmlFor="id4">
|
|
101
|
+
<label className="control-label" htmlFor="id4">
|
|
102
|
+
No has-* class
|
|
103
|
+
</label>
|
|
91
104
|
<Input id="id4" value="Neptune is cool" />
|
|
92
105
|
<InlineAlert type="negative">{message}</InlineAlert>
|
|
93
106
|
</div>
|
|
@@ -214,6 +214,6 @@ describe('SelectInput', () => {
|
|
|
214
214
|
<SelectInput items={[{ type: 'option', value: 'USD' }]} value="USD" />
|
|
215
215
|
</Field>,
|
|
216
216
|
);
|
|
217
|
-
expect(screen.getByLabelText(
|
|
217
|
+
expect(screen.getByLabelText('Currency')).toHaveAttribute('aria-haspopup');
|
|
218
218
|
});
|
|
219
219
|
});
|
|
@@ -1,53 +1,37 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
|
|
3
|
+
import Info from '../info/Info';
|
|
3
4
|
import { Input } from '../inputs/Input';
|
|
4
5
|
import { Label } from './Label';
|
|
5
|
-
import InlineAlert from '../inlineAlert/InlineAlert';
|
|
6
|
-
import { lorem10 } from '../test-utils';
|
|
7
6
|
|
|
8
7
|
export default {
|
|
9
8
|
component: Label,
|
|
10
9
|
title: 'Label',
|
|
11
|
-
tags: ['autodocs'],
|
|
12
10
|
};
|
|
13
11
|
|
|
14
12
|
export const Basic = () => {
|
|
15
13
|
const [value, setValue] = useState<string | undefined>('This is some text');
|
|
16
14
|
return (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<Label className="m-b-2">
|
|
24
|
-
<Label.Optional>Phone number</Label.Optional>
|
|
25
|
-
<Input value={value} id="input" onChange={({ target }) => setValue(target.value)} />
|
|
26
|
-
</Label>
|
|
27
|
-
|
|
28
|
-
<Label className="m-b-2">
|
|
29
|
-
<Label.Optional>Phone number</Label.Optional>
|
|
30
|
-
<Label.Description>This an field Description</Label.Description>
|
|
31
|
-
<Input value={value} id="input" onChange={({ target }) => setValue(target.value)} />
|
|
32
|
-
</Label>
|
|
33
|
-
|
|
34
|
-
<Label htmlFor="phone-number-1">
|
|
35
|
-
<Label.Optional>Phone number</Label.Optional>
|
|
36
|
-
<Label.Description>This an field Description</Label.Description>
|
|
37
|
-
</Label>
|
|
38
|
-
<Input
|
|
39
|
-
id="phone-number-1"
|
|
40
|
-
className="m-b-2"
|
|
41
|
-
value={value}
|
|
42
|
-
onChange={({ target }) => setValue(target.value)}
|
|
43
|
-
/>
|
|
15
|
+
<Label>
|
|
16
|
+
Phone number
|
|
17
|
+
<Input value={value} id="input" onChange={({ target }) => setValue(target.value)} />
|
|
18
|
+
</Label>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
44
21
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
22
|
+
export const WithInfo = () => {
|
|
23
|
+
const [value, setValue] = useState<string | undefined>('This is some text');
|
|
24
|
+
return (
|
|
25
|
+
<Label>
|
|
26
|
+
<span className="d-flex">
|
|
27
|
+
Phone number{' '}
|
|
28
|
+
<Info
|
|
29
|
+
content="This is some help in popover"
|
|
30
|
+
aria-label="The aria label"
|
|
31
|
+
className="m-l-1"
|
|
32
|
+
/>
|
|
33
|
+
</span>
|
|
34
|
+
<Input value={value} id="input" onChange={({ target }) => setValue(target.value)} />
|
|
35
|
+
</Label>
|
|
52
36
|
);
|
|
53
37
|
};
|
package/src/label/Label.tsx
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import Body from '../body';
|
|
3
|
-
import { useIntl } from 'react-intl';
|
|
4
|
-
import messages from './Label.messages';
|
|
5
|
-
import { CommonProps } from '../common';
|
|
6
|
-
import { PropsWithChildren } from 'react';
|
|
7
2
|
|
|
8
3
|
export type LabelProps = {
|
|
9
4
|
id?: string;
|
|
@@ -12,51 +7,14 @@ export type LabelProps = {
|
|
|
12
7
|
children?: React.ReactNode;
|
|
13
8
|
};
|
|
14
9
|
|
|
15
|
-
const Label = ({ id, htmlFor, className, children }: LabelProps) => {
|
|
10
|
+
export const Label = ({ id, htmlFor, className, children }: LabelProps) => {
|
|
16
11
|
return (
|
|
17
12
|
<label
|
|
18
13
|
id={id}
|
|
19
14
|
htmlFor={htmlFor}
|
|
20
|
-
className={classNames(
|
|
21
|
-
'd-flex',
|
|
22
|
-
'flex-column',
|
|
23
|
-
'm-b-0',
|
|
24
|
-
'np-text-body-default-bold',
|
|
25
|
-
'text-primary',
|
|
26
|
-
className,
|
|
27
|
-
)}
|
|
15
|
+
className={classNames('control-label d-flex flex-column gap-y-1 m-b-0', className)}
|
|
28
16
|
>
|
|
29
17
|
{children}
|
|
30
18
|
</label>
|
|
31
19
|
);
|
|
32
20
|
};
|
|
33
|
-
|
|
34
|
-
export type LabelOptionalProps = PropsWithChildren<CommonProps>;
|
|
35
|
-
|
|
36
|
-
const Optional = ({ children, className }: LabelOptionalProps) => {
|
|
37
|
-
const { formatMessage } = useIntl();
|
|
38
|
-
return (
|
|
39
|
-
<div>
|
|
40
|
-
{children}
|
|
41
|
-
<Body
|
|
42
|
-
as="span"
|
|
43
|
-
aria-label={formatMessage(messages.optionalAriaLabel)}
|
|
44
|
-
className={classNames('text-secondary', 'm-l-1', className)}
|
|
45
|
-
>
|
|
46
|
-
{formatMessage(messages.optionalLabel)}
|
|
47
|
-
</Body>
|
|
48
|
-
</div>
|
|
49
|
-
);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export type LabelDescriptionProps = PropsWithChildren<CommonProps>;
|
|
53
|
-
|
|
54
|
-
const Description = ({ children, className }: LabelDescriptionProps) =>
|
|
55
|
-
children ? (
|
|
56
|
-
<Body className={classNames('text-secondary', 'm-b-1', className)}>{children}</Body>
|
|
57
|
-
) : null;
|
|
58
|
-
|
|
59
|
-
Label.Optional = Optional;
|
|
60
|
-
Label.Description = Description;
|
|
61
|
-
|
|
62
|
-
export { Label };
|
package/src/main.css
CHANGED
|
@@ -1719,10 +1719,18 @@ 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
|
+
}
|
|
1722
1726
|
.np-theme-personal .np-date-trigger {
|
|
1723
1727
|
padding-left: 16px;
|
|
1724
1728
|
padding-left: var(--size-16);
|
|
1725
1729
|
}
|
|
1730
|
+
.np-theme-personal .np-date-trigger .control-label + span {
|
|
1731
|
+
font-weight: 400;
|
|
1732
|
+
font-weight: var(--font-weight-regular);
|
|
1733
|
+
}
|
|
1726
1734
|
.clear-btn {
|
|
1727
1735
|
transition: color 0.15s ease-in-out;
|
|
1728
1736
|
color: #c9cbce;
|