diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 35a7c15..9d44a3b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: - uses: pnpm/action-setup@v4 name: Install pnpm with: - version: 8 + version: 9.4.0+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a run_install: false - name: Install Node.js diff --git a/src-old/Button.js b/src-old/Button.js deleted file mode 100644 index 7769e57..0000000 --- a/src-old/Button.js +++ /dev/null @@ -1,129 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const ManagerContext = require('./ManagerContext'); -const { refType } = require("./propTypes"); -const specialAssign = require('./specialAssign'); - -const checkedProps = { - ambManager: PropTypes.object.isRequired, - children: PropTypes.node.isRequired, - disabled: PropTypes.bool, - forwardedRef: refType, - tag: PropTypes.string -}; - -// List retrieved from https://www.w3schools.com/tags/att_disabled.asp -const disabledSupportedTags = () => [ - 'button', - 'fieldset', - 'input', - 'optgroup', - 'option', - 'select', - 'textarea' -]; - -class AriaMenuButtonButton extends React.Component { - static propTypes = checkedProps; - - static defaultProps = { tag: 'span' }; - - ref = React.createRef(); - - componentDidMount() { - this.props.ambManager.button = this; - } - - componentWillUnmount() { - this.props.ambManager.destroy(); - } - - handleKeyDown = event => { - if (this.props.disabled) return; - - const ambManager = this.props.ambManager; - - switch (event.key) { - case 'ArrowDown': - event.preventDefault(); - if (!ambManager.isOpen) { - ambManager.openMenu(); - } else { - ambManager.focusItem(0); - } - break; - case 'Enter': - case ' ': - event.preventDefault(); - ambManager.toggleMenu(); - break; - case 'Escape': - ambManager.handleMenuKey(event); - break; - default: - // (Potential) letter keys - ambManager.handleButtonNonArrowKey(event); - } - }; - - handleClick = () => { - if (this.props.disabled) return; - this.props.ambManager.toggleMenu({}, { focusMenu: false }); - }; - - setRef = instance => { - this.ref.current = instance; - if (typeof this.props.forwardedRef === "function") { - this.props.forwardedRef(instance); - } else if (this.props.forwardedRef) { - this.props.forwardedRef.current = instance; - } - }; - - render() { - const props = this.props; - const ambManager = this.props.ambManager; - - const buttonProps = { - // "The menu button itself has a role of button." - role: 'button', - tabIndex: props.disabled ? '' : '0', - // "The menu button has an aria-haspopup property, set to true." - 'aria-haspopup': true, - 'aria-expanded': ambManager.isOpen, - 'aria-disabled': props.disabled, - onKeyDown: this.handleKeyDown, - onClick: this.handleClick - }; - - const reserved = {}; - specialAssign(reserved, checkedProps); - // The disabled property should be passed down to the Button element - // if the tag has support for disabled attribute. So it needs to be removed - // from the reserved property object - if (disabledSupportedTags().indexOf(props.tag) >= 0) { - delete reserved.disabled; - } - if (ambManager.options.closeOnBlur) { - buttonProps.onBlur = ambManager.handleBlur; - } - specialAssign(buttonProps, props, reserved); - specialAssign(buttonProps, { ref: this.setRef }); - - return React.createElement(props.tag, buttonProps, props.children); - } -} - -module.exports = React.forwardRef((props, ref) => React.createElement( - ManagerContext.Consumer, - null, - (ambManager) => { - const buttonProps = { ambManager, forwardedRef: ref }; - specialAssign(buttonProps, props, { - ambManager: checkedProps.ambManager, - children: checkedProps.children, - forwardedRef: checkedProps.forwardedRef - }); - return React.createElement(AriaMenuButtonButton, buttonProps, props.children); - } -)); diff --git a/src-old/ManagerContext.js b/src-old/ManagerContext.js deleted file mode 100644 index 1e18078..0000000 --- a/src-old/ManagerContext.js +++ /dev/null @@ -1,5 +0,0 @@ -const React = require('react'); - -const AriaMenuButtonManagerContext = React.createContext(); - -module.exports = AriaMenuButtonManagerContext; diff --git a/src-old/Menu.js b/src-old/Menu.js deleted file mode 100644 index 52e0c8a..0000000 --- a/src-old/Menu.js +++ /dev/null @@ -1,118 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const createTapListener = require('teeny-tap'); -const ManagerContext = require('./ManagerContext'); -const { refType } = require("./propTypes"); -const specialAssign = require('./specialAssign'); - -const checkedProps = { - ambManager: PropTypes.object.isRequired, - children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired, - forwardedRef: refType, - tag: PropTypes.string -}; - -class AriaMenuButtonMenu extends React.Component { - static propTypes = checkedProps; - static defaultProps = { tag: 'div' }; - - ref = React.createRef(); - - componentDidMount() { - this.props.ambManager.menu = this; - } - - componentDidUpdate() { - const ambManager = this.props.ambManager; - if (!ambManager.options.closeOnBlur) return; - if (ambManager.isOpen && !this.tapListener) { - this.addTapListener(); - } else if (!ambManager.isOpen && this.tapListener) { - this.tapListener.remove(); - delete this.tapListener; - } - - if (!ambManager.isOpen) { - // Clear the ambManager's items, so they - // can be reloaded next time this menu opens - ambManager.clearItems(); - } - } - - componentWillUnmount() { - if (this.tapListener) this.tapListener.remove(); - this.props.ambManager.destroy(); - } - - addTapListener = () => { - const el = this.ref.current; - if (!el) return; - const doc = el.ownerDocument; - if (!doc) return; - this.tapListener = createTapListener(doc.documentElement, this.handleTap); - }; - - handleTap = event => { - if (this.ref.current.contains(event.target)) return; - if ( - this.props.ambManager.button.ref.current.contains( - event.target - ) - ) - return; - this.props.ambManager.closeMenu(); - }; - - setRef = instance => { - this.ref.current = instance; - if (typeof this.props.forwardedRef === "function") { - this.props.forwardedRef(instance); - } else if (this.props.forwardedRef) { - this.props.forwardedRef.current = instance; - } - }; - - render() { - const props = this.props; - const ambManager = this.props.ambManager; - - const childrenToRender = (function() { - if (typeof props.children === 'function') { - return props.children({ isOpen: ambManager.isOpen }); - } - if (ambManager.isOpen) return props.children; - return false; - })(); - - if (!childrenToRender) return false; - - const menuProps = { - onKeyDown: ambManager.handleMenuKey, - role: 'menu', - tabIndex: -1 - }; - - if (ambManager.options.closeOnBlur) { - menuProps.onBlur = ambManager.handleBlur; - } - - specialAssign(menuProps, props, checkedProps); - specialAssign(menuProps, { ref: this.setRef }); - - return React.createElement(props.tag, menuProps, childrenToRender); - } -} - -module.exports = React.forwardRef((props, ref) => React.createElement( - ManagerContext.Consumer, - null, - (ambManager) => { - const buttonProps = { ambManager, forwardedRef: ref }; - specialAssign(buttonProps, props, { - ambManager: checkedProps.ambManager, - children: checkedProps.children, - forwardedRef: checkedProps.forwardedRef - }); - return React.createElement(AriaMenuButtonMenu, buttonProps, props.children); - } -)); diff --git a/src-old/MenuItem.js b/src-old/MenuItem.js deleted file mode 100644 index eb47cf1..0000000 --- a/src-old/MenuItem.js +++ /dev/null @@ -1,84 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const ManagerContext = require('./ManagerContext'); -const { refType } = require("./propTypes"); -const specialAssign = require('./specialAssign'); - -const checkedProps = { - ambManager: PropTypes.object.isRequired, - children: PropTypes.node.isRequired, - forwardedRef: refType, - tag: PropTypes.string, - text: PropTypes.string, - value: PropTypes.any -}; - -class AriaMenuButtonMenuItem extends React.Component { - static propTypes = checkedProps; - static defaultProps = { tag: 'div' }; - - ref = React.createRef(); - - componentDidMount() { - this.props.ambManager.addItem({ - node: this.ref.current, - text: this.props.text - }); - } - - handleKeyDown = event => { - if (event.key !== 'Enter' && event.key !== ' ') return; - if (this.props.tag === 'a' && this.props.href) return; - event.preventDefault(); - this.selectItem(event); - }; - - selectItem = event => { - // If there's no value, we'll send the child - const value = typeof this.props.value !== 'undefined' - ? this.props.value - : this.props.children; - this.props.ambManager.handleSelection(value, event); - }; - - setRef = instance => { - this.ref.current = instance; - if (typeof this.props.forwardedRef === "function") { - this.props.forwardedRef(instance); - } else if (this.props.forwardedRef) { - this.props.forwardedRef.current = instance; - } - }; - - render() { - const menuItemProps = { - onClick: this.selectItem, - onKeyDown: this.handleKeyDown, - role: 'menuitem', - tabIndex: '-1', - ref: this.setRef - }; - - specialAssign(menuItemProps, this.props, checkedProps); - - return React.createElement( - this.props.tag, - menuItemProps, - this.props.children - ); - } -} - -module.exports = React.forwardRef((props, ref) => React.createElement( - ManagerContext.Consumer, - null, - (ambManager) => { - const buttonProps = { ambManager, forwardedRef: ref }; - specialAssign(buttonProps, props, { - ambManager: checkedProps.ambManager, - children: checkedProps.children, - forwardedRef: checkedProps.forwardedRef - }); - return React.createElement(AriaMenuButtonMenuItem, buttonProps, props.children); - } -)); diff --git a/src-old/Wrapper.js b/src-old/Wrapper.js deleted file mode 100644 index e813af7..0000000 --- a/src-old/Wrapper.js +++ /dev/null @@ -1,62 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const createManager = require('./createManager'); -const ManagerContext = require('./ManagerContext'); -const { refType } = require("./propTypes"); -const specialAssign = require('./specialAssign'); - -const checkedProps = { - children: PropTypes.node.isRequired, - forwardedRef: refType, - onMenuToggle: PropTypes.func, - onSelection: PropTypes.func, - closeOnSelection: PropTypes.bool, - closeOnBlur: PropTypes.bool, - tag: PropTypes.string -}; - -const managerOptionsFromProps = (props) => { - return { - onMenuToggle: props.onMenuToggle, - onSelection: props.onSelection, - closeOnSelection: props.closeOnSelection, - closeOnBlur: props.closeOnBlur, - id: props.id - } -} - -class AriaMenuButtonWrapper extends React.Component { - static propTypes = checkedProps; - static defaultProps = { tag: 'div' }; - - constructor(props) { - super(props); - this.manager = createManager(managerOptionsFromProps(props)); - } - - componentDidUpdate() { - this.manager.updateOptions(managerOptionsFromProps(this.props)) - } - - render() { - const wrapperProps = {}; - specialAssign(wrapperProps, this.props, checkedProps); - - return React.createElement( - ManagerContext.Provider, - { value: this.manager }, - React.createElement( - this.props.tag, - wrapperProps, - this.props.children, - ), - ); - } -} - -module.exports = React.forwardRef((props, ref) => { - const wrapperProps = { forwardedRef: ref }; - specialAssign(wrapperProps, props, { children: checkedProps.children, forwardedRef: checkedProps.forwardedRef }); - specialAssign(wrapperProps, { forwardedRef: ref }); - return React.createElement(AriaMenuButtonWrapper, wrapperProps, props.children); -}); diff --git a/src-old/__tests__/Button.test.js b/src-old/__tests__/Button.test.js deleted file mode 100644 index dad92b3..0000000 --- a/src-old/__tests__/Button.test.js +++ /dev/null @@ -1,169 +0,0 @@ -const React = require('react'); -const ReactDOMServer = require('react-dom/server'); -const shallow = require('enzyme').shallow; -const shallowToJson = require('enzyme-to-json').shallowToJson; -const Button = require('../Button'); -const ManagerContext = require('../ManagerContext'); -const MockWrapper = require('./helpers/MockWrapper'); -const createMockKeyEvent = require('./helpers/createMockKeyEvent'); -const createMockManager = require('./helpers/createMockManager'); -const createManager = require('../createManager'); - -const el = React.createElement; - -describe(' -`; - -exports[`