diff --git a/packages/clay-autocomplete/src/Item.tsx b/packages/clay-autocomplete/src/Item.tsx index 917442b89a..0be0067eaa 100644 --- a/packages/clay-autocomplete/src/Item.tsx +++ b/packages/clay-autocomplete/src/Item.tsx @@ -37,12 +37,7 @@ const ClayAutocompleteItem: React.FunctionComponent = ({ const fuzzyMatch = fuzzy.match(match, value, optionsFuzzy); return ( - + {match && fuzzyMatch ? (
-
  • +
  • Bar diff --git a/packages/clay-autocomplete/src/index.tsx b/packages/clay-autocomplete/src/index.tsx index 37ad3c03f5..b18b9b8889 100644 --- a/packages/clay-autocomplete/src/index.tsx +++ b/packages/clay-autocomplete/src/index.tsx @@ -28,38 +28,53 @@ interface IProps extends React.HTMLAttributes { component?: React.ForwardRefExoticComponent; } -const ClayAutocomplete: React.FunctionComponent & { +type Autocomplete = React.ForwardRefExoticComponent & { DropDown: typeof DropDown; Input: typeof Input; Item: typeof Item; LoadingIndicator: typeof LoadingIndicator; -} = ({ - children, - className, - component: Component = AutocompleteMarkup, - ...otherProps -}: IProps) => { - const containerElementRef = useRef(null); - const [loading, setLoading] = useState(false); +}; + +const ClayAutocomplete = React.forwardRef( + ( + { + children, + className, + component: Component = AutocompleteMarkup, + ...otherProps + }: IProps, + ref + ) => { + const containerElementRef = useRef(null); + const [loading, setLoading] = useState(false); - return ( - - setLoading(loading), + return ( + { + containerElementRef.current = r; + if (typeof ref === 'function') { + ref(r); + } else if (ref !== null) { + (ref.current as React.MutableRefObject) = r; + } }} > - {children} - - - ); -}; + + setLoading(loading), + }} + > + {children} + + + ); + } +) as Autocomplete; ClayAutocomplete.DropDown = DropDown; ClayAutocomplete.Input = Input; diff --git a/packages/clay-autocomplete/stories/index.tsx b/packages/clay-autocomplete/stories/index.tsx index 7991fd0f44..1e9574e8ef 100644 --- a/packages/clay-autocomplete/stories/index.tsx +++ b/packages/clay-autocomplete/stories/index.tsx @@ -8,16 +8,12 @@ import ClayAutocomplete from '../src'; import ClayDropDown from '@clayui/drop-down'; import React, {useEffect, useRef, useState} from 'react'; import {FetchPolicy, NetworkStatus} from '@clayui/data-provider/src/types'; +import {FocusScope, useDebounce} from '@clayui/shared'; import {storiesOf} from '@storybook/react'; -import {useDebounce, useFocusManagement} from '@clayui/shared'; import {useResource} from '@clayui/data-provider'; import '@clayui/css/lib/css/atlas.css'; -const TAB_KEY_CODE = 9; -const ARROW_UP_KEY_CODE = 38; -const ARROW_DOWN_KEY_CODE = 40; - const LoadingWithDebounce = ({ loading, networkStatus, @@ -72,61 +68,41 @@ const AutocompleteWithKeyboardFunctionality = () => { const inputRef = useRef(null); const [value, setValue] = useState(''); const [active, setActive] = useState(!!value); - const focusManager = useFocusManagement(); const filteredItems = ['one', 'two', 'three', 'four', 'five'].filter(item => item.match(value) ); - const onKeyDown = (event: React.KeyboardEvent) => { - const {keyCode, shiftKey} = event; - - if ( - keyCode === ARROW_DOWN_KEY_CODE || - (keyCode === TAB_KEY_CODE && !shiftKey) - ) { - event.preventDefault(); - focusManager.focusNext(); - } else if ( - keyCode === ARROW_UP_KEY_CODE || - (keyCode === TAB_KEY_CODE && shiftKey) - ) { - event.preventDefault(); - focusManager.focusPrevious(); - } - }; - useEffect(() => { setActive(!!value); }, [value]); return ( - - setValue(event.target.value)} - ref={ref => { - focusManager.createScope(ref, 'input'); - inputRef.current = ref; - }} - value={value} - /> - - - - {filteredItems.map((item, i) => ( - - focusManager.createScope(ref, `item${i}`, true) - } - key={item} - match={value} - onClick={() => setValue(item)} - value={item} - /> - ))} - - - + + + setValue(event.target.value)} + ref={inputRef} + value={value} + /> + + + + {filteredItems.map(item => ( + setValue(item)} + value={item} + /> + ))} + + + + ); }; diff --git a/packages/clay-drop-down/src/DropDown.tsx b/packages/clay-drop-down/src/DropDown.tsx index 7ccb036a10..4a9d30c89b 100644 --- a/packages/clay-drop-down/src/DropDown.tsx +++ b/packages/clay-drop-down/src/DropDown.tsx @@ -15,6 +15,7 @@ import ItemList from './ItemList'; import Menu, {Align} from './Menu'; import React, {useRef} from 'react'; import Search from './Search'; +import {FocusScope} from '@clayui/shared'; interface IProps extends React.HTMLAttributes { /** @@ -89,39 +90,41 @@ const ClayDropDown: React.FunctionComponent & { }; return ( - - {React.cloneElement(trigger, { - className: classNames( - 'dropdown-toggle', - trigger.props.className - ), - onClick: () => onActiveChange(!active), - ref: (node: HTMLButtonElement) => { - triggerElementRef.current = node; - // Call the original ref, if any. - const {ref} = trigger; - if (typeof ref === 'function') { - ref(node); - } - }, - })} - - + - {children} - - + {React.cloneElement(trigger, { + className: classNames( + 'dropdown-toggle', + trigger.props.className + ), + onClick: () => onActiveChange(!active), + ref: (node: HTMLButtonElement) => { + triggerElementRef.current = node; + // Call the original ref, if any. + const {ref} = trigger; + if (typeof ref === 'function') { + ref(node); + } + }, + })} + + + {children} + + + ); }; diff --git a/packages/clay-drop-down/src/DropDownWithItems.tsx b/packages/clay-drop-down/src/DropDownWithItems.tsx index d41fd027df..7ab38dc60a 100644 --- a/packages/clay-drop-down/src/DropDownWithItems.tsx +++ b/packages/clay-drop-down/src/DropDownWithItems.tsx @@ -96,7 +96,11 @@ interface IProps extends IDropDownContentProps { searchValue?: string; } -const Checkbox: React.FunctionComponent = ({ +interface IInternalItem { + spritemap?: string; +} + +const Checkbox: React.FunctionComponent = ({ checked = false, onChange = () => {}, ...otherProps @@ -119,10 +123,9 @@ const Checkbox: React.FunctionComponent = ({ const ClayDropDownContext = React.createContext({close: () => {}}); -const Item: React.FunctionComponent> = ({ - onClick, - ...props -}) => { +const Item: React.FunctionComponent< + Omit & IInternalItem +> = ({label, onClick, ...props}) => { const {close} = React.useContext(ClayDropDownContext); return ( @@ -136,12 +139,12 @@ const Item: React.FunctionComponent> = ({ }} {...props} > - {props.label} + {label} ); }; -const Group: React.FunctionComponent = ({ +const Group: React.FunctionComponent = ({ items, label, spritemap, @@ -160,7 +163,10 @@ interface IRadioContext { const RadioGroupContext = React.createContext({} as IRadioContext); -const Radio: React.FunctionComponent = ({value = '', ...otherProps}) => { +const Radio: React.FunctionComponent = ({ + value = '', + ...otherProps +}) => { const {checked, name, onChange} = useContext(RadioGroupContext); return ( @@ -177,7 +183,7 @@ const Radio: React.FunctionComponent = ({value = '', ...otherProps}) => { ); }; -const RadioGroup: React.FunctionComponent = ({ +const RadioGroup: React.FunctionComponent = ({ items, label, name, @@ -253,7 +259,6 @@ export const ClayDropDownWithItems: React.FunctionComponent = ({ trigger, }: IProps) => { const [active, setActive] = useState(false); - const hasRightSymbols = !!items.find(item => item.symbolRight); const hasLeftSymbols = !!items.find(item => item.symbolLeft); diff --git a/packages/clay-drop-down/src/Item.tsx b/packages/clay-drop-down/src/Item.tsx index f2baffaa1a..db10c39d9d 100644 --- a/packages/clay-drop-down/src/Item.tsx +++ b/packages/clay-drop-down/src/Item.tsx @@ -65,7 +65,7 @@ const ClayDropDownItem: React.FunctionComponent = ({ const ItemElement = href ? 'a' : clickableElement; return ( -
  • +
  • (( useDropdownCloseInteractions([alignElementRef, subPortalRef], onSetActive); - useLayoutEffect(() => { + useEffect(() => { if ( alignElementRef.current && (ref as React.RefObject).current diff --git a/packages/clay-drop-down/src/Search.tsx b/packages/clay-drop-down/src/Search.tsx index 0241c2900d..5a7587c2d6 100644 --- a/packages/clay-drop-down/src/Search.tsx +++ b/packages/clay-drop-down/src/Search.tsx @@ -30,27 +30,22 @@ const ClayDropDownSearch: React.FunctionComponent = ({ className, spritemap, ...otherProps -}: IProps) => { - return ( -
    -
    - - - +}: IProps) => ( + +
    + + + - - - - - - - -
    - - ); -}; + + + + + +
    +
    +
    + +); export default ClayDropDownSearch; diff --git a/packages/clay-drop-down/src/__tests__/__snapshots__/DropDownWithItems.tsx.snap b/packages/clay-drop-down/src/__tests__/__snapshots__/DropDownWithItems.tsx.snap index 841e9461f3..3ae3dfb0a4 100644 --- a/packages/clay-drop-down/src/__tests__/__snapshots__/DropDownWithItems.tsx.snap +++ b/packages/clay-drop-down/src/__tests__/__snapshots__/DropDownWithItems.tsx.snap @@ -23,12 +23,9 @@ exports[`ClayDropDownWithItems renders a DropDownWithItems 1`] = `
      -
    • +
    • @@ -38,13 +35,10 @@ exports[`ClayDropDownWithItems renders a DropDownWithItems 1`] = ` class="dropdown-divider" role="presentation" /> -
    • +
    • linkable @@ -79,13 +73,10 @@ exports[`ClayDropDownWithItems renders a DropDownWithItems with caption 1`] = `
        -
      • +
      • linkable @@ -134,9 +125,7 @@ exports[`ClayDropDownWithItems renders a DropDownWithItems with checkbox 1`] = `
          -
        • +
        • @@ -164,9 +153,7 @@ exports[`ClayDropDownWithItems renders a DropDownWithItems with checkbox 1`] = `
  • -
  • +
  • @@ -228,13 +215,10 @@ exports[`ClayDropDownWithItems renders a DropDownWithItems with footer content 1