diff --git a/packages/react/src/components/DataTable/TableToolbar.js b/packages/react/src/components/DataTable/TableToolbar.tsx similarity index 74% rename from packages/react/src/components/DataTable/TableToolbar.js rename to packages/react/src/components/DataTable/TableToolbar.tsx index 405646742e17..e55322ca01c6 100644 --- a/packages/react/src/components/DataTable/TableToolbar.js +++ b/packages/react/src/components/DataTable/TableToolbar.tsx @@ -8,10 +8,27 @@ import cx from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; -import { AriaLabelPropType } from '../../prop-types/AriaPropTypes'; import { usePrefix } from '../../internal/usePrefix'; +import { AriaLabelPropType } from '../../prop-types/AriaPropTypes'; + +export interface TableToolbarProps + extends React.HTMLAttributes { + /** + * Pass in the children that will be rendered inside the TableToolbar + */ + children: React.ReactNode; + + /** + * `lg` Change the row height of table + */ + size?: 'sm' | 'lg'; +} -const TableToolbar = ({ children, size, ...rest }) => { +const TableToolbar: React.FC = ({ + children, + size, + ...rest +}) => { const prefix = usePrefix(); const className = cx({ [`${prefix}--table-toolbar`]: true, diff --git a/packages/react/src/components/DataTable/TableToolbarAction.js b/packages/react/src/components/DataTable/TableToolbarAction.js deleted file mode 100644 index 7ac9ec8d9b69..000000000000 --- a/packages/react/src/components/DataTable/TableToolbarAction.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright IBM Corp. 2016, 2023 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -import PropTypes from 'prop-types'; -import React from 'react'; -import OverflowMenuItem from '../OverflowMenuItem'; - -const TableToolbarAction = React.forwardRef(({ children, ...rest }, ref) => { - return ; -}); - -TableToolbarAction.displayName = 'TableToolbarAction'; -TableToolbarAction.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - onClick: PropTypes.func.isRequired, -}; - -export default TableToolbarAction; diff --git a/packages/react/src/components/DataTable/TableToolbarAction.tsx b/packages/react/src/components/DataTable/TableToolbarAction.tsx new file mode 100644 index 000000000000..e747201b1a5c --- /dev/null +++ b/packages/react/src/components/DataTable/TableToolbarAction.tsx @@ -0,0 +1,44 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import PropTypes from 'prop-types'; +import React from 'react'; +import OverflowMenuItem from '../OverflowMenuItem'; +import { ForwardRefReturn } from '../../types/common'; + +export interface TableToolbarActionProps + extends Omit, 'onClick'> { + /** + * Pass in the children that will be rendered inside the TableToolbarAction + */ + children?: React.ReactNode; + + /** + * onClick handler for the TableToolbarAction + */ + onClick: (event: React.MouseEvent) => void; +} + +export type TableToolbarActionComponent = ForwardRefReturn< + HTMLDivElement, + TableToolbarActionProps +>; + +const TableToolbarAction: TableToolbarActionComponent = React.forwardRef( + ({ children, ...rest }, ref) => { + return ; + } +); + +TableToolbarAction.displayName = 'TableToolbarAction'; +TableToolbarAction.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + onClick: PropTypes.func.isRequired, +}; + +export default TableToolbarAction; diff --git a/packages/react/src/components/DataTable/TableToolbarContent.js b/packages/react/src/components/DataTable/TableToolbarContent.tsx similarity index 100% rename from packages/react/src/components/DataTable/TableToolbarContent.js rename to packages/react/src/components/DataTable/TableToolbarContent.tsx diff --git a/packages/react/src/components/DataTable/TableToolbarMenu.js b/packages/react/src/components/DataTable/TableToolbarMenu.tsx similarity index 76% rename from packages/react/src/components/DataTable/TableToolbarMenu.js rename to packages/react/src/components/DataTable/TableToolbarMenu.tsx index 532bede28638..2fd3baca6612 100644 --- a/packages/react/src/components/DataTable/TableToolbarMenu.js +++ b/packages/react/src/components/DataTable/TableToolbarMenu.tsx @@ -5,14 +5,34 @@ * LICENSE file in the root directory of this source tree. */ +import { Settings } from '@carbon/icons-react'; import cx from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; -import OverflowMenu from '../OverflowMenu'; -import { Settings } from '@carbon/icons-react'; import { usePrefix } from '../../internal/usePrefix'; +import OverflowMenu from '../OverflowMenu'; + +export interface TableToolbarMenuProps + extends React.HTMLAttributes { + children: React.ReactNode; + + /** + * Provide an optional class name for the toolbar menu + */ + className?: string; + + /** + * The description of the menu icon. + */ + iconDescription: string; + + /** + * Optional prop to allow overriding the default menu icon + */ + renderIcon?: React.ReactNode; +} -const TableToolbarMenu = ({ +const TableToolbarMenu: React.FC = ({ className, renderIcon, iconDescription, diff --git a/packages/react/src/components/OverflowMenuItem/OverflowMenuItem.js b/packages/react/src/components/OverflowMenuItem/OverflowMenuItem.js deleted file mode 100644 index 128adc13a7de..000000000000 --- a/packages/react/src/components/OverflowMenuItem/OverflowMenuItem.js +++ /dev/null @@ -1,187 +0,0 @@ -/** - * Copyright IBM Corp. 2016, 2023 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -import cx from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { match, keys } from '../../internal/keyboard'; -import { warning } from '../../internal/warning'; -import { usePrefix } from '../../internal/usePrefix'; - -const OverflowMenuItem = React.forwardRef(function OverflowMenuItem( - { - className, - closeMenu, - disabled = false, - handleOverflowMenuItemFocus, - hasDivider = false, - href, - isDelete = false, - index, - itemText = 'Provide itemText', - onClick = () => {}, - onKeyDown = () => {}, - requireTitle, - title, - wrapperClassName, - ...rest - }, - ref -) { - const prefix = usePrefix(); - - function setTabFocus(evt) { - if (match(evt, keys.ArrowDown)) { - handleOverflowMenuItemFocus({ - currentIndex: index, - direction: 1, - }); - } - if (match(evt, keys.ArrowUp)) { - handleOverflowMenuItemFocus({ - currentIndex: index, - direction: -1, - }); - } - } - - function handleClick(evt) { - onClick(evt); - if (closeMenu) { - closeMenu(); - } - } - - if (__DEV__) { - warning( - closeMenu, - '`` detected missing `closeMenu` prop. ' + - '`closeMenu` is required to let `` close the menu upon actions on ``. ' + - 'Please make sure `` is a direct child of `.' - ); - } - - const overflowMenuBtnClasses = cx( - `${prefix}--overflow-menu-options__btn`, - className - ); - const overflowMenuItemClasses = cx( - `${prefix}--overflow-menu-options__option`, - { - [`${prefix}--overflow-menu--divider`]: hasDivider, - [`${prefix}--overflow-menu-options__option--danger`]: isDelete, - [`${prefix}--overflow-menu-options__option--disabled`]: disabled, - }, - wrapperClassName - ); - - const TagToUse = href ? 'a' : 'button'; - - const OverflowMenuItemContent = (() => { - if (typeof itemText !== 'string') { - return itemText; - } - return ( -
- {itemText} -
- ); - })(); - - return ( -
  • - { - setTabFocus(evt); - onKeyDown(evt); - }} - role="menuitem" - ref={ref} - tabIndex="-1" - title={requireTitle ? title || itemText : null} - {...rest}> - {OverflowMenuItemContent} - -
  • - ); -}); - -OverflowMenuItem.propTypes = { - /** - * The CSS class name to be placed on the button element - */ - className: PropTypes.string, - - /** - * A callback to tell the parent menu component that the menu should be closed. - */ - closeMenu: PropTypes.func, - - /** - * `true` to make this menu item disabled. - */ - disabled: PropTypes.bool, - - handleOverflowMenuItemFocus: PropTypes.func, - - /** - * `true` to make this menu item a divider. - */ - hasDivider: PropTypes.bool, - - /** - * If given, overflow item will render as a link with the given href - */ - href: PropTypes.string, - - index: PropTypes.number, - - /** - * `true` to make this menu item a "danger button". - */ - isDelete: PropTypes.bool, - - /** - * The text in the menu item. - */ - itemText: PropTypes.node.isRequired, - - /** - * event handlers - */ - onBlur: PropTypes.func, - onClick: PropTypes.func, - onFocus: PropTypes.func, - onKeyDown: PropTypes.func, - onKeyUp: PropTypes.func, - onMouseDown: PropTypes.func, - onMouseEnter: PropTypes.func, - onMouseLeave: PropTypes.func, - onMouseUp: PropTypes.func, - - /** - * `true` if this menu item has long text and requires a browser tooltip - */ - requireTitle: PropTypes.bool, - - /** - * Specify a title for the OverflowMenuItem - */ - title: PropTypes.string, - - /** - * The CSS class name to be placed on the wrapper list item element - */ - wrapperClassName: PropTypes.string, -}; - -export default OverflowMenuItem; diff --git a/packages/react/src/components/OverflowMenuItem/OverflowMenuItem.tsx b/packages/react/src/components/OverflowMenuItem/OverflowMenuItem.tsx new file mode 100644 index 000000000000..374f69af13b0 --- /dev/null +++ b/packages/react/src/components/OverflowMenuItem/OverflowMenuItem.tsx @@ -0,0 +1,260 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import cx from 'classnames'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { keys, match } from '../../internal/keyboard'; +import { usePrefix } from '../../internal/usePrefix'; +import { warning } from '../../internal/warning'; +import { ForwardRefReturn } from '../../types/common'; + +export interface OverflowMenuItemProps + extends React.HTMLAttributes { + /** + * The CSS class name to be placed on the button element + */ + className?: string; + + /** + * A callback to tell the parent menu component that the menu should be closed. + */ + closeMenu?: () => void; + + /** + * `true` to make this menu item disabled. + */ + disabled?: boolean; + + handleOverflowMenuItemFocus?: (options: { + currentIndex?: number; + direction: number; + }) => void; + + /** + * `true` to make this menu item a divider. + */ + hasDivider?: boolean; + + /** + * If given, overflow item will render as a link with the given href + */ + href?: string; + + index?: number; + + /** + * The text to show for the menu item + */ + itemText?: React.ReactNode; + + /** + * `true` to make this menu item a danger button. + */ + isDelete?: boolean; + + /** + * `true` to require the title attribute. + */ + requireTitle?: boolean; + + /** + * The title attribute. + */ + title?: string; + + /** + * The CSS class name to be placed on the wrapper element + */ + wrapperClassName?: string; +} + +export type OverflowMenuItemComponent = ForwardRefReturn< + HTMLElement, + OverflowMenuItemProps +>; + +const OverflowMenuItem: OverflowMenuItemComponent = React.forwardRef( + function OverflowMenuItem( + { + className, + closeMenu, + disabled = false, + handleOverflowMenuItemFocus, + hasDivider = false, + href, + isDelete = false, + index, + itemText = 'Provide itemText', + onClick = () => {}, + onKeyDown = () => {}, + requireTitle, + title, + wrapperClassName, + ...rest + }, + ref + ) { + const prefix = usePrefix(); + + function setTabFocus(evt) { + if (match(evt, keys.ArrowDown)) { + handleOverflowMenuItemFocus?.({ + currentIndex: index, + direction: 1, + }); + } + if (match(evt, keys.ArrowUp)) { + handleOverflowMenuItemFocus?.({ + currentIndex: index, + direction: -1, + }); + } + } + + function handleClick(evt) { + onClick(evt); + if (closeMenu) { + closeMenu(); + } + } + + if (__DEV__) { + warning( + closeMenu, + '`` detected missing `closeMenu` prop. ' + + '`closeMenu` is required to let `` close the menu upon actions on ``. ' + + 'Please make sure `` is a direct child of `.' + ); + } + + const overflowMenuBtnClasses = cx( + `${prefix}--overflow-menu-options__btn`, + className + ); + const overflowMenuItemClasses = cx( + `${prefix}--overflow-menu-options__option`, + { + [`${prefix}--overflow-menu--divider`]: hasDivider, + [`${prefix}--overflow-menu-options__option--danger`]: isDelete, + [`${prefix}--overflow-menu-options__option--disabled`]: disabled, + }, + wrapperClassName + ); + + const TagToUse = href ? 'a' : 'button'; + + const OverflowMenuItemContent = (() => { + if (typeof itemText !== 'string') { + return itemText; + } + return ( +
    + {itemText} +
    + ); + })(); + + return ( +
  • + { + setTabFocus(evt); + onKeyDown(evt); + }} + role="menuitem" + // ref as any: the type of `ref` is `ForwardedRef` in `Button` component + // but `OverflowMenuItem` can be rendered as `a` tag as well, which is `HTMLAnchorElement` + // so we have to use `any` here + ref={ref as any} + tabIndex={-1} + // itemText as any: itemText may be a ReactNode, but `title` only accepts string + // to avoid compatibility issue, we use `any` here. Consider to enforce `itemText` to be `string?` + // in the next major release + title={requireTitle ? title || (itemText as any) : undefined} + {...rest}> + {OverflowMenuItemContent} + +
  • + ); + } +); + +OverflowMenuItem.propTypes = { + /** + * The CSS class name to be placed on the button element + */ + className: PropTypes.string, + + /** + * A callback to tell the parent menu component that the menu should be closed. + */ + closeMenu: PropTypes.func, + + /** + * `true` to make this menu item disabled. + */ + disabled: PropTypes.bool, + + handleOverflowMenuItemFocus: PropTypes.func, + + /** + * `true` to make this menu item a divider. + */ + hasDivider: PropTypes.bool, + + /** + * If given, overflow item will render as a link with the given href + */ + href: PropTypes.string, + + index: PropTypes.number, + + /** + * `true` to make this menu item a "danger button". + */ + isDelete: PropTypes.bool, + + /** + * The text in the menu item. + */ + itemText: PropTypes.node.isRequired, + + /** + * event handlers + */ + onBlur: PropTypes.func, + onClick: PropTypes.func, + onFocus: PropTypes.func, + onKeyDown: PropTypes.func, + onKeyUp: PropTypes.func, + onMouseDown: PropTypes.func, + onMouseEnter: PropTypes.func, + onMouseLeave: PropTypes.func, + onMouseUp: PropTypes.func, + + /** + * `true` if this menu item has long text and requires a browser tooltip + */ + requireTitle: PropTypes.bool, + + /** + * Specify a title for the OverflowMenuItem + */ + title: PropTypes.string, + + /** + * The CSS class name to be placed on the wrapper list item element + */ + wrapperClassName: PropTypes.string, +}; + +export default OverflowMenuItem;