tabPanels.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import {useContext, useRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import {AriaTabPanelProps, useTabPanel} from '@react-aria/tabs';
  4. import {useCollection} from '@react-stately/collections';
  5. import {ListCollection} from '@react-stately/list';
  6. import {TabListState} from '@react-stately/tabs';
  7. import {CollectionBase, Node, Orientation} from '@react-types/shared';
  8. import {TabsContext} from './index';
  9. import {Item} from './item';
  10. import {tabsShouldForwardProp} from './utils';
  11. const collectionFactory = (nodes: Iterable<Node<any>>) => new ListCollection(nodes);
  12. interface TabPanelsProps extends AriaTabPanelProps, CollectionBase<any> {
  13. className?: string;
  14. }
  15. /**
  16. * To be used as a direct child of the <Tabs /> component. See example usage
  17. * in tabs.stories.js
  18. */
  19. export function TabPanels(props: TabPanelsProps) {
  20. const {
  21. rootProps: {orientation, items},
  22. tabListState,
  23. } = useContext(TabsContext);
  24. // Parse child tab panels from props and identify the selected panel
  25. const collection = useCollection({items, ...props}, collectionFactory, {
  26. suppressTextValueWarning: true,
  27. });
  28. const selectedPanel = tabListState
  29. ? collection.getItem(tabListState.selectedKey)
  30. : null;
  31. if (!tabListState) {
  32. return null;
  33. }
  34. return (
  35. <TabPanel
  36. {...props}
  37. state={tabListState}
  38. orientation={orientation}
  39. key={tabListState?.selectedKey}
  40. >
  41. {selectedPanel?.props.children}
  42. </TabPanel>
  43. );
  44. }
  45. TabPanels.Item = Item;
  46. interface TabPanelProps extends AriaTabPanelProps {
  47. orientation: Orientation;
  48. state: TabListState<any>;
  49. children?: React.ReactNode;
  50. className?: string;
  51. }
  52. function TabPanel({state, orientation, className, children, ...props}: TabPanelProps) {
  53. const ref = useRef<HTMLDivElement>(null);
  54. const {tabPanelProps} = useTabPanel(props, state, ref);
  55. return (
  56. <TabPanelWrap
  57. {...tabPanelProps}
  58. orientation={orientation}
  59. className={className}
  60. ref={ref}
  61. >
  62. {children}
  63. </TabPanelWrap>
  64. );
  65. }
  66. const TabPanelWrap = styled('div', {shouldForwardProp: tabsShouldForwardProp})<{
  67. orientation: Orientation;
  68. }>`
  69. border-radius: ${p => p.theme.borderRadius};
  70. ${p => (p.orientation === 'horizontal' ? `height: 100%;` : `width: 100%;`)};
  71. &.focus-visible {
  72. outline: none;
  73. box-shadow: inset ${p => p.theme.focusBorder} 0 0 0 1px,
  74. ${p => p.theme.focusBorder} 0 0 0 1px;
  75. z-index: 1;
  76. }
  77. `;