Skip to content
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

feat(NumberInput): add new component #1826

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open

feat(NumberInput): add new component #1826

wants to merge 33 commits into from

Conversation

DaryaLari
Copy link
Contributor

No description provided.

@gravity-ui-bot
Copy link
Contributor

Preview is ready.

@DaryaLari DaryaLari changed the title NumberInput feat(NumberInput): add new component Aug 28, 2024
@gravity-ui-bot
Copy link
Contributor

Visual Tests Report is ready.

@DaryaLari
Copy link
Contributor Author

@korvin89 @amje
Hope that for now I have fixed all visible flaws... Could you check the changes, please?

@DaryaLari DaryaLari force-pushed the number-input branch 3 times, most recently from be77a52 to 29bfffd Compare September 19, 2024 16:34
@DaryaLari DaryaLari force-pushed the number-input branch 4 times, most recently from cd9c3bd to cc9165b Compare September 26, 2024 10:12
onKeyPress: () => {},
};

const DefaultTemplate: StoryFn<NumberInputProps> = (args) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use newer format of stories (CSF3), see Button as a reference. Right now controls are unusable. The idea is that one single story should show particular prop behavior and be altered with controls. For example, Size - variants of sizes, View - variants of views, Error - variants of how error can be displayed, Step - how step works, Min/Max - how minimum and maximum works and so on.

await expectScreenshot();
});

test('render story: <Showcase>', async ({mount, expectScreenshot}) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep only default story screenshot for now, current stories are not suitable for such kind of tests

onInput: handleInput,
...props.controlProps,
onWheel: allowMouseWheel && active ? handleWheel : undefined,
role: 'spinbutton',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's correct. It's an input for numeric text, not spinbutton.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native input type number has spinbutton role

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let's keep it.

@@ -94,7 +104,7 @@ export const TextInput = React.forwardRef<HTMLSpanElement, TextInputProps>(
note,
onUpdate,
onChange,
} = props;
} = propsWithDefaults;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need this? Defaults eventually will be aplied anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because some of these TextInput defaults (which were moved to a separate object) are also required in NumberInput

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use it in React way then? TextInput.defaultProps = {...}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultProps for function components is deprecated in React 19. https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-deprecated-react-apis

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you'd help me to deal with fc typings with defaultProps^ then I'll change it to react way
I would really appreciate you help

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From default props only size and view are needed, right? Let's set default only for them ('m', and 'normal') in NumberInput.

Copy link
Contributor Author

@DaryaLari DaryaLari Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ValeraS
Also disabled is used in NumberInput directly.
But, wouldn't it be better to store default props in one object to be sure that they wouldn't differ in different controls one day? And what if we'll need to use more default props from TextInput in NumberInput itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've checked that other controls define default values of these props themselves, so I reverted these changes in TextInput

value,
defaultValue,
shiftMultiplier,
} = getInternalVariables({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getInternalState seems to be more descriptive name

onBlur?.(e);
};

const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can only use onUpdate for updating the value. onChange handler is redundant

);

--_--border-width: var(--g-text-input-border-width, 1px);
border-style: solid;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like these styles are duplicated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which styles and where is their duplicate is located?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

border styles between NumericArrows.scss and NumberInput.scss

Comment on lines 1 to 4
@use '../../../../../styles/mixins';
@use '../../../variables';
@use '../../../controls/mixins.scss' as control-mixins;
@use '../../../controls/variables.scss' as control-variables;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use any of these in the file

Comment on lines +4 to +5
export {getNumericInputValidator} from './utils';
export type {GetNumericInputValidatorParams} from './utils';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these internal helpers? Why we export them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they are not used in component. This utility function is for external use only. NumberInput itself doesn't show any validation errors

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then why keep this code? We cannot maintain it properly without specific usecases

return clampedValue;
}

export function warnAboutInvalidProps({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will span a lot. What's the benefit of this? Component won't allow invalid value anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will spam only with invalid props passed.
I think it would be better to notify programmer about invalid component usage6 but not just fix props silently

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok then it should use warnOnce function from utils in format of [NumberInput] <message> instead of console.warn, see usages across the codebase

@DaryaLari DaryaLari force-pushed the number-input branch 2 times, most recently from 2174b81 to f54c958 Compare October 4, 2024 13:17
@DaryaLari DaryaLari marked this pull request as draft October 7, 2024 08:58
@DaryaLari DaryaLari marked this pull request as ready for review October 7, 2024 08:59
@DaryaLari
Copy link
Contributor Author

@ValeraS @amje @korvin89
Hopefully I've fixed all previous comments and I'm waiting for your review again

}

&_view_normal {
--_-g-number-input-numeric-arrows-border-color: var(--g-color-line-generic);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--_-g-number-input-numeric-arrows-border-color: var(--g-color-line-generic);
--_--arrows-border-color: var(--g-color-line-generic);

It's a private var so no need to specify full name

Comment on lines +26 to +27
--_--border-color-hover: var(--g-color-line-generic-hover);
--_--border-color-active: var(--g-color-line-generic-active);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What these variables for? They duplicate TextInput styles

--_-g-number-input-numeric-arrows-border-color: transparent;
}

&__numeric-arrows {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&__numeric-arrows {
&__arrows {

Let's be compact here

/** An optional element displayed under the lower right corner of the control and sharing the place with the error container */
note?: React.ReactNode;
/**Describes the validation state */
validationState?: 'invalid' | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prop already in the BaseInputControlProps, no need to specify it again

/** Enables changing value by scrolling mousewheel on with cursor on the input
* @default false
*/
allowMouseWheel?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've decided to remove the wheel behaviour completely. It turned out that currently it brings a lot of bugs and inconsistency between mouse and touchpad devices. Maybe we reimplement it in the future.

onInput: handleInput,
...props.controlProps,
onWheel: allowMouseWheel && active ? handleWheel : undefined,
role: 'spinbutton',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let's keep it.

...props.controlProps,
onWheel: allowMouseWheel && active ? handleWheel : undefined,
role: 'spinbutton',
inputMode: 'numeric',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when allowDecimal = true, we should pass decimal here to have correct keyborad on mobile devices

$block: '.#{variables.$ns}numeric-arrows';

#{$block} {
--_--numeric-arrows-border-color: var(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--_--numeric-arrows-border-color: var(
--_--arrows-border-color: var(

view: 'flat-secondary',
disabled,
tabIndex: -1,
width: 'max',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's hide the buttons from screenreaders via aria-hidden="true"

Comment on lines +4 to +5
export {getNumericInputValidator} from './utils';
export type {GetNumericInputValidatorParams} from './utils';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then why keep this code? We cannot maintain it properly without specific usecases

@amje
Copy link
Contributor

amje commented Oct 15, 2024

Extra zero digits not deleted on blur:

2024-10-15.20.41.16.mov

Typing dot when allowDecimal = false deletes one digit at time, should do nothing:

2024-10-15.20.41.37.mov

Leading dot not deleted on blur:

2024-10-15.20.42.29.mov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants