tabPanels.tsx 2.3 KB

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