-
Notifications
You must be signed in to change notification settings - Fork 201
feat(stepper): s2 number field/stepper migration #3681
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
base: spectrum-two
Are you sure you want to change the base?
feat(stepper): s2 number field/stepper migration #3681
Conversation
🦋 Changeset detectedLatest commit: 785d2f9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
File metricsSummaryTotal size: 1.39 MB*
stepper
* An ASCII character in UTF-8 is 8 bits or 1 byte. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
stylelint
Custom property --spectrum-number-field-edge-to-validation-icon-extra-large not defined
spectrum-css/components/stepper/index.css
Line 132 in 58fcc4f
--spectrum-numberfield-spacing-validation-icon-to-stepper-hidden: var(--spectrum-number-field-edge-to-validation-icon-extra-large); |
Expected empty line before rule
spectrum-css/components/stepper/index.css
Lines 246 to 250 in 58fcc4f
.spectrum-NumberField-textfield:not(:has(.spectrum-Textfield-validationIcon)) { | |
.spectrum-NumberField-input { | |
padding-inline-end: 0; | |
} | |
} |
Expected ".hide-stepper" to match pattern "^(spectrum-|is-|u-)[A-Za-z0-9-]+"
spectrum-css/components/stepper/index.css
Line 166 in 58fcc4f
--mod-textfield-min-width: var(--mod-numberfield-hidden-stepper-min-inline-size, var(--spectrum-numberfield-hidden-stepper-min-inline-size)); |
Expected ".hide-stepper" to match pattern "^(spectrum-|is-|u-)[A-Za-z0-9-]+"
spectrum-css/components/stepper/index.css
Line 231 in 58fcc4f
min-inline-size: var(--mod-numberfield-hidden-stepper-min-inline-size, var(--spectrum-numberfield-hidden-stepper-min-inline-size)); |
Expected ".hide-stepper" to match pattern "^(spectrum-|is-|u-)[A-Za-z0-9-]+"
spectrum-css/components/stepper/index.css
Line 240 in 58fcc4f
&.spectrum-Textfield.is-invalid .spectrum-Textfield-validationIcon { |
🚀 Deployed on https://pr-3681--spectrum-css.netlify.app |
55e94b1
to
840fffe
Compare
Template, | ||
testData: [ | ||
{ | ||
testHeading: "Default", | ||
}, | ||
{ | ||
testHeading: "Quiet", | ||
isQuiet: true, | ||
testHeading: "Hidden stepper", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the hidden stepper to its own testData object instead of a "state," since the validation icon placement is different between the default/with buttons and the hidden stepper buttons.
{ | ||
testHeading: "Hide stepper", | ||
testHeading: "Default + truncation", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the truncation test cases, do you think its necessary to demonstrate the field label and/or the help text wrapping? Those situations are already captured in their respective Chromatic tests, but is it something we also need to capture here in the number field tests?
isInvalid: { | ||
...TextfieldStories?.argTypes?.isInvalid ?? {}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reservations on pulling the isInvalid
arg from Textfield here, instead of from the shared types? I particularly liked the description of the invalid state that textfield has, which is why I opted for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this decison. It feels more specific to the component and it is using a TextField
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems fine, since textfield will pull it from the shared types, no need to add a duplicate description.
isInvalid, | ||
isFocused, | ||
isDisabled, | ||
displayLabel: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hardcoded this displayLabel: false
(as opposed to displayLabel
getting passed into Textfield) so that we wouldn't get duplicate field labels.
Does that make sense, or should I refactor? I'm pretty sure I could just use the embedded field label (and maybe even the help text) that's already within the textfield component, with some additional CSS edits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh, this is a little weird... my initial instinct is that we shouldn't be dealing with field labels in each. But using textfield's field label also feels weird because it's a bit different (I think) from what SWC does, and it'd be better to be more aligned rather than less aligned.
It kind of feels like it's Textfield's fault that you have to do this. What would be pros/cons of separating the Textfield input from the Textfield with the field label and help text in the template? Like, that Textfield input could be a separate export that we could use in number field? I feel like Picker is also composed in this way? What do you think? If we did something like that, it doesn't have to be done here, I think this works fine for now, because if we change textfield's template, we'll start potentially affecting other components that use textfield too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, why is field label a boolean situation with label text and help text is just a string (in textfield)? That feels inconsistent.
...customClasses.reduce((a, c) => ({ ...a, [c]: true }), {}), | ||
})} | ||
@keyup=${function(e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inspiration from this PR: #3354
I wanted to make sure the correct keyboard focus styles were being applied when I actually navigated to the number field with the tab key.
e2354a0
to
b1f40f5
Compare
@@ -46,7 +46,7 @@ | |||
display: block; | |||
} | |||
|
|||
/* Fix extra space after inline-flex elements such as stepper. */ | |||
/* Fix extra space after inline-flex elements such as number field. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to tell me to revert this- it's probably not necessary but I wanted to clarify the component's new name.
components/stepper/index.css
Outdated
--spectrum-numberfield-background-color-disabled: var(--mod-numberfield-background-color-disabled, var(--spectrum-disabled-background-color)); | ||
--spectrum-numberfield-background-color-disabled: var(--mod-numberfield-background-color-disabled, var(--spectrum-gray-25)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have 2 background-color-disabled props currently. The first matched the token specs, where disabled-background-color
is used. The second follows what's actually defined in Figma, which is gray-25
.
gray-25
looks like all of the Figma designs, where using disabled-background-color
(even though that's what's in the token specs) looks more like S1. I think @rise-erpelding had the same issue in the textfield S2 migration.
isInline: true, | ||
size, | ||
customClasses: [`${rootClass}-button`], | ||
isDisabled, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just added a click to the inline buttons while I was playing around with this. You can now decrement or increment. I was thinking not add some interactivity for fun?
onAdd: function () {
const newValue = String(parseFloat(value) + 0.5);
updateArgs?.({ value: newValue });
},
onMinus: function () {
const newValue = String(parseFloat(value) - 0.5);
updateArgs?.({ value: newValue });
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! I didn't realize we already had these args baked into the the inline buttons so we could pass down increment/decrement functions. We often try to avoid JavaScript implementation in the template because it's unnecessary overhead and we don't ship it anywhere, but this is a really small enhancement that I think would be nice.
@@ -1,22 +1,22 @@ | |||
import { Sizes } from "@spectrum-css/preview/decorators"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import { Sizes } from "@spectrum-css/preview/decorators"; | |
import { Sizes, withDownStateDimensionCapture } from "@spectrum-css/preview/decorators"; |
Let's get that in-field button some life when you click it
@@ -51,7 +69,7 @@ export default { | |||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We then add the decorator:
decorators: [
withDownStateDimensionCapture,
],
displayLabel: true, | ||
label: "Field label", | ||
labelPosition: "top", | ||
helpText: "", | ||
}, | ||
parameters: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then in the parameters:
downState: {
selectors: [".spectrum-InfieldButton:not(:disabled)"],
},
This adds the class to activate the downstate interaction.
Awesome work on this @marissahuysentruyt ! Only thing I can think of right now is adding the Storybook downstate interaction on the infield button and click functions in the isInline clicks to add and subtract. |
- updates rootClass to NumberField - imports new nested components - use inline infield buttons instead of separate stacked infield buttons - adds support for side label - updates templates for docs page
- updates documentation to use number field language instead of stepper - imports new numberfield templates - adds support for displaying the field label, label position, help text and label text - adds side label, invalid states stories - updates some sentence-case display names for stories - removes quiet variant stories - updates display title to Number field
- updates any stepper language to number field - adds test coverage for hidden stepper, side label, help text, invalid, minimum width, and truncation - adds test case for focus + hover, keyboardFocus + hover, disabled+ keyboardFocus
- new tokens used - cleans up/standardizes mod usage for textfield - cleans up/standardizes selectors so they are consistent across states/ variants - updates all custom properties to use numberfield prefix instead of stepper - adds style definitions for new features including hidden stepper, side label, help text, invalid, minimum width
- updates form to use number field import
32555b2
to
785d2f9
Compare
// { | ||
// testHeading: "Internationalization (Thai)", | ||
// value: "๐๑๒๓๔๕๖๗๘๙๑๐", | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! I really wanted to include an internationalization test to the grid (specifically with all of our line-height bug fixes for Thai in textfield/picker/action button), but I couldn't get the Thai numerals to display. Maybe I don't actually have the right characters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be because it's input type number, which... a quick Google search didn't pull up the answer but the AI said it would only accept Arabic numerals (as in the number characters that we're familiar with) and not Thai characters. I think it's fine to leave it out, but we can still hold on to it as a question or possible follow-up item?
TODO: add |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great considering it's a really huge migration (from what it looked like before)! Left a few small comments, and I'm wondering particularly about the textfield passthroughs on the CSS.
isInvalid: { | ||
...TextfieldStories?.argTypes?.isInvalid ?? {}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems fine, since textfield will pull it from the shared types, no need to add a duplicate description.
* Steppers come in four different sizes: small, medium, large, and extra-large. The medium size is the default and most frequently used option. Use the other sizes sparingly; they should be used to create a hierarchy of importance within the page. | ||
* Number fields come in four different sizes: small, medium, large, and extra-large. The medium size is the default and most frequently used option. Use the other sizes sparingly; they should be used to create a hierarchy of importance within the page. | ||
* | ||
* Number fields have a [field label](/docs/components-field-label--docs) that is positioned above the field by default, with a secondary option to be positioned on the side of the field. The [inline infield buttons](/docs/components-in-field-button--docs#inline) are usually visible, but can be hidden. When the label is to long for the available space, it will wrap to the next line. If the value within the number field input overflows, it will truncate with an ellipsis. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a tiny tiny to/too nitpick/grammar suggestion here.
* Number fields have a [field label](/docs/components-field-label--docs) that is positioned above the field by default, with a secondary option to be positioned on the side of the field. The [inline infield buttons](/docs/components-in-field-button--docs#inline) are usually visible, but can be hidden. When the label is to long for the available space, it will wrap to the next line. If the value within the number field input overflows, it will truncate with an ellipsis. | |
* Number fields have a [field label](/docs/components-field-label--docs) that is positioned above the field by default, with a secondary option to be positioned on the side of the field. The [inline infield buttons](/docs/components-in-field-button--docs#inline) are usually visible, but can be hidden. When the label is too long for the available space, it will wrap to the next line. If the value within the number field input overflows, it will truncate with an ellipsis. |
export const InvalidStates = AllDefaultVariantsGroup.bind({}); | ||
InvalidStates.args = { | ||
isInvalid: true, | ||
helpText: "Help text is here to assist", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes me think of a superhero for some reason 🦸♀️
{ | ||
testHeading: "Disabled + keyboard-focused", | ||
isDisabled: true, | ||
isKeyboardFocused: true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is extra so we're getting two on the grid.
// { | ||
// testHeading: "Internationalization (Thai)", | ||
// value: "๐๑๒๓๔๕๖๗๘๙๑๐", | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be because it's input type number, which... a quick Google search didn't pull up the answer but the AI said it would only accept Arabic numerals (as in the number characters that we're familiar with) and not Thai characters. I think it's fine to leave it out, but we can still hold on to it as a question or possible follow-up item?
isInvalid, | ||
isFocused, | ||
isDisabled, | ||
displayLabel: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, why is field label a boolean situation with label text and help text is just a string (in textfield)? That feels inconsistent.
--mod-textfield-border-color-invalid-keyboard-focus: var(--mod-numberfield-border-color-invalid-keyboard-focus, var(--spectrum-numberfield-border-color-invalid-keyboard-focus)); | ||
--mod-textfield-icon-spacing-block-invalid: calc(var(--spectrum-numberfield-spacing-block-start-edge-to-alert-icon) - var(--spectrum-numberfield-border-width)); | ||
--mod-textfield-icon-spacing-inline-end-invalid: var(--spectrum-numberfield-spacing-validation-icon-to-stepper); | ||
--mod-textfield-width: var(--mod-numberfield-inline-size, var(--spectrum-numberfield-inline-size)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.spectrum-NumberField-input { | ||
line-height: var(--spectrum-numberfield-line-height); | ||
padding-inline-start: 0; | ||
padding-inline-end: var(--spectrum-numberfield-spacing-min-inline-end-text-to-stepper); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if the spacing needs a few adjustments, I noticed that when I type in many numbers, the padding creates a lot of white space between the last number and the buttons, definitely more than the spec:
Inspecting it seems like that text-to-stepper token is being overridden so it never gets used:
/* @passthrough start -- MODS for sub components */ | ||
/* nested textfield */ | ||
--mod-textfield-corner-radius: var(--mod-numberfield-border-radius, var(--spectrum-numberfield-border-radius)); | ||
--mod-textfield-border-width: var(--mod-numberfield-border-width, var(--spectrum-numberfield-border-width)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have another comment below because I saw this with inline-size first, but it looks like we're doing passthroughs to textfield that are passed through but being overridden for border width and some other properties:
Looks like the border, for instance, is also being set on .spectrum-NumberField-textfield
:
isInline: true, | ||
size, | ||
customClasses: [`${rootClass}-button`], | ||
isDisabled, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! I didn't realize we already had these args baked into the the inline buttons so we could pass down increment/decrement functions. We often try to avoid JavaScript implementation in the template because it's unnecessary overhead and we don't ship it anywhere, but this is a really small enhancement that I think would be nice.
Description
Welcome to the new & improved number field (previously known as stepper)! 🥳🔢 This migration was quite complex, and added a LOT of new features to our humble number field.
New features include:
Following React's lead, the markup of the number field has changed. You'll see that the
.spectrum-Textfield
div is where the S2 design language lives (instead of on the input element), while the actualinput
is unstyled and incorporated more subtly. Based on design's, React's and SWC's naming conventions, the display name for this component has also changed fromstepper
tonumberField
. This introduced breaking changes in all previous custom properties, where any--spectrum-stepper-*
or--mod-stepper-*
properties moved to--spectrum-numberfield-*
or--mod-numberfield-*
. This also applied to class names, where.spectrum-Stepper
changed to.spectrum-NumberField
. Thehide-stepper
class has also been updated to match our class naming conventions (.spectrum-NumberField--hiddenStepper
).Because of all the new features and to align more with design, SWC and React, below is a quick recap of the following tokens & classes that have been renamed in the CSS:
.spectrum-Stepper*
class names have been converted to.spectrum-NumberField*
.hide-stepper
class has been converted to.spectrum-NumberField--hiddenStepper
--spectrum-stepper*
to--spectrum-numberfield*
--mod-stepper*
to--mod-numberfield
Removed custom properties include:
--mod-stepper-animation-duration
--mod-stepper-button-border-width
--mod-stepper-button-width
--mod-stepper-button-width-quiet
--mod-stepper-buttons-background-color
--mod-stepper-buttons-border-color
--mod-stepper-buttons-border-color-focus
--mod-stepper-buttons-border-color-focus-hover
--mod-stepper-buttons-border-color-hover
--mod-stepper-buttons-border-color-keyboard-focus
--mod-stepper-buttons-border-style
--mod-stepper-buttons-border-width
--mod-stepper-focus-indicator-visibility
--mod-stepper-height (renamed to
--mod-numberfield-block-size
)--mod-stepper-width (renamed to
--mod-numberfield-inline-size
)New custom properties include:
--mod-numberfield-background-color
--mod-numberfield-background-color-disabled
--mod-numberfield-block-size (renamed from
--mod-stepper-height
)--mod-numberfield-border-color-disabled
--mod-numberfield-border-color-invalid-default
--mod-numberfield-border-color-invalid-focus
--mod-numberfield-border-color-invalid-focus-hover
--mod-numberfield-border-color-invalid-hover
--mod-numberfield-border-color-invalid-keyboard-focus
--mod-numberfield-button-inline-offset
--mod-numberfield-font-family
--mod-numberfield-font-size
--mod-numberfield-font-style
--mod-numberfield-font-weight
--mod-numberfield-hidden-stepper-min-inline-size
--mod-numberfield-inline-size (renamed from
--mod-stepper-width
)--mod-numberfield-label-to-field
--mod-numberfield-line-height
--mod-numberfield-min-inline-size
--mod-numberfield-spacing-block-end-edge-to-text
--mod-numberfield-spacing-block-start-edge-to-text
--mod-numberfield-spacing-field-to-helptext
This PR also incorporates the refactoring and test coverage that was introduced and tested in both #3558 and #3670 (both of which could be closed after this PR is merged 👍)
Jira/Specs
CSS-1120
Figma token specs (under Number field)
Figma desktop designs (under Number field)
How and where has this been tested?
Please tag yourself on the tests you've marked complete to confirm the tests have been run by someone other than the author.
Validation steps
field-label-to-component
(inspect.spectrum-NumberField-fieldLabel
)in-field-stepper-to-end-*
sizing tokens to correspond to t-shirt sized number fields (inspect.spectrum-NumberField-buttons
)help-text-to-component
(inspect.spectrum-NumberField-helpText
in an invalid number field, for instance)field-default-width-*
sizing tokens to correspond to t-shirt sized number fieldsnumber-field-minimum-width-multiplier
(inspect.spectrum-NumberField--hiddenStepper
/the hidden stepper number field)number-field-with-stepper-minimum-width-*
sizing tokens to correspond to t-shirt sized number fields (inspect.spectrum-NumberField
)component-height-*
sizing tokens to correspond to t-shirt sized number fields (inspect.spectrum-NumberField-textfield
)corner-radius-medium-size-*
sizing tokens to correspond to t-shirt sized number fields (inspect.spectrum-NumberField-textfield
)component-edge-to-text-*
sizing tokens to correspond to t-shirt sized number fields (inspect.spectrum-NumberField-textfield
)component-top-to-text-*
sizing tokens to correspond to t-shirt sized number fields (inspect.spectrum-NumberField-textfield
)component-bottom-to-text-*
sizing tokens to correspond to t-shirt sized number fields (inspect the textfield mods in.spectrum-NumberField-input.spectrum-Textfield-input
)text-to-visual-*
sizing tokens to correspond to t-shirt sized number fields (inspect the.spectrum-NumberField-input
element of a default number field)border-width-200
(inspect.spectrum-NumberField-textfield
)focus-indicator-thickness
,focus-indicator-color
, andfocus-indicator-gap
(inspect.spectrum-NumberField-inputs
in a keyboard focused number field)workflow-icon-size-*
for each t-shirt size (for invalid number fields)component-top-to-workflow-icon-*
for each t-shirt size (check through the mods for textfield's icon spacing)text-to-visual-*
for each t-shirt size (inspect.spectrum-NumberField-input.spectrum-Textfield-input
in the invalid number field)number-field-visual-to-in-field-stepper-*
for each t-shirt size (inspect.spectrum-NumberField-input.spectrum-Textfield-input
in the invalid number field)gray-25
(inspect.spectrum-NumberField-textfield
and the mods for textfield's background color)gray-300
,gray-400
,gray-800
andgray-900
for the various default variant border colors and states (inspect.spectrum-NumberField-textfield
)negative-border-color-default
,negative-border-color-hover
,negative-border-color-focus-hover
,negative-border-color-focus
andnegative-border-color-key-focus
for the various invalid variant border colors and states (inspect.spectrum-NumberField-textfield
)neutral-content-color-default
,neutral-content-color-hover
,neutral-content-color-focus-hover
,neutral-content-color-focus
andneutral-content-color-key-focus
for the various id variant border colors and states (inspect.spectrum-NumberField-input
and mods for the textfield text color)negative-visual-color
of the icondisabled-content-color
,disabled-border-color
,disabled-background-color
for the disabled statedefault-font-family
,regular-font-weight
,default-font-style
,line-height-100
as font stylescjk-line-height-100
as font styles in the CJK contextsfont-size-*
for each t-shirt sizeAdditional Validation
Stepper
in your IDE. No function calls, and no imports in references toStepper
should exist. As a caveat, there will still be references to stepper. The NPM package is still named "stepper," and all of the previous changelogs still use "stepper" as the component name, so not everything has been converted to "number field." We also have arguments in stories file that use the word "stepper," but all of the function calls to this component and any imports should be changed toNumberField
.hide-stepper
in your IDE. Nothing should be returned (except maybe some older JSON).--spectrum-Stepper
and--mod-stepper
in your IDE. Nothing should be returned except for changelogs.Regression testing
Validate:
Screenshots
S1


S2


To-do list