Skip to content

Commit 47f59e1

Browse files
authored
Merge pull request #84 from jupyterlab-contrib/ft/add-error-msg
Add invalid styling for inputs
2 parents 810f74a + 0406ebe commit 47f59e1

File tree

81 files changed

+1188
-476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1188
-476
lines changed

packages/components/.storybook/preview-head.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,17 @@
2222
/* For testing reaction to JupyterLab theme */
2323
:root {
2424
--jp-brand-color1: var(--md-blue-700);
25+
--jp-error-color1: var(--md-red-700);
2526
--jp-border-width: 1px;
2627
--jp-border-color1: var(--md-grey-400);
2728
--jp-ui-font-size1: 13px;
2829
--md-grey-400: #78909C;
2930
--md-blue-700: #1976D2;
31+
--md-red-700: #d32f2f;
32+
}
33+
34+
form {
35+
display: flex;
36+
align-items: center;
3037
}
3138
</style>

packages/components/src/anchor/anchor.stories.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ export default {
1010
appearance: {
1111
control: 'select',
1212
options: [
13-
'Accent',
14-
'Lightweight',
15-
'Neutral',
16-
'Outline',
17-
'Stealth',
18-
'Hypertext'
13+
'accent',
14+
'lightweight',
15+
'neutral',
16+
'outline',
17+
'stealth',
18+
'hypertext'
1919
]
2020
},
2121
startIcon: { control: 'boolean' },
@@ -26,7 +26,7 @@ export default {
2626
const Template: StoryFn = (args, context): string => {
2727
return `<jp-anchor
2828
href="#"
29-
${args.appearance ? `appearance="${args.appearance.toLowerCase()}` : ''}">
29+
${args.appearance ? `appearance="${args.appearance}` : ''}">
3030
${args.startIcon ? getFaIcon('plus', 'start') : ''}${args.label ?? 'Link'}
3131
${args.endIcon ? getFaIcon('plus', 'end') : ''}
3232
</jp-anchor>`;

packages/components/src/button/button.stories.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ export default {
1919
'Stealth'
2020
]
2121
},
22-
isDisabled: { control: 'boolean' },
23-
isAutoFocused: { control: 'boolean' },
24-
isMinimal: { control: 'boolean' },
22+
disabled: { control: 'boolean' },
23+
autofocus: { control: 'boolean' },
24+
minimal: { control: 'boolean' },
2525
startIcon: { control: 'boolean' },
2626
onClick: {
2727
action: 'clicked',
@@ -42,9 +42,9 @@ const Template: StoryFn = (args): HTMLElement => {
4242
'afterbegin',
4343
`<jp-button
4444
${args.appearance ? `appearance=${args.appearance.toLowerCase()}` : ''}
45-
${args.isDisabled ? 'disabled' : ''}
46-
${args.isAutoFocused ? 'autofocus' : ''}
47-
${args.isMinimal ? 'minimal' : ''}
45+
${args.disabled ? 'disabled' : ''}
46+
${args.autofocus ? 'autofocus' : ''}
47+
${args.minimal ? 'minimal' : ''}
4848
${args.ariaPressed !== 'none' ? `aria-pressed=${args.ariaPressed}` : ''}
4949
>${args.startIcon ? getFaIcon('plus', args.label ? 'start' : null) : ''}${
5050
args.label ?? ''
@@ -62,9 +62,9 @@ export const Accent: StoryObj = { render: Template.bind({}) };
6262
Accent.args = {
6363
label: 'Button Text',
6464
appearance: 'Accent',
65-
isDisabled: false,
66-
isAutoFocused: false,
67-
isMinimal: false,
65+
disabled: false,
66+
autofocus: false,
67+
minimal: false,
6868
startIcon: false,
6969
ariaPressed: 'none',
7070
onClick: action('button-clicked')
@@ -91,13 +91,13 @@ Lightweight.args = {
9191
export const WithAutofocus: StoryObj = { render: Template.bind({}) };
9292
WithAutofocus.args = {
9393
...Accent.args,
94-
isAutoFocused: true
94+
autofocus: true
9595
};
9696

9797
export const WithDisabled: StoryObj = { render: Template.bind({}) };
9898
WithDisabled.args = {
9999
...Accent.args,
100-
isDisabled: true
100+
disabled: true
101101
};
102102

103103
export const WithStartIcon: StoryObj = { render: Template.bind({}) };

packages/components/src/button/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { buttonStyles as styles } from './button.styles.js';
1515
*/
1616
export type ButtonAppearance =
1717
| 'accent'
18+
| 'error'
1819
| 'lightweight'
1920
| 'neutral'
2021
| 'outline'
Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,93 @@
11
// Copyright (c) Jupyter Development Team.
22
// Distributed under the terms of the Modified BSD License.
3-
import type { StoryFn, Meta, StoryObj } from '@storybook/html';
3+
import type { Meta, StoryFn, StoryObj } from '@storybook/html';
44
import { action } from '@storybook/addon-actions';
55
import { Checkbox } from './index';
66

77
export default {
88
title: 'Components/Checkbox',
99
argTypes: {
1010
label: { control: 'text' },
11-
isChecked: { control: 'boolean' },
12-
isDisabled: { control: 'boolean' },
13-
isIndeterminate: { control: 'boolean' },
11+
checked: { control: 'boolean' },
12+
disabled: { control: 'boolean' },
13+
indeterminate: { control: 'boolean' },
14+
ariaInvalid: { control: 'boolean' },
1415
onChange: {
1516
action: 'changed',
1617
table: {
1718
disable: true
1819
}
20+
},
21+
onInvalid: {
22+
action: 'invalid',
23+
table: {
24+
disable: true
25+
}
1926
}
20-
}
27+
},
28+
decorators: []
2129
} as Meta;
2230

2331
const Template: StoryFn = (args): HTMLElement => {
2432
const container = document.createElement('div');
2533
container.insertAdjacentHTML(
2634
'afterbegin',
2735
`<jp-checkbox
28-
${args.isChecked ? 'checked' : ''}
29-
${args.isDisabled ? 'disabled' : ''}
36+
${args.checked ? 'checked' : ''}
37+
${args.disabled ? 'disabled' : ''}
38+
${args.ariaInvalid ? `aria-invalid="${args.ariaInvalid}"` : ''}
3039
>
3140
${args.label}
3241
</jp-checkbox>`
3342
);
3443

3544
const checkbox = container.firstChild as Checkbox;
3645

37-
if (args.isIndeterminate) {
46+
if (args.indeterminate) {
3847
checkbox.indeterminate = true;
3948
}
4049

4150
if (args.onChange) {
4251
checkbox.addEventListener('change', args.onChange);
4352
}
53+
if (args.onInvalid) {
54+
checkbox.addEventListener('invalid', args.onInvalid);
55+
}
4456

4557
return checkbox;
4658
};
4759

4860
export const Default: StoryObj = { render: Template.bind({}) };
4961
Default.args = {
5062
label: 'Checkbox',
51-
isChecked: false,
52-
isDisabled: false,
53-
isIndeterminate: false,
54-
onChange: action('checkbox-onchange')
63+
checked: false,
64+
disabled: false,
65+
indeterminate: false,
66+
ariaInvalid: false,
67+
onChange: action('change'),
68+
onInvalid: action('invalid')
5569
};
5670

5771
export const WithChecked: StoryObj = { render: Template.bind({}) };
5872
WithChecked.args = {
5973
...Default.args,
60-
isChecked: true
74+
checked: true
6175
};
6276

6377
export const WithDisabled: StoryObj = { render: Template.bind({}) };
6478
WithDisabled.args = {
6579
...Default.args,
66-
isDisabled: true
80+
disabled: true
6781
};
6882

6983
export const WithIndeterminate: StoryObj = { render: Template.bind({}) };
7084
WithIndeterminate.args = {
7185
...Default.args,
72-
isIndeterminate: true
86+
indeterminate: true
87+
};
88+
89+
export const WithError: StoryObj = { render: Template.bind({}) };
90+
WithError.args = {
91+
...Default.args,
92+
ariaInvalid: true
7393
};

packages/components/src/checkbox/checkbox.styles.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import {
2121
controlCornerRadius,
2222
designUnit,
2323
disabledOpacity,
24+
errorFillActive,
25+
errorFillFocus,
26+
errorFillHover,
27+
errorFillRest,
2428
focusStrokeWidth,
2529
foregroundOnAccentActive,
2630
foregroundOnAccentHover,
@@ -68,6 +72,10 @@ export const checkboxStyles: FoundationElementTemplate<
6872
cursor: pointer;
6973
}
7074
75+
:host([aria-invalid='true']) .control {
76+
border-color: ${errorFillRest};
77+
}
78+
7179
.label {
7280
font-family: ${bodyFont};
7381
color: ${neutralForegroundRest};
@@ -116,11 +124,23 @@ export const checkboxStyles: FoundationElementTemplate<
116124
border-color: ${neutralStrokeActive};
117125
}
118126
127+
:host([aria-invalid='true']:not([disabled])) .control:hover {
128+
border-color: ${errorFillHover};
129+
}
130+
131+
:host([aria-invalid='true']:not([disabled])) .control:active {
132+
border-color: ${errorFillActive};
133+
}
134+
119135
:host(:${focusVisible}) .control {
120136
outline: calc(${focusStrokeWidth} * 1px) solid ${accentFillFocus};
121137
outline-offset: 2px;
122138
}
123139
140+
:host([aria-invalid='true']:${focusVisible}) .control {
141+
outline-color: ${errorFillFocus};
142+
}
143+
124144
:host([aria-checked='true']) .control {
125145
background: ${accentFillRest};
126146
border: calc(${strokeWidth} * 1px) solid ${accentFillRest};
@@ -131,6 +151,17 @@ export const checkboxStyles: FoundationElementTemplate<
131151
border: calc(${strokeWidth} * 1px) solid ${accentFillHover};
132152
}
133153
154+
:host([aria-invalid='true'][aria-checked='true']) .control {
155+
background-color: ${errorFillRest};
156+
border-color: ${errorFillRest};
157+
}
158+
159+
:host([aria-invalid='true'][aria-checked='true']:not([disabled]))
160+
.control:hover {
161+
background-color: ${errorFillHover};
162+
border-color: ${errorFillHover};
163+
}
164+
134165
:host([aria-checked='true']:not([disabled]))
135166
.control:hover
136167
.checked-indicator {
@@ -148,6 +179,12 @@ export const checkboxStyles: FoundationElementTemplate<
148179
border: calc(${strokeWidth} * 1px) solid ${accentFillActive};
149180
}
150181
182+
:host([aria-invalid='true'][aria-checked='true']:not([disabled]))
183+
.control:active {
184+
background-color: ${errorFillActive};
185+
border-color: ${errorFillActive};
186+
}
187+
151188
:host([aria-checked='true']:not([disabled]))
152189
.control:active
153190
.checked-indicator {
@@ -165,6 +202,10 @@ export const checkboxStyles: FoundationElementTemplate<
165202
outline-offset: 2px;
166203
}
167204
205+
:host([aria-invalid='true'][aria-checked="true"]:${focusVisible}:not([disabled])) .control {
206+
outline-color: ${errorFillFocus};
207+
}
208+
168209
:host([disabled]) .label,
169210
:host([readonly]) .label,
170211
:host([readonly]) .control,
@@ -187,6 +228,9 @@ export const checkboxStyles: FoundationElementTemplate<
187228
border-color: ${SystemColors.FieldText};
188229
background: ${SystemColors.Field};
189230
}
231+
:host([aria-invalid='true']) .control {
232+
border-style: dashed;
233+
}
190234
.checked-indicator {
191235
fill: ${SystemColors.FieldText};
192236
}

packages/components/src/checkbox/checkbox.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,11 @@ test('Indeterminate', async ({ page }) => {
3434
'checkbox-indeterminate.png'
3535
);
3636
});
37+
38+
test('Error', async ({ page }) => {
39+
await page.goto('/iframe.html?id=components-checkbox--with-error');
40+
41+
expect(await page.locator('jp-checkbox').screenshot()).toMatchSnapshot(
42+
'checkbox-error.png'
43+
);
44+
});
Loading
Loading
Loading

0 commit comments

Comments
 (0)