Skip to content

Commit 468b426

Browse files
authored
fix(textfield): icon positioning with field label (#2380)
1 parent e3eda5d commit 468b426

File tree

3 files changed

+151
-22
lines changed

3 files changed

+151
-22
lines changed

components/textfield/index.css

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ governing permissions and limitations under the License.
435435
/* Firefox and Safari - Remove the margin for input. */
436436
margin: 0;
437437

438+
/* TODO: Determine if the vendor prefix toggling of appearance is still needed */
438439
/* Firefox -
439440
Removes the native spin buttons in Firefox; -moz-appearance: none results in spinners.
440441
This has to come after -webkit-appearance or it gets overridden (#214)
@@ -443,6 +444,7 @@ governing permissions and limitations under the License.
443444
Sets the opacity to 1 as normalize.css sets an opacity to placeholders
444445
Details: https://github.com/csstools/normalize.css/blob/main/normalize.css#L297
445446
*/
447+
/* stylelint-disable-next-line value-no-vendor-prefix */
446448
-moz-appearance: textfield;
447449

448450
/* All browsers - Change the input font styles */
@@ -521,6 +523,11 @@ governing permissions and limitations under the License.
521523
grid-column: 2;
522524
}
523525

526+
.spectrum-Textfield.spectrum-Textfield--sideLabel & {
527+
grid-row: 1 / span 1;
528+
grid-column: 2 / span 1;
529+
}
530+
524531
/****** Validation Icon - Valid ✅ ******/
525532
.spectrum-Textfield.is-valid & {
526533
inset-block-start: var(
@@ -531,10 +538,6 @@ governing permissions and limitations under the License.
531538
--mod-textfield-icon-spacing-block-valid,
532539
var(--spectrum-textfield-icon-spacing-block-valid)
533540
);
534-
inset-inline-start: var(
535-
--mod-textfield-icon-spacing-inline-start-valid,
536-
var(--spectrum-textfield-icon-spacing-inline-start-valid)
537-
);
538541
inset-inline-end: var(
539542
--mod-textfield-icon-spacing-inline-end-valid,
540543
var(--spectrum-textfield-icon-spacing-inline-end-valid)
@@ -566,10 +569,6 @@ governing permissions and limitations under the License.
566569
--mod-textfield-icon-spacing-block-invalid,
567570
var(--spectrum-textfield-icon-spacing-block-invalid)
568571
);
569-
inset-inline-start: var(
570-
--mod-textfield-icon-spacing-inline-start-invalid,
571-
var(--spectrum-textfield-icon-spacing-inline-start-invalid)
572-
);
573572
inset-inline-end: var(
574573
--mod-textfield-icon-spacing-inline-end-invalid,
575574
var(--spectrum-textfield-icon-spacing-inline-end-invalid)
@@ -782,10 +781,10 @@ governing permissions and limitations under the License.
782781

783782
text-overflow: ellipsis;
784783

785-
/* Show the overflow for input in Edge. */
786-
overflow: visible;
787-
784+
/* TODO: Determine if the vendor prefix toggling of appearance is still needed */
785+
/* stylelint-disable-next-line value-no-vendor-prefix */
788786
-webkit-appearance: none;
787+
789788
/*
790789
Removes the native spin buttons in Firefox; -moz-appearance: none results in spinners.
791790
This has to come after -webkit-appearance or it gets overridden (#214)
@@ -794,6 +793,7 @@ governing permissions and limitations under the License.
794793
Sets the opacity to 1 as normalize.css sets an opacity to placeholders
795794
Details: https://github.com/csstools/normalize.css/blob/main/normalize.css#L297
796795
*/
796+
/* stylelint-disable-next-line value-no-vendor-prefix */
797797
-moz-appearance: textfield;
798798

799799
/* place in same cell: input, focus indicator, and grows sizer */
@@ -811,6 +811,7 @@ governing permissions and limitations under the License.
811811
/* http://stackoverflow.com/questions/23372903/hide-spinner-in-input-number-firefox-29 */
812812
&::-webkit-inner-spin-button,
813813
&::-webkit-outer-spin-button {
814+
/* stylelint-disable-next-line value-no-vendor-prefix */
814815
-webkit-appearance: none;
815816
margin: 0;
816817
}
@@ -825,14 +826,14 @@ governing permissions and limitations under the License.
825826
*/
826827
/* stylelint-disable selector-no-vendor-prefix */
827828
&::-ms-input-placeholder {
828-
opacity: 1;
829+
opacity: 100%;
829830
}
830831
/* stylelint-enable selector-no-vendor-prefix */
831832

832833

833834
/*** Input Placeholder Text ***/
834835
&::placeholder {
835-
opacity: 1;
836+
opacity: 100%;
836837
font-size: var(
837838
--mod-textfield-placeholder-font-size,
838839
var(--spectrum-textfield-placeholder-font-size)
@@ -1127,7 +1128,7 @@ governing permissions and limitations under the License.
11271128
resize: none;
11281129

11291130
/* The opacity must be set to 1 */
1130-
opacity: 1;
1131+
opacity: 100%;
11311132

11321133
&::placeholder {
11331134
color: var(
@@ -1275,6 +1276,7 @@ governing permissions and limitations under the License.
12751276
/*** Text Area ***/
12761277
.spectrum-Textfield--multiline {
12771278
--spectrum-textfield-input-line-height: normal;
1279+
12781280
.spectrum-Textfield-input {
12791281
min-inline-size: var(
12801282
--mod-text-area-min-inline-size,
@@ -1289,7 +1291,11 @@ governing permissions and limitations under the License.
12891291

12901292
&.spectrum-Textfield--grows {
12911293
.spectrum-Textfield-input {
1292-
grid-row: 1 / auto;
1294+
grid-row: 2 / auto;
1295+
}
1296+
1297+
&.spectrum-Textfield--sideLabel .spectrum-Textfield-input {
1298+
grid-row: 1 / auto
12931299
}
12941300
}
12951301

@@ -1300,6 +1306,7 @@ governing permissions and limitations under the License.
13001306
--mod-text-area-min-block-size-quiet,
13011307
var(--spectrum-text-area-min-block-size-quiet)
13021308
);
1309+
13031310
/* Treat all quiet inputs and text areas the same */
13041311
resize: none;
13051312
overflow-y: hidden;

components/textfield/stories/template.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { when } from "lit/directives/when.js";
77

88
import { Template as Icon } from "@spectrum-css/icon/stories/template.js";
99
import { Template as ProgressCircle } from "@spectrum-css/progresscircle/stories/template.js";
10+
import { Template as FieldLabel } from "@spectrum-css/fieldlabel/stories/template.js";
1011

1112
import "../index.css";
1213

@@ -28,6 +29,9 @@ export const Template = ({
2829
isReadOnly = false,
2930
isKeyboardFocused = false,
3031
isLoading = false,
32+
displayLabel = false,
33+
labelPosition = "top",
34+
labelText,
3135
iconName,
3236
pattern,
3337
placeholder,
@@ -62,6 +66,7 @@ export const Template = ({
6266
[`${rootClass}--multiline`]: multiline,
6367
[`${rootClass}--grows`]: grows,
6468
[`${rootClass}--quiet`]: isQuiet,
69+
[`${rootClass}--sideLabel`]: labelPosition === "side",
6570
"is-invalid": isInvalid,
6671
"is-valid": isValid,
6772
"is-focused": isFocused,
@@ -86,6 +91,12 @@ export const Template = ({
8691
}}
8792
id=${ifDefined(id)}
8893
>
94+
${when(displayLabel, () => FieldLabel({
95+
...globals,
96+
size,
97+
label: labelText,
98+
})
99+
)}
89100
${when(iconName, () => Icon({
90101
...globals,
91102
size,
@@ -97,7 +108,7 @@ export const Template = ({
97108
...customIconClasses,
98109
],
99110
}))}
100-
${when(multiline,
111+
${when(multiline,
101112
() => html`<textarea
102113
placeholder=${ifDefined(placeholder)}
103114
name=${ifDefined(name)}
@@ -112,7 +123,7 @@ export const Template = ({
112123
[`${rootClass}-input`]: true,
113124
...customInputClasses.reduce((a, c) => ({ ...a, [c]: true }), {}),
114125
})}
115-
/>`,
126+
/>`,
116127
() => html`<input
117128
type=${ifDefined(type)}
118129
placeholder=${ifDefined(placeholder)}

components/textfield/stories/textfield.stories.js

Lines changed: 116 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Import the component markup template
22
import { Template } from "./template";
3+
import { html } from "lit";
34

45
export default {
56
title: "Components/Text field",
@@ -16,6 +17,36 @@ export default {
1617
},
1718
control: "boolean",
1819
},
20+
displayLabel: {
21+
name: "Display field label",
22+
type: { name: "boolean" },
23+
table: {
24+
type: { summary: "boolean" },
25+
category: "Component",
26+
},
27+
control: "boolean",
28+
},
29+
labelPosition: {
30+
name: "Label position",
31+
type: { name: "boolean" },
32+
table: {
33+
type: { summary: "boolean" },
34+
category: "Component",
35+
},
36+
options: ["top", "side"],
37+
control: "select",
38+
if: { arg: "displayLabel", truthy: true },
39+
},
40+
labelText: {
41+
name: "Label text",
42+
type: { name: "text" },
43+
table: {
44+
type: { summary: "text" },
45+
category: "Component",
46+
},
47+
control: "text",
48+
if: { arg: "displayLabel", truthy: true },
49+
},
1950
isInvalid: {
2051
name: "Invalid",
2152
type: { name: "boolean" },
@@ -146,6 +177,9 @@ export default {
146177
isFocused: false,
147178
isKeyboardFocused: false,
148179
isLoading: false,
180+
displayLabel: false,
181+
labelPosition: "top",
182+
labelText: "Username",
149183
size: "m",
150184
multiline: false,
151185
grows: false,
@@ -163,13 +197,90 @@ export default {
163197
},
164198
};
165199

166-
export const Default = Template.bind({});
167-
Default.args = {};
200+
const TextFieldGroup = ({
201+
...args
202+
}) => {
203+
return html`
204+
<div style="display: flex; flex-direction: column; gap: 2rem;">
205+
${Template({
206+
...args
207+
})}
208+
${window.isChromatic() ?
209+
Template({
210+
displayLabel: true,
211+
labelText: "Username",
212+
})
213+
: null }
214+
${window.isChromatic() ?
215+
Template({
216+
displayLabel: true,
217+
labelText: "Username that is really long and wraps onto a second line",
218+
isInvalid: true,
219+
})
220+
: null }
221+
${window.isChromatic() ?
222+
Template({
223+
displayLabel: true,
224+
labelText: "Username",
225+
labelPosition: 'side',
226+
isValid: true,
227+
value: "username@reallylongemail.com"
228+
})
229+
: null }
230+
</div>
231+
`;
232+
};
233+
234+
const TextAreaGroup = ({
235+
...args
236+
}) => {
237+
return html`
238+
<div style="display: flex; flex-direction: column; gap: 2rem;">
239+
${Template({
240+
...args,
241+
multiline: true,
242+
value: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt."
243+
})}
244+
${window.isChromatic() ?
245+
Template({
246+
displayLabel: true,
247+
labelText: "Username",
248+
multiline: true,
249+
value: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.",
250+
})
251+
: null }
252+
${window.isChromatic() ?
253+
Template({
254+
displayLabel: true,
255+
labelText: "Username that is really long and wraps onto a second line",
256+
isInvalid: true,
257+
multiline: true,
258+
value: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.",
259+
})
260+
: null }
261+
${window.isChromatic() ?
262+
Template({
263+
displayLabel: true,
264+
labelText: "Username",
265+
labelPosition: 'side',
266+
isValid: true,
267+
multiline: true,
268+
value: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.",
269+
})
270+
: null }
271+
</div>
272+
`;
273+
};
274+
275+
276+
export const Default = TextFieldGroup.bind({});
277+
Default.args = {
278+
279+
};
168280

169-
export const TextArea = Template.bind({});
281+
export const TextArea = TextAreaGroup.bind({});
170282
TextArea.args = {
171283
multiline: true,
172284
grows: true,
173-
value:
174-
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.",
285+
value: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.",
175286
};

0 commit comments

Comments
 (0)