Skip to content

Commit

Permalink
Switching tabs with context
Browse files Browse the repository at this point in the history
  • Loading branch information
dlnr committed Feb 8, 2024
1 parent 564aa29 commit 3a9eed2
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 127 deletions.
40 changes: 21 additions & 19 deletions packages/css/src/components/tabs/tabs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,42 +30,44 @@
}
}

.amsterdam-tabs__link {
color: var(--amsterdam-tabs-link-color);
.amsterdam-tabs__button {
background-color: var(--amsterdam-tabs-button-background-color);
border: var(--amsterdam-tabs-button-border);
color: var(--amsterdam-tabs-button-color);
cursor: pointer;
display: inline-block;
font-family: var(--amsterdam-tabs-link-font-family);
font-size: var(--amsterdam-tabs-link-spacious-font-size);
font-weight: var(--amsterdam-tabs-link-font-weight);
line-height: var(--amsterdam-tabs-link-spacious-line-height);
outline-offset: var(--amsterdam-tabs-link-outline-offset);
padding-block: var(--amsterdam-tabs-link-padding-block);
padding-inline: var(--amsterdam-tabs-link-padding-inline);
font-family: var(--amsterdam-tabs-button-font-family);
font-size: var(--amsterdam-tabs-button-spacious-font-size);
font-weight: var(--amsterdam-tabs-button-font-weight);
line-height: var(--amsterdam-tabs-button-spacious-line-height);
outline-offset: var(--amsterdam-tabs-button-outline-offset);
padding-block: var(--amsterdam-tabs-button-padding-block);
padding-inline: var(--amsterdam-tabs-button-padding-inline);
position: relative;
text-decoration: none;

&:hover:not(.amsterdam-tabs__link--selected, .amsterdam-tabs__link--disabled)::after {
&:hover:not(.amsterdam-tabs__button--selected, .amsterdam-tabs__button--disabled)::after {
background-color: currentColor;
@extend .amsterdam-tabs-underline;
}

.amsterdam-theme--compact & {
font-size: var(--amsterdam-tabs-link-compact-font-size);
line-height: var(--amsterdam-tabs-link-compact-line-height);
font-size: var(--amsterdam-tabs-button-compact-font-size);
line-height: var(--amsterdam-tabs-button-compact-line-height);
}

&:hover:not(.amsterdam-tabs__link--selected, .amsterdam-tabs__link--disabled) {
color: var(--amsterdam-tabs-link-hover-color);
&:hover:not(.amsterdam-tabs__button--selected, .amsterdam-tabs__button--disabled) {
color: var(--amsterdam-tabs-button-hover-color);
}
}

.amsterdam-tabs__link--selected {
background-color: var(--amsterdam-tabs-link-selected-background-color);
color: var(--amsterdam-tabs-link-selected-color);
.amsterdam-tabs__button--selected {
background-color: var(--amsterdam-tabs-button-selected-background-color);
color: var(--amsterdam-tabs-button-selected-color);
}

.amsterdam-tabs__link--disabled {
color: var(--amsterdam-tabs-link-disabled-color);
.amsterdam-tabs__button--disabled {
color: var(--amsterdam-tabs-button-disabled-color);

// TODO: Disabled cursor after button refactor
// cursor: var(--amsterdam-action-disabled-cursor);
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/Tabs/Tabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('Tabs', () => {
})

it('supports ForwardRef in React', () => {
const ref = createRef<HTMLElement>()
const ref = createRef<HTMLDivElement>()

const { container } = render(<Tabs ref={ref} />)

Expand Down
51 changes: 25 additions & 26 deletions packages/react/src/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,53 @@
*/

import clsx from 'clsx'
import { forwardRef, useState, useTransition } from 'react'
import { createContext, forwardRef, useState } from 'react'
import type { ForwardedRef, ForwardRefExoticComponent, HTMLAttributes, PropsWithChildren, RefAttributes } from 'react'
import { TabsLink } from './TabsLink'
import { TabsButton } from './TabsButton'
// import TabsContext from './TabsContext'
import { TabsList } from './TabsList'
import { TabsPanel } from './TabsPanel'

export type TabsProps = {} & PropsWithChildren<HTMLAttributes<HTMLDivElement>>

type TabsComponent = {
List: typeof TabsList
Link: typeof TabsLink
Button: typeof TabsButton
Panel: typeof TabsPanel
} & ForwardRefExoticComponent<TabsProps & RefAttributes<HTMLDivElement>>

type TabsIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
// eslint-disable-next-line no-unused-vars
export const TabsContext = createContext({ activeTab: 0, updateTab: (_tab: number) => {} })

export const Tabs = forwardRef(
({ children, className, ...restProps }: TabsProps, ref: ForwardedRef<HTMLDivElement>) => {
const [selectedTab, setSelectedTab] = useState<TabsIndex>(0)
const [isPending, startTransition] = useTransition()

const onTabClick = (tab: TabsIndex) => {
startTransition(() => {
setSelectedTab(tab)
})
// const [activeTab] = useState(null)
// const [isPending, startTransition] = useTransition()
const [activeTab, setActiveTab] = useState(0)
const updateTab = (tab: number) => {
setActiveTab(tab)
}

return (
<div
{...restProps}
ref={ref}
className={clsx('amsterdam-tabs', isPending && 'amsterdam-tabs--pending', className)}
>
<TabsList>
<TabsLink label="Gegevens" onClick={() => onTabClick(0)} selected={selectedTab === 0} />
<TabsLink label="Aanslagen" onClick={() => onTabClick(1)} selected={selectedTab === 1} />
<TabsLink label="Bezwaar" onClick={() => onTabClick(2)} selected={selectedTab === 2} />
<TabsContext.Provider value={{ activeTab, updateTab }}>
<div {...restProps} ref={ref} className={clsx('amsterdam-tabs', className)}>
{/* <TabsList>
<TabsButton label="Gegevens" onClick={() => onTabClick(0)} selected={activeTab === 0} />
<TabsButton label="Aanslagen" onClick={() => onTabClick(1)} selected={activeTab === 1} />
<TabsButton label="Bezwaar" onClick={() => onTabClick(2)} selected={activeTab === 2} />
</TabsList>
{selectedTab === 0 && <TabsPanel>Gegevens</TabsPanel>}
{selectedTab === 1 && <TabsPanel>Aanslagen</TabsPanel>}
{selectedTab === 2 && <TabsPanel>Bezwaar</TabsPanel>}
{children}
</div>
{activeTab === 0 && <TabsPanel>Gegevens</TabsPanel>}
{activeTab === 1 && <TabsPanel>Aanslagen</TabsPanel>}
{activeTab === 2 && <TabsPanel>Bezwaar</TabsPanel>} */}

{children}
</div>
</TabsContext.Provider>
)
},
) as TabsComponent

Tabs.List = TabsList
Tabs.Link = TabsLink
Tabs.Button = TabsButton
Tabs.Panel = TabsPanel
Tabs.displayName = 'Tabs'
44 changes: 44 additions & 0 deletions packages/react/src/Tabs/TabsButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2023 Gemeente Amsterdam
*/

import clsx from 'clsx'
import { forwardRef, startTransition, useContext } from 'react'
import type { ButtonHTMLAttributes, ForwardedRef, PropsWithChildren } from 'react'
import { TabsContext } from './Tabs'
// import TabsContext from './TabsContext'

export type TabsButtonProps = {
label: string
tab: number
isDisabled?: boolean
} & PropsWithChildren<ButtonHTMLAttributes<HTMLButtonElement>>

export const TabsButton = forwardRef(
({ label, tab = 0, className, isDisabled, ...restProps }: TabsButtonProps, ref: ForwardedRef<HTMLButtonElement>) => {
const { activeTab, updateTab } = useContext(TabsContext)

return (
<button
{...restProps}
ref={ref}
onClick={() => {
startTransition(() => {
updateTab(tab)
})
}}
className={clsx(
'amsterdam-tabs__button',
activeTab === tab && 'amsterdam-tabs__button--selected',
isDisabled && 'amsterdam-tabs__button--disabled',
className,
)}
>
{label}
</button>
)
},
)

TabsButton.displayName = 'Tabs.Button'
13 changes: 13 additions & 0 deletions packages/react/src/Tabs/TabsContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createContext } from 'react'

export type TabsContextValue = {
activeTab: number
}

const defaultValues: TabsContextValue = {
activeTab: 0,
}

const TabsContext = createContext(defaultValues)

export default TabsContext
35 changes: 0 additions & 35 deletions packages/react/src/Tabs/TabsLink.tsx

This file was deleted.

25 changes: 18 additions & 7 deletions packages/react/src/Tabs/TabsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,28 @@
*/

import clsx from 'clsx'
import { forwardRef } from 'react'
import { forwardRef, useContext } from 'react'
import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react'
import { TabsContext } from './Tabs'

export type TabsPanelProps = {} & PropsWithChildren<HTMLAttributes<HTMLDivElement>>
export type TabsPanelProps = {
tab: number
} & PropsWithChildren<HTMLAttributes<HTMLDivElement>>

export const TabsPanel = forwardRef(
({ children, className, ...restProps }: TabsPanelProps, ref: ForwardedRef<HTMLDivElement>) => (
<div {...restProps} ref={ref} className={clsx('amsterdam-tabs__panel', className)}>
{children}
</div>
),
({ tab, children, className, ...restProps }: TabsPanelProps, ref: ForwardedRef<HTMLDivElement>) => {
const { activeTab } = useContext(TabsContext)

if (tab !== activeTab) {
return null
}

return (
<div {...restProps} ref={ref} className={clsx('amsterdam-tabs__panel', className)}>
{children}
</div>
)
},
)

TabsPanel.displayName = 'Tabs.Panel'
4 changes: 3 additions & 1 deletion proprietary/tokens/src/components/amsterdam/tabs.tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"list": {
"border-color": { "value": "{amsterdam.color.primary-blue}" }
},
"link": {
"button": {
"background-color": { "value": "transparent" },
"border": { "value": "none" },
"color": { "value": "{amsterdam.link-appearance.color}" },
"font-family": { "value": "{amsterdam.typography.font-family}" },
"font-weight": { "value": "{amsterdam.typography.font-weight.normal}" },
Expand Down
Loading

0 comments on commit 3a9eed2

Please sign in to comment.