Skip to content

Commit 0975754

Browse files
fix(fuselage): PaginatedSelectFiltered filter state (#661)
* fix * Simplify stories * Split into subcomponents * Rename directory Co-authored-by: Tiago Evangelista Pinto <tiago.evangelista@rocket.chat>
1 parent 9e170ff commit 0975754

17 files changed

+417
-4318
lines changed

packages/fuselage/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"@storybook/addon-links": "~6.4.18",
7474
"@storybook/addons": "~6.4.18",
7575
"@storybook/builder-webpack5": "~6.4.18",
76+
"@storybook/client-api": "~6.4.19",
7677
"@storybook/manager-webpack5": "~6.4.18",
7778
"@storybook/react": "~6.4.18",
7879
"@storybook/source-loader": "~6.4.18",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { useArgs } from '@storybook/client-api';
2+
import type { ComponentStory, ComponentMeta } from '@storybook/react';
3+
import React from 'react';
4+
5+
import { PaginatedMultiSelectFiltered } from '.';
6+
7+
export default {
8+
title: 'Inputs/PaginatedMultiSelectFiltered',
9+
component: PaginatedMultiSelectFiltered,
10+
args: {
11+
placeholder: 'Placeholder here...',
12+
options: Array.from({ length: 1000 }, (_, i) => ({
13+
value: i,
14+
label: `Item #${i}`,
15+
})),
16+
},
17+
parameters: {
18+
actions: { argTypesRegex: '^on.*' },
19+
layout: 'centered',
20+
},
21+
} as ComponentMeta<typeof PaginatedMultiSelectFiltered>;
22+
23+
export const Normal: ComponentStory<typeof PaginatedMultiSelectFiltered> = (
24+
args
25+
) => {
26+
const [, updateArgs] = useArgs();
27+
28+
return (
29+
<PaginatedMultiSelectFiltered
30+
setFilter={(filter) => updateArgs({ filter })}
31+
{...args}
32+
/>
33+
);
34+
};
35+
36+
export const Errored: ComponentStory<typeof PaginatedMultiSelectFiltered> = (
37+
args
38+
) => <PaginatedMultiSelectFiltered {...args} />;
39+
Errored.args = {
40+
error: true,
41+
};
42+
43+
export const Disabled: ComponentStory<typeof PaginatedMultiSelectFiltered> = (
44+
args
45+
) => <PaginatedMultiSelectFiltered {...args} />;
46+
Disabled.args = {
47+
disabled: true,
48+
};

packages/fuselage/src/components/SelectPaginated/PaginatedSelect.tsx packages/fuselage/src/components/PaginatedSelect/PaginatedSelect.tsx

+17-45
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {
33
useMutableCallback,
44
useResizeObserver,
55
} from '@rocket.chat/fuselage-hooks';
6-
import type { SyntheticEvent, ComponentProps, Ref, ElementType } from 'react';
7-
import React, { useState, useRef, forwardRef, useMemo, useEffect } from 'react';
6+
import type { SyntheticEvent, ElementType } from 'react';
7+
import React, { useState, useRef, useMemo, useEffect } from 'react';
88

99
import type { SelectProps } from '..';
1010
import AnimatedVisibility from '../AnimatedVisibility';
@@ -13,6 +13,9 @@ import { Icon } from '../Icon';
1313
import { useVisible } from '../Options/useVisible';
1414
import { OptionsPaginated } from '../OptionsPaginated';
1515
import PositionAnimated from '../PositionAnimated';
16+
import PaginatedSelectAddon from './PaginatedSelectAddon';
17+
import PaginatedSelectFocus from './PaginatedSelectFocus';
18+
import PaginatedSelectWrapper from './PaginatedSelectWrapper';
1619

1720
type PaginatedOptionType = {
1821
value: string | number;
@@ -23,35 +26,9 @@ export type PaginatedSelectProps = Omit<SelectProps, 'options'> & {
2326
options: PaginatedOptionType[];
2427
withTitle?: boolean;
2528
endReached: (index: number) => void;
26-
setFilter: (value: string | undefined | number) => void;
29+
setFilter?: (value: string | undefined | number) => void;
2730
};
2831

29-
type AddonProps = ComponentProps<typeof Box>;
30-
31-
const Addon = forwardRef((props: AddonProps, ref: Ref<HTMLDivElement>) => (
32-
<Box is='div' rcx-select__addon ref={ref} {...props} />
33-
));
34-
35-
type WrapperProps = ComponentProps<typeof Box>;
36-
37-
const Wrapper = forwardRef((props: WrapperProps, ref: Ref<HTMLDivElement>) => (
38-
<Box is='div' rcx-select__wrapper ref={ref} {...props} />
39-
));
40-
41-
type FocusProps = ComponentProps<typeof Box>;
42-
43-
const Focus = forwardRef((props: FocusProps, ref: Ref<HTMLButtonElement>) => (
44-
<Box
45-
ref={ref}
46-
fontScale='p2m'
47-
color='hint'
48-
rcx-select__focus
49-
is='button'
50-
type='button'
51-
{...props}
52-
/>
53-
));
54-
5532
const prevent = (e: SyntheticEvent) => {
5633
e.preventDefault();
5734
e.stopPropagation();
@@ -78,7 +55,7 @@ export const PaginatedSelect = ({
7855
error,
7956
disabled,
8057
options = [],
81-
anchor: Anchor = Focus,
58+
anchor: Anchor = PaginatedSelectFocus,
8259
onChange = () => {},
8360
placeholder = '',
8461
renderOptions: _Options = OptionsPaginated,
@@ -133,7 +110,7 @@ export const PaginatedSelect = ({
133110
)}
134111
{...props}
135112
>
136-
<Wrapper
113+
<PaginatedSelectWrapper
137114
display='flex'
138115
mi='neg-x4'
139116
rcx-select__wrapper--hidden={!!visibleText}
@@ -159,20 +136,15 @@ export const PaginatedSelect = ({
159136
onClick={show}
160137
onBlur={hide}
161138
/>
162-
<Addon
163-
mi='x4'
164-
children={
165-
<Icon
166-
name={
167-
visible === AnimatedVisibility.VISIBLE
168-
? 'cross'
169-
: 'chevron-down'
170-
}
171-
size='x20'
172-
/>
173-
}
174-
/>
175-
</Wrapper>
139+
<PaginatedSelectAddon mi='x4'>
140+
<Icon
141+
name={
142+
visible === AnimatedVisibility.VISIBLE ? 'cross' : 'chevron-down'
143+
}
144+
size='x20'
145+
/>
146+
</PaginatedSelectAddon>
147+
</PaginatedSelectWrapper>
176148
<PositionAnimated visible={visible} anchor={containerRef}>
177149
<_Options
178150
{...(withTitle && { title: withTitle })}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { ComponentProps, Ref } from 'react';
2+
import React, { forwardRef } from 'react';
3+
4+
import { Box } from '../Box';
5+
6+
type PaginatedSelectAddonProps = ComponentProps<typeof Box>;
7+
8+
const PaginatedSelectAddon = forwardRef(function PaginatedSelectAddon(
9+
props: PaginatedSelectAddonProps,
10+
ref: Ref<HTMLDivElement>
11+
) {
12+
return <Box is='div' rcx-select__addon ref={ref} {...props} />;
13+
});
14+
15+
export default PaginatedSelectAddon;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { ComponentStory, ComponentMeta } from '@storybook/react';
2+
import React from 'react';
3+
4+
import { PaginatedSelectFiltered } from '.';
5+
6+
export default {
7+
title: 'Inputs/PaginatedSelectFiltered',
8+
component: PaginatedSelectFiltered,
9+
args: {
10+
placeholder: 'Placeholder here...',
11+
options: Array.from({ length: 1000 }, (_, i) => ({
12+
value: i,
13+
label: `Item #${i}`,
14+
})),
15+
width: '250px',
16+
},
17+
parameters: {
18+
actions: { argTypesRegex: '^on.*' },
19+
layout: 'centered',
20+
},
21+
} as ComponentMeta<typeof PaginatedSelectFiltered>;
22+
23+
const Template: ComponentStory<typeof PaginatedSelectFiltered> = (args) => (
24+
<PaginatedSelectFiltered {...args} />
25+
);
26+
27+
export const normal = Template.bind({});
28+
29+
export const errored = Template.bind({});
30+
errored.args = {
31+
error: 'Error',
32+
};
33+
34+
export const disabled = Template.bind({});
35+
disabled.args = {
36+
disabled: true,
37+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
2+
import type { FormEvent, Ref } from 'react';
3+
import React, { useMemo, forwardRef } from 'react';
4+
5+
import { InputBox } from '../InputBox';
6+
import type { PaginatedSelectProps } from './PaginatedSelect';
7+
import { PaginatedSelect } from './PaginatedSelect';
8+
9+
type PaginatedSelectFilteredProps = Omit<PaginatedSelectProps, 'setFilter'> & {
10+
setFilter: (value: string | undefined | number) => void;
11+
};
12+
13+
export const PaginatedSelectFiltered = ({
14+
filter,
15+
setFilter,
16+
options,
17+
placeholder,
18+
...props
19+
}: PaginatedSelectFilteredProps) => {
20+
const anchor = useMemo(
21+
() =>
22+
forwardRef(
23+
(
24+
{
25+
filter,
26+
onChange: _onChange,
27+
...props
28+
}: PaginatedSelectFilteredProps,
29+
ref: Ref<HTMLInputElement>
30+
) => (
31+
<InputBox.Input
32+
mi='x4'
33+
flexGrow={1}
34+
className='rcx-select__focus'
35+
ref={ref}
36+
placeholder={placeholder}
37+
value={filter}
38+
onChange={useMutableCallback((e: FormEvent<HTMLInputElement>) => {
39+
setFilter(e.currentTarget.value);
40+
})}
41+
{...props}
42+
rcx-input-box--undecorated
43+
/>
44+
)
45+
),
46+
[placeholder, setFilter]
47+
);
48+
49+
return (
50+
<PaginatedSelect
51+
placeholder={undefined}
52+
filter={filter}
53+
options={options}
54+
{...props}
55+
anchor={anchor}
56+
/>
57+
);
58+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { ComponentProps, Ref } from 'react';
2+
import React, { forwardRef } from 'react';
3+
4+
import { Box } from '../Box';
5+
6+
type PaginatedSelectFocusProps = ComponentProps<typeof Box>;
7+
8+
const PaginatedSelectFocus = forwardRef(function PaginatedSelectFocus(
9+
props: PaginatedSelectFocusProps,
10+
ref: Ref<HTMLButtonElement>
11+
) {
12+
return (
13+
<Box
14+
ref={ref}
15+
fontScale='p2m'
16+
color='hint'
17+
rcx-select__focus
18+
is='button'
19+
type='button'
20+
{...props}
21+
/>
22+
);
23+
});
24+
25+
export default PaginatedSelectFocus;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { ComponentProps, Ref } from 'react';
2+
import React, { forwardRef } from 'react';
3+
4+
import { Box } from '../Box';
5+
6+
type PaginatedSelectWrapperProps = ComponentProps<typeof Box>;
7+
8+
const PaginatedSelectWrapper = forwardRef(function PaginatedSelectWrapper(
9+
props: PaginatedSelectWrapperProps,
10+
ref: Ref<HTMLDivElement>
11+
) {
12+
return <Box is='div' rcx-select__wrapper ref={ref} {...props} />;
13+
});
14+
15+
export default PaginatedSelectWrapper;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { PaginatedSelectFiltered } from './PaginatedSelectFiltered';
2+
export { PaginatedMultiSelectFiltered } from './PaginatedMultiSelect';

0 commit comments

Comments
 (0)