Skip to content

Commit d430773

Browse files
im-adithyagabriellshtassoevan
authored
feat: Visibility toggle for PasswordInput (#377)
* Update fuselage.d.ts * Update index.js * Update spec.js * Update index.js * Update fuselage.d.ts * Update index.js * Update spec.js * Update PasswordInput.stories.mdx * Invert toggle state icon * Convert PasswordInput to TypeScript Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Co-authored-by: Tasso Evangelista <tasso.evangelista@rocket.chat>
1 parent 3333d7f commit d430773

21 files changed

+107
-135
lines changed
+17-25
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
useState,
3-
DispatchWithoutAction,
4-
Dispatch,
5-
SetStateAction,
6-
} from 'react';
1+
import { useState, SetStateAction } from 'react';
72

83
import { useMutableCallback } from './useMutableCallback';
94

@@ -14,11 +9,9 @@ import { useMutableCallback } from './useMutableCallback';
149
* @returns a state boolean value and a state toggler function
1510
* @public
1611
*/
17-
export const useToggle = <
18-
D extends DispatchWithoutAction | Dispatch<SetStateAction<boolean>>
19-
>(
12+
export const useToggle = (
2013
initialValue?: boolean | (() => boolean)
21-
): [boolean, D] => {
14+
): [boolean, (forcedValue?: SetStateAction<boolean>) => void] => {
2215
const [value, setValue] = useState(() => {
2316
if (typeof initialValue === 'function') {
2417
return !!initialValue();
@@ -27,23 +20,22 @@ export const useToggle = <
2720
return !!initialValue;
2821
});
2922

30-
const dispatch = useMutableCallback<
31-
D extends DispatchWithoutAction ? [] : [SetStateAction<boolean>],
32-
void
33-
>((forcedValue?: SetStateAction<boolean>) => {
34-
// uses value from scope to avoid multiple toggles in one render cycle
35-
setValue(() => {
36-
if (typeof forcedValue === 'boolean') {
37-
return forcedValue;
38-
}
23+
const dispatch = useMutableCallback(
24+
(forcedValue?: SetStateAction<boolean>) => {
25+
// uses value from scope to avoid multiple toggles in one render cycle
26+
setValue(() => {
27+
if (typeof forcedValue === 'boolean') {
28+
return forcedValue;
29+
}
3930

40-
if (typeof forcedValue === 'function') {
41-
return forcedValue(value);
42-
}
31+
if (typeof forcedValue === 'function') {
32+
return forcedValue(value);
33+
}
4334

44-
return !value;
45-
});
46-
}) as D;
35+
return !value;
36+
});
37+
}
38+
);
4739

4840
return [value, dispatch];
4941
};
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading

packages/fuselage/src/components/PasswordInput/spec.js packages/fuselage/src/components/PasswordInput/PasswordInput.spec.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
33

4-
import { PasswordInput } from '.';
4+
import PasswordInput from '.';
55

66
it('renders without crashing', () => {
77
const div = document.createElement('div');

packages/fuselage/src/components/PasswordInput/PasswordInput.stories.mdx

-93
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Meta, Story } from '@storybook/react';
2+
import React from 'react';
3+
4+
import { Icon, PasswordInput } from '../..';
5+
import PropsVariation from '../../.storybook/PropsVariation';
6+
7+
export default {
8+
title: 'Forms/Inputs/PasswordInput',
9+
component: PasswordInput,
10+
parameters: { jest: ['PasswordInput.spec.tsx'] },
11+
} as Meta;
12+
13+
export const Default: Story = () => <PasswordInput />;
14+
15+
export const WithValue: Story = () => <PasswordInput defaultValue='password' />;
16+
17+
export const WithIconAddon: Story = () => (
18+
<PasswordInput addon={<Icon name='send' size={20} />} />
19+
);
20+
21+
export const Invalid: Story = () => <PasswordInput error='Error' />;
22+
23+
export const Disabled: Story = () => <PasswordInput disabled />;
24+
25+
export const WithPlaceholder: Story = () => (
26+
<PasswordInput placeholder='Placeholder' />
27+
);
28+
29+
export const States: Story = () => (
30+
<PropsVariation
31+
component={PasswordInput}
32+
common={{ onChange: () => undefined }}
33+
xAxis={{
34+
'default': {},
35+
'with placeholder': { placeholder: 'Placeholder' },
36+
'with value': { value: 'Value' },
37+
'with icon': { addon: <Icon name='key' size='x20' />, value: 'Value' },
38+
}}
39+
yAxis={{
40+
'default': {},
41+
'hover': { className: 'hover' },
42+
'active': { className: 'active' },
43+
'focus': { className: 'focus' },
44+
'disabled': { disabled: true },
45+
'errored': { error: 'Error' },
46+
'errored + hover': { className: 'hover', error: 'Error' },
47+
'errored + active': { className: 'active', error: 'Error' },
48+
'errored + focus': { className: 'focus', error: 'Error' },
49+
}}
50+
/>
51+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useToggle } from '@rocket.chat/fuselage-hooks';
2+
import React, { ComponentProps, forwardRef, Ref } from 'react';
3+
4+
import { Icon } from '../Icon';
5+
import { InputBox } from '../InputBox';
6+
7+
// TODO: fix a11y issues
8+
9+
type PasswordInputProps = Omit<ComponentProps<typeof InputBox>, 'type'>;
10+
11+
const PasswordInput = forwardRef(function PasswordInput(
12+
props: PasswordInputProps,
13+
ref: Ref<HTMLInputElement>
14+
) {
15+
const [hidden, toggle] = useToggle(true);
16+
const handleAddonClick = () => {
17+
toggle();
18+
};
19+
20+
return (
21+
<InputBox
22+
type={hidden ? 'password' : 'text'}
23+
addon={
24+
<Icon
25+
name={hidden ? 'eye-off' : 'eye'}
26+
size={20}
27+
onClick={handleAddonClick}
28+
/>
29+
}
30+
ref={ref}
31+
{...props}
32+
/>
33+
);
34+
});
35+
36+
export default PasswordInput;

packages/fuselage/src/components/PasswordInput/index.d.ts

-8
This file was deleted.

packages/fuselage/src/components/PasswordInput/index.js

-7
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './PasswordInput';

packages/fuselage/src/components/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export * from './NumberInput';
2626
export * from './Options';
2727
export * from './Options/Option';
2828
export * from './Pagination';
29-
export * from './PasswordInput';
29+
export { default as PasswordInput } from './PasswordInput';
3030
export * from './StatusBullet';
3131
export * from './ProgressBar';
3232
export * from './RadioButton';

0 commit comments

Comments
 (0)