Skip to content

Commit a5a1c55

Browse files
authored
OEL-4110: Focus states for inputs. (#706)
* OEL-4110: Focus states for inputs. * OEL-4110: PR feedback. * OEL-4110: Fix netlify issue. * OEL-4110: Changed multiselect invalid icon.
1 parent c3fc9aa commit a5a1c55

File tree

7 files changed

+310
-53
lines changed

7 files changed

+310
-53
lines changed

src/components/bcl-form/form.story.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import demoDisabled from "@openeuropa/bcl-data-form/data--disabled.js";
33
import demoGrid from "@openeuropa/bcl-data-form/data--grid.js";
44
import demoHorizontal from "@openeuropa/bcl-data-form/data--horizontal.js";
55
import demoInline from "@openeuropa/bcl-data-form/data--inline.js";
6+
import demoAllInputs from "@openeuropa/bcl-data-form/data--all-inputs.js";
67
import form from "@openeuropa/bcl-form/form.html.twig";
78

89
export default {
@@ -54,3 +55,6 @@ export const Horizontal = () => form(demoHorizontal);
5455
Horizontal.storyName = "Horizontal (with default browser validation)";
5556

5657
export const Inline = () => form(demoInline);
58+
59+
export const AllInputsControls = () => form(demoAllInputs);
60+
AllInputsControls.storyName = "All controls";

src/data/form/data--all-inputs.js

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
const { DrupalAttribute } = require("drupal-attribute");
2+
3+
const singleSelectOptions = [
4+
{ value: "", label: "Choose an option", hidden: true },
5+
{ value: "option-1", label: "First option" },
6+
{ value: "option-2", label: "Second option", selected: true },
7+
{ value: "option-3", label: "Third option" },
8+
];
9+
10+
const multiSelectOptions = [
11+
{ value: "alpha", label: "Alpha" },
12+
{ value: "beta", label: "Beta", selected: true },
13+
{ value: "gamma", label: "Gamma", selected: true },
14+
{ value: "delta", label: "Delta" },
15+
];
16+
17+
const buildRadioAttributes = () =>
18+
new DrupalAttribute().setAttribute("name", "validRadios");
19+
20+
module.exports = {
21+
attributes: new DrupalAttribute()
22+
.addClass(["needs-validation", "row", "gy-4"])
23+
.setAttribute("novalidate", true)
24+
.setAttribute("onsubmit", "return false;"),
25+
items: [
26+
[
27+
{
28+
wrapper_classes: "col-12 col-md-6",
29+
input_type: "text",
30+
label: "Text input",
31+
id: "validTextInput",
32+
placeholder: "Type something",
33+
},
34+
{
35+
wrapper_classes: "col-12 col-md-6",
36+
input_type: "text",
37+
label: "Text input",
38+
id: "validTextInput",
39+
valid: true,
40+
placeholder: "Type something",
41+
},
42+
{
43+
wrapper_classes: "col-12 col-md-6",
44+
input_type: "email",
45+
label: "Email input",
46+
id: "validEmailInput",
47+
invalid: true,
48+
placeholder: "[email protected]",
49+
},
50+
{
51+
wrapper_classes: "col-12 col-md-6",
52+
input_type: "password",
53+
label: "Password input",
54+
id: "validPasswordInput",
55+
},
56+
{
57+
wrapper_classes: "col-12 col-md-6",
58+
input_type: "search",
59+
label: "Search input",
60+
id: "validSearchInput",
61+
placeholder: "Search term",
62+
},
63+
{
64+
wrapper_classes: "col-12 col-md-6",
65+
input_type: "tel",
66+
label: "Telephone input",
67+
id: "validTelInput",
68+
placeholder: "+32 123 45 67",
69+
},
70+
{
71+
wrapper_classes: "col-12 col-md-6",
72+
input_type: "number",
73+
label: "Number input",
74+
id: "validNumberInput",
75+
},
76+
{
77+
wrapper_classes: "col-12 col-md-6",
78+
input_type: "url",
79+
label: "URL input",
80+
id: "validUrlInput",
81+
placeholder: "https://example.com",
82+
},
83+
{
84+
wrapper_classes: "col-12 col-md-6",
85+
input_type: "date",
86+
label: "Date input",
87+
id: "validDateInput",
88+
},
89+
{
90+
wrapper_classes: "col-12 col-md-6",
91+
input_type: "time",
92+
label: "Time input",
93+
id: "validTimeInput",
94+
},
95+
{
96+
wrapper_classes: "col-12 col-md-6",
97+
input_type: "file",
98+
label: "File input",
99+
id: "validFileInput",
100+
},
101+
{
102+
wrapper_classes: "col-12",
103+
input_type: "range",
104+
label: "Range input",
105+
id: "validRangeInput",
106+
attributes: new DrupalAttribute()
107+
.setAttribute("min", 0)
108+
.setAttribute("max", 100)
109+
.setAttribute("value", 42),
110+
},
111+
{
112+
wrapper_classes: "col-12",
113+
type: "textarea",
114+
label: "Textarea",
115+
id: "validTextarea",
116+
text: "Multiline content",
117+
rows: 4,
118+
},
119+
{
120+
wrapper_classes: "col-12 col-md-6",
121+
type: "select",
122+
label: "Select",
123+
id: "validSelect",
124+
options: singleSelectOptions,
125+
},
126+
{
127+
wrapper_classes: "col-12 col-md-6",
128+
type: "select",
129+
label: "Valid Select",
130+
valid: true,
131+
id: "validSelect",
132+
options: singleSelectOptions,
133+
},
134+
{
135+
wrapper_classes: "col-12 col-md-6",
136+
type: "select",
137+
label: "Invalid Select",
138+
invalid: true,
139+
id: "validSelect",
140+
options: singleSelectOptions,
141+
},
142+
{
143+
wrapper_classes: "col-12 col-md-6",
144+
type: "select",
145+
label: "Disabled Select",
146+
disabled: true,
147+
id: "validSelect",
148+
options: singleSelectOptions,
149+
},
150+
{
151+
wrapper_classes: "col-12 col-md-6",
152+
type: "select",
153+
label: "Multiple select",
154+
id: "validMultiSelect",
155+
multiple: true,
156+
options: multiSelectOptions,
157+
},
158+
{
159+
wrapper_classes: "col-12 col-md-6",
160+
input_type: "checkbox",
161+
label: "Checkbox",
162+
id: "validCheckbox",
163+
checked: true,
164+
},
165+
{
166+
wrapper_classes: "col-12 col-md-6",
167+
input_type: "checkbox",
168+
label: "Switch",
169+
id: "validSwitch",
170+
checked: true,
171+
switch: true,
172+
},
173+
{
174+
wrapper_classes: "col-12 col-md-6",
175+
input_type: "radio",
176+
label: "Radio option A",
177+
id: "validRadioA",
178+
checked: true,
179+
attributes: buildRadioAttributes(),
180+
},
181+
{
182+
wrapper_classes: "col-12 col-md-6",
183+
input_type: "radio",
184+
label: "Radio option B",
185+
id: "validRadioB",
186+
attributes: buildRadioAttributes(),
187+
},
188+
],
189+
],
190+
submit: {
191+
wrapper: "col-12",
192+
label: "Submit",
193+
type: "submit",
194+
variant: "primary",
195+
},
196+
};

src/themes/default/src/scss/_input.scss

Lines changed: 72 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,57 @@
11
/* stylelint-disable no-duplicate-selectors, selector-no-qualifying-type, no-descending-specificity */
22

3+
$default-border-color: $gray-600;
4+
35
.form-select {
46
padding-top: $input-padding-y-lg;
57
padding-bottom: $input-padding-y-lg;
68
padding-left: $input-padding-x-lg;
79
font-size: $form-font-size-lg;
10+
border-color: $default-border-color;
11+
&:focus-visible {
12+
border-color: $default-border-color;
13+
box-shadow: none;
14+
@include form-focus-ring();
15+
&.is-valid {
16+
outline-color: $success;
17+
&:focus {
18+
box-shadow: none;
19+
border-color: $default-border-color;
20+
}
21+
}
22+
&.is-invalid {
23+
outline-color: $danger;
24+
&:focus {
25+
box-shadow: none;
26+
border-color: $default-border-color;
27+
}
28+
}
29+
}
30+
&:focus {
31+
box-shadow: none;
32+
border-color: $default-border-color;
33+
}
34+
&.is-valid,
35+
&.is-invalid {
36+
&:focus {
37+
box-shadow: none;
38+
}
39+
}
40+
}
41+
42+
.form-check-input {
43+
border-color: $primary;
844
&:focus-visible {
9-
outline: 2px solid $primary;
45+
&[type="radio"] {
46+
border-radius: 50%;
47+
}
48+
}
49+
&:focus {
50+
border-color: $primary;
1051
box-shadow: none;
11-
border-radius: 4px;
12-
outline-offset: -1px;
52+
}
53+
&:focus-visible {
54+
@include form-focus-ring(1px);
1355
}
1456
}
1557

@@ -18,16 +60,35 @@
1860
padding: $input-padding-y-lg $input-padding-x-lg;
1961
font-size: $form-font-size-lg;
2062
border-radius: 0.3rem;
63+
border-color: $default-border-color;
2164
&::file-selector-button {
2265
padding: $input-padding-y-lg $input-padding-x-lg;
2366
margin: (-$input-padding-y-lg) $input-padding-x-lg (-$input-padding-y-lg)
2467
(-$input-padding-x-lg);
2568
}
26-
&:focus-visible {
27-
outline: 2px solid $primary;
28-
box-shadow: none;
29-
border-radius: 4px;
30-
outline-offset: -1px;
69+
&:focus:focus-visible {
70+
border-color: $default-border-color;
71+
@include form-focus-ring();
72+
}
73+
&.is-valid,
74+
&.is-invalid {
75+
&:focus {
76+
box-shadow: none;
77+
}
78+
}
79+
&.is-valid {
80+
&:focus:focus-visible {
81+
transition: none;
82+
border-color: $default-border-color;
83+
@include form-focus-ring($outline-color: $success);
84+
}
85+
}
86+
&.is-invalid {
87+
&:focus:focus-visible {
88+
transition: none;
89+
border-color: $default-border-color;
90+
@include form-focus-ring($outline-color: $danger);
91+
}
3192
}
3293
}
3394
.form-check:not(.form-switch) {
@@ -41,20 +102,6 @@
41102
margin-top: 0.15rem;
42103
}
43104
}
44-
.form-check-input {
45-
&:focus-visible {
46-
outline: 4px solid $primary;
47-
box-shadow: none;
48-
border-radius: 4px;
49-
outline-offset: 0;
50-
&[type="radio"] {
51-
border-radius: 50%;
52-
}
53-
}
54-
&:checked:focus-visible {
55-
border-color: $white;
56-
}
57-
}
58105

59106
@include media-breakpoint-up(md) {
60107
.form-check:not(.form-switch) {
@@ -90,24 +137,18 @@
90137
textarea.form-control,
91138
.form-control {
92139
&.is-invalid {
93-
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM8 4C7.46459 4 7.04623 4.46229 7.0995 4.99504L7.45025 8.50248C7.47849 8.78492 7.71616 9 8 9C8.28384 9 8.52151 8.78492 8.54975 8.50248L8.9005 4.99504C8.95377 4.46228 8.53541 4 8 4ZM8.00154 10C7.44926 10 7.00154 10.4477 7.00154 11C7.00154 11.5523 7.44926 12 8.00154 12C8.55383 12 9.00154 11.5523 9.00154 11C9.00154 10.4477 8.55383 10 8.00154 10Z' fill='%23D72E3D'/%3E%3C/svg%3E%0A");
140+
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM8 4C7.46459 4 7.04623 4.46229 7.0995 4.99504L7.45025 8.50248C7.47849 8.78492 7.71616 9 8 9C8.28384 9 8.52151 8.78492 8.54975 8.50248L8.9005 4.99504C8.95377 4.46228 8.53541 4 8 4ZM8.00154 10C7.44926 10 7.00154 10.4477 7.00154 11C7.00154 11.5523 7.44926 12 8.00154 12C8.55383 12 9.00154 11.5523 9.00154 11C9.00154 10.4477 8.55383 10 8.00154 10Z' fill='%23A51F2C'/%3E%3C/svg%3E%0A");
94141
}
95142
&.is-valid {
96143
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM12.0303 4.96967C11.7374 4.67678 11.2626 4.67678 10.9697 4.96967C10.9626 4.97674 10.9559 4.98424 10.9498 4.9921L7.4774 9.41674L5.38388 7.32322C5.09098 7.03033 4.61611 7.03033 4.32322 7.32322C4.03032 7.61612 4.03032 8.09099 4.32322 8.38388L6.96966 11.0303C7.26256 11.3232 7.73743 11.3232 8.03032 11.0303C8.03685 11.0238 8.043 11.0169 8.04876 11.0097L12.041 6.01947C12.3232 5.72582 12.3196 5.25897 12.0303 4.96967Z' fill='%2328A745'/%3E%3C/svg%3E%0A");
97144
}
98145
}
99146

100-
.form-select:not([multiple]):not([size]) {
101-
&:focus-visible {
102-
outline: 2px solid $primary;
103-
box-shadow: none;
104-
border-radius: 4px;
105-
outline-offset: -1px;
106-
}
147+
select.form-select:not([multiple]):not([size]) {
107148
&.is-invalid {
108149
background-image:
109150
url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3E%3C/svg%3E"),
110-
url("data:image/svg+xml;charset=utf-8,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM8 4C7.46459 4 7.04623 4.46229 7.0995 4.99504L7.45025 8.50248C7.47849 8.78492 7.71616 9 8 9C8.28384 9 8.52151 8.78492 8.54975 8.50248L8.9005 4.99504C8.95377 4.46228 8.53541 4 8 4ZM8.00154 10C7.44926 10 7.00154 10.4477 7.00154 11C7.00154 11.5523 7.44926 12 8.00154 12C8.55383 12 9.00154 11.5523 9.00154 11C9.00154 10.4477 8.55383 10 8.00154 10Z' fill='%23D72E3D'/%3E%3C/svg%3E%0A");
151+
url("data:image/svg+xml;charset=utf-8,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM8 4C7.46459 4 7.04623 4.46229 7.0995 4.99504L7.45025 8.50248C7.47849 8.78492 7.71616 9 8 9C8.28384 9 8.52151 8.78492 8.54975 8.50248L8.9005 4.99504C8.95377 4.46228 8.53541 4 8 4ZM8.00154 10C7.44926 10 7.00154 10.4477 7.00154 11C7.00154 11.5523 7.44926 12 8.00154 12C8.55383 12 9.00154 11.5523 9.00154 11C9.00154 10.4477 8.55383 10 8.00154 10Z' fill='%23A51F2C'/%3E%3C/svg%3E%0A");
111152
}
112153
&.is-valid {
113154
background-image:

0 commit comments

Comments
 (0)