From 6fb7b7160ca0249ed8f74ea02f1da713d92661c3 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Fri, 6 Jun 2025 18:17:35 +0000 Subject: [PATCH 1/3] Migrate TabNav to use CSS modules --- packages/react/src/TabNav/TabNav.module.css | 39 ++++++++ packages/react/src/TabNav/TabNav.tsx | 89 ++++++------------- .../src/TabNav/__tests__/TabNav.test.tsx | 5 +- 3 files changed, 69 insertions(+), 64 deletions(-) create mode 100644 packages/react/src/TabNav/TabNav.module.css diff --git a/packages/react/src/TabNav/TabNav.module.css b/packages/react/src/TabNav/TabNav.module.css new file mode 100644 index 00000000000..19cfd862e4e --- /dev/null +++ b/packages/react/src/TabNav/TabNav.module.css @@ -0,0 +1,39 @@ +.TabNavTabList { + display: flex; + /* stylelint-disable-next-line primer/spacing */ + margin-bottom: -1px; + overflow: auto; +} + +.TabNavNav { + margin-top: 0; + border-bottom: var(--borderWidth-thin) solid var(--borderColor-default); +} + +.TabNavLink { + padding: var(--base-size-8) var(--base-size-12); + font-size: var(--text-body-size-medium); + /* stylelint-disable-next-line primer/typography */ + line-height: 20px; + color: var(--fgColor-default); + text-decoration: none; + background-color: transparent; + border: var(--borderWidth-thin) solid transparent; + border-bottom: 0; + + &:hover, + &:focus { + color: var(--fgColor-default); + text-decoration: none; + + @mixin focusOutline -6px; + } + + &.Selected { + color: var(--fgColor-default); + background-color: var(--bgColor-default); + border-color: var(--borderColor-default); + border-top-left-radius: var(--borderRadius-medium); + border-top-right-radius: var(--borderRadius-medium); + } +} diff --git a/packages/react/src/TabNav/TabNav.tsx b/packages/react/src/TabNav/TabNav.tsx index b634e89c264..4131fba98a7 100644 --- a/packages/react/src/TabNav/TabNav.tsx +++ b/packages/react/src/TabNav/TabNav.tsx @@ -1,37 +1,17 @@ -import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' import {clsx} from 'clsx' import type {To} from 'history' import React, {useRef, useState} from 'react' -import styled from 'styled-components' -import {get} from '../constants' import {FocusKeys, useFocusZone} from '../hooks/useFocusZone' import type {SxProp} from '../sx' -import sx from '../sx' import type {ComponentProps} from '../utils/types' -import getGlobalFocusStyles from '../internal/utils/getGlobalFocusStyles' -const ITEM_CLASS = 'TabNav-item' -const SELECTED_CLASS = 'selected' - -const TabNavBase = styled.div` - ${sx} -` - -const TabNavTabList = styled.div` - display: flex; - margin-bottom: -1px; - overflow: auto; -` - -const TabNavNav = styled.nav` - margin-top: 0; - border-bottom: 1px solid ${get('colors.border.default')}; -` +import styles from './TabNav.module.css' +import {BoxWithFallback} from '../internal/components/BoxWithFallback' /** * @deprecated */ -export type TabNavProps = ComponentProps +export type TabNavProps = ComponentProps /** * @deprecated @@ -73,11 +53,13 @@ function TabNav({children, 'aria-label': ariaLabel, ...rest}: TabNavProps) { ) return ( - }> - - {children} - - + }> + + ) } @@ -88,44 +70,29 @@ export type TabNavLinkProps = React.DetailedHTMLProps(props => ({ - className: clsx(ITEM_CLASS, props.selected && SELECTED_CLASS, props.className), - role: 'tab', - 'aria-selected': !!props.selected, - tabIndex: -1, -}))` - padding: 8px 12px; - font-size: ${get('fontSizes.1')}; - line-height: 20px; - color: ${get('colors.fg.default')}; - text-decoration: none; - background-color: transparent; - border: 1px solid transparent; - border-bottom: 0; - - ${getGlobalFocusStyles('-6px')}; - - &:hover, - &:focus { - color: ${get('colors.fg.default')}; - text-decoration: none; - } - - &.selected { - color: ${get('colors.fg.default')}; - border-color: ${get('colors.border.default')}; - border-top-right-radius: ${get('radii.2')}; - border-top-left-radius: ${get('radii.2')}; - background-color: ${get('colors.canvas.default')}; - } - - ${sx}; -` as PolymorphicForwardRefComponent<'a', TabNavLinkProps> +const TabNavLink = React.forwardRef(function TabNavLink( + {selected, className, as = 'a', ...rest}: TabNavLinkProps, + ref, +) { + return ( + + ) +}) TabNavLink.displayName = 'TabNav.Link' diff --git a/packages/react/src/TabNav/__tests__/TabNav.test.tsx b/packages/react/src/TabNav/__tests__/TabNav.test.tsx index 77ede90915f..ec1fcbbc524 100644 --- a/packages/react/src/TabNav/__tests__/TabNav.test.tsx +++ b/packages/react/src/TabNav/__tests__/TabNav.test.tsx @@ -3,11 +3,10 @@ import TabNav from '..' import {render, screen} from '@testing-library/react' import userEvent from '@testing-library/user-event' import {Button} from '../../Button' -import Box from '../../Box' describe('TabNav', () => { const tabNavMarkup = ( - +
First @@ -21,7 +20,7 @@ describe('TabNav', () => { - +
) describe('TabNav.Link', () => { From 26ae72b543045eb91028f9a788d612282bb6125b Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Fri, 6 Jun 2025 11:18:48 -0700 Subject: [PATCH 2/3] Create thin-bears-change.md --- .changeset/thin-bears-change.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/thin-bears-change.md diff --git a/.changeset/thin-bears-change.md b/.changeset/thin-bears-change.md new file mode 100644 index 00000000000..717cbc087d5 --- /dev/null +++ b/.changeset/thin-bears-change.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +Migrate the TabNav component to use CSS modules From 25e3be489380ea02c9ba2c0055e122629a8a37c6 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Fri, 6 Jun 2025 18:24:10 +0000 Subject: [PATCH 3/3] Removing outdated type check --- .../react/src/TabNav/__tests__/TabNav.types.test.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/react/src/TabNav/__tests__/TabNav.types.test.tsx b/packages/react/src/TabNav/__tests__/TabNav.types.test.tsx index d5484ca97d9..b6ed4b42365 100644 --- a/packages/react/src/TabNav/__tests__/TabNav.types.test.tsx +++ b/packages/react/src/TabNav/__tests__/TabNav.types.test.tsx @@ -10,17 +10,6 @@ export function shouldAcceptCallWithNoProps() { ) } -export function shouldNotAcceptSystemProps() { - return ( - <> - {/* @ts-expect-error system props should not be accepted */} - - {/* @ts-expect-error system props should not be accepted */} - - - ) -} - export function shouldAcceptButtonAsProps() { return }