Browse Source

ref(tabs): Export `Item` as property of `TabList` & `TabPanels` (#44620)

Rather than:
```jsx
import {Item, Tabs, TabList, TabPanels} from 'sentry/components/tabs'
…
<Tabs>
  <TabList>
    <Item>…</Item>
    <Item>…</Item>
  </TabList>
  <TabPanels>
    <Item>…</Item>
    <Item>…</Item>
  </TabPanels>
</Tabs>
```

we should now write:
```jsx
import {Tabs, TabList, TabPanels} from 'sentry/components/tabs'
…
<Tabs>
  <TabList>
    <TabList.Item>…</TabList.Item>
    <TabList.Item>…</TabList.Item>
  </TabList>
  <TabPanels>
    <TabPanels.Item>…</TabPanels.Item>
    <TabPanels.Item>…</TabPanels.Item>
  </TabPanels>
</Tabs>
```
Vu Luong 2 years ago
parent
commit
180b0f3db1

+ 7 - 7
docs-ui/stories/views/tabs.stories.js

@@ -1,6 +1,6 @@
 import styled from '@emotion/styled';
 
-import {Item, TabList, TabPanels, Tabs} from 'sentry/components/tabs';
+import {TabList, TabPanels, Tabs} from 'sentry/components/tabs';
 import {space} from 'sentry/styles/space';
 
 export default {
@@ -43,14 +43,14 @@ export const Default = args => {
     <Tabs {...args}>
       <TabList>
         {TABS.map(tab => (
-          <Item key={tab.key} disabled={tab.disabled}>
+          <TabList.Item key={tab.key} disabled={tab.disabled}>
             {tab.label}
-          </Item>
+          </TabList.Item>
         ))}
       </TabList>
       <StyledTabPanels orientation={args.orientation}>
         {TABS.map(tab => (
-          <Item key={tab.key}>{tab.content}</Item>
+          <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
         ))}
       </StyledTabPanels>
     </Tabs>
@@ -102,14 +102,14 @@ export const TabLinks = ({selectedValue, ...args}) => {
     <Tabs {...args} value={selectedValue}>
       <TabList>
         {TABS_LINKS.map(tab => (
-          <Item key={tab.key} to={tab.to}>
+          <TabList.Item key={tab.key} to={tab.to}>
             {tab.label}
-          </Item>
+          </TabList.Item>
         ))}
       </TabList>
       <StyledTabPanels orientation={args.orientation}>
         {TABS_LINKS.map(tab => (
-          <Item key={tab.key}>{tab.content}</Item>
+          <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
         ))}
       </StyledTabPanels>
     </Tabs>

+ 7 - 7
static/app/components/activity/note/input.tsx

@@ -4,7 +4,7 @@ import {Theme, useTheme} from '@emotion/react';
 import styled from '@emotion/styled';
 
 import {Button} from 'sentry/components/button';
-import {Item, TabList, TabPanels, Tabs} from 'sentry/components/tabs';
+import {TabList, TabPanels, Tabs} from 'sentry/components/tabs';
 import {IconMarkdown} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import MemberListStore from 'sentry/stores/memberListStore';
@@ -160,11 +160,11 @@ function NoteInput({
     <NoteInputForm data-test-id="note-input-form" noValidate onSubmit={handleSubmit}>
       <Tabs>
         <StyledTabList>
-          <Item key="edit">{existingItem ? t('Edit') : t('Write')}</Item>
-          <Item key="preview">{t('Preview')}</Item>
+          <TabList.Item key="edit">{existingItem ? t('Edit') : t('Write')}</TabList.Item>
+          <TabList.Item key="preview">{t('Preview')}</TabList.Item>
         </StyledTabList>
         <NoteInputPanel>
-          <Item key="edit">
+          <TabPanels.Item key="edit">
             <MentionsInput
               aria-errormessage={errorMessage ? errorId : undefined}
               style={mentionStyle({theme, minHeight})}
@@ -191,13 +191,13 @@ function NoteInput({
                 appendSpaceOnAdd
               />
             </MentionsInput>
-          </Item>
-          <Item key="preview">
+          </TabPanels.Item>
+          <TabPanels.Item key="preview">
             <NotePreview
               minHeight={minHeight}
               dangerouslySetInnerHTML={{__html: marked(cleanMarkdown)}}
             />
-          </Item>
+          </TabPanels.Item>
         </NoteInputPanel>
       </Tabs>
       <Footer>

+ 17 - 17
static/app/components/tabs/index.spec.tsx

@@ -1,6 +1,6 @@
 import {render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary';
 
-import {Item, TabList, TabPanels, Tabs} from 'sentry/components/tabs';
+import {TabList, TabPanels, Tabs} from 'sentry/components/tabs';
 
 const TABS = [
   {key: 'details', label: 'Details', content: 'So by colonel hearted ferrars.'},
@@ -28,12 +28,12 @@ describe('Tabs', () => {
       <Tabs>
         <TabList>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.label}</Item>
+            <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
           ))}
         </TabList>
         <TabPanels>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.content}</Item>
+            <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
           ))}
         </TabPanels>
       </Tabs>
@@ -59,12 +59,12 @@ describe('Tabs', () => {
       <Tabs disabled>
         <TabList>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.label}</Item>
+            <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
           ))}
         </TabList>
         <TabPanels>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.content}</Item>
+            <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
           ))}
         </TabPanels>
       </Tabs>
@@ -91,12 +91,12 @@ describe('Tabs', () => {
       <Tabs>
         <TabList>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.label}</Item>
+            <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
           ))}
         </TabList>
         <TabPanels>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.content}</Item>
+            <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
           ))}
         </TabPanels>
       </Tabs>
@@ -118,12 +118,12 @@ describe('Tabs', () => {
       <Tabs>
         <TabList>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.label}</Item>
+            <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
           ))}
         </TabList>
         <TabPanels>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.content}</Item>
+            <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
           ))}
         </TabPanels>
       </Tabs>
@@ -149,12 +149,12 @@ describe('Tabs', () => {
       <Tabs orientation="vertical">
         <TabList>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.label}</Item>
+            <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
           ))}
         </TabList>
         <TabPanels>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.content}</Item>
+            <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
           ))}
         </TabPanels>
       </Tabs>
@@ -180,14 +180,14 @@ describe('Tabs', () => {
       <Tabs>
         <TabList>
           {TABS.map(tab => (
-            <Item key={tab.key} disabled>
+            <TabList.Item key={tab.key} disabled>
               {tab.label}
-            </Item>
+            </TabList.Item>
           ))}
         </TabList>
         <TabPanels>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.content}</Item>
+            <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
           ))}
         </TabPanels>
       </Tabs>
@@ -207,14 +207,14 @@ describe('Tabs', () => {
       <Tabs>
         <TabList>
           {TABS.map(tab => (
-            <Item key={tab.key} to="/some-link">
+            <TabList.Item key={tab.key} to="/some-link">
               {tab.label}
-            </Item>
+            </TabList.Item>
           ))}
         </TabList>
         <TabPanels>
           {TABS.map(tab => (
-            <Item key={tab.key}>{tab.content}</Item>
+            <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
           ))}
         </TabPanels>
       </Tabs>,

+ 1 - 2
static/app/components/tabs/index.tsx

@@ -6,12 +6,11 @@ import {AriaTabListProps} from '@react-aria/tabs';
 import {TabListProps, TabListState} from '@react-stately/tabs';
 import {Orientation} from '@react-types/shared';
 
-import {Item} from './item';
 import {TabList} from './tabList';
 import {TabPanels} from './tabPanels';
 import {tabsShouldForwardProp} from './utils';
 
-export {Item, TabList, TabPanels};
+export {TabList, TabPanels};
 
 export interface TabsProps<T>
   extends Omit<TabListProps<any>, 'children'>,

+ 4 - 2
static/app/components/tabs/tabList.tsx

@@ -2,19 +2,19 @@ import {useContext, useEffect, useMemo, useRef, useState} from 'react';
 import {browserHistory} from 'react-router';
 import styled from '@emotion/styled';
 import {AriaTabListProps, useTabList} from '@react-aria/tabs';
-import {Item, useCollection} from '@react-stately/collections';
+import {useCollection} from '@react-stately/collections';
 import {ListCollection} from '@react-stately/list';
 import {useTabListState} from '@react-stately/tabs';
 import {Node, Orientation} from '@react-types/shared';
 
 import {CompactSelect} from 'sentry/components/compactSelect';
 import DropdownButton from 'sentry/components/dropdownButton';
-import {TabListItemProps} from 'sentry/components/tabs/item';
 import {IconEllipsis} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 
 import {TabsContext} from './index';
+import {Item, TabListItemProps} from './item';
 import {Tab} from './tab';
 import {tabsShouldForwardProp} from './utils';
 
@@ -242,6 +242,8 @@ export function TabList({items, ...props}: TabListProps) {
   );
 }
 
+TabList.Item = Item;
+
 const TabListOuterWrap = styled('div')`
   position: relative;
 `;

+ 3 - 0
static/app/components/tabs/tabPanels.tsx

@@ -7,6 +7,7 @@ import {TabListState} from '@react-stately/tabs';
 import {CollectionBase, Node, Orientation} from '@react-types/shared';
 
 import {TabsContext} from './index';
+import {Item} from './item';
 import {tabsShouldForwardProp} from './utils';
 
 const collectionFactory = (nodes: Iterable<Node<any>>) => new ListCollection(nodes);
@@ -49,6 +50,8 @@ export function TabPanels(props: TabPanelsProps) {
   );
 }
 
+TabPanels.Item = Item;
+
 interface TabPanelProps extends AriaTabPanelProps {
   orientation: Orientation;
   state: TabListState<any>;

+ 3 - 3
static/app/views/issueDetails/groupDetails.tsx

@@ -12,7 +12,7 @@ import LoadingIndicator from 'sentry/components/loadingIndicator';
 import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
 import MissingProjectMembership from 'sentry/components/projects/missingProjectMembership';
 import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
-import {Item, TabPanels, Tabs} from 'sentry/components/tabs';
+import {TabPanels, Tabs} from 'sentry/components/tabs';
 import {t} from 'sentry/locale';
 import SentryTypes from 'sentry/sentryTypes';
 import GroupStore from 'sentry/stores/groupStore';
@@ -627,9 +627,9 @@ class GroupDetails extends Component<Props, State> {
           project={project as Project}
         />
         <GroupTabPanels>
-          <Item key={currentTab}>
+          <TabPanels.Item key={currentTab}>
             {isValidElement(children) ? cloneElement(children, childProps) : children}
-          </Item>
+          </TabPanels.Item>
         </GroupTabPanels>
       </Tabs>
     );

+ 25 - 21
static/app/views/issueDetails/header.tsx

@@ -21,7 +21,7 @@ import ReplayCountBadge from 'sentry/components/replays/replayCountBadge';
 import ReplaysFeatureBadge from 'sentry/components/replays/replaysFeatureBadge';
 import useReplaysCount from 'sentry/components/replays/useReplaysCount';
 import ShortId from 'sentry/components/shortId';
-import {Item, TabList} from 'sentry/components/tabs';
+import {TabList} from 'sentry/components/tabs';
 import {Tooltip} from 'sentry/components/tooltip';
 import {IconChat} from 'sentry/icons';
 import {t} from 'sentry/locale';
@@ -78,14 +78,14 @@ function GroupHeaderTabs({
 
   return (
     <StyledTabList hideBorder>
-      <Item
+      <TabList.Item
         key={Tab.DETAILS}
         disabled={disabledTabs.includes(Tab.DETAILS)}
         to={`${baseUrl}${location.search}`}
       >
         {t('Details')}
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.ACTIVITY}
         textValue={t('Activity')}
         disabled={disabledTabs.includes(Tab.ACTIVITY)}
@@ -96,8 +96,8 @@ function GroupHeaderTabs({
           {group.numComments}
           <IconChat size="xs" />
         </IconBadge>
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.USER_FEEDBACK}
         textValue={t('User Feedback')}
         hidden={!issueTypeConfig.userFeedback.enabled}
@@ -105,50 +105,54 @@ function GroupHeaderTabs({
         to={`${baseUrl}feedback/${location.search}`}
       >
         {t('User Feedback')} <Badge text={group.userReportCount} />
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.ATTACHMENTS}
         hidden={!hasEventAttachments || !issueTypeConfig.attachments.enabled}
         disabled={disabledTabs.includes(Tab.ATTACHMENTS)}
         to={`${baseUrl}attachments/${location.search}`}
       >
         {t('Attachments')}
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.TAGS}
         disabled={disabledTabs.includes(Tab.TAGS)}
         to={`${baseUrl}tags/${location.search}`}
       >
         {t('Tags')}
-      </Item>
-      <Item key={Tab.EVENTS} disabled={disabledTabs.includes(Tab.EVENTS)} to={eventRoute}>
+      </TabList.Item>
+      <TabList.Item
+        key={Tab.EVENTS}
+        disabled={disabledTabs.includes(Tab.EVENTS)}
+        to={eventRoute}
+      >
         {t('All Events')}
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.MERGED}
         hidden={!issueTypeConfig.mergedIssues.enabled}
         disabled={disabledTabs.includes(Tab.MERGED)}
         to={`${baseUrl}merged/${location.search}`}
       >
         {t('Merged Issues')}
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.GROUPING}
         hidden={!hasGroupingTreeUI || !issueTypeConfig.grouping.enabled}
         disabled={disabledTabs.includes(Tab.GROUPING)}
         to={`${baseUrl}grouping/${location.search}`}
       >
         {t('Grouping')}
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.SIMILAR_ISSUES}
         hidden={!hasSimilarView || !issueTypeConfig.similarIssues.enabled}
         disabled={disabledTabs.includes(Tab.SIMILAR_ISSUES)}
         to={`${baseUrl}similar/${location.search}`}
       >
         {t('Similar Issues')}
-      </Item>
-      <Item
+      </TabList.Item>
+      <TabList.Item
         key={Tab.REPLAYS}
         textValue={t('Replays')}
         hidden={!hasSessionReplay || !issueTypeConfig.replays.enabled}
@@ -157,7 +161,7 @@ function GroupHeaderTabs({
         {t('Replays')}
         <ReplayCountBadge count={replaysCount} />
         <ReplaysFeatureBadge noTooltip />
-      </Item>
+      </TabList.Item>
     </StyledTabList>
   );
 }

+ 5 - 5
static/app/views/issueList/header.tsx

@@ -9,7 +9,7 @@ import GlobalEventProcessingAlert from 'sentry/components/globalEventProcessingA
 import * as Layout from 'sentry/components/layouts/thirds';
 import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionTooltip';
 import QueryCount from 'sentry/components/queryCount';
-import {Item, TabList, Tabs} from 'sentry/components/tabs';
+import {TabList, Tabs} from 'sentry/components/tabs';
 import {Tooltip} from 'sentry/components/tooltip';
 import {SLOW_TOOLTIP_DELAY} from 'sentry/constants';
 import {IconPause, IconPlay, IconStar} from 'sentry/icons';
@@ -198,7 +198,7 @@ function IssueListHeader({
                 });
 
                 return (
-                  <Item key={tabQuery} to={to} textValue={queryName}>
+                  <TabList.Item key={tabQuery} to={to} textValue={queryName}>
                     <IssueListHeaderTabContent
                       tooltipTitle={tooltipTitle}
                       tooltipHoverable={tooltipHoverable}
@@ -207,11 +207,11 @@ function IssueListHeader({
                       hasMore={queryCounts[tabQuery]?.hasMore}
                       query={tabQuery}
                     />
-                  </Item>
+                  </TabList.Item>
                 );
               }
             ),
-            <Item
+            <TabList.Item
               hidden={!savedSearchTabActive}
               key={EXTRA_TAB_KEY}
               to={{query: queryParms, pathname: location.pathname}}
@@ -222,7 +222,7 @@ function IssueListHeader({
                 count={queryCount}
                 query={query}
               />
-            </Item>,
+            </TabList.Item>,
           ]}
         </TabList>
       </StyledTabs>

+ 4 - 4
static/app/views/performance/landing/index.tsx

@@ -14,7 +14,7 @@ import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionT
 import TransactionNameSearchBar from 'sentry/components/performance/searchBar';
 import * as TeamKeyTransactionManager from 'sentry/components/performance/teamKeyTransactionsManager';
 import ProjectPageFilter from 'sentry/components/projectPageFilter';
-import {Item, TabList, TabPanels, Tabs} from 'sentry/components/tabs';
+import {TabList, TabPanels, Tabs} from 'sentry/components/tabs';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import {Organization, PageFilters, Project} from 'sentry/types';
@@ -180,7 +180,7 @@ export function PerformanceLanding(props: Props) {
 
             <TabList hideBorder>
               {LANDING_DISPLAYS.map(({label, field}) => (
-                <Item key={field}>{label}</Item>
+                <TabList.Item key={field}>{label}</TabList.Item>
               ))}
             </TabList>
           </Layout.Header>
@@ -188,7 +188,7 @@ export function PerformanceLanding(props: Props) {
           <Layout.Body data-test-id="performance-landing-body">
             <Layout.Main fullWidth>
               <TabPanels>
-                <Item key={landingDisplay.field}>
+                <TabPanels.Item key={landingDisplay.field}>
                   <MetricsCardinalityProvider
                     sendOutcomeAnalytics
                     organization={organization}
@@ -266,7 +266,7 @@ export function PerformanceLanding(props: Props) {
                       }}
                     </MetricsDataSwitcher>
                   </MetricsCardinalityProvider>
-                </Item>
+                </TabPanels.Item>
               </TabPanels>
             </Layout.Main>
           </Layout.Body>

Some files were not shown because too many files changed in this diff