From 989f094e76510e9ff6f4f8d675a9dd6f768099da Mon Sep 17 00:00:00 2001 From: Osama Abdul Latif <62595605+OsamaAbdellateef@users.noreply.github.com> Date: Wed, 16 Aug 2023 08:17:06 +0300 Subject: [PATCH] [DST-111]: enhance styling tabs (#3250) * enhance tabs * Test styles added via theme * moving classNames to tab panel * Add styles via theme * Fixing tests * Remove styling via `className` over components * Add changes * Fixing tests * Create itchy-spies-greet.md --------- Co-authored-by: Sebastian Sebald --- .changeset/itchy-spies-greet.md | 8 +++ packages/components/src/Tabs/Context.ts | 7 ++- packages/components/src/Tabs/TabPanel.tsx | 9 ++- packages/components/src/Tabs/Tabs.test.tsx | 56 +++++++++++++------ packages/components/src/Tabs/Tabs.tsx | 27 +++++---- .../src/Tabs/__snapshots__/Tabs.test.tsx.snap | 3 + packages/system/src/types/theme.ts | 5 +- .../theme-b2b/src/components/Tabs.styles.ts | 2 + .../theme-core/src/components/Tabs.styles.ts | 2 + 9 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 .changeset/itchy-spies-greet.md create mode 100644 packages/components/src/Tabs/__snapshots__/Tabs.test.tsx.snap diff --git a/.changeset/itchy-spies-greet.md b/.changeset/itchy-spies-greet.md new file mode 100644 index 0000000000..7680bcc052 --- /dev/null +++ b/.changeset/itchy-spies-greet.md @@ -0,0 +1,8 @@ +--- +"@marigold/components": minor +"@marigold/system": minor +"@marigold/theme-b2b": minor +"@marigold/theme-core": minor +--- + +[DST-111]: enhance styling tabs diff --git a/packages/components/src/Tabs/Context.ts b/packages/components/src/Tabs/Context.ts index edf9deed5c..c70e6635e9 100644 --- a/packages/components/src/Tabs/Context.ts +++ b/packages/components/src/Tabs/Context.ts @@ -1,6 +1,11 @@ import { createContext, useContext } from 'react'; export const TabContext = createContext<{ - classNames: { tabs: string; tab: string }; + classNames: { + container: string; + tabs: string; + tab: string; + tabpanel: string; + }; }>({} as any); export const useTabContext = () => useContext(TabContext); diff --git a/packages/components/src/Tabs/TabPanel.tsx b/packages/components/src/Tabs/TabPanel.tsx index 12cd0de1ae..5cfb591d70 100644 --- a/packages/components/src/Tabs/TabPanel.tsx +++ b/packages/components/src/Tabs/TabPanel.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { useRef } from 'react'; import { AriaTabPanelProps, useTabPanel } from '@react-aria/tabs'; import { TabListState } from '@react-stately/tabs'; +import { useTabContext } from './Context'; +import { cn } from '@marigold/system'; export interface TabPanelProps extends AriaTabPanelProps { state: TabListState; @@ -10,9 +12,12 @@ export interface TabPanelProps extends AriaTabPanelProps { export const TabPanel = ({ state, ...props }: TabPanelProps) => { const ref = useRef(null); const { tabPanelProps } = useTabPanel(props, state, ref); + const selectedItemProps = state.selectedItem?.props; + const { classNames } = useTabContext(); + return ( -
- {state.selectedItem?.props.children} +
+ {selectedItemProps?.children}
); }; diff --git a/packages/components/src/Tabs/Tabs.test.tsx b/packages/components/src/Tabs/Tabs.test.tsx index 06caf95c93..7c23703c46 100644 --- a/packages/components/src/Tabs/Tabs.test.tsx +++ b/packages/components/src/Tabs/Tabs.test.tsx @@ -8,13 +8,12 @@ const theme: Theme = { name: 'tabs test', components: { Tabs: { + container: cva('flex'), + tabpanel: cva('border-3 border-solid border-red-400'), tabs: cva('mb-[10px]'), tab: cva( [ - 'min-h-[40px]', - 'data-[hover]:text-tabs-tab-text data-[hover]:border-b-tabs-tab-hover data-[hover]:border-b-8 data-[hover]:border-solid', - ' disabled:text-tabs-tab-disabled', - ' selected:border-b-primary-600 selected:border-b-8 selected:border-solid ', + 'selected:border-red-500 selected:border-b-8 selected:border-solid ', ], { variants: { @@ -62,7 +61,7 @@ test('Supporting default size', () => { ); expect(screen.getByText('tab').className).toMatchInlineSnapshot( - `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed min-h-[40px] data-[hover]:text-tabs-tab-text data-[hover]:border-b-tabs-tab-hover data-[hover]:border-b-8 data-[hover]:border-solid disabled:text-tabs-tab-disabled selected:border-b-primary-600 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` + `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed selected:border-red-500 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` ); }); @@ -97,9 +96,28 @@ test('set defaultValue via props in tabs', () => { expect(screen.getByText('tab-2 content')).toBeVisible(); }); -test('cursor indicates interactivity', () => { +test('open tabpanel when its tab controller is clicked', () => { render( - + + + tab-1 content + + + tab-2 content + + + ); + const tab = screen.getByText('tab2'); + fireEvent.click(tab); + expect(tab.className).toMatchInlineSnapshot( + `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed selected:border-red-500 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` + ); + expect(screen.getByText('tab-2 content')).toBeVisible(); +}); + +test('allows styling "focus" state via theme', () => { + render( + tab-1 content @@ -110,28 +128,30 @@ test('cursor indicates interactivity', () => { ); const tabs = screen.getAllByRole('tab'); expect(tabs[0].className).toMatchInlineSnapshot( - `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed min-h-[40px] data-[hover]:text-tabs-tab-text data-[hover]:border-b-tabs-tab-hover data-[hover]:border-b-8 data-[hover]:border-solid disabled:text-tabs-tab-disabled selected:border-b-primary-600 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` + `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed selected:border-red-500 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` ); expect(tabs[1].className).toMatchInlineSnapshot( - `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed min-h-[40px] data-[hover]:text-tabs-tab-text data-[hover]:border-b-tabs-tab-hover data-[hover]:border-b-8 data-[hover]:border-solid disabled:text-tabs-tab-disabled selected:border-b-primary-600 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` + `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed selected:border-red-500 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` ); }); -test('open tabpanel when its tab controller is clicked', () => { +test('allow styling TabPanel & container via theme', () => { render( - - + + tab-1 content - + tab-2 content ); - const tab = screen.getByText('tab2'); - fireEvent.click(tab); - expect(tab.className).toMatchInlineSnapshot( - `"flex cursor-pointer justify-center aria-disabled:cursor-not-allowed min-h-[40px] data-[hover]:text-tabs-tab-text data-[hover]:border-b-tabs-tab-hover data-[hover]:border-b-8 data-[hover]:border-solid disabled:text-tabs-tab-disabled selected:border-b-primary-600 selected:border-b-8 selected:border-solid px-2 pb-2 text-lg"` + const tabPanel = screen.getByText('tab-1 content'); + const container = screen.getByLabelText('tabs container'); + + expect(container.className).toMatchSnapshot('flex gap-2'); + + expect(tabPanel.className).toMatchInlineSnapshot( + `"border-3 border-solid border-red-400"` ); - expect(screen.getByText('tab-2 content')).toBeVisible(); }); diff --git a/packages/components/src/Tabs/Tabs.tsx b/packages/components/src/Tabs/Tabs.tsx index a4f3c3e0ae..8c147f7a62 100644 --- a/packages/components/src/Tabs/Tabs.tsx +++ b/packages/components/src/Tabs/Tabs.tsx @@ -12,6 +12,8 @@ import { TabContext } from './Context'; import { Tab } from './Tab'; import { TabPanel } from './TabPanel'; +//props +// ---------------------- interface TabsProps extends Omit, 'orientation' | 'isDisabled'>, GapSpaceProp { @@ -19,6 +21,9 @@ interface TabsProps disabled?: boolean; variant?: string; } + +// component +// ---------------------- export const Tabs = ({ space = 2, size = 'medium', @@ -40,19 +45,21 @@ export const Tabs = ({ size, variant, }); - return ( -
- {[...state.collection].map(item => { - return ; - })} + {/* tabs container */} +
+
+ {[...state.collection].map(item => { + return ; + })} +
+
- ); }; diff --git a/packages/components/src/Tabs/__snapshots__/Tabs.test.tsx.snap b/packages/components/src/Tabs/__snapshots__/Tabs.test.tsx.snap new file mode 100644 index 0000000000..0b93110236 --- /dev/null +++ b/packages/components/src/Tabs/__snapshots__/Tabs.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`allow styling TabPanel & container via theme: flex gap-2 1`] = `"flex gap-2 mb-[10px]"`; diff --git a/packages/system/src/types/theme.ts b/packages/system/src/types/theme.ts index 5c4a85a1d0..aa0ef28b75 100644 --- a/packages/system/src/types/theme.ts +++ b/packages/system/src/types/theme.ts @@ -109,7 +109,10 @@ export type Theme = { 'container' | 'arrow', ComponentStyleFunction >; - Tabs?: Record<'tabs' | 'tab', ComponentStyleFunction>; + Tabs?: Record< + 'tabs' | 'container' | 'tabpanel' | 'tab', + ComponentStyleFunction + >; Underlay?: ComponentStyleFunction; Calendar?: Record< 'calendar' | 'calendarCell' | 'calendarControllers', diff --git a/themes/theme-b2b/src/components/Tabs.styles.ts b/themes/theme-b2b/src/components/Tabs.styles.ts index cba495cd9e..6dff76816d 100644 --- a/themes/theme-b2b/src/components/Tabs.styles.ts +++ b/themes/theme-b2b/src/components/Tabs.styles.ts @@ -1,7 +1,9 @@ import { ThemeComponent, cva } from '@marigold/system'; export const Tabs: ThemeComponent<'Tabs'> = { + container: cva(''), tabs: cva('mb-[10px]'), + tabpanel: cva(''), tab: cva( [ 'min-h-[40px]', diff --git a/themes/theme-core/src/components/Tabs.styles.ts b/themes/theme-core/src/components/Tabs.styles.ts index 59e86960cf..ae31e7b834 100644 --- a/themes/theme-core/src/components/Tabs.styles.ts +++ b/themes/theme-core/src/components/Tabs.styles.ts @@ -1,6 +1,8 @@ import { ThemeComponent, cva } from '@marigold/system'; export const Tabs: ThemeComponent<'Tabs'> = { + container: cva(''), + tabpanel: cva(''), tabs: cva('mb-[10px]'), tab: cva( [