Skip to content

Commit

Permalink
fix(fuselage, regression): Select filter and anchor overhaul (#654)
Browse files Browse the repository at this point in the history
  • Loading branch information
juliajforesti authored Feb 23, 2022
1 parent 874604a commit 10ad4f1
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 75 deletions.
42 changes: 30 additions & 12 deletions packages/fuselage/src/components/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import {
useMutableCallback,
useResizeObserver,
} from '@rocket.chat/fuselage-hooks';
import type { ComponentProps, DependencyList, Ref, ElementType } from 'react';
import type {
ComponentProps,
DependencyList,
Ref,
ElementType,
ReactNode,
} from 'react';
import React, { useState, useRef, useEffect, forwardRef, useMemo } from 'react';

import { isForwardRefType } from '../../helpers/isForwardRefType';
import AnimatedVisibility from '../AnimatedVisibility';
import { Box } from '../Box';
import { Icon } from '../Icon';
Expand All @@ -14,6 +21,7 @@ import type { OptionType } from '../Options';
import { Options, useCursor } from '../Options';
import PositionAnimated from '../PositionAnimated';
import SelectAddon from './SelectAddon';
import type { SelectAnchorParams } from './SelectAnchorParams';
import SelectFocus from './SelectFocus';

export type SelectOption = readonly [
Expand Down Expand Up @@ -116,6 +124,18 @@ export const Select = forwardRef(
const innerRef = useRef<HTMLInputElement | null>(null);
const anchorRef = useMergedRefs(ref, innerRef);

const renderAnchor = (params: SelectAnchorParams) => {
if (isForwardRefType(Anchor)) {
return <Anchor {...params} />;
}

if (typeof Anchor === 'function') {
return (Anchor as (params: SelectAnchorParams) => ReactNode)(params);
}

return null;
};

const { ref: containerRef, borderBoxSize } = useResizeObserver();

useDidUpdate(reset, [filter, internalValue]);
Expand Down Expand Up @@ -171,17 +191,15 @@ export const Select = forwardRef(
{visibleText}
</Box>
))}
<Anchor
disabled={disabled}
rcx-input-box--undecorated
filter={filter}
ref={anchorRef}
aria-haspopup='listbox'
onClick={show}
onBlur={hide}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
/>
{renderAnchor({
ref: anchorRef,
children: !value ? option || placeholder : null,
disabled: disabled ?? false,
onClick: show,
onBlur: hide,
onKeyDown: handleKeyDown,
onKeyUp: handleKeyUp,
})}
<Margins inline='x4'>
<SelectAddon
children={
Expand Down
17 changes: 17 additions & 0 deletions packages/fuselage/src/components/Select/SelectAnchorParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type {
FocusEventHandler,
KeyboardEventHandler,
MouseEventHandler,
ReactNode,
Ref,
} from 'react';

export type SelectAnchorParams = {
ref: Ref<Element>;
children: ReactNode;
disabled: boolean;
onClick: MouseEventHandler;
onBlur: FocusEventHandler;
onKeyUp: KeyboardEventHandler;
onKeyDown: KeyboardEventHandler;
};
92 changes: 29 additions & 63 deletions packages/fuselage/src/components/Select/SelectFiltered.tsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,40 @@
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import type {
ComponentProps,
Dispatch,
FormEvent,
Ref,
SetStateAction,
} from 'react';
import React, { forwardRef, useCallback, useState } from 'react';
import type { ComponentProps, Dispatch, SetStateAction } from 'react';
import React, { useState } from 'react';

import { Select } from '.';
import type { Icon } from '..';
import { InputBox } from '../InputBox';
import type { SelectAnchorParams } from './SelectAnchorParams';
import SelectFilteredAnchor from './SelectFilteredAnchor';

export type SelectFilteredProps = ComponentProps<typeof Select> & {
filter?: string;
setFilter?: Dispatch<SetStateAction<string>>;
addonIcon?: ComponentProps<typeof Icon>['name'];
};

export const SelectFiltered = forwardRef(
(
{
options,
placeholder,
filter: propFilter,
setFilter: propSetFilter,
...props
}: SelectFilteredProps,
ref: Ref<HTMLInputElement>
) => {
const [filter, setFilter] = useState('');
const anchor = useCallback(
forwardRef(
(
{
children: _children,
filter,
...props
}: ComponentProps<typeof InputBox>,
ref: Ref<HTMLInputElement>
) => (
<InputBox.Input
mi='x4'
flexGrow={1}
className='rcx-select__focus'
ref={ref}
placeholder={placeholder}
value={propFilter || filter}
onChange={useMutableCallback((e: FormEvent<HTMLInputElement>) =>
propSetFilter
? propSetFilter(e.currentTarget.value)
: setFilter(e.currentTarget.value)
)}
{...props}
rcx-input-box--undecorated
/>
)
),
[]
);
export const SelectFiltered = ({
options,
placeholder,
filter: propFilter,
setFilter: propSetFilter,
...props
}: SelectFilteredProps) => {
const [filter, setFilter] = useState('');

return (
<Select
ref={ref}
placeholder={placeholder}
filter={filter}
options={options}
{...props}
anchor={anchor}
/>
);
}
);
return (
<Select
placeholder={placeholder}
filter={propFilter || filter}
options={options}
{...props}
anchor={(params: SelectAnchorParams) => (
<SelectFilteredAnchor
placeholder={placeholder}
filter={propFilter || filter}
onChangeFilter={propSetFilter || setFilter}
{...params}
/>
)}
/>
);
};
52 changes: 52 additions & 0 deletions packages/fuselage/src/components/Select/SelectFilteredAnchor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type {
FocusEventHandler,
FormEvent,
KeyboardEventHandler,
MouseEventHandler,
ReactNode,
Ref,
} from 'react';
import React, { forwardRef } from 'react';

import { InputBox } from '../InputBox';

type SelectFilteredAnchorProps = {
children: ReactNode;
disabled: boolean;
filter: string;
onChangeFilter: (filter: string) => void;
placeholder?: string;
onClick: MouseEventHandler;
onBlur: FocusEventHandler;
onKeyUp: KeyboardEventHandler;
onKeyDown: KeyboardEventHandler;
};

const SelectFilteredAnchor = forwardRef(function SelectFilteredAnchor(
{
children: _children,
filter,
onChangeFilter,
placeholder,
...props
}: SelectFilteredAnchorProps,
ref: Ref<Element>
) {
return (
<InputBox.Input
mi='x4'
flexGrow={1}
className='rcx-select__focus'
ref={ref}
placeholder={placeholder}
value={filter}
onInput={(e: FormEvent<HTMLInputElement>) =>
onChangeFilter(e.currentTarget.value)
}
{...props}
rcx-input-box--undecorated
/>
);
});

export default SelectFilteredAnchor;

0 comments on commit 10ad4f1

Please sign in to comment.