diff --git a/packages/@react-spectrum/dialog/package.json b/packages/@react-spectrum/dialog/package.json index 26f844625c9..ed79e792584 100644 --- a/packages/@react-spectrum/dialog/package.json +++ b/packages/@react-spectrum/dialog/package.json @@ -43,6 +43,7 @@ "@react-spectrum/typography": "^3.0.0-alpha.1", "@react-spectrum/utils": "^3.0.0-alpha.2", "@react-spectrum/view": "^3.0.0-alpha.1", + "@react-stately/dialog": "^3.0.0-alpha.1", "@react-stately/utils": "^3.0.0-alpha.2", "@react-types/dialog": "^3.0.0-alpha.2", "@react-types/shared": "^3.0.0-alpha.2", diff --git a/packages/@react-spectrum/dialog/src/DialogTrigger.tsx b/packages/@react-spectrum/dialog/src/DialogTrigger.tsx index 4a98ed0c268..0b4c3b25a8c 100644 --- a/packages/@react-spectrum/dialog/src/DialogTrigger.tsx +++ b/packages/@react-spectrum/dialog/src/DialogTrigger.tsx @@ -15,7 +15,7 @@ import {Modal, Overlay, Popover, Tray} from '@react-spectrum/overlays'; import {PressResponder} from '@react-aria/interactions'; import React, {Fragment, ReactElement, useRef} from 'react'; import {SpectrumDialogClose, SpectrumDialogProps, SpectrumDialogTriggerProps} from '@react-types/dialog'; -import {useControlledState} from '@react-stately/utils'; +import {useDialogTriggerState} from '@react-stately/dialog'; import {useMediaQuery} from '@react-spectrum/utils'; import {useOverlayPosition, useOverlayTrigger} from '@react-aria/overlays'; @@ -47,7 +47,8 @@ export function DialogTrigger(props: SpectrumDialogTriggerProps) { type = mobileType; } - let [isOpen, setOpen] = useControlledState(props.isOpen, props.defaultOpen || false, props.onOpenChange); + let {isOpen, setOpen} = useDialogTriggerState(props); + let onPress = () => { setOpen(!isOpen); }; diff --git a/packages/@react-spectrum/menu/package.json b/packages/@react-spectrum/menu/package.json index 76eaee672e8..8157ed4ad36 100644 --- a/packages/@react-spectrum/menu/package.json +++ b/packages/@react-spectrum/menu/package.json @@ -45,6 +45,7 @@ "@react-spectrum/typography": "^3.0.0-alpha.1", "@react-spectrum/utils": "^3.0.0-rc.1", "@react-stately/collections": "^3.0.0-alpha.2", + "@react-stately/menu": "^3.0.0-alpha.1", "@react-stately/tree": "^3.0.0-alpha.2", "@react-stately/utils": "^3.0.0-rc.1", "@react-types/menu": "^3.0.0-alpha.2", diff --git a/packages/@react-spectrum/menu/src/MenuTrigger.tsx b/packages/@react-spectrum/menu/src/MenuTrigger.tsx index 980db2b0261..431546a7424 100644 --- a/packages/@react-spectrum/menu/src/MenuTrigger.tsx +++ b/packages/@react-spectrum/menu/src/MenuTrigger.tsx @@ -11,15 +11,15 @@ */ import {FocusScope} from '@react-aria/focus'; -import {FocusStrategy, SpectrumMenuTriggerProps} from '@react-types/menu'; import {MenuContext} from './context'; import {Overlay, Popover, Tray} from '@react-spectrum/overlays'; import {Placement, useOverlayPosition} from '@react-aria/overlays'; import {PressResponder} from '@react-aria/interactions'; -import React, {Fragment, useRef, useState} from 'react'; -import {useControlledState} from '@react-stately/utils'; +import React, {Fragment, useRef} from 'react'; +import {SpectrumMenuTriggerProps} from '@react-types/menu'; import {useMediaQuery} from '@react-spectrum/utils'; import {useMenuTrigger} from '@react-aria/menu'; +import {useMenuTriggerState} from '@react-stately/menu'; export function MenuTrigger(props: SpectrumMenuTriggerProps) { let menuPopoverRef = useRef(); @@ -27,7 +27,6 @@ export function MenuTrigger(props: SpectrumMenuTriggerProps) { let menuRef = useRef(); let { children, - onOpenChange, align = 'start', shouldFlip = true, direction = 'bottom', @@ -35,23 +34,17 @@ export function MenuTrigger(props: SpectrumMenuTriggerProps) { } = props; let [menuTrigger, menu] = React.Children.toArray(children); - let [isOpen, setOpen] = useControlledState(props.isOpen, props.defaultOpen || false, onOpenChange); - let [focusStrategy, setFocusStrategy] = useState('first' as FocusStrategy); + let state = useMenuTriggerState(props); let onClose = () => { - setOpen(false); + state.setOpen(false); }; let {menuTriggerProps, menuProps} = useMenuTrigger( { ref: menuTriggerRef }, - { - isOpen, - setOpen, - focusStrategy, - setFocusStrategy - } + state ); let {overlayProps, placement} = useOverlayPosition({ @@ -60,7 +53,7 @@ export function MenuTrigger(props: SpectrumMenuTriggerProps) { scrollRef: menuRef, placement: `${direction} ${align}` as Placement, shouldFlip: shouldFlip, - isOpen + isOpen: state.isOpen }); let isMobile = useMediaQuery('(max-width: 700px)'); @@ -69,7 +62,7 @@ export function MenuTrigger(props: SpectrumMenuTriggerProps) { ref: menuRef, onClose, closeOnSelect, - autoFocus: focusStrategy, + autoFocus: state.focusStrategy, UNSAFE_style: { width: isMobile ? '100%' : undefined } @@ -79,7 +72,7 @@ export function MenuTrigger(props: SpectrumMenuTriggerProps) { let overlay; if (isMobile) { overlay = ( - + {menu} @@ -102,11 +95,11 @@ export function MenuTrigger(props: SpectrumMenuTriggerProps) { return ( - + {menuTrigger} - + {overlay} diff --git a/packages/@react-stately/dialog/README.md b/packages/@react-stately/dialog/README.md new file mode 100644 index 00000000000..acd46fb1a19 --- /dev/null +++ b/packages/@react-stately/dialog/README.md @@ -0,0 +1,3 @@ +# @react-stately/dialog + +This package is part of [react-spectrum](https://github.com/adobe-private/react-spectrum-v3). See the repo for more details. diff --git a/packages/@react-stately/dialog/index.ts b/packages/@react-stately/dialog/index.ts new file mode 100644 index 00000000000..1210ae1e402 --- /dev/null +++ b/packages/@react-stately/dialog/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export * from './src'; diff --git a/packages/@react-stately/dialog/package.json b/packages/@react-stately/dialog/package.json new file mode 100644 index 00000000000..783a9620da6 --- /dev/null +++ b/packages/@react-stately/dialog/package.json @@ -0,0 +1,30 @@ +{ + "name": "@react-stately/dialog", + "version": "3.0.0-alpha.1", + "description": "Spectrum UI components in React", + "license": "Apache-2.0", + "private": true, + "main": "dist/main.js", + "module": "dist/module.js", + "types": "dist/types.d.ts", + "source": "src/index.ts", + "files": [ + "dist" + ], + "sideEffects": false, + "repository": { + "type": "git", + "url": "https://github.com/adobe-private/react-spectrum-v3" + }, + "dependencies": { + "@babel/runtime": "^7.6.2", + "@react-stately/utils": "^3.0.0-alpha.2", + "@react-types/dialog": "^3.0.0-alpha.2" + }, + "peerDependencies": { + "react": "^16.8.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/@react-stately/dialog/src/index.ts b/packages/@react-stately/dialog/src/index.ts new file mode 100644 index 00000000000..f63a1ce2657 --- /dev/null +++ b/packages/@react-stately/dialog/src/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export * from './useDialogTriggerState'; diff --git a/packages/@react-stately/dialog/src/useDialogTriggerState.ts b/packages/@react-stately/dialog/src/useDialogTriggerState.ts new file mode 100644 index 00000000000..1cfa1750a2c --- /dev/null +++ b/packages/@react-stately/dialog/src/useDialogTriggerState.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import {DialogTriggerProps} from '@react-types/dialog'; +import {useControlledState} from '@react-stately/utils'; + +export interface DialogTriggerState { + isOpen: boolean, + setOpen: (value: boolean) => void, +} + +export function useDialogTriggerState(props: DialogTriggerProps):DialogTriggerState { + let [isOpen, setOpen] = useControlledState(props.isOpen, props.defaultOpen || false, props.onOpenChange); + + return { + isOpen, + setOpen + }; +} diff --git a/packages/@react-stately/menu/README.md b/packages/@react-stately/menu/README.md new file mode 100644 index 00000000000..808b6dd521c --- /dev/null +++ b/packages/@react-stately/menu/README.md @@ -0,0 +1,3 @@ +# @react-stately/menu + +This package is part of [react-spectrum](https://github.com/adobe-private/react-spectrum-v3). See the repo for more details. diff --git a/packages/@react-stately/menu/index.ts b/packages/@react-stately/menu/index.ts new file mode 100644 index 00000000000..1210ae1e402 --- /dev/null +++ b/packages/@react-stately/menu/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export * from './src'; diff --git a/packages/@react-stately/menu/package.json b/packages/@react-stately/menu/package.json new file mode 100644 index 00000000000..973865280ab --- /dev/null +++ b/packages/@react-stately/menu/package.json @@ -0,0 +1,30 @@ +{ + "name": "@react-stately/menu", + "version": "3.0.0-alpha.1", + "description": "Spectrum UI components in React", + "license": "Apache-2.0", + "private": true, + "main": "dist/main.js", + "module": "dist/module.js", + "types": "dist/types.d.ts", + "source": "src/index.ts", + "files": [ + "dist" + ], + "sideEffects": false, + "repository": { + "type": "git", + "url": "https://github.com/adobe-private/react-spectrum-v3" + }, + "dependencies": { + "@babel/runtime": "^7.6.2", + "@react-stately/utils": "^3.0.0-alpha.2", + "@react-types/menu": "^3.0.0-alpha.2" + }, + "peerDependencies": { + "react": "^16.8.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/@react-stately/menu/src/index.ts b/packages/@react-stately/menu/src/index.ts new file mode 100644 index 00000000000..374e2c53067 --- /dev/null +++ b/packages/@react-stately/menu/src/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export * from './useMenuTriggerState'; diff --git a/packages/@react-stately/menu/src/useMenuTriggerState.ts b/packages/@react-stately/menu/src/useMenuTriggerState.ts new file mode 100644 index 00000000000..c0f99227783 --- /dev/null +++ b/packages/@react-stately/menu/src/useMenuTriggerState.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import {FocusStrategy, MenuTriggerProps, MenuTriggerState} from '@react-types/menu'; +import {useControlledState} from '@react-stately/utils'; +import {useState} from 'react'; + +export function useMenuTriggerState(props: MenuTriggerProps):MenuTriggerState { + let [isOpen, setOpen] = useControlledState(props.isOpen, props.defaultOpen || false, props.onOpenChange); + let [focusStrategy, setFocusStrategy] = useState('first' as FocusStrategy); + + return { + isOpen, + setOpen, + focusStrategy, + setFocusStrategy + }; +} diff --git a/packages/@react-stately/select/package.json b/packages/@react-stately/select/package.json index 0a2beb8f6f1..938e147aed5 100644 --- a/packages/@react-stately/select/package.json +++ b/packages/@react-stately/select/package.json @@ -18,6 +18,7 @@ "@babel/runtime": "^7.6.2", "@react-stately/collections": "^3.0.0-alpha.1", "@react-stately/list": "^3.0.0-alpha.1", + "@react-stately/menu": "^3.0.0-alpha.1", "@react-stately/selection": "^3.0.0-alpha.1", "@react-stately/utils": "^3.0.0-alpha.1" }, diff --git a/packages/@react-stately/select/src/useSelectState.ts b/packages/@react-stately/select/src/useSelectState.ts index 7e6f46c4056..843fe7f463f 100644 --- a/packages/@react-stately/select/src/useSelectState.ts +++ b/packages/@react-stately/select/src/useSelectState.ts @@ -12,11 +12,12 @@ import {Collection, Node} from '@react-stately/collections'; import {FocusStrategy} from '@react-types/menu'; -import {Key, useMemo, useState} from 'react'; +import {Key, useMemo} from 'react'; import {SelectionManager} from '@react-stately/selection'; import {SelectProps} from '@react-types/select'; import {useControlledState} from '@react-stately/utils'; import {useListState} from '@react-stately/list'; // TODO: move +import {useMenuTriggerState} from '@react-stately/menu'; export interface SelectState { collection: Collection>, @@ -44,9 +45,7 @@ export function useSelectState(props: SelectProps): SelectState { } }); - // TODO: move to useMenuTriggerState - let [isOpen, setOpen] = useControlledState(props.isOpen, props.defaultOpen || false, props.onOpenChange); - let [focusStrategy, setFocusStrategy] = useState('first' as FocusStrategy); + let {isOpen, setOpen, focusStrategy, setFocusStrategy} = useMenuTriggerState(props); return { collection, @@ -60,7 +59,7 @@ export function useSelectState(props: SelectProps): SelectState { setFocusStrategy, toggle(focusStrategy = 'first') { setFocusStrategy(focusStrategy); - setOpen(isOpen => !isOpen); + setOpen(!isOpen); } }; } diff --git a/packages/@react-types/dialog/src/index.d.ts b/packages/@react-types/dialog/src/index.d.ts index 788959ed92a..f68fc886fd3 100644 --- a/packages/@react-types/dialog/src/index.d.ts +++ b/packages/@react-types/dialog/src/index.d.ts @@ -16,15 +16,18 @@ import {ReactElement, ReactNode, RefObject} from 'react'; export type SpectrumDialogClose = (close: () => void) => ReactElement; -export interface SpectrumDialogTriggerProps extends PositionProps { +export interface DialogTriggerProps { + isOpen?: boolean, + defaultOpen?: boolean, + onOpenChange?: (isOpen: boolean) => void +} + +export interface SpectrumDialogTriggerProps extends PositionProps, DialogTriggerProps { children: [ReactElement, SpectrumDialogClose | ReactElement], type?: 'modal' | 'popover' | 'tray' | 'fullscreen' | 'fullscreenTakeover', mobileType?: 'modal' | 'tray' | 'fullscreen' | 'fullscreenTakeover', hideArrow?: boolean, targetRef?: RefObject, - isOpen?: boolean, - defaultOpen?: boolean, - onOpenChange?: (isOpen: boolean) => void, isDismissable?: boolean }