Skip to content

fix(number-field): sp-number-field UI fixes for validation and width #5401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/silly-rooms-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@spectrum-web-components/number-field': patch
'@spectrum-web-components/textfield': patch
---

The changes included resolve UI issues with number-field by proxy of textfield. The validation icons in number-field no longer overlap the infield buttons. The width of the number-field now calculates accurately and can be modified via `--mod-stepper-width` token as it was before.
12 changes: 12 additions & 0 deletions packages/number-field/README.md
Original file line number Diff line number Diff line change
@@ -267,3 +267,15 @@ The `<sp-number-field>` component doesn't manage a default value by itself. This
});
});
</script>

## States

Use the `required` attribute to indicate a number field value is required. Dictate the validity or invalidity state of the text entry with the `valid` or `invalid` attributes.

```html
<sp-field-label for="number-1" required>Count</sp-field-label>
<sp-number-field id="number-1" valid value="12343"></sp-number-field>
<br />
<sp-field-label for="number-2" required>Size</sp-field-label>
<sp-number-field id="number-2" invalid value="15212"></sp-number-field>
```
88 changes: 88 additions & 0 deletions packages/number-field/src/number-field.css
Original file line number Diff line number Diff line change
@@ -10,9 +10,34 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License.
*/

@import url('@spectrum-web-components/infield-button/src/infield-button.css');
@import url('./spectrum-number-field.css');
@import url('./number-field-overrides.css');

:host {
--spectrum-stepper-width: calc(
var(--mod-stepper-height, var(--spectrum-textfield-height)) *
var(
--mod-stepper-min-width-multiplier,
var(--spectrum-text-field-minimum-width-multiplier)
) +
var(
--mod-stepper-button-width,
var(--spectrum-infield-button-width)
) +
var(
--mod-stepper-border-width,
var(--spectrum-stepper-border-width)
) * 2
);

inline-size: var(--mod-stepper-width, var(--spectrum-stepper-width));
}

#textfield {
inline-size: 100%;
}

.input {
font-variant-numeric: tabular-nums;
}
@@ -59,3 +84,66 @@ governing permissions and limitations under the License.
var(--spectrum-stepper-border-color-focus-hover)
);
}

:host(:not([hide-stepper])) #textfield {
--mod-stepper-width: calc(
var(--spectrum-stepper-height) *
var(
--mod-stepper-min-width-multiplier,
var(--spectrum-text-field-minimum-width-multiplier)
) + var(--spectrum-stepper-button-width) * 2 +
var(
--mod-stepper-border-width,
var(--spectrum-stepper-border-width)
) * 2
);
}

:host([invalid]) .input {
padding-inline-end: calc(
var(
--mod-textfield-icon-spacing-inline-start-valid,
var(--spectrum-textfield-icon-spacing-inline-start-valid)
) +
var(
--mod-textfield-icon-size-valid,
var(--spectrum-textfield-icon-size-valid)
) +
var(
--mod-textfield-icon-spacing-inline-end-valid,
var(--spectrum-textfield-icon-spacing-inline-end-valid)
) -
var(
--mod-textfield-border-width,
var(--spectrum-textfield-border-width)
)
);
}

:host([invalid]:not([hide-stepper])) #textfield .icon {
inset-inline-end: calc(
var(--spectrum-stepper-button-width) +
var(--spectrum-textfield-icon-spacing-inline-end-invalid)
);
}

:host([valid]:not([hide-stepper])) #textfield .icon {
inset-inline-end: calc(
var(--spectrum-stepper-button-width) +
var(--spectrum-textfield-icon-spacing-inline-end-valid)
);
}

:host(:not([hide-stepper])) {
--mod-stepper-width: calc(
var(--spectrum-textfield-height) *
var(
--mod-stepper-min-width-multiplier,
var(--spectrum-text-field-minimum-width-multiplier)
) + var(--spectrum-infield-button-width) * 2 +
var(
--mod-stepper-border-width,
var(--spectrum-stepper-border-width)
) * 2
);
}
36 changes: 27 additions & 9 deletions packages/number-field/stories/number-field.stories.ts
Original file line number Diff line number Diff line change
@@ -208,7 +208,7 @@ export const Default = (args: StoryArgs = {}): TemplateResult => {
onInput((event.target as NumberField).value)}
@change=${(event: Event) =>
onChange((event.target as NumberField).value)}
style=${ifDefined(args.quiet ? undefined : 'width: 150px')}
style=${ifDefined(args.quiet ? undefined : '')}
></sp-number-field>
`;
};
@@ -239,7 +239,6 @@ export const decimals = (args: StoryArgs): TemplateResult => {
</sp-field-label>
<sp-number-field
id="decimals"
style="width: 200px"
...=${spreadProps(args)}
@change=${args.onChange}
@input=${args.onInput}
@@ -268,7 +267,6 @@ export const germanDecimals = (args: StoryArgs): TemplateResult => {
<sp-theme lang="de" dir="${currentDir}">
<sp-number-field
id="decimals"
style="width: 200px"
...=${spreadProps(args)}
@change=${args.onChange}
@input=${args.onInput}
@@ -291,7 +289,6 @@ export const percents = (args: StoryArgs = {}): TemplateResult => {
<sp-field-label for="percents">Enter a percentage</sp-field-label>
<sp-number-field
id="percents"
style="width: 200px"
...=${spreadProps(args)}
@change=${args.onChange}
.formatOptions=${{
@@ -310,7 +307,6 @@ export const currency = (args: StoryArgs = {}): TemplateResult => {
return html`
<sp-field-label for="currency">Enter a value in Euros</sp-field-label>
<sp-number-field
style="width: 200px"
...=${spreadProps(args)}
@change=${args.onChange}
.formatOptions=${{
@@ -332,7 +328,6 @@ export const units = (args: StoryArgs): TemplateResult => {
<sp-field-label for="units">Enter a lengths in inches</sp-field-label>
<sp-number-field
id="units"
style="width: 200px"
...=${spreadProps(args)}
@change=${args.onChange}
.formatOptions=${{
@@ -353,7 +348,6 @@ export const pixels = (args: StoryArgs): TemplateResult => {
<sp-field-label for="units">Enter a lengths in pixels</sp-field-label>
<sp-number-field
id="units"
style="width: 200px"
.formatOptions=${{
style: 'unit',
unit: 'px',
@@ -374,7 +368,6 @@ export const minMax = (args: StoryArgs): TemplateResult => html`
</sp-field-label>
<sp-number-field
id="min-max"
style="width: 200px"
...=${spreadProps(args)}
@change=${args.onChange}
></sp-number-field>
@@ -455,6 +448,32 @@ readOnly.args = {
value: '15',
};

export const validationIcons = (args: StoryArgs): TemplateResult => {
return html`
<sp-field-label for="invalidHiddenStepper">
Invalid Number Field without Stepper
</sp-field-label>
<sp-number-field
id="invalidHiddenStepper"
...=${spreadProps(args)}
@change=${args.onChange}
></sp-number-field>
<sp-field-label for="validStepper">
Valid Number Field with Stepper
</sp-field-label>
<sp-number-field id="validStepper" valid></sp-number-field>
<sp-field-label for="invalidStepper">
Invalid Number Field with Stepper
</sp-field-label>
<sp-number-field id="invalidStepper" invalid></sp-number-field>
`;
};
validationIcons.args = {
invalid: true,
value: '15',
hideStepper: true,
};

export const ScrollingContainer = (args: StoryArgs = {}): TemplateResult => {
const onChange =
(args.onChange as (value: number) => void) ||
@@ -490,7 +509,6 @@ export const ScrollingContainer = (args: StoryArgs = {}): TemplateResult => {
onInput((event.target as NumberField).value)}
@change=${(event: Event) =>
onChange((event.target as NumberField).value)}
style="width: 150px"
></sp-number-field>
<p>
This box should not scroll when the focus is inside the
33 changes: 0 additions & 33 deletions packages/textfield/src/spectrum-config.js
Original file line number Diff line number Diff line change
@@ -45,39 +45,6 @@ export default {
},
// Default to `size='m'` without needing the attribute
converter.classToHost('spectrum-Textfield--sizeM'),
{
find: [builder.class('spectrum-Textfield--sizeS')],
replace: [
{
replace: builder.id('textfield'),
},
{
replace: builder.attribute('size', 's'),
},
],
},
{
find: [builder.class('spectrum-Textfield--sizeL')],
replace: [
{
replace: builder.id('textfield'),
},
{
replace: builder.attribute('size', 'l'),
},
],
},
{
find: [builder.class('spectrum-Textfield--sizeXL')],
replace: [
{
replace: builder.id('textfield'),
},
{
replace: builder.attribute('size', 'xl'),
},
],
},
{
// .spectrum-Textfield--quiet:after
find: [
6 changes: 3 additions & 3 deletions packages/textfield/src/spectrum-textfield.css
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ governing permissions and limitations under the License.
--spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-100);
}

:host([size='s']) #textfield {
:host([size='s']) {
--spectrum-textfield-height: var(--spectrum-component-height-75);
--spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-small);
--spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-100);
@@ -91,7 +91,7 @@ governing permissions and limitations under the License.
--spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-75);
}

:host([size='l']) #textfield {
:host([size='l']) {
--spectrum-textfield-height: var(--spectrum-component-height-200);
--spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-large);
--spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-200);
@@ -111,7 +111,7 @@ governing permissions and limitations under the License.
--spectrum-text-area-min-block-size-quiet: var(--spectrum-component-height-200);
}

:host([size='xl']) #textfield {
:host([size='xl']) {
--spectrum-textfield-height: var(--spectrum-component-height-300);
--spectrum-textfield-label-spacing-block-quiet: var(--spectrum-field-label-to-component-quiet-extra-large);
--spectrum-textfield-label-spacing-inline-side-label: var(--spectrum-spacing-200);
6 changes: 3 additions & 3 deletions packages/textfield/src/textfield-overrides.css
Original file line number Diff line number Diff line change
@@ -40,19 +40,19 @@ governing permissions and limitations under the License.
);
}

:host([size='s']) #textfield#textfield {
:host([size='s']) #textfield {
--spectrum-textfield-icon-spacing-block-invalid: var(
--system-textfield-size-s-icon-spacing-block-invalid
);
}

:host([size='l']) #textfield#textfield {
:host([size='l']) #textfield {
--spectrum-textfield-icon-spacing-block-invalid: var(
--system-textfield-size-l-icon-spacing-block-invalid
);
}

:host([size='xl']) #textfield#textfield {
:host([size='xl']) #textfield {
--spectrum-textfield-icon-spacing-block-invalid: var(
--system-textfield-size-xl-icon-spacing-block-invalid
);
11 changes: 10 additions & 1 deletion packages/textfield/src/textfield.css
Original file line number Diff line number Diff line change
@@ -32,6 +32,8 @@ governing permissions and limitations under the License.
}

#textfield {
--spectrum-textfield-input-line-height: var(--spectrum-textfield-height);

inline-size: 100%;
}

@@ -41,7 +43,14 @@ textarea {
}

.input {
min-inline-size: var(--spectrum-textfield-min-width);
--spectrum-textfield-min-width: calc(
var(--spectrum-textfield-height) * 1.5
);

min-inline-size: var(
--mod-textfield-min-width,
var(--spectrum-textfield-min-width)
);
}

:host([focused]) .input {