feat: add smart view with custom json (#2000)

This commit is contained in:
Aman Harwara
2022-11-15 18:58:13 +05:30
committed by GitHub
parent 7732f55a28
commit 68991abba7
10 changed files with 387 additions and 10 deletions

View File

@@ -0,0 +1,35 @@
import { classNames } from '@/Utils/ConcatenateClassNames'
import { ComponentPropsWithoutRef } from 'react'
import { useTabStateContext } from './useTabState'
type Props = { id: string } & ComponentPropsWithoutRef<'button'>
const Tab = ({ id, className, children, ...props }: Props) => {
const { state } = useTabStateContext()
const { activeTab, setActiveTab } = state
const isActive = activeTab === id
return (
<button
role="tab"
id={`tab-control-${id}`}
onClick={() => {
setActiveTab(id)
}}
aria-selected={isActive}
aria-controls={`tab-panel-${id}`}
className={classNames(
'relative cursor-pointer border-0 bg-default px-3 py-2.5 text-sm focus:shadow-inner',
isActive ? 'font-medium text-info' : 'text-text',
isActive && 'after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-full after:bg-info',
className,
)}
{...props}
>
{children}
</button>
)
}
export default Tab

View File

@@ -0,0 +1,25 @@
import { ComponentPropsWithoutRef, useMemo } from 'react'
import { TabStateContext, TabState } from './useTabState'
type Props = {
state: TabState
} & ComponentPropsWithoutRef<'div'>
const TabList = ({ state, children, ...props }: Props) => {
const providerValue = useMemo(
() => ({
state,
}),
[state],
)
return (
<TabStateContext.Provider value={providerValue}>
<div role="tablist" {...props}>
{children}
</div>
</TabStateContext.Provider>
)
}
export default TabList

View File

@@ -0,0 +1,22 @@
import { ComponentPropsWithoutRef } from 'react'
import { TabState } from './useTabState'
type Props = { state: TabState; id: string } & ComponentPropsWithoutRef<'div'>
const TabPanel = ({ state, id, children, ...props }: Props) => {
const { activeTab } = state
const isActive = activeTab === id
if (!isActive) {
return null
}
return (
<div role="tabpanel" id={`tab-panel-${id}`} aria-labelledby={`tab-control-${id}`} {...props}>
{children}
</div>
)
}
export default TabPanel

View File

@@ -0,0 +1,29 @@
import Tab from './Tab'
import TabList from './TabList'
import { TabState } from './useTabState'
type Props = {
tabs: {
id: string
title: string
}[]
state: TabState
children: React.ReactNode
}
const TabsContainer = ({ tabs, state, children }: Props) => {
return (
<div className="overflow-hidden rounded-md border border-border">
<TabList state={state} className="border-b border-border">
{tabs.map(({ id, title }) => (
<Tab key={id} id={id} className="first:rounded-tl-md">
{title}
</Tab>
))}
</TabList>
{children}
</div>
)
}
export default TabsContainer

View File

@@ -0,0 +1,29 @@
import { createContext, useContext, useState } from 'react'
export const useTabState = ({ defaultTab }: { defaultTab: string }) => {
const [activeTab, setActiveTab] = useState(defaultTab)
return { activeTab, setActiveTab }
}
export type TabState = ReturnType<typeof useTabState>
type TabContextValue = {
state: TabState
}
export const TabStateContext = createContext<TabContextValue | undefined>(undefined)
export const useTabStateContext = () => {
const context = useContext(TabStateContext)
if (context === undefined) {
throw new Error('useTabStateContext must be used within a <TabList/>')
}
if (context.state === undefined) {
throw new Error('Tab state must be provided to the parent <TabList/>')
}
return context
}