diff --git a/packages/eslint-config-alt/typescript/index.js b/packages/eslint-config-alt/typescript/index.js index 96a02c8bed..a088af8015 100644 --- a/packages/eslint-config-alt/typescript/index.js +++ b/packages/eslint-config-alt/typescript/index.js @@ -8,6 +8,7 @@ module.exports = { plugins: ['@typescript-eslint', 'prettier'], rules: { '@typescript-eslint/ban-ts-ignore': 'off', + '@typescript-eslint/ban-ts-comment': 'warn', '@typescript-eslint/indent': 'off', '@typescript-eslint/no-empty-function': 'error', '@typescript-eslint/no-extra-parens': 'off', diff --git a/packages/fuselage-hooks/src/useAutoFocus.ts b/packages/fuselage-hooks/src/useAutoFocus.ts index 4554e47912..0c8e84c67f 100644 --- a/packages/fuselage-hooks/src/useAutoFocus.ts +++ b/packages/fuselage-hooks/src/useAutoFocus.ts @@ -7,12 +7,15 @@ import { useEffect, useRef, Ref } from 'react'; * @param options - options of the focus request * @returns the ref which holds the element * @public + * @deprecated */ -export const useAutoFocus = ( +export const useAutoFocus = < + T extends { focus: (options?: FocusOptions) => void } +>( isFocused = true, options?: FocusOptions -): Ref<{ focus: (options?: FocusOptions) => void }> => { - const elementRef = useRef<{ focus: (options?: FocusOptions) => void }>(); +): Ref => { + const elementRef = useRef(); const { preventScroll } = options || {}; diff --git a/packages/fuselage-ui-kit/src/elements/OverflowElement.tsx b/packages/fuselage-ui-kit/src/elements/OverflowElement.tsx index c661fd9f36..3b39eeaa4d 100644 --- a/packages/fuselage-ui-kit/src/elements/OverflowElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/OverflowElement.tsx @@ -4,6 +4,7 @@ import { Options, Icon, useCursor, + OptionType, } from '@rocket.chat/fuselage'; import * as UiKit from '@rocket.chat/ui-kit'; import React, { useRef, useCallback, ReactElement, useMemo } from 'react'; @@ -49,7 +50,7 @@ const OverflowElement = ({ }, [show]); const handleSelection = useCallback( - ([value]: [unknown, string]) => { + ([value]: OptionType) => { action({ target: { value } }); reset(); hide(); diff --git a/packages/fuselage/package.json b/packages/fuselage/package.json index 3f5f5717fb..81b253d963 100644 --- a/packages/fuselage/package.json +++ b/packages/fuselage/package.json @@ -69,11 +69,11 @@ "@babel/plugin-transform-runtime": "^7.16.0", "@babel/preset-env": "^7.16.0", "@babel/preset-react": "^7.16.0", - "@rocket.chat/eslint-config-alt": "workspace:packages/eslint-config-alt", - "@rocket.chat/fuselage-hooks": "workspace:packages/fuselage-hooks", - "@rocket.chat/fuselage-polyfills": "workspace:packages/fuselage-polyfills", - "@rocket.chat/icons": "workspace:packages/icons", - "@rocket.chat/prettier-config": "workspace:packages/prettier-config", + "@rocket.chat/eslint-config-alt": "workspace:^", + "@rocket.chat/fuselage-hooks": "workspace:^", + "@rocket.chat/fuselage-polyfills": "workspace:^", + "@rocket.chat/icons": "workspace:^", + "@rocket.chat/prettier-config": "workspace:^", "@storybook/addon-essentials": "~6.4.18", "@storybook/addon-jest": "~6.4.18", "@storybook/addon-links": "~6.4.18", @@ -110,7 +110,6 @@ "postcss-logical": "^4.0.2", "postcss-svg": "^3.0.0", "prettier": "^2.3.2", - "prop-types": "^15.7.2", "react": "^17.0.2", "react-dom": "^17.0.2", "react-live": "^2.3.0", diff --git a/packages/fuselage/src/components/Accordion/AccordionItem.tsx b/packages/fuselage/src/components/Accordion/AccordionItem.tsx index 262368ea46..a4ac539705 100644 --- a/packages/fuselage/src/components/Accordion/AccordionItem.tsx +++ b/packages/fuselage/src/components/Accordion/AccordionItem.tsx @@ -1,12 +1,12 @@ import { useToggle, useUniqueId } from '@rocket.chat/fuselage-hooks'; -import PropTypes from 'prop-types'; -import React, { FC, KeyboardEvent, MouseEvent, ReactNode } from 'react'; +import React, { FormEvent, KeyboardEvent, MouseEvent, ReactNode } from 'react'; import { Box } from '../Box'; import { Chevron } from '../Chevron'; import { ToggleSwitch } from '../ToggleSwitch'; -export const AccordionItem: FC<{ +type AccordionItemProps = { + children?: ReactNode; className?: string; defaultExpanded?: boolean; disabled?: boolean; @@ -14,13 +14,11 @@ export const AccordionItem: FC<{ tabIndex?: number; title: ReactNode; noncollapsible?: boolean; - onToggle?: ( - e: MouseEvent | KeyboardEvent - ) => void; - onToggleEnabled?: ( - e: MouseEvent | KeyboardEvent - ) => void; -}> = function Item({ + onToggle?: (e: MouseEvent | KeyboardEvent) => void; + onToggleEnabled?: (e: FormEvent) => void; +}; + +export const AccordionItem = function Item({ children, className, defaultExpanded, @@ -32,12 +30,10 @@ export const AccordionItem: FC<{ onToggle, onToggleEnabled, ...props -}) { +}: AccordionItemProps) { const [stateExpanded, toggleStateExpanded] = useToggle(defaultExpanded); const expanded = propExpanded || stateExpanded; - const toggleExpanded = ( - event: MouseEvent | KeyboardEvent - ) => { + const toggleExpanded = (event: MouseEvent | KeyboardEvent) => { if (onToggle) { onToggle.call(event.currentTarget, event); return; @@ -51,7 +47,7 @@ export const AccordionItem: FC<{ const titleId = useUniqueId(); const panelId = useUniqueId(); - const handleClick = (e: MouseEvent) => { + const handleClick = (e: MouseEvent) => { if (disabled) { return; } @@ -59,7 +55,7 @@ export const AccordionItem: FC<{ toggleExpanded(e); }; - const handleKeyDown = (event: KeyboardEvent) => { + const handleKeyDown = (event: KeyboardEvent) => { if (disabled || event.currentTarget !== event.target) { return; } @@ -85,13 +81,13 @@ export const AccordionItem: FC<{ 'tabIndex': !disabled ? tabIndex : undefined, 'onClick': handleClick, 'onKeyDown': handleKeyDown, - }; + } as const; const nonCollapsibleProps = { 'aria-disabled': 'true', 'aria-expanded': 'true', 'aria-labelledby': titleId, - }; + } as const; const barProps = noncollapsible ? nonCollapsibleProps : collapsibleProps; @@ -135,13 +131,3 @@ export const AccordionItem: FC<{ ); }; - -AccordionItem.propTypes = { - defaultExpanded: PropTypes.bool, - disabled: PropTypes.bool, - expanded: PropTypes.bool, - tabIndex: PropTypes.number, - title: PropTypes.node, - onToggle: PropTypes.func, - onToggleEnabled: PropTypes.func, -}; diff --git a/packages/fuselage/src/components/AutoComplete/AutoComplete.d.ts b/packages/fuselage/src/components/AutoComplete/AutoComplete.d.ts new file mode 100644 index 0000000000..075ffc2345 --- /dev/null +++ b/packages/fuselage/src/components/AutoComplete/AutoComplete.d.ts @@ -0,0 +1,18 @@ +import { ElementType, FC } from 'react'; + +type AutoCompleteProps = { + value: unknown[]; + filter: string; + setFilter?: (filter: string) => void; + options?: { label: string; value: unknown }[]; + renderItem?: ElementType; + renderSelected?: ElementType; + onChange: (value: unknown, action: 'remove' | undefined) => void; + getLabel?: (option: { label: string; value: unknown }) => string; + getValue?: (option: { label: string; value: unknown }) => unknown; + renderEmpty?: ElementType; + placeholder?: string; + error?: boolean; + disabled?: boolean; +}; +export const AutoComplete: FC; diff --git a/packages/fuselage/src/components/AutoComplete/AutoComplete.tsx b/packages/fuselage/src/components/AutoComplete/AutoComplete.js similarity index 69% rename from packages/fuselage/src/components/AutoComplete/AutoComplete.tsx rename to packages/fuselage/src/components/AutoComplete/AutoComplete.js index e2e64a33c5..9e879c77d2 100644 --- a/packages/fuselage/src/components/AutoComplete/AutoComplete.tsx +++ b/packages/fuselage/src/components/AutoComplete/AutoComplete.js @@ -2,15 +2,7 @@ import { useMutableCallback, useResizeObserver, } from '@rocket.chat/fuselage-hooks'; -import React, { - useEffect, - useRef, - useMemo, - useState, - ComponentProps, - ElementType, - FC, -} from 'react'; +import React, { useEffect, useRef, useMemo, useState } from 'react'; import { Box, PositionAnimated, AnimatedVisibility } from '../Box'; import Chip from '../Chip'; @@ -18,36 +10,11 @@ import { Icon } from '../Icon'; import { InputBox } from '../InputBox'; import Margins from '../Margins'; import { useCursor, Options } from '../Options'; -import { Option } from '../Options/useCursor'; -type OptionValue = string | number; -type OptionType = { - value: OptionValue; - label?: string | number; -}; - -type AutoCompleteProps = Omit, 'options'> & { - value: OptionValue; - filter: string; - setFilter?: (filter: string) => void; - options?: OptionType[]; - renderItem?: ElementType; - renderSelected?: ElementType; - onChange: (value: OptionValue, action?: 'remove' | undefined) => void; - getLabel?: (option: OptionType) => string; - getValue?: (option: OptionType) => OptionValue; - renderEmpty?: ElementType; - placeholder?: string; - error?: boolean; - disabled?: boolean; -}; - -const Addon = (props: ComponentProps) => ( - -); +const Addon = (props) => ; const SelectedOptions = React.memo((props) => ); -export const AutoComplete: FC = ({ +export function AutoComplete({ value, filter, setFilter = () => {}, @@ -55,39 +22,34 @@ export const AutoComplete: FC = ({ renderItem, renderSelected: RenderSelected = SelectedOptions, onChange = () => {}, - getLabel = ({ label }) => label, + getLabel = ({ label } = {}) => label, getValue = ({ value }) => value, renderEmpty, placeholder, error, disabled, -}) => { +}) { const { ref: containerRef, borderBoxSize } = useResizeObserver(); - const ref = useRef(null); + const ref = useRef(); const [selected, setSelected] = useState(() => options.find((option) => getValue(option) === value) ); - const index = (selected && options.indexOf(selected)) || 0; - const selectByKeyboard = useMutableCallback(([value]) => { setSelected(options.find((option) => getValue(option) === value)); onChange(value); setFilter(''); }); - const memoizedOptions = useMemo<[unknown, string, boolean?][]>( - () => - options.map( - ({ label, value }) => [value, label] as [unknown, string, boolean?] - ), + const memoizedOptions = useMemo( + () => options.map(({ label, value }) => [value, label]), [options] ); const [cursor, handleKeyDown, , reset, [optionsAreVisible, hide, show]] = - useCursor(index, memoizedOptions as Option[], selectByKeyboard); + useCursor(value, memoizedOptions, selectByKeyboard); const onSelect = useMutableCallback(([value]) => { setSelected(options.find((option) => getValue(option) === value)); @@ -102,7 +64,7 @@ export const AutoComplete: FC = ({ ref.current && ref.current.focus())} + onClick={useMutableCallback(() => ref.current.focus())} flexGrow={1} className={useMemo( () => [error && 'invalid', disabled && 'disabled'], @@ -171,4 +133,4 @@ export const AutoComplete: FC = ({ ); -}; +} diff --git a/packages/fuselage/src/components/AutoComplete/AutoComplete.spec.tsx b/packages/fuselage/src/components/AutoComplete/AutoComplete.spec.tsx index 521dfefce0..23be74c4b1 100644 --- a/packages/fuselage/src/components/AutoComplete/AutoComplete.spec.tsx +++ b/packages/fuselage/src/components/AutoComplete/AutoComplete.spec.tsx @@ -10,7 +10,7 @@ it('renders without crashing', () => { render( null} onChange={jest.fn()} /> diff --git a/packages/fuselage/src/components/AutoComplete/AutoComplete.stories.tsx b/packages/fuselage/src/components/AutoComplete/AutoComplete.stories.tsx index 94a9c759e2..dbc5139ed8 100644 --- a/packages/fuselage/src/components/AutoComplete/AutoComplete.stories.tsx +++ b/packages/fuselage/src/components/AutoComplete/AutoComplete.stories.tsx @@ -19,7 +19,8 @@ export default { export const Example = () => { const [options, setOptions] = useState([]); const [filter, setFilter] = useState(''); - const [value, setValue] = useState(''); + + const [value, setValue] = useState([]); useEffect(() => { (async () => { @@ -27,13 +28,21 @@ export const Example = () => { setOptions(result); })(); }, [filter]); + + const handleValue = (value: unknown, action: 'remove' | undefined): void => { + if (action) { + return; + } + setValue([]); + }; + return ( ); }; diff --git a/packages/fuselage/src/components/Avatar/Avatar.tsx b/packages/fuselage/src/components/Avatar/Avatar.tsx index 3c2b8e585f..ad13ba283a 100644 --- a/packages/fuselage/src/components/Avatar/Avatar.tsx +++ b/packages/fuselage/src/components/Avatar/Avatar.tsx @@ -1,19 +1,9 @@ -import React, { - ComponentPropsWithoutRef, - FC, - DetailedHTMLProps, - HTMLAttributes, -} from 'react'; +import React, { DetailedHTMLProps, HTMLAttributes } from 'react'; import flattenChildren from 'react-keyed-flatten-children'; -import { Box } from '..'; import { prependClassName } from '../../helpers/prependClassName'; -type AvatarProps = Omit< - ComponentPropsWithoutRef, - 'title' | 'size' | 'className' -> & { - title?: string; +export type AvatarProps = { size?: | 'x16' | 'x18' @@ -30,19 +20,16 @@ type AvatarProps = Omit< rounded?: boolean; objectFit?: boolean; url: string; - className?: string; -}; +} & HTMLAttributes; -export const Avatar: FC & { - Stack: typeof AvatarStack; -} = function Avatar({ +export const Avatar = ({ title, size = 'x36', rounded = false, objectFit = false, url, ...props -}) { +}: AvatarProps) => { props.className = prependClassName( props.className, ['rcx-box rcx-box--full rcx-avatar', size && `rcx-avatar--${size}`] @@ -65,9 +52,12 @@ export const Avatar: FC & { ); }; -const AvatarStack: FC< - DetailedHTMLProps, HTMLDivElement> -> = ({ children, ...props }) => { +type AvatarStackProps = DetailedHTMLProps< + HTMLAttributes, + HTMLDivElement +>; + +const AvatarStack = ({ children, ...props }: AvatarStackProps) => { props.className = prependClassName(props.className, 'rcx-avatar-stack'); return
{flattenChildren(children).reverse()}
; }; diff --git a/packages/fuselage/src/components/Badge/Badge.tsx b/packages/fuselage/src/components/Badge/Badge.tsx index d9186a319b..8fc6470ddc 100644 --- a/packages/fuselage/src/components/Badge/Badge.tsx +++ b/packages/fuselage/src/components/Badge/Badge.tsx @@ -2,7 +2,7 @@ import React, { ElementType } from 'react'; import { prependClassName } from '../../helpers/prependClassName'; -type BadgeProps = { +export type BadgeProps = { is?: ElementType; variant?: 'secondary' | 'primary' | 'danger' | 'warning' | 'ghost'; disabled?: boolean; diff --git a/packages/fuselage/src/components/Banner/Banner.tsx b/packages/fuselage/src/components/Banner/Banner.tsx index 60ebe2878e..303b0c1109 100644 --- a/packages/fuselage/src/components/Banner/Banner.tsx +++ b/packages/fuselage/src/components/Banner/Banner.tsx @@ -3,7 +3,6 @@ import React, { useRef, useCallback, useMemo, - FC, ReactNode, AllHTMLAttributes, } from 'react'; @@ -35,7 +34,7 @@ type BannerProps = { onClose?: () => void; } & AllHTMLAttributes; -const Banner: FC = ({ +const Banner = ({ inline = false, children, className, @@ -47,7 +46,7 @@ const Banner: FC = ({ onAction, onClose, ...props -}) => { +}: BannerProps) => { useStyleSheet(); useStyleSheet(styleSheet); diff --git a/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.tsx b/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.tsx index 9b4300a6b6..387ea5bb06 100644 --- a/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.tsx +++ b/packages/fuselage/src/components/Box/AnimatedVisibility/AnimatedVisibility.tsx @@ -1,5 +1,5 @@ import { css, keyframes } from '@rocket.chat/css-in-js'; -import React, { FC, ReactNode, useCallback, useEffect, useState } from 'react'; +import React, { ReactNode, useCallback, useEffect, useState } from 'react'; import { appendClassName } from '../../../helpers/appendClassName'; import { useStyle } from '../../../hooks/useStyle'; @@ -24,7 +24,7 @@ const Visibility = { UNHIDING: 'unhiding' as VisibilityType, }; -const AnimatedVisibility: FC = (props) => { +const AnimatedVisibility = (props: AnimatedVisibilityProps) => { const propVisibility = props.visibility || Visibility.HIDDEN; const [visibility, setVisibility] = useState(propVisibility); diff --git a/packages/fuselage/src/components/Box/Position/Position.tsx b/packages/fuselage/src/components/Box/Position/Position.tsx index 67c011f5d8..683eec8200 100644 --- a/packages/fuselage/src/components/Box/Position/Position.tsx +++ b/packages/fuselage/src/components/Box/Position/Position.tsx @@ -6,15 +6,19 @@ import { cloneElement, RefObject, ComponentProps, + ReactPortal, + ReactElement, } from 'react'; import { createPortal } from 'react-dom'; import { Box } from '..'; type PositionProps = { - anchor?: RefObject; + anchor: RefObject; + children: ReactElement; + margin?: number; placement?: Placements; -} & ComponentProps; +} & Omit, 'children' | 'margin'>; const Position = ({ anchor, @@ -23,7 +27,7 @@ const Position = ({ margin, className, ...props -}: PositionProps) => { +}: PositionProps): ReactPortal => { const target = useRef(null); const { style: positionStyle, placement: positionPlacement } = usePosition( diff --git a/packages/fuselage/src/components/Box/Position/PositionAnimated.tsx b/packages/fuselage/src/components/Box/Position/PositionAnimated.tsx index c23d6ffef0..5ecfb55b48 100644 --- a/packages/fuselage/src/components/Box/Position/PositionAnimated.tsx +++ b/packages/fuselage/src/components/Box/Position/PositionAnimated.tsx @@ -1,4 +1,4 @@ -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import Position from '.'; import AnimatedVisibility from '../AnimatedVisibility'; @@ -7,12 +7,12 @@ type PositionAnimatedProps = { visible?: 'hidden' | 'visible' | 'hiding' | 'unhiding'; } & ComponentProps; -const PositionAnimated: FC = ({ +const PositionAnimated = ({ width, visible, children, ...props -}) => ( +}: PositionAnimatedProps) => ( {children} diff --git a/packages/fuselage/src/components/Box/Scrollable/Scrollable.tsx b/packages/fuselage/src/components/Box/Scrollable/Scrollable.tsx index c6cfb4c8ca..d0820b0ccd 100644 --- a/packages/fuselage/src/components/Box/Scrollable/Scrollable.tsx +++ b/packages/fuselage/src/components/Box/Scrollable/Scrollable.tsx @@ -6,7 +6,6 @@ import React, { PropsWithChildren, MouseEvent, MutableRefObject, - FC, } from 'react'; import { appendClassName } from '../../../helpers/appendClassName'; @@ -48,13 +47,13 @@ const pollTouchingEdges = ( } }; -export const Scrollable: FC = ({ +export const Scrollable = ({ children, horizontal, vertical, smooth, onScrollContent, -}) => { +}: ScrollableProps) => { const scrollTimeoutRef = useRef>(); const touchingEdgesRef = useRef({}); diff --git a/packages/fuselage/src/components/Box/index.d.ts b/packages/fuselage/src/components/Box/index.d.ts index 9ff6bc493b..93f8162322 100644 --- a/packages/fuselage/src/components/Box/index.d.ts +++ b/packages/fuselage/src/components/Box/index.d.ts @@ -1,10 +1,9 @@ import type { css } from '@rocket.chat/css-in-js'; -import { +import type { AllHTMLAttributes, + ComponentProps, CSSProperties, ElementType, - ForwardRefExoticComponent, - PropsWithChildren, ReactElement, RefAttributes, SVGAttributes, @@ -29,16 +28,11 @@ type FontScale = | 'c2' | 'micro'; -type BoxProps = PropsWithChildren<{ - is?: - | ReactElement> - | (ElementType & string) - | string; - className?: - | string - | ReturnType - | (string | ReturnType)[]; - style?: CSSProperties; +type Falsy = false | 0 | '' | null | undefined; + +type EvaluableCss = ReturnType; + +type BoxStylingProps = { border?: CSSProperties['border']; borderBlock?: CSSProperties['borderBlock']; borderBlockStart?: CSSProperties['borderBlockStart']; @@ -154,6 +148,7 @@ type BoxProps = PropsWithChildren<{ textTransform?: CSSProperties['textTransform']; textDecorationLine?: CSSProperties['textDecorationLine']; + animated?: boolean; elevation?: '0' | '1' | '2'; invisible?: boolean; withRichContent?: boolean | string; @@ -162,12 +157,37 @@ type BoxProps = PropsWithChildren<{ minSize?: CSSProperties['blockSize']; maxSize?: CSSProperties['blockSize']; fontScale?: FontScale; -}> & - Omit, 'className' | 'size'> & - Omit, keyof AllHTMLAttributes> & - RefAttributes; -export const Box: ForwardRefExoticComponent; + className?: string | EvaluableCss | (string | EvaluableCss | Falsy)[]; +}; + +export type BoxProps = { + is?: TElementType; + htmlSize?: 'size' extends keyof ComponentProps + ? ComponentProps['size'] + : never; +} & BoxStylingProps & + Omit, 'is' | 'className' | 'size'>; + +type UnsafeBoxProps = { + is?: ElementType; + htmlSize?: AllHTMLAttributes['size']; +} & BoxStylingProps & + Omit, 'ref' | 'is' | 'className' | 'size'> & + Omit, keyof AllHTMLAttributes> & + RefAttributes; + +export const Box: { + // `Box` unfortunately cannot be a generic component because of the abuse of `ComponentProps` + // ( + // props: BoxProps + // ): ReactElement | null; + (props: UnsafeBoxProps): ReactElement | null; + defaultProps?: undefined; + propTypes?: undefined; + displayName?: string | undefined; + readonly $$typeof: symbol; +}; export { default as AnimatedVisibility } from './AnimatedVisibility'; export { default as Flex } from './Flex'; diff --git a/packages/fuselage/src/components/Box/index.js b/packages/fuselage/src/components/Box/index.js index 4e1ceebffb..e99a3d2db2 100644 --- a/packages/fuselage/src/components/Box/index.js +++ b/packages/fuselage/src/components/Box/index.js @@ -1,5 +1,4 @@ import { css } from '@rocket.chat/css-in-js'; -import PropTypes from 'prop-types'; import React, { createElement, forwardRef, memo } from 'react'; import { appendClassName } from '../../helpers/appendClassName'; @@ -103,22 +102,7 @@ export const Box = memo( }) ); -if (process.env.NODE_ENV !== 'production') { - Box.displayName = 'Box'; - - Box.propTypes = { - is: PropTypes.elementType, - className: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.func, - PropTypes.array, - ]), - }; -} - -Box.defaultProps = { - is: 'div', -}; +Box.displayName = 'Box'; export { default as AnimatedVisibility } from './AnimatedVisibility'; export { default as Flex } from './Flex'; diff --git a/packages/fuselage/src/components/Button/ActionButton.tsx b/packages/fuselage/src/components/Button/ActionButton.tsx index dfa35cca11..3a2a356f15 100644 --- a/packages/fuselage/src/components/Button/ActionButton.tsx +++ b/packages/fuselage/src/components/Button/ActionButton.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, ForwardRefExoticComponent } from 'react'; +import React, { ComponentProps, forwardRef, Ref } from 'react'; import { Button } from '.'; import { Icon } from '../Icon'; @@ -11,7 +11,7 @@ type ButtonSize = { }; type ActionButtonProps = ButtonProps & ButtonSize & { - icon: string; + icon: ComponentProps['name']; }; const getSize = ({ tiny, mini, small }: ButtonSize) => { @@ -24,10 +24,11 @@ const getSize = ({ tiny, mini, small }: ButtonSize) => { return 'x20'; }; -export const ActionButton: ForwardRefExoticComponent = - forwardRef(({ icon, children, ...props }, ref) => ( +export const ActionButton = forwardRef( + ({ icon, children, ...props }: ActionButtonProps, ref: Ref) => ( - )); + ) +); diff --git a/packages/fuselage/src/components/Button/Button.tsx b/packages/fuselage/src/components/Button/Button.tsx index 1c5acc576d..7167a8affc 100644 --- a/packages/fuselage/src/components/Button/Button.tsx +++ b/packages/fuselage/src/components/Button/Button.tsx @@ -1,9 +1,4 @@ -import React, { - ComponentProps, - forwardRef, - ForwardRefExoticComponent, - useMemo, -} from 'react'; +import React, { ComponentProps, forwardRef, Ref, useMemo } from 'react'; import { Box } from '../Box'; @@ -23,77 +18,75 @@ export type ButtonProps = ComponentProps & { external?: boolean; }; -export const Button: ForwardRefExoticComponent = forwardRef( - function Button( - { - info, - success, - warning, - danger, - primary, - ghost, - nude, - ghostish, - external, - is = 'button', - rel, - small, - tiny, - mini, - square, - ...props - }, - ref - ) { - const extraProps = - (is === 'a' && { - rel: external && 'noopener noreferrer', - target: external && '_blank', - }) || - (is === 'button' && { - type: 'button', - }) || - {}; +export const Button = forwardRef(function Button( + { + info, + success, + warning, + danger, + primary, + ghost, + nude, + ghostish, + external, + is = 'button', + rel, + small, + tiny, + mini, + square, + ...props + }: ButtonProps, + ref: Ref +) { + const extraProps = + (is === 'a' && { + rel: external ? 'noopener noreferrer' : undefined, + target: external ? '_blank' : undefined, + }) || + (is === 'button' && { + type: 'button', + }) || + {}; - const kindAndVariantProps = useMemo(() => { - const variant = - (info && 'info') || - (success && 'success') || - (warning && 'warning') || - (danger && 'danger'); + const kindAndVariantProps = useMemo(() => { + const variant = + (info && 'info') || + (success && 'success') || + (warning && 'warning') || + (danger && 'danger'); - const kind = - (primary && !ghost && !nude && !ghostish && 'primary') || - (!primary && ghost && !nude && !ghostish && 'ghost') || - (!primary && !ghost && nude && !ghostish && 'nude') || - (!primary && !ghost && !nude && ghostish && 'ghostish'); + const kind = + (primary && !ghost && !nude && !ghostish && 'primary') || + (!primary && ghost && !nude && !ghostish && 'ghost') || + (!primary && !ghost && nude && !ghostish && 'nude') || + (!primary && !ghost && !nude && ghostish && 'ghostish'); - if (kind || variant) { - return { - [`rcx-button--${[kind, variant].filter(Boolean).join('-')}`]: true, - }; - } + if (kind || variant) { + return { + [`rcx-button--${[kind, variant].filter(Boolean).join('-')}`]: true, + }; + } - return {}; - }, [danger, ghost, ghostish, info, nude, primary, success, warning]); + return {}; + }, [danger, ghost, ghostish, info, nude, primary, success, warning]); - return ( - - ); - } -); + return ( + + ); +}); export default Button; diff --git a/packages/fuselage/src/components/ButtonGroup/ButtonGroup.tsx b/packages/fuselage/src/components/ButtonGroup/ButtonGroup.tsx index ea527ca40a..3b6f382ad1 100644 --- a/packages/fuselage/src/components/ButtonGroup/ButtonGroup.tsx +++ b/packages/fuselage/src/components/ButtonGroup/ButtonGroup.tsx @@ -1,11 +1,10 @@ -import PropTypes from 'prop-types'; -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import { appendClassName } from '../../helpers/appendClassName'; import { patchChildren } from '../../helpers/patchChildren'; import { Box } from '../Box'; -type ButtonGroupProps = ComponentProps & { +type ButtonGroupProps = Omit, 'wrap'> & { align?: 'start' | 'center' | 'end'; stretch?: boolean; wrap?: boolean; @@ -14,8 +13,8 @@ type ButtonGroupProps = ComponentProps & { medium?: boolean; }; -export const ButtonGroup: FC = ({ - align, +export const ButtonGroup = ({ + align = 'start', children, stretch, vertical, @@ -23,7 +22,7 @@ export const ButtonGroup: FC = ({ small, medium, ...props -}) => ( +}: ButtonGroupProps) => ( = ({ )} ); - -ButtonGroup.defaultProps = { - align: 'start', -}; - -ButtonGroup.propTypes = { - /** The alignment that should be applied to the items */ - align: PropTypes.oneOf(['start', 'center', 'end']), - /** Will be the items stretched to fill space? */ - stretch: PropTypes.bool, - /** Is the items vertically placed? */ - vertical: PropTypes.bool, - /** Will wrap the items when they exceed the container space? */ - wrap: PropTypes.bool, - small: PropTypes.bool, - medium: PropTypes.bool, -}; diff --git a/packages/fuselage/src/components/Callout/Callout.tsx b/packages/fuselage/src/components/Callout/Callout.tsx index f4e69ec2cb..3eeec58e08 100644 --- a/packages/fuselage/src/components/Callout/Callout.tsx +++ b/packages/fuselage/src/components/Callout/Callout.tsx @@ -1,4 +1,4 @@ -import React, { ComponentProps, FC, ReactNode } from 'react'; +import React, { ComponentProps, ReactNode } from 'react'; import { Box } from '../Box'; import { Icon } from '../Icon'; @@ -6,15 +6,15 @@ import { Icon } from '../Icon'; type CalloutProps = Omit, 'type' | 'name'> & { type?: 'info' | 'success' | 'warning' | 'danger'; title?: ReactNode; - children: ReactNode; + children?: ReactNode; }; -export const Callout: FC = function Callout({ +export const Callout = ({ children, title, type = 'info', ...props -}) { +}: CalloutProps) => { const iconName: 'info-circled' | 'checkmark-circled' | 'warning' | 'ban' = (type === 'info' && 'info-circled') || (type === 'success' && 'checkmark-circled') || diff --git a/packages/fuselage/src/components/CheckBox/CheckBox.tsx b/packages/fuselage/src/components/CheckBox/CheckBox.tsx index 998a899cbf..9c53b19cc0 100644 --- a/packages/fuselage/src/components/CheckBox/CheckBox.tsx +++ b/packages/fuselage/src/components/CheckBox/CheckBox.tsx @@ -5,8 +5,8 @@ import React, { useRef, useCallback, ComponentProps, - ForwardRefExoticComponent, - FormEventHandler, + Ref, + FormEvent, } from 'react'; import { Box } from '../Box'; @@ -14,90 +14,74 @@ import { Label } from '../Label'; type CheckBoxProps = ComponentProps & { 'indeterminate'?: boolean; - 'autoComplete': string; - 'checked': boolean; - 'defaultChecked': boolean; - 'disabled': boolean; - 'form': string; - 'id': string; - 'name': string; - 'required': boolean; - 'tabIndex': number; - 'value': string; - 'qa': string; - 'data-qa': string; - 'onChange': FormEventHandler; - 'onInput': () => void; - 'onInvalid': () => void; + 'qa'?: string; + 'data-qa'?: string; }; -export const CheckBox: ForwardRefExoticComponent = forwardRef( - function CheckBox( - { - autoComplete, - checked, - defaultChecked, - disabled, - form, - id, - indeterminate, - name, - required, - tabIndex, - value, - qa, - 'data-qa': dataQa, - onChange, - onInput, - onInvalid, - ...props - }, - ref - ) { - const innerRef = useRef(null); - const mergedRef = useMergedRefs(ref, innerRef); +export const CheckBox = forwardRef(function CheckBox( + { + autoComplete, + checked, + defaultChecked, + disabled, + form, + id, + indeterminate, + name, + required, + tabIndex, + value, + qa, + 'data-qa': dataQa, + onChange, + onInput, + onInvalid, + ...props + }: CheckBoxProps, + ref: Ref +) { + const innerRef = useRef(null); + const mergedRef = useMergedRefs(ref, innerRef); + + useLayoutEffect(() => { + if (innerRef && innerRef.current && indeterminate !== undefined) { + innerRef.current.indeterminate = indeterminate; + } + }, [innerRef, indeterminate]); - useLayoutEffect(() => { + const handleChange = useCallback( + (event: FormEvent) => { if (innerRef && innerRef.current && indeterminate !== undefined) { innerRef.current.indeterminate = indeterminate; } - }, [innerRef, indeterminate]); - - const handleChange = useCallback>( - (event) => { - console.log(event); - if (innerRef && innerRef.current && indeterminate !== undefined) { - innerRef.current.indeterminate = indeterminate; - } - onChange && onChange.call(innerRef.current, event); - }, - [innerRef, indeterminate, onChange] - ); + onChange && onChange.call(innerRef.current, event); + }, + [innerRef, indeterminate, onChange] + ); - return ( - - - - ); - } -); + return ( + + + + ); +}); diff --git a/packages/fuselage/src/components/Chip/Chip.tsx b/packages/fuselage/src/components/Chip/Chip.tsx index cb83cb16ab..dbd629f1ad 100644 --- a/packages/fuselage/src/components/Chip/Chip.tsx +++ b/packages/fuselage/src/components/Chip/Chip.tsx @@ -1,13 +1,14 @@ -import PropTypes from 'prop-types'; -import React, { ComponentProps, FC } from 'react'; +import React, { HTMLAttributes } from 'react'; import { Avatar, Box } from '..'; import { prependClassName } from '../../helpers/prependClassName'; import { Icon } from '../Icon'; import Margins from '../Margins'; -type ChipProps = ComponentProps & { +type ChipProps = Omit, 'type'> & { thumbUrl: string; + renderThumb?: (props: { url: string }) => React.ReactNode; + renderDismissSymbol?: () => React.ReactNode; }; const defaultRenderThumb = ({ url }: { url: string }) => ( @@ -17,7 +18,7 @@ const defaultRenderThumb = ({ url }: { url: string }) => ( ); const defaultRenderDismissSymbol = () => ; -export const Chip: FC = ({ +export const Chip = ({ children, className, thumbUrl, @@ -26,7 +27,7 @@ export const Chip: FC = ({ renderThumb = defaultRenderThumb, renderDismissSymbol = defaultRenderDismissSymbol, ...rest -}) => { +}: ChipProps) => { const onDismiss = onClick || onMouseDown; return ( @@ -46,12 +47,4 @@ export const Chip: FC = ({ ); }; -if (process.env.NODE_ENV !== 'production') { - Chip.displayName = 'Chip'; - - Chip.propTypes = { - thumbUrl: PropTypes.string, - renderThumb: PropTypes.func, - renderDismissSymbol: PropTypes.func, - }; -} +Chip.displayName = 'Chip'; diff --git a/packages/fuselage/src/components/Divider/Divider.tsx b/packages/fuselage/src/components/Divider/Divider.tsx index a672e36fe9..7ea1d011e5 100644 --- a/packages/fuselage/src/components/Divider/Divider.tsx +++ b/packages/fuselage/src/components/Divider/Divider.tsx @@ -1,10 +1,8 @@ -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import { Box } from '../Box'; type DividerProps = ComponentProps; -const Divider: FC = (props) => ( - -); +const Divider = (props: DividerProps) => ; export { Divider }; diff --git a/packages/fuselage/src/components/EmailInput/EmailInput.tsx b/packages/fuselage/src/components/EmailInput/EmailInput.tsx index cb42e3d6fc..54e856de24 100644 --- a/packages/fuselage/src/components/EmailInput/EmailInput.tsx +++ b/packages/fuselage/src/components/EmailInput/EmailInput.tsx @@ -1,14 +1,8 @@ -import React, { - ComponentProps, - forwardRef, - ForwardRefExoticComponent, - ReactNode, -} from 'react'; +import React, { ComponentProps, forwardRef, ReactNode, Ref } from 'react'; -import { Box } from '..'; import { InputBox } from '../InputBox'; -type EmailInputProps = Omit, 'type'> & { +type EmailInputProps = Omit, 'type'> & { addon?: ReactNode; error?: string; }; @@ -43,7 +37,9 @@ type InputType = const type: InputType = 'email'; -export const EmailInput: ForwardRefExoticComponent = - forwardRef(function EmailInput(props: EmailInputProps, ref) { - return ; - }); +export const EmailInput = forwardRef(function EmailInput( + props: EmailInputProps, + ref: Ref +) { + return ; +}); diff --git a/packages/fuselage/src/components/Field/FieldDescription.tsx b/packages/fuselage/src/components/Field/FieldDescription.tsx index a1f0b0986f..72581069a5 100644 --- a/packages/fuselage/src/components/Field/FieldDescription.tsx +++ b/packages/fuselage/src/components/Field/FieldDescription.tsx @@ -1,10 +1,9 @@ -import React, { ComponentPropsWithoutRef, FC } from 'react'; +import React, { ComponentPropsWithoutRef } from 'react'; import { Box } from '../Box'; type FieldDescriptionProps = ComponentPropsWithoutRef; -export const FieldDescription: FC = - function FieldDescription(props) { - return ; - }; +export const FieldDescription = (props: FieldDescriptionProps) => ( + +); diff --git a/packages/fuselage/src/components/Field/FieldError.tsx b/packages/fuselage/src/components/Field/FieldError.tsx index 6a69c74a11..af9dd004f3 100644 --- a/packages/fuselage/src/components/Field/FieldError.tsx +++ b/packages/fuselage/src/components/Field/FieldError.tsx @@ -1,9 +1,9 @@ -import React, { ComponentPropsWithoutRef, FC } from 'react'; +import React, { ComponentPropsWithoutRef } from 'react'; import { Box } from '../Box'; type FieldErrorProps = ComponentPropsWithoutRef; -export const FieldError: FC = function FieldError(props) { - return ; -}; +export const FieldError = (props: FieldErrorProps) => ( + +); diff --git a/packages/fuselage/src/components/Field/FieldHint.tsx b/packages/fuselage/src/components/Field/FieldHint.tsx index 8f007c2e66..4e8a179bd6 100644 --- a/packages/fuselage/src/components/Field/FieldHint.tsx +++ b/packages/fuselage/src/components/Field/FieldHint.tsx @@ -1,9 +1,9 @@ -import React, { ComponentPropsWithoutRef, FC } from 'react'; +import React, { ComponentPropsWithoutRef } from 'react'; import { Box } from '../Box'; type FieldHintProps = ComponentPropsWithoutRef; -export const FieldHint: FC = function FieldHint(props) { - return ; -}; +export const FieldHint = (props: FieldHintProps) => ( + +); diff --git a/packages/fuselage/src/components/Field/FieldLabel.tsx b/packages/fuselage/src/components/Field/FieldLabel.tsx index 2f794ec18f..5bf86f17b0 100644 --- a/packages/fuselage/src/components/Field/FieldLabel.tsx +++ b/packages/fuselage/src/components/Field/FieldLabel.tsx @@ -1,10 +1,10 @@ -import React, { ComponentPropsWithoutRef, FC } from 'react'; +import React, { ComponentPropsWithoutRef } from 'react'; import { Box } from '../Box'; import { Label } from '../Label'; type FieldLabelProps = ComponentPropsWithoutRef; -export const FieldLabel: FC = function FieldLabel(props) { - return ; -}; +export const FieldLabel = (props: FieldLabelProps) => ( + +); diff --git a/packages/fuselage/src/components/Field/FieldRow.tsx b/packages/fuselage/src/components/Field/FieldRow.tsx index 8575f8e5d7..6635580d41 100644 --- a/packages/fuselage/src/components/Field/FieldRow.tsx +++ b/packages/fuselage/src/components/Field/FieldRow.tsx @@ -1,9 +1,9 @@ -import React, { ComponentPropsWithoutRef, FC } from 'react'; +import React, { ComponentPropsWithoutRef } from 'react'; import { Box } from '../Box'; type FieldRowProps = ComponentPropsWithoutRef; -export const FieldRow: FC = function FieldRow(props) { - return ; -}; +export const FieldRow = (props: FieldRowProps) => ( + +); diff --git a/packages/fuselage/src/components/FieldGroup/FieldGroup.tsx b/packages/fuselage/src/components/FieldGroup/FieldGroup.tsx index 6084ab2c2e..c12a56945e 100644 --- a/packages/fuselage/src/components/FieldGroup/FieldGroup.tsx +++ b/packages/fuselage/src/components/FieldGroup/FieldGroup.tsx @@ -1,4 +1,4 @@ -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import { appendClassName } from '../../helpers/appendClassName'; import { patchChildren } from '../../helpers/patchChildren'; @@ -6,7 +6,7 @@ import { Box } from '../Box'; type FieldGroupProps = ComponentProps; -export const FieldGroup: FC = ({ children, ...props }) => ( +export const FieldGroup = ({ children, ...props }: FieldGroupProps) => ( {patchChildren( children, diff --git a/packages/fuselage/src/components/Grid/Grid.stories.tsx b/packages/fuselage/src/components/Grid/Grid.stories.tsx index 42ed7e945b..d3dd141bb1 100644 --- a/packages/fuselage/src/components/Grid/Grid.stories.tsx +++ b/packages/fuselage/src/components/Grid/Grid.stories.tsx @@ -6,7 +6,7 @@ import { ArgsTable, } from '@storybook/addon-docs'; import { ComponentStory, ComponentMeta } from '@storybook/react'; -import React from 'react'; +import React, { Fragment } from 'react'; import { Table, TableBody, TableCell, TableHead, TableRow } from '..'; import { Grid, Tile } from '../..'; @@ -113,7 +113,7 @@ export const ExtraSmall: ComponentStory = () => { {Array.from({ length: 4 }) .map((_, i) => (i + 1) as ColumnsType) .map((columns) => ( - + xs={columns} @@ -122,7 +122,7 @@ export const ExtraSmall: ComponentStory = () => { xs={4 - columns} )} - + ))} ); @@ -136,7 +136,7 @@ export const Small: ComponentStory = () => { {Array.from({ length: 8 }) .map((_, i) => (i + 1) as ColumnsType) .map((columns) => ( - + sm={columns} @@ -145,7 +145,7 @@ export const Small: ComponentStory = () => { sm={8 - columns} )} - + ))} ); @@ -159,7 +159,7 @@ export const Medium: ComponentStory = () => { {Array.from({ length: 8 }) .map((_, i) => (i + 1) as ColumnsType) .map((columns) => ( - + md={columns} @@ -168,7 +168,7 @@ export const Medium: ComponentStory = () => { md={8 - columns} )} - + ))} ); @@ -182,7 +182,7 @@ export const Large: ComponentStory = () => { {Array.from({ length: 12 }) .map((_, i) => (i + 1) as ColumnsType) .map((columns) => ( - + lg={columns} @@ -191,7 +191,7 @@ export const Large: ComponentStory = () => { lg={12 - columns} )} - + ))} ); @@ -205,7 +205,7 @@ export const ExtraLarge: ComponentStory = () => { {Array.from({ length: 12 }) .map((_, i) => (i + 1) as ColumnsType) .map((columns) => ( - + xl={columns} @@ -214,7 +214,7 @@ export const ExtraLarge: ComponentStory = () => { xl={12 - columns} )} - + ))} ); diff --git a/packages/fuselage/src/components/Grid/Grid.tsx b/packages/fuselage/src/components/Grid/Grid.tsx index b0a8014249..6bd61fe1c8 100644 --- a/packages/fuselage/src/components/Grid/Grid.tsx +++ b/packages/fuselage/src/components/Grid/Grid.tsx @@ -1,5 +1,4 @@ -import PropTypes from 'prop-types'; -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import { Box } from '../Box'; import { GridItem } from './GridItem'; @@ -12,14 +11,7 @@ type GridProps = ComponentProps & { xl?: boolean; }; -export const Grid: FC & { Item: typeof GridItem } = ({ - xs, - sm, - md, - lg, - xl, - ...props -}) => ( +export const Grid = ({ xs, sm, md, lg, xl, ...props }: GridProps) => ( & { Item: typeof GridItem } = ({ ); -Grid.propTypes = { - xs: PropTypes.bool, - sm: PropTypes.bool, - md: PropTypes.bool, - lg: PropTypes.bool, - xl: PropTypes.bool, -}; - Grid.Item = GridItem; diff --git a/packages/fuselage/src/components/Grid/GridItem.tsx b/packages/fuselage/src/components/Grid/GridItem.tsx index 7f7fe2452d..859d618d92 100644 --- a/packages/fuselage/src/components/Grid/GridItem.tsx +++ b/packages/fuselage/src/components/Grid/GridItem.tsx @@ -1,5 +1,4 @@ -import PropTypes from 'prop-types'; -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import { Box } from '../Box'; @@ -11,14 +10,7 @@ type GridItemProps = ComponentProps & { xl?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; }; -export const GridItem: FC = ({ - xs, - sm, - md, - lg, - xl, - ...props -}) => ( +export const GridItem = ({ xs, sm, md, lg, xl, ...props }: GridItemProps) => ( = ({ {...props} /> ); - -GridItem.propTypes = { - xs: PropTypes.oneOf([1, 2, 3, 4]), - sm: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8]), - md: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8]), - lg: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), - xl: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), -}; diff --git a/packages/fuselage/src/components/Icon/Icon.tsx b/packages/fuselage/src/components/Icon/Icon.tsx index 7a80065ae4..4fe95681f9 100644 --- a/packages/fuselage/src/components/Icon/Icon.tsx +++ b/packages/fuselage/src/components/Icon/Icon.tsx @@ -1,20 +1,16 @@ import nameToCharacterMapping, { Keys } from '@rocket.chat/icons'; -import PropTypes from 'prop-types'; -import React, { ComponentProps, forwardRef } from 'react'; +import React, { ComponentProps, forwardRef, Ref } from 'react'; -import { createPropType } from '../../helpers/createPropType'; -import { size } from '../../styleTokens'; import { Box } from '../Box'; -import { iconsList } from './IconsList'; -type IconProps = Omit, 'size'> & { +export type IconProps = Omit, 'name' | 'size'> & { name: Keys; size?: ComponentProps['width']; }; -export const Icon = forwardRef(function Icon( - { name, size, ...props }, - ref +export const Icon = forwardRef(function Icon( + { name, size, ...props }: IconProps, + ref: Ref ) { return ( (function Icon( /> ); }); - -Icon.propTypes = { - name: PropTypes.oneOf(iconsList).isRequired, - size: createPropType(size), -}; diff --git a/packages/fuselage/src/components/Icon/IconsList.ts b/packages/fuselage/src/components/Icon/IconsList.ts index ea1c2ccb00..bd474ef748 100644 --- a/packages/fuselage/src/components/Icon/IconsList.ts +++ b/packages/fuselage/src/components/Icon/IconsList.ts @@ -1,4 +1,8 @@ -export const iconsList = [ +import type { ComponentProps } from 'react'; + +import { Icon } from '.'; + +export const iconsList: ComponentProps['name'][] = [ 'arrow-back', 'arrow-collapse', 'arrow-down', @@ -241,8 +245,6 @@ export const iconsList = [ 'loading', 'play-solid', 'reply', - 'sort-down', - 'sort-up', 'adobe', 'facebook', 'github', @@ -252,4 +254,4 @@ export const iconsList = [ 'hubot', 'linkedin', 'twitter', -] as const; +]; diff --git a/packages/fuselage/src/components/InputBox/Addon.tsx b/packages/fuselage/src/components/InputBox/Addon.tsx index 4c3fe75ee5..f7572761dd 100644 --- a/packages/fuselage/src/components/InputBox/Addon.tsx +++ b/packages/fuselage/src/components/InputBox/Addon.tsx @@ -1,7 +1,12 @@ -import React, { ComponentProps, forwardRef } from 'react'; +import React, { ComponentProps, forwardRef, Ref } from 'react'; import { Box } from '../Box'; -export const Addon = forwardRef>( - (props, ref) => -); +type AddonProps = ComponentProps; + +export const Addon = forwardRef(function Addon( + props: AddonProps, + ref: Ref +) { + return ; +}); diff --git a/packages/fuselage/src/components/InputBox/Input.tsx b/packages/fuselage/src/components/InputBox/Input.tsx index e41676c678..3c34cb02bc 100644 --- a/packages/fuselage/src/components/InputBox/Input.tsx +++ b/packages/fuselage/src/components/InputBox/Input.tsx @@ -1,7 +1,12 @@ -import React, { ComponentProps, forwardRef } from 'react'; +import React, { ComponentProps, forwardRef, Ref } from 'react'; import { Box } from '../Box'; -export const Input = forwardRef>( - (props, ref) => -); +type InputProps = ComponentProps; + +export const Input = forwardRef(function Input( + props: InputProps, + ref: Ref +) { + return ; +}); diff --git a/packages/fuselage/src/components/InputBox/InputBox.tsx b/packages/fuselage/src/components/InputBox/InputBox.tsx index 3b4ea48390..24dc10aedb 100644 --- a/packages/fuselage/src/components/InputBox/InputBox.tsx +++ b/packages/fuselage/src/components/InputBox/InputBox.tsx @@ -1,11 +1,11 @@ /* eslint-disable complexity */ import { useMergedRefs } from '@rocket.chat/fuselage-hooks'; -import PropTypes from 'prop-types'; import React, { ComponentProps, forwardRef, ForwardRefExoticComponent, ReactNode, + Ref, useCallback, useLayoutEffect, useRef, @@ -23,6 +23,7 @@ type InputBoxProps = ComponentProps & { multiple?: boolean; error?: string; placeholder?: string; + placeholderVisible?: boolean; type: | 'button' | 'checkbox' @@ -51,12 +52,15 @@ type InputBoxProps = ComponentProps & { | 'select'; }; -export const InputBox: ForwardRefExoticComponent & { - Input?: ComponentProps; - Skeleton?: ComponentProps; - Option?: ComponentProps; - Placeholder?: ComponentProps; -} = forwardRef(function InputBox( +export type InputBox = ForwardRefExoticComponent & { + Input: ForwardRefExoticComponent>; + Skeleton: ForwardRefExoticComponent>; + Option: ForwardRefExoticComponent>; + Placeholder: ForwardRefExoticComponent>; +}; + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const InputBox = forwardRef(function InputBox( { className, addon, @@ -65,13 +69,15 @@ export const InputBox: ForwardRefExoticComponent & { invisible, multiple, placeholderVisible, - type, + type = 'text', onChange, ...props - }, - ref + }: InputBoxProps, + ref: Ref | null ) { - const innerRef = useRef(null); + const innerRef = useRef< + HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement + >(null); const mergedRef = useMergedRefs(ref, innerRef); useLayoutEffect(() => { @@ -90,7 +96,7 @@ export const InputBox: ForwardRefExoticComponent & { }, []); const handleChange = useCallback( - (event, ...args) => { + (event) => { if (addon && innerRef.current && innerRef.current.parentElement) { innerRef.current.parentElement.classList.toggle( 'invalid', @@ -98,7 +104,7 @@ export const InputBox: ForwardRefExoticComponent & { ); } - return onChange && onChange.call(event.currentTarget, event, ...args); + onChange?.call(event.currentTarget, event); }, [addon, onChange] ); @@ -132,7 +138,10 @@ export const InputBox: ForwardRefExoticComponent & { return ( ); -}); - -InputBox.defaultProps = { - type: 'text', -}; - -InputBox.propTypes = { - addon: PropTypes.element, - input: PropTypes.element, - error: PropTypes.string, - type: PropTypes.oneOf([ - 'button', - 'checkbox', - 'color', - 'date', - 'datetime', - 'datetime-local', - 'email', - 'file', - 'hidden', - 'image', - 'month', - 'number', - 'password', - 'radio', - 'range', - 'reset', - 'search', - 'submit', - 'tel', - 'text', - 'time', - 'url', - 'week', - 'textarea', - 'select', - ]).isRequired, -}; +}) as unknown as InputBox; diff --git a/packages/fuselage/src/components/InputBox/Option.tsx b/packages/fuselage/src/components/InputBox/Option.tsx index 0fc59e3651..f33fc0f786 100644 --- a/packages/fuselage/src/components/InputBox/Option.tsx +++ b/packages/fuselage/src/components/InputBox/Option.tsx @@ -4,7 +4,7 @@ import { Box } from '../Box'; type OptionProps = ComponentProps; -export const Option = forwardRef(function Option( +export const Option = forwardRef(function Option( props: OptionProps, ref: Ref ) { diff --git a/packages/fuselage/src/components/InputBox/Placeholder.tsx b/packages/fuselage/src/components/InputBox/Placeholder.tsx index 2c4bf79962..0074aab56d 100644 --- a/packages/fuselage/src/components/InputBox/Placeholder.tsx +++ b/packages/fuselage/src/components/InputBox/Placeholder.tsx @@ -1,14 +1,12 @@ -import React, { - ComponentProps, - forwardRef, - ForwardRefExoticComponent, -} from 'react'; +import React, { ComponentProps, forwardRef, Ref } from 'react'; import { Box } from '../Box'; type PlaceholderProps = ComponentProps; -export const Placeholder: ForwardRefExoticComponent = - forwardRef(function Placeholder(props: PlaceholderProps, ref) { - return ; - }); +export const Placeholder = forwardRef(function Placeholder( + props: PlaceholderProps, + ref: Ref +) { + return ; +}); diff --git a/packages/fuselage/src/components/InputBox/styles.scss b/packages/fuselage/src/components/InputBox/styles.scss index b0378cce4c..22b5a0780f 100644 --- a/packages/fuselage/src/components/InputBox/styles.scss +++ b/packages/fuselage/src/components/InputBox/styles.scss @@ -147,6 +147,7 @@ resize: none; vertical-align: middle; + white-space: initial; } &--type-select { diff --git a/packages/fuselage/src/components/Margins/Margins.tsx b/packages/fuselage/src/components/Margins/Margins.tsx index 06b778c769..124f4383e8 100644 --- a/packages/fuselage/src/components/Margins/Margins.tsx +++ b/packages/fuselage/src/components/Margins/Margins.tsx @@ -1,10 +1,5 @@ import { css } from '@rocket.chat/css-in-js'; -import React, { - ComponentProps, - FC, - PropsWithChildren, - useCallback, -} from 'react'; +import React, { ComponentProps, PropsWithChildren, useCallback } from 'react'; import { Box } from '..'; import { appendClassName } from '../../helpers/appendClassName'; @@ -24,7 +19,7 @@ type MarginsProps = PropsWithChildren<{ className?: string; }>; -export const Margins: FC = (props) => { +export const Margins = (props: MarginsProps) => { const { children, className, diff --git a/packages/fuselage/src/components/Menu/Menu.tsx b/packages/fuselage/src/components/Menu/Menu.tsx index 265dc1b454..2c052a5ce1 100644 --- a/packages/fuselage/src/components/Menu/Menu.tsx +++ b/packages/fuselage/src/components/Menu/Menu.tsx @@ -4,22 +4,13 @@ import React, { useCallback, ComponentProps, ReactElement, - ReactNode, - FC, + ElementType, } from 'react'; -import { - ActionButton, - PositionAnimated, - Options, - useCursor, - Box, - Option, -} from '..'; -import type { Option as OptionType } from '../Options/useCursor'; +import { ActionButton, PositionAnimated, Options, useCursor, Box } from '..'; +import type { OptionType } from '../Options'; -type MenuProps = Omit, 'icon'> & { - icon?: string; +export type MenuProps = Omit, 'icon'> & { options: { [id: string]: { label: ReactElement | string; @@ -28,30 +19,32 @@ type MenuProps = Omit, 'icon'> & { }; optionWidth?: ComponentProps['width']; placement?: Placements; - renderItem?: (props: ComponentProps) => ReactNode; + renderItem?: ElementType; + icon?: ComponentProps['icon']; }; const menuAction = ([selected]: OptionType, options: MenuProps['options']) => { options[selected].action(); }; -const mapOptions = (options: MenuProps['options']) => +const mapOptions = (options: MenuProps['options']): OptionType[] => Object.entries(options).map(([value, { label }]) => [value, label]); -export const Menu: FC = ({ +export const Menu = ({ tiny, mini, - small = tiny || mini ? null : true, + small = !(tiny || mini), options, optionWidth, placement = 'bottom-start', renderItem, maxHeight, + icon = 'kebab', ...props -}) => { +}: MenuProps) => { const mappedOptions = mapOptions(options); const [cursor, handleKeyDown, handleKeyUp, reset, [visible, hide, show]] = - useCursor(-1, mappedOptions as OptionType[], (args, [, hide]) => { + useCursor(-1, mappedOptions, (args, [, hide]) => { menuAction(args, options); reset(); hide(); @@ -90,7 +83,7 @@ export const Menu: FC = ({ onBlur={hide} onKeyUp={handleKeyUp} onKeyDown={handleKeyDown} - icon='kebab' + icon={icon} {...props} /> & { className?: string; }; -export const Message = forwardRef( - function Message({ className, clickable, sequential, ...props }, ref) { - return ( -
- ); - } -); +export const Message = forwardRef(function Message( + { className, clickable, sequential, ...props }: MessageProps, + ref: Ref +) { + return ( +
+ ); +}); diff --git a/packages/fuselage/src/components/Message/MessageBlock.tsx b/packages/fuselage/src/components/Message/MessageBlock.tsx index ac99ae74e8..c133f4876e 100644 --- a/packages/fuselage/src/components/Message/MessageBlock.tsx +++ b/packages/fuselage/src/components/Message/MessageBlock.tsx @@ -1,8 +1,9 @@ -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import { Box } from '../Box'; -export const MessageBlock: FC> = - function MessageBlock({ className, ...props }) { - return ; - }; +type MessageBlockProps = ComponentProps; + +export const MessageBlock = ({ className, ...props }: MessageBlockProps) => ( + +); diff --git a/packages/fuselage/src/components/Message/MessageContainer.tsx b/packages/fuselage/src/components/Message/MessageContainer.tsx index 7b8cc8b43c..9bd090a870 100644 --- a/packages/fuselage/src/components/Message/MessageContainer.tsx +++ b/packages/fuselage/src/components/Message/MessageContainer.tsx @@ -1,7 +1,9 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -export const MessageContainer: FC = function MessageContainer(props) { - return ( -
- ); +type MessageContainerProps = { + children?: ReactNode; }; + +export const MessageContainer = (props: MessageContainerProps) => ( +
+); diff --git a/packages/fuselage/src/components/Message/MessageContainerFixed.tsx b/packages/fuselage/src/components/Message/MessageContainerFixed.tsx index 7c01e53cb4..9732c4049c 100644 --- a/packages/fuselage/src/components/Message/MessageContainerFixed.tsx +++ b/packages/fuselage/src/components/Message/MessageContainerFixed.tsx @@ -1,10 +1,12 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -export const MessageContainerFixed: FC = function MessageContainerFixed(props) { - return ( -
- ); +type MessageContainerFixedProps = { + children?: ReactNode; }; + +export const MessageContainerFixed = (props: MessageContainerFixedProps) => ( +
+); diff --git a/packages/fuselage/src/components/Message/MessageDivider/MessageDivider.tsx b/packages/fuselage/src/components/Message/MessageDivider/MessageDivider.tsx index e556bbaf7c..3ac0a1fc14 100644 --- a/packages/fuselage/src/components/Message/MessageDivider/MessageDivider.tsx +++ b/packages/fuselage/src/components/Message/MessageDivider/MessageDivider.tsx @@ -1,8 +1,15 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -export const MessageDivider: FC<{ +type MessageDividerProps = { + children?: ReactNode; unreadLabel?: string; -}> = ({ children, unreadLabel, ...props }) => ( +}; + +export const MessageDivider = ({ + children, + unreadLabel, + ...props +}: MessageDividerProps) => (
> = ( - props +export const MessageGenericPreview = ( + props: HTMLAttributes ) =>
; diff --git a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewContent.tsx b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewContent.tsx index 1caf6c6c8d..de11bd54a0 100644 --- a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewContent.tsx +++ b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewContent.tsx @@ -1,16 +1,16 @@ -import React, { FC, ReactElement } from 'react'; +import React, { ReactElement, ReactNode } from 'react'; type MessageGenericPreviewContentProps = { + children?: ReactNode; thumb?: ReactElement; }; -export const MessageGenericPreviewContent: FC = - ({ thumb, ...props }) => ( -
- {thumb} -
-
- ); +export const MessageGenericPreviewContent = ({ + thumb, + ...props +}: MessageGenericPreviewContentProps) => ( +
+ {thumb} +
+
+); diff --git a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewDescription.tsx b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewDescription.tsx index bbd6cf634b..6a97364f7a 100644 --- a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewDescription.tsx +++ b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewDescription.tsx @@ -1,16 +1,14 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -// const clamp = css` -// display: -webkit-box; -// -webkit-line-clamp: 1; -// -webkit-box-orient: vertical; -// overflow: hidden; -// `; +type MessageGenericPreviewDescriptionProps = { + children?: ReactNode; + clamp?: boolean; +}; -export const MessageGenericPreviewDescription: FC<{ clamp?: boolean }> = ({ +export const MessageGenericPreviewDescription = ({ children, clamp = false, -}) => ( +}: MessageGenericPreviewDescriptionProps) => (
= ({ +type MessageGenericPreviewFooterProps = { + children?: ReactNode; + clamp?: boolean; +}; + +export const MessageGenericPreviewFooter = ({ children, -}) =>
{children}
; +}: MessageGenericPreviewFooterProps) => ( +
{children}
+); diff --git a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewImage.tsx b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewImage.tsx index b88d2f045b..625313efc9 100644 --- a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewImage.tsx +++ b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewImage.tsx @@ -1,10 +1,17 @@ -import React, { FC } from 'react'; +import React from 'react'; -export const MessageGenericPreviewImage: FC<{ +type MessageGenericPreviewImageProps = { url: string; width: number; height: number; -}> = ({ url, width, height, ...props }) => ( +}; + +export const MessageGenericPreviewImage = ({ + url, + width, + height, + ...props +}: MessageGenericPreviewImageProps) => (
-> = (props) => ( -
-); +export const MessageGenericPreviewThumb = ( + props: HTMLAttributes +) =>
; diff --git a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewTitle.tsx b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewTitle.tsx index 9ef99af10e..f438da9031 100644 --- a/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewTitle.tsx +++ b/packages/fuselage/src/components/Message/MessageGenericPreview/MessageGenericPreviewTitle.tsx @@ -1,18 +1,21 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; type MessageGenericPreviewTitleProps = { + children?: ReactNode; externalUrl?: string; }; -export const MessageGenericPreviewTitle: FC = - ({ externalUrl, ...props }) => - externalUrl ? ( - - ) : ( - - ); +export const MessageGenericPreviewTitle = ({ + externalUrl, + ...props +}: MessageGenericPreviewTitleProps) => + externalUrl ? ( + + ) : ( + + ); diff --git a/packages/fuselage/src/components/Message/MessageHeader.tsx b/packages/fuselage/src/components/Message/MessageHeader.tsx index 435842a2c9..9f2a4727b3 100644 --- a/packages/fuselage/src/components/Message/MessageHeader.tsx +++ b/packages/fuselage/src/components/Message/MessageHeader.tsx @@ -1,11 +1,13 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -export const MessageHeader: FC = function MessageHeader({ children }) { - return ( -
-
- {children} -
-
- ); +type MessageHeaderProps = { + children?: ReactNode; }; + +export const MessageHeader = ({ children }: MessageHeaderProps) => ( +
+
+ {children} +
+
+); diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetrics.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetrics.tsx index 8749660cd1..d8f3a8987f 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetrics.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetrics.tsx @@ -1,8 +1,10 @@ -import React, { FC, HTMLAttributes } from 'react'; +import React, { HTMLAttributes } from 'react'; import { MessageMetricsContentItem } from './MessageMetricsContentItem'; -export const MessageMetrics: FC> = (props) => ( +type MessageMetricsProps = HTMLAttributes; + +export const MessageMetrics = (props: MessageMetricsProps) => (
diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContent.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContent.tsx index f9fa0cc3e6..5327ddb62a 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContent.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContent.tsx @@ -1,5 +1,9 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -export const Content: FC = (props) => ( +type ContentProps = { + children?: ReactNode; +}; + +export const Content = (props: ContentProps) => (
); diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContentItem.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContentItem.tsx index 561836b69e..3e0d35152c 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContentItem.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsContentItem.tsx @@ -1,5 +1,9 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -export const MessageMetricsContentItem: FC = (props) => ( -
-); +type MessageMetricsContentItemProps = { + children?: ReactNode; +}; + +export const MessageMetricsContentItem = ( + props: MessageMetricsContentItemProps +) =>
; diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsFollowing.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsFollowing.tsx index eb914f8330..a664ac8aa1 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsFollowing.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsFollowing.tsx @@ -1,10 +1,12 @@ -import React, { FC } from 'react'; +import React from 'react'; import { ActionButton } from '../..'; -type FollowingProps = { name: 'bell' | 'bell-off' }; +type MessageMetricsFollowingProps = { name: 'bell' | 'bell-off' }; -export const MessageMetricsFollowing: FC = ({ name }) => ( +export const MessageMetricsFollowing = ({ + name, +}: MessageMetricsFollowingProps) => ( diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItem.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItem.tsx index 81a8853543..bbc4409f8e 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItem.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItem.tsx @@ -1,5 +1,7 @@ -import React, { FC, HTMLAttributes } from 'react'; +import React, { HTMLAttributes } from 'react'; -export const MessageMetricsItem: FC> = ( - props -) =>
; +type MessageMetricsItemProps = HTMLAttributes; + +export const MessageMetricsItem = (props: MessageMetricsItemProps) => ( +
+); diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemIcon.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemIcon.tsx index e6772aa0d8..bea3243132 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemIcon.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemIcon.tsx @@ -1,9 +1,11 @@ -import React, { FC } from 'react'; +import React from 'react'; import { Icon } from '../../../..'; -type IconProps = { name: 'thread' | 'user' | 'clock' | 'discussion' }; +type MessageMetricsItemIconProps = { + name: 'thread' | 'user' | 'clock' | 'discussion'; +}; -export const MessageMetricsItemIcon: FC = (props) => ( +export const MessageMetricsItemIcon = (props: MessageMetricsItemIconProps) => ( ); diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemLabel.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemLabel.tsx index 86b523863d..80bcf7c3a7 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemLabel.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsItem/MessageMetricsItemLabel.tsx @@ -1,5 +1,9 @@ -import React, { FC } from 'react'; +import React, { ReactNode } from 'react'; -export const MessageMetricsItemLabel: FC = (props) => ( -
-); +type MessageMetricsItemLabelProps = { + children?: ReactNode; +}; + +export const MessageMetricsItemLabel = ( + props: MessageMetricsItemLabelProps +) =>
; diff --git a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsReply.tsx b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsReply.tsx index 4635db5e10..f47cdc19e8 100644 --- a/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsReply.tsx +++ b/packages/fuselage/src/components/Message/MessageMetrics/MessageMetricsReply.tsx @@ -1,11 +1,11 @@ -import React, { ComponentProps, FC } from 'react'; +import React, { ComponentProps } from 'react'; import { Button } from '../..'; import MessageMetricsItem from './MessageMetricsItem'; -export const MessageMetricsReply: FC> = ( - props -) => ( +type MessageMetricsReplyProps = ComponentProps; + +export const MessageMetricsReply = (props: MessageMetricsReplyProps) => (