Skip to content

Commit

Permalink
feat(fuselage): Component Dropdown (#594)
Browse files Browse the repository at this point in the history
Co-authored-by: juliajforesti <juliajforesti@gmail.com>
  • Loading branch information
ggazzo and juliajforesti committed Dec 18, 2021
1 parent 62ba8f1 commit 31314b3
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 15 deletions.
43 changes: 28 additions & 15 deletions packages/fuselage-hooks/src/usePosition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,24 @@ type VariantBoundaries = {
};

type PositionStyle = {
top?: string;
left?: string;
top: string;
left: string;
position?: 'fixed';
zIndex?: '9999';
transition?: 'none !important';
opacity?: 0 | 1;
ZIndex: '9999';
transition: 'none !important';
bottom?: 0;
display?: 'flex';
display: 'flex';
};

type PositionEmptyResult = {
visibility: 'hidden';
top: '-9999px';
left: '-9999px';
position: 'fixed';
};

type PositionResult = {
style?: PositionStyle;
style: PositionStyle | PositionEmptyResult;
placement?: Placements;
};

Expand All @@ -89,6 +95,15 @@ const fallbackOrder = {
left: 'lrbt',
} as const;

const emptyStyle: PositionResult = {
style: {
position: 'fixed',
visibility: 'hidden',
top: '-9999px',
left: '-9999px',
},
};

const getParents = function (element: Element): Array<Element | Window> {
// Set up a parent array
const parents = [];
Expand Down Expand Up @@ -148,7 +163,7 @@ export const getPositionStyle = ({
margin?: number;
}): PositionResult => {
if (!targetBoundaries) {
return {};
return emptyStyle;
}

const { top, left, bottom, right } = container;
Expand Down Expand Up @@ -222,8 +237,7 @@ export const getPositionStyle = ({
bottom: margin,
display: 'flex',
}),
zIndex: '9999',
opacity: 1,
ZIndex: '9999',
},
placement: `${PlacementMap[placementAttempt]}-${
PlacementMap[variantsAttempts[0]]
Expand Down Expand Up @@ -274,9 +288,9 @@ export const getVariantBoundaries = ({
* @public
*/

export const usePosition = (
reference: RefObject<Element>,
target: RefObject<Element>,
export const usePosition = <T extends Element, R extends Element>(
reference: RefObject<R>,
target: RefObject<T>,
options: PositionOptions
): PositionResult => {
const {
Expand All @@ -287,7 +301,7 @@ export const usePosition = (
} = options;
const container = useRef(containerElement);

const [style, setStyle] = useDebouncedState<PositionResult>({}, 10);
const [style, setStyle] = useDebouncedState<PositionResult>(emptyStyle, 10);

const callback = useMutableCallback(() => {
const boundaries = target.current.getBoundingClientRect();
Expand Down Expand Up @@ -315,6 +329,5 @@ export const usePosition = (
useBoundingClientRect(target, watch, callback);
useBoundingClientRect(reference, watch, callback);
useBoundingClientRect(container, watch, callback);

return style;
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions packages/fuselage/src/components/Dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useRef } from 'react';

import { ActionButton, Box } from '..';
import Option from '../Options/Option/Option';
import { Dropdown } from './Dropdown';

export default {
title: 'Dropdown/Dropdown',
component: Dropdown,
parameters: {
jest: ['Dropdown.spec.tsx'],
},
};

export const Default = () => {
const anchor = useRef(null);
const target = useRef(null);

const list = Array.from(new Array(20));

return (
<Box
w='400px'
h='500px'
display='flex'
justifyContent='center'
alignItems='center'
>
<ActionButton ref={anchor} icon='doner' />
<Dropdown ref={target} reference={anchor} placement='bottom-end'>
{list.map((_, i) => (
<Option>Example {i + 1}</Option>
))}
</Dropdown>
</Box>
);
};
34 changes: 34 additions & 0 deletions packages/fuselage/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useMediaQuery, usePosition } from '@rocket.chat/fuselage-hooks';
import React, { forwardRef, ReactNode, Ref, RefObject } from 'react';

import { DropdownDesktop } from './DropdownDesktop';
import { DropdownMobile } from './DropdownMobile';

export const Dropdown = forwardRef(function Dropdown<
T extends HTMLElement,
R extends HTMLElement
>(
{
children,
reference,
placement = 'bottom-start',
}: {
reference: RefObject<T>;
placement?: Parameters<typeof usePosition>[2]['placement'];
children: ReactNode;
},
ref: Ref<R>
) {
const notSmall = useMediaQuery('(min-width: 500px)');

return notSmall ? (
<DropdownDesktop
reference={reference}
children={children}
placement={placement}
ref={ref}
/>
) : (
<DropdownMobile children={children} ref={ref} />
);
});
39 changes: 39 additions & 0 deletions packages/fuselage/src/components/Dropdown/DropdownDesktop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { usePosition } from '@rocket.chat/fuselage-hooks';
import React, { forwardRef, ReactNode, Ref, RefObject } from 'react';

import { Box, Tile } from '..';

export const DropdownDesktop = forwardRef(function DropdownDesktop<
T extends HTMLElement,
R extends HTMLElement
>(
{
children,
reference,
placement = 'bottom-start',
}: {
reference: RefObject<T>;
placement?: Parameters<typeof usePosition>[2]['placement'];
children: ReactNode;
},
ref: Ref<R>
) {
const { style } = usePosition(reference, ref as RefObject<R>, { placement });

return (
<Tile
style={style}
ref={ref}
elevation='2'
pi='0'
pb='0'
display='flex'
flexDirection='column'
overflow='auto'
>
<Box flexShrink={1} pb='x16'>
{children}
</Box>
</Tile>
);
});
35 changes: 35 additions & 0 deletions packages/fuselage/src/components/Dropdown/DropdownMobile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { forwardRef, ReactNode, Ref } from 'react';

import { Box, Tile } from '..';

export const DropdownMobile = forwardRef(function DropdownMobile<
R extends HTMLElement
>(
{
children,
}: {
children: ReactNode;
},
ref: Ref<R>
) {
return (
<Tile
ref={ref}
elevation='2'
pi='0'
pb='0'
w='100%'
maxHeight='80%'
position='fixed'
display='flex'
flexDirection='column'
overflow='auto'
style={{ bottom: 0, left: 0 }}
zIndex={2}
>
<Box flexShrink={1} pb='x16'>
{children}
</Box>
</Tile>
);
});
1 change: 1 addition & 0 deletions packages/fuselage/src/components/Dropdown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Dropdown';
1 change: 1 addition & 0 deletions packages/fuselage/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './CheckBox';
export * from './Chevron';
export { default as Chip } from './Chip';
export * from './Divider';
export * from './Dropdown';
export * from './EmailInput';
export * from './Field';
export * from './FieldGroup';
Expand Down

0 comments on commit 31314b3

Please sign in to comment.