From 2ca2011a8d3f955d84d9401cf305e9f4494032c8 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Tue, 6 Feb 2024 15:02:46 +0800 Subject: [PATCH 01/11] feat: Added VerticalTab [WIP] --- .../PasswordInput/PasswordInput.scss | 7 +- lib/components/VerticalTab/VerticalTab.scss | 42 +++++++++++ lib/components/VerticalTab/VerticalTab.tsx | 20 +++++ .../VerticalTab/VerticalTabItems.tsx | 31 ++++++++ lib/components/VerticalTab/index.ts | 2 + src/main.tsx | 73 +++++++++++++------ 6 files changed, 151 insertions(+), 24 deletions(-) create mode 100644 lib/components/VerticalTab/VerticalTab.scss create mode 100644 lib/components/VerticalTab/VerticalTab.tsx create mode 100644 lib/components/VerticalTab/VerticalTabItems.tsx create mode 100644 lib/components/VerticalTab/index.ts diff --git a/lib/components/PasswordInput/PasswordInput.scss b/lib/components/PasswordInput/PasswordInput.scss index 1238d002..9a965252 100644 --- a/lib/components/PasswordInput/PasswordInput.scss +++ b/lib/components/PasswordInput/PasswordInput.scss @@ -19,6 +19,11 @@ $ERROR: #ec3f3f; display: flex; align-items: center; justify-content: center; - width: 100%; + width: 16px; + height: 16px; + & > *{ + width: 100%; + height: 100%; + } } } diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss new file mode 100644 index 00000000..9950825d --- /dev/null +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -0,0 +1,42 @@ +.vertical-tab__wrapper { + background: #F2F3F4; + padding: 8px; + display: flex; + flex-direction: column; + justify-content: center; + border-radius: 8px; +} + +.vertical-tab { + &__item { + display: flex; + padding: 10px 16px; + align-items: center; + cursor: pointer; + border-radius: 4px; + box-sizing: content-box; + + &:hover{ + background-color: #e6e9e9; + } + + &--active { + background-color: #fff; + border-left: 4px solid #ff444f; + + &:hover{ + background-color: #fff; + } + } + } + + &__icon { + width: 16px; + height: 16px; + margin-right: 16px; + } + + &__label { + flex:1; + } +} \ No newline at end of file diff --git a/lib/components/VerticalTab/VerticalTab.tsx b/lib/components/VerticalTab/VerticalTab.tsx new file mode 100644 index 00000000..5a8cc772 --- /dev/null +++ b/lib/components/VerticalTab/VerticalTab.tsx @@ -0,0 +1,20 @@ +// Code: +import React from 'react'; +import clsx from 'clsx'; +import './VerticalTab.scss'; + +type VerticalTabProps = { + className?: string; + style?: React.CSSProperties; +} + +export const VerticalTab = ({ + className, + children +}: React.PropsWithChildren) => { + return ( +
+ {children} +
+ ); +} \ No newline at end of file diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx new file mode 100644 index 00000000..59b1d2fb --- /dev/null +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -0,0 +1,31 @@ +import { Text } from '../Text'; +import clsx from 'clsx'; + +type VerticalTabItemsProps = { + activeTab?: string; + onclick?: (index: number) => void; + className?: string; + iconClassName?: string; + labelClassName?: string; + items: { + icon: React.ReactNode; + title: string; + }[]; + +} +export const VerticalTabItems = ({ items, className, iconClassName, labelClassName, activeTab }: VerticalTabItemsProps) => { + return items.map((item) => ( +
+ {item?.icon} + {item?.title} +
+ ) + ); +} \ No newline at end of file diff --git a/lib/components/VerticalTab/index.ts b/lib/components/VerticalTab/index.ts new file mode 100644 index 00000000..37fa7427 --- /dev/null +++ b/lib/components/VerticalTab/index.ts @@ -0,0 +1,2 @@ +export {VerticalTab} from './VerticalTab' +export {VerticalTabItems} from './VerticalTabItems' \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 6661c4e6..21ea6698 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,31 +1,58 @@ import React from 'react' import ReactDOM from 'react-dom/client' -import { Loader } from '../dist/components/Loader'; -import { Button } from '../dist/components/Button'; -import { Text } from '../dist/components/Text'; -import { Tab, Tabs } from '../dist/components/Tabs'; -import {Dropdown} from '../dist/components/Dropdown'; +import {VerticalTab,VerticalTabItems} from '../dist/components/VerticalTab' + import './style.scss' -ReactDOM.createRoot(document.getElementById('root')!).render( - - <> - console.log(value)} - name='test name' - /> - +const Icon = + + + + + + + + +; +const items = [ + { + title: 'Item 1', + icon: Icon, + subItems: [ + { + title: 'Sub Item 1', + icon: Icon, + component:
Sub Item 1
+ }, + { + title: 'Sub Item 2', + icon: Icon, + }, + { + title: 'Sub Item 3', + icon: Icon, + } + ], + component:
Item 1
+ }, + { + title: 'Item 2', + icon: Icon, + }, + { + title: 'Item 3', + icon: Icon, + } +] + +ReactDOM.createRoot(document.getElementById('root')!).render( + +
+ + + +
, ) From f01dabf469e5264ff93ab5ca465fd5486c813b56 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 7 Feb 2024 10:30:54 +0800 Subject: [PATCH 02/11] chore: adding collapsible vertical tab [WIP] --- lib/components/VerticalTab/VerticalTab.scss | 51 ++++++++++++- .../VerticalTab/VerticalTabItems.tsx | 76 +++++++++++++++---- 2 files changed, 109 insertions(+), 18 deletions(-) diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index 9950825d..e098d2f2 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -1,12 +1,23 @@ .vertical-tab__wrapper { - background: #F2F3F4; + // background: #F2F3F4; padding: 8px; display: flex; flex-direction: column; justify-content: center; border-radius: 8px; } - +.shayan { + display: flex; +} +.vertical-tab__pane { + flex: 2; +} +.vertical-tab__item-container{ + background: #f2f3f4; + flex: 1; + border-radius: 4px; + padding: 8px; +} .vertical-tab { &__item { display: flex; @@ -14,7 +25,6 @@ align-items: center; cursor: pointer; border-radius: 4px; - box-sizing: content-box; &:hover{ background-color: #e6e9e9; @@ -23,7 +33,42 @@ &--active { background-color: #fff; border-left: 4px solid #ff444f; + padding-left: 12px; + + &:hover{ + background-color: #fff; + } + } + } + + &__icon { + width: 16px; + height: 16px; + margin-right: 16px; + } + &__label { + flex:1; + } +} + +.collapsible-vertical-tab { + &__item { + display: flex; + padding: 10px 16px; + align-items: center; + cursor: pointer; + border-radius: 4px; + + &:hover{ + background-color: #e6e9e9; + } + + &--open { + background-color: #fff; + border-left: 4px solid #ff444f; + padding-left: 12px; + font-weight: bold; &:hover{ background-color: #fff; } diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index 59b1d2fb..ae7b9895 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -1,31 +1,77 @@ +import React, { useState } from 'react'; import { Text } from '../Text'; import clsx from 'clsx'; type VerticalTabItemsProps = { - activeTab?: string; - onclick?: (index: number) => void; + activeTab: string; + onSelectItem?: (index: number) => void; className?: string; iconClassName?: string; labelClassName?: string; items: { icon: React.ReactNode; title: string; + component: React.ReactNode; + subItems?: { + icon: React.ReactNode; + title: string; + component: React.ReactNode; + }[]; }[]; } -export const VerticalTabItems = ({ items, className, iconClassName, labelClassName, activeTab }: VerticalTabItemsProps) => { - return items.map((item) => ( -
- {item?.icon} - {item?.title} + +const ArrowDownIcon = () => + +; +export const VerticalTabItems = ({ items, className, iconClassName, labelClassName, activeTab, onSelectItem }: VerticalTabItemsProps) => { + const [selectedTab, setSelectedTab] = useState(activeTab); + + const onSelectItemHandler = (index: number) => { + setSelectedTab(items[index]?.title); + onSelectItem?.(index); + } + return ( +
+
+ {items.map((item, index) => { + if (!item?.subItems) { + return ( +
onSelectItemHandler(index)} + > + {item?.icon} + {item?.title} +
+ ) + } else { + return ( +
subItem?.title === selectedTab), + }, className) + } + onClick={() => onSelectItemHandler(index)} + > + {item?.icon} + {item?.title} + +
+ ) + } + })} +
+
+ {items.find((item) => item?.title === selectedTab)?.component} +
- ) ); } \ No newline at end of file From d2c37c360e0d0b02d2616e1fd655bcd78a8d75e8 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 7 Feb 2024 13:19:55 +0800 Subject: [PATCH 03/11] chore: adding onClick logic for nested items [WIP] --- lib/components/VerticalTab/VerticalTab.scss | 2 +- .../VerticalTab/VerticalTabItems.tsx | 82 ++++++++++++++----- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index e098d2f2..e65f85a2 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -53,7 +53,7 @@ } .collapsible-vertical-tab { - &__item { + &__header { display: flex; padding: 10px 16px; align-items: center; diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index ae7b9895..dff883c5 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -1,19 +1,18 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Text } from '../Text'; import clsx from 'clsx'; type VerticalTabItemsProps = { activeTab: string; - onSelectItem?: (index: number) => void; + onSelectItem?: (title: string) => void; className?: string; iconClassName?: string; labelClassName?: string; items: { icon: React.ReactNode; title: string; - component: React.ReactNode; + component?: React.ReactNode; subItems?: { - icon: React.ReactNode; title: string; component: React.ReactNode; }[]; @@ -27,14 +26,37 @@ const ArrowDownIcon = () => { const [selectedTab, setSelectedTab] = useState(activeTab); - const onSelectItemHandler = (index: number) => { - setSelectedTab(items[index]?.title); - onSelectItem?.(index); + const findActiveTab = (title: string) => { + let clicked_item = undefined; + for (const item of items) { + if (item?.subItems) { + clicked_item = item?.subItems.find((subItem) => subItem?.title === title); + }else{ + if (item?.title === title) { + return item?.title; + } + } + } + + return clicked_item?.title; + } + + const onSelectItemHandler = (title: string) => { + console.log("item clicked", title) + setSelectedTab(() => findActiveTab(title) ?? activeTab); + onSelectItem?.(title); } + + useEffect(() => { + if (activeTab) { + setSelectedTab(activeTab); + } + }, [activeTab]); + return (
- {items.map((item, index) => { + {items.map((item) => { if (!item?.subItems) { return (
onSelectItemHandler(index)} + onClick={() => onSelectItemHandler(item?.title)} > {item?.icon} {item?.title} @@ -54,23 +76,43 @@ export const VerticalTabItems = ({ items, className, iconClassName, labelClassNa return (
subItem?.title === selectedTab), - }, className) - } - onClick={() => onSelectItemHandler(index)} - > - {item?.icon} - {item?.title} - + className={clsx(`collapsible-vertical-tab`)}> +
subItem?.title === selectedTab), + }, className)}> + {item?.icon} + {item?.title} + +
+
+ {item?.subItems.map((subItem) => { + return ( +
onSelectItemHandler(subItem?.title)} + > + {subItem?.title} +
+ ) + })} +
) } })}
- {items.find((item) => item?.title === selectedTab)?.component} + {items.find((item) => { + if (item?.subItems) { + return item?.subItems.find((subItem) => subItem?.title === selectedTab) + } + return item?.title === selectedTab + })?.component}
); From ed778b2d28b2becae4e371da32b44f3bfe5d867e Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 7 Feb 2024 15:08:24 +0800 Subject: [PATCH 04/11] chore: added onClick logic --- lib/components/VerticalTab/VerticalTab.scss | 8 +------ .../VerticalTab/VerticalTabItems.tsx | 24 ++++++++----------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index e65f85a2..06ab025c 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -64,14 +64,8 @@ background-color: #e6e9e9; } - &--open { - background-color: #fff; - border-left: 4px solid #ff444f; - padding-left: 12px; + &--open > :nth-child(2) { font-weight: bold; - &:hover{ - background-color: #fff; - } } } diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index dff883c5..562a240e 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -27,23 +27,24 @@ export const VerticalTabItems = ({ items, className, iconClassName, labelClassNa const [selectedTab, setSelectedTab] = useState(activeTab); const findActiveTab = (title: string) => { - let clicked_item = undefined; for (const item of items) { if (item?.subItems) { - clicked_item = item?.subItems.find((subItem) => subItem?.title === title); - }else{ + const foundItem = item?.subItems.find((subItem) => subItem?.title === title); + if (foundItem) { + return foundItem; + } + } else { if (item?.title === title) { - return item?.title; + return item; } } } - - return clicked_item?.title; } const onSelectItemHandler = (title: string) => { - console.log("item clicked", title) - setSelectedTab(() => findActiveTab(title) ?? activeTab); + const new_active_tab = findActiveTab(title)?.title; + // console.log('new_active_tab:', new_active_tab); + setSelectedTab(() => new_active_tab ?? activeTab); onSelectItem?.(title); } @@ -107,12 +108,7 @@ export const VerticalTabItems = ({ items, className, iconClassName, labelClassNa })}
- {items.find((item) => { - if (item?.subItems) { - return item?.subItems.find((subItem) => subItem?.title === selectedTab) - } - return item?.title === selectedTab - })?.component} + {findActiveTab(selectedTab)?.component}
); From bba460ab4e98927568f2ff3d93fb05a01cf6707a Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 7 Feb 2024 18:30:25 +0800 Subject: [PATCH 05/11] chore: cleanedup the code --- .../CollapsibleVerticalTabItem.tsx | 60 +++++++++++++ lib/components/VerticalTab/VerticalTab.scss | 8 +- lib/components/VerticalTab/VerticalTab.tsx | 8 +- .../VerticalTab/VerticalTabItem.tsx | 39 +++++++++ .../VerticalTab/VerticalTabItems.tsx | 85 ++++++------------- 5 files changed, 132 insertions(+), 68 deletions(-) create mode 100644 lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx create mode 100644 lib/components/VerticalTab/VerticalTabItem.tsx diff --git a/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx b/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx new file mode 100644 index 00000000..ad9cfde5 --- /dev/null +++ b/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx @@ -0,0 +1,60 @@ + +import React, { useState } from 'react'; +import { Text } from '../Text'; +import clsx from 'clsx'; +import { VerticalTabItem, TabItem } from './VerticalTabItem'; + +type CollapsibleVerticalTabItemProps = { + item: TabItem; + onSelectItemHandler: (title: string) => void; + selectedTab: string; + className?: string; + iconClassName?: string; + labelClassName?: string; +} + + +const ArrowIcon = ({ is_open }: { is_open: boolean }) => + +; + +export const CollapsibleVerticalTabItem = ({ + item, + onSelectItemHandler, + selectedTab, + className, + iconClassName, + labelClassName +}: CollapsibleVerticalTabItemProps) => { + const [open, setOpen] = useState(false); + + const onClickHandler = () => { + const shouldCollapse = !item?.subItems?.find((subItem) => subItem?.title === selectedTab); + if (shouldCollapse) + setOpen(!open); + } + return ( +
+
subItem?.title === selectedTab), + }, className)} + onClick={() => onClickHandler()} + > + {item?.icon} + {item?.title} + +
+ {open &&
+ {item?.subItems?.map((subItem) => { + return ( + onSelectItemHandler(subItem?.title)} /> + ) + })} +
} +
+ ) +} diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index 06ab025c..a9274827 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -60,10 +60,6 @@ cursor: pointer; border-radius: 4px; - &:hover{ - background-color: #e6e9e9; - } - &--open > :nth-child(2) { font-weight: bold; } @@ -78,4 +74,8 @@ &__label { flex:1; } +} + +.vertical-tab__arrow--open{ + transform: rotate(180deg); } \ No newline at end of file diff --git a/lib/components/VerticalTab/VerticalTab.tsx b/lib/components/VerticalTab/VerticalTab.tsx index 5a8cc772..88e99203 100644 --- a/lib/components/VerticalTab/VerticalTab.tsx +++ b/lib/components/VerticalTab/VerticalTab.tsx @@ -1,5 +1,5 @@ // Code: -import React from 'react'; +import React, { memo } from 'react'; import clsx from 'clsx'; import './VerticalTab.scss'; @@ -8,7 +8,7 @@ type VerticalTabProps = { style?: React.CSSProperties; } -export const VerticalTab = ({ +export const VerticalTab = memo(({ className, children }: React.PropsWithChildren) => { @@ -17,4 +17,6 @@ export const VerticalTab = ({ {children} ); -} \ No newline at end of file +}) + +VerticalTab.displayName = 'VerticalTab'; \ No newline at end of file diff --git a/lib/components/VerticalTab/VerticalTabItem.tsx b/lib/components/VerticalTab/VerticalTabItem.tsx new file mode 100644 index 00000000..bb808cb3 --- /dev/null +++ b/lib/components/VerticalTab/VerticalTabItem.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import clsx from 'clsx'; + +import { Text } from '../Text'; + +export type TabItem = { + icon?: React.ReactNode; + title: string; + component?: React.ReactNode; + subItems?: { + title: string; + component: React.ReactNode; + }[]; +} + +type VerticalTabItemProps = { + tab: TabItem; + onClick: (title: string) => void; + className?: string; + selectedTab: string; + iconClassName?: string; + labelClassName?: string; +} + +export const VerticalTabItem = ({ tab, onClick, className, selectedTab, iconClassName,labelClassName }: VerticalTabItemProps) => { + return ( +
onClick(tab?.title)} + > + {tab?.icon} + {tab?.title} +
+ ) +} \ No newline at end of file diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index 562a240e..d54b2df8 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -1,30 +1,27 @@ -import React, { useEffect, useState } from 'react'; +import React, { memo, useEffect, useState } from 'react'; import { Text } from '../Text'; import clsx from 'clsx'; +import { VerticalTabItem, type TabItem } from './VerticalTabItem' +import { CollapsibleVerticalTabItem } from './CollapsibleVerticalTabItem'; + type VerticalTabItemsProps = { activeTab: string; onSelectItem?: (title: string) => void; className?: string; iconClassName?: string; labelClassName?: string; - items: { - icon: React.ReactNode; - title: string; - component?: React.ReactNode; - subItems?: { - title: string; - component: React.ReactNode; - }[]; - }[]; - + items: TabItem[]; } -const ArrowDownIcon = () => - -; -export const VerticalTabItems = ({ items, className, iconClassName, labelClassName, activeTab, onSelectItem }: VerticalTabItemsProps) => { + +export const VerticalTabItems = memo(({ items, className, iconClassName, labelClassName, activeTab, onSelectItem }: VerticalTabItemsProps) => { const [selectedTab, setSelectedTab] = useState(activeTab); + useEffect(() => { + if (activeTab) { + setSelectedTab(activeTab); + } + }, [activeTab]); const findActiveTab = (title: string) => { for (const item of items) { @@ -43,16 +40,10 @@ export const VerticalTabItems = ({ items, className, iconClassName, labelClassNa const onSelectItemHandler = (title: string) => { const new_active_tab = findActiveTab(title)?.title; - // console.log('new_active_tab:', new_active_tab); setSelectedTab(() => new_active_tab ?? activeTab); onSelectItem?.(title); } - useEffect(() => { - if (activeTab) { - setSelectedTab(activeTab); - } - }, [activeTab]); return (
@@ -60,49 +51,19 @@ export const VerticalTabItems = ({ items, className, iconClassName, labelClassNa {items.map((item) => { if (!item?.subItems) { return ( -
onSelectItemHandler(item?.title)} - > - {item?.icon} - {item?.title} -
+ onSelectItemHandler(item?.title)} /> ) } else { return ( -
-
subItem?.title === selectedTab), - }, className)}> - {item?.icon} - {item?.title} - -
-
- {item?.subItems.map((subItem) => { - return ( -
onSelectItemHandler(subItem?.title)} - > - {subItem?.title} -
- ) - })} -
-
+ item={item} + selectedTab={selectedTab} + onSelectItemHandler={onSelectItemHandler} + labelClassName={labelClassName} + className={className} + iconClassName={iconClassName} + /> ) } })} @@ -112,4 +73,6 @@ export const VerticalTabItems = ({ items, className, iconClassName, labelClassNa
); -} \ No newline at end of file +}) + +VerticalTabItems.displayName = 'VerticalTabItems'; \ No newline at end of file From 44b419dbe72ff4c8b01160d3722a2ac1e9776bcc Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Wed, 7 Feb 2024 18:32:36 +0800 Subject: [PATCH 06/11] ci: fixed build error --- lib/components/VerticalTab/VerticalTabItems.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index d54b2df8..644d0708 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -1,6 +1,4 @@ import React, { memo, useEffect, useState } from 'react'; -import { Text } from '../Text'; -import clsx from 'clsx'; import { VerticalTabItem, type TabItem } from './VerticalTabItem' import { CollapsibleVerticalTabItem } from './CollapsibleVerticalTabItem'; From a2d479c696a3a939eaeef6491ce6b3b6948d151a Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Fri, 9 Feb 2024 09:14:55 +0800 Subject: [PATCH 07/11] chore: improved some styling issues --- lib/components/VerticalTab/VerticalTab.scss | 37 +++++++++++---------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index a9274827..d9217792 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -1,24 +1,21 @@ .vertical-tab__wrapper { - // background: #F2F3F4; padding: 8px; display: flex; - flex-direction: column; justify-content: center; border-radius: 8px; + @include mobile { + flex-direction: column;; + } } -.shayan { - display: flex; -} -.vertical-tab__pane { - flex: 2; -} -.vertical-tab__item-container{ - background: #f2f3f4; - flex: 1; - border-radius: 4px; - padding: 8px; -} + .vertical-tab { + &__items-container{ + background: #f2f3f4; + flex: 1; + border-radius: 4px; + padding: 8px; + } + &__item { display: flex; padding: 10px 16px; @@ -50,6 +47,14 @@ &__label { flex:1; } + + &__pane { + flex: 2; + } + + &__arrow--open{ + transform: rotate(180deg); + } } .collapsible-vertical-tab { @@ -75,7 +80,3 @@ flex:1; } } - -.vertical-tab__arrow--open{ - transform: rotate(180deg); -} \ No newline at end of file From 58f0039abea0191518cbbe25935460995b6c1e78 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Fri, 9 Feb 2024 15:49:47 +0800 Subject: [PATCH 08/11] chore: resolved pr comments --- .../CollapsibleVerticalTabItem.tsx | 15 ++-- lib/components/VerticalTab/VerticalTab.scss | 27 +++++- lib/components/VerticalTab/VerticalTab.tsx | 4 - .../VerticalTab/VerticalTabItem.tsx | 23 ++--- .../VerticalTab/VerticalTabItems.tsx | 87 +++++++++++++++---- lib/main.ts | 1 + 6 files changed, 116 insertions(+), 41 deletions(-) diff --git a/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx b/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx index ad9cfde5..68898dbb 100644 --- a/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx +++ b/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx @@ -10,7 +10,6 @@ type CollapsibleVerticalTabItemProps = { selectedTab: string; className?: string; iconClassName?: string; - labelClassName?: string; } @@ -26,12 +25,12 @@ export const CollapsibleVerticalTabItem = ({ selectedTab, className, iconClassName, - labelClassName }: CollapsibleVerticalTabItemProps) => { - const [open, setOpen] = useState(false); + const selectedSubItemSelected = item?.subItems?.find((subItem) => subItem?.title === selectedTab) + const [open, setOpen] = useState(selectedSubItemSelected ? true : false); const onClickHandler = () => { - const shouldCollapse = !item?.subItems?.find((subItem) => subItem?.title === selectedTab); + const shouldCollapse = !selectedSubItemSelected; if (shouldCollapse) setOpen(!open); } @@ -40,18 +39,18 @@ export const CollapsibleVerticalTabItem = ({ key={item.title} className={clsx(`collapsible-vertical-tab`)}>
subItem?.title === selectedTab), - }, className)} + 'collapsible-vertical-tab__header--open': selectedSubItemSelected, + })} onClick={() => onClickHandler()} > {item?.icon} - {item?.title} + {item?.title}
{open &&
{item?.subItems?.map((subItem) => { return ( - onSelectItemHandler(subItem?.title)} /> + onSelectItemHandler(subItem?.title)} /> ) })}
} diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index d9217792..4708f3f1 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -2,7 +2,7 @@ padding: 8px; display: flex; justify-content: center; - border-radius: 8px; + gap:25px; @include mobile { flex-direction: column;; } @@ -36,6 +36,17 @@ background-color: #fff; } } + + &--disabled { + & > span{ + color: #999999; + } + + &:hover{ + cursor: unset; + background-color: inherit; + } + } } &__icon { @@ -80,3 +91,17 @@ flex:1; } } + + +.test-1{ + background-color: purple; +} +.test-2{ + background-color: forestgreen; +} +.test-3{ + background-color: hotpink; +} +.test-item{ + background-color: yellow; +} diff --git a/lib/components/VerticalTab/VerticalTab.tsx b/lib/components/VerticalTab/VerticalTab.tsx index 88e99203..9e33bdd1 100644 --- a/lib/components/VerticalTab/VerticalTab.tsx +++ b/lib/components/VerticalTab/VerticalTab.tsx @@ -1,11 +1,9 @@ -// Code: import React, { memo } from 'react'; import clsx from 'clsx'; import './VerticalTab.scss'; type VerticalTabProps = { className?: string; - style?: React.CSSProperties; } export const VerticalTab = memo(({ @@ -18,5 +16,3 @@ export const VerticalTab = memo(({ ); }) - -VerticalTab.displayName = 'VerticalTab'; \ No newline at end of file diff --git a/lib/components/VerticalTab/VerticalTabItem.tsx b/lib/components/VerticalTab/VerticalTabItem.tsx index bb808cb3..0eacc7d0 100644 --- a/lib/components/VerticalTab/VerticalTabItem.tsx +++ b/lib/components/VerticalTab/VerticalTabItem.tsx @@ -5,12 +5,14 @@ import { Text } from '../Text'; export type TabItem = { icon?: React.ReactNode; - title: string; - component?: React.ReactNode; + is_disabled?: boolean; + panel?: React.ReactNode; subItems?: { + is_disabled?: boolean; + panel: React.ReactNode; title: string; - component: React.ReactNode; }[]; + title: string; } type VerticalTabItemProps = { @@ -18,22 +20,21 @@ type VerticalTabItemProps = { onClick: (title: string) => void; className?: string; selectedTab: string; - iconClassName?: string; - labelClassName?: string; } -export const VerticalTabItem = ({ tab, onClick, className, selectedTab, iconClassName,labelClassName }: VerticalTabItemProps) => { +export const VerticalTabItem = ({ tab, onClick, className, selectedTab }: VerticalTabItemProps) => { return (
onClick(tab?.title)} + onClick={() => !tab.is_disabled && onClick(tab.title)} > - {tab?.icon} - {tab?.title} + {tab?.icon} + {tab.title}
) -} \ No newline at end of file +} diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index 644d0708..684dcb00 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -1,19 +1,76 @@ import React, { memo, useEffect, useState } from 'react'; - -import { VerticalTabItem, type TabItem } from './VerticalTabItem' import { CollapsibleVerticalTabItem } from './CollapsibleVerticalTabItem'; +import { VerticalTabItem, type TabItem } from './VerticalTabItem' +import clsx from 'clsx'; type VerticalTabItemsProps = { activeTab: string; onSelectItem?: (title: string) => void; - className?: string; - iconClassName?: string; - labelClassName?: string; + wrapperClassName?: string; + panelClassName?: string; + itemClassName?: string; items: TabItem[]; } +/** + * Component to display the vertical tab items. iit should be wrapperd inside the VerticalTab component + * @param {TabItem} items - tab items + * @param {string} panelClassName -it applies the classname to the right panel + * @param {string} wrapperClassName - it applies the classname to the left side menu container + * @param {string} itemClassName - it applies the classname to the each items whether it's sub-item or single item + * @param {string} activeTab - indicates the active tab. you can pass the title of the tab + * @param {Function} onSelectItem - callback to handle selecting each tab item + * @returns {React.JSX.Element} - returns the vertical tab component + * + * @example + * const items = [ + * { + * title: 'Item 1', + * icon: Icon, + * panel:
Item 1 pane
+ * }, + * { + * title: 'Item 2', + * icon: Icon, + * panel:
Item 2 pane
, + * subItems: [ + * { + * title: 'Item 2.1', + * icon: Icon, + * panel:
Item 2.1 pane
+ * }, +* { + * title: 'Item 2.2', + * icon: Icon, + * is_disabled: true, + * panel:
Item 2.2 pane
+ * }, + * ] + * }, + * { + * title: 'Item 3', + * icon: Icon, + * panel:
Item 3 pane
+ * }, + * ] + * + * + * console.log('clicked on:', title) + * } + * /> + * + */ -export const VerticalTabItems = memo(({ items, className, iconClassName, labelClassName, activeTab, onSelectItem }: VerticalTabItemsProps) => { +export const VerticalTabItems = memo(({ + items, + panelClassName, + wrapperClassName, + itemClassName, + activeTab, + onSelectItem }: VerticalTabItemsProps) => { const [selectedTab, setSelectedTab] = useState(activeTab); useEffect(() => { if (activeTab) { @@ -44,12 +101,12 @@ export const VerticalTabItems = memo(({ items, className, iconClassName, labelCl return ( -
-
+ <> +
{items.map((item) => { if (!item?.subItems) { return ( - onSelectItemHandler(item?.title)} /> + onSelectItemHandler(item?.title)} /> ) } else { return ( @@ -58,19 +115,15 @@ export const VerticalTabItems = memo(({ items, className, iconClassName, labelCl item={item} selectedTab={selectedTab} onSelectItemHandler={onSelectItemHandler} - labelClassName={labelClassName} - className={className} - iconClassName={iconClassName} + className={itemClassName} /> ) } })}
-
- {findActiveTab(selectedTab)?.component} +
+ {findActiveTab(selectedTab)?.panel}
-
+ ); }) - -VerticalTabItems.displayName = 'VerticalTabItems'; \ No newline at end of file diff --git a/lib/main.ts b/lib/main.ts index 1ca619c1..60591de4 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -12,3 +12,4 @@ export { useOnClickOutside } from "./hooks/useOnClickOutside"; export { PasswordInput } from "./components/PasswordInput"; export { InlineMessage } from "./components/InlineMessage"; export { Checkbox } from "./components/Checkbox"; +export { VerticalTab, VerticalTabItems } from "./components/VerticalTab"; From 20e41b78ea68f3e0d14e503328227bd00b53c7c0 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Fri, 9 Feb 2024 16:09:15 +0800 Subject: [PATCH 09/11] fix: fixed minor bugs --- .../VerticalTab/CollapsibleVerticalTabItem.tsx | 14 +++++++------- lib/components/VerticalTab/VerticalTab.scss | 2 +- lib/components/VerticalTab/VerticalTab.tsx | 2 +- lib/components/VerticalTab/VerticalTabItem.tsx | 6 ++++-- lib/components/VerticalTab/VerticalTabItems.tsx | 12 +++++------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx b/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx index 68898dbb..8cd8f0fd 100644 --- a/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx +++ b/lib/components/VerticalTab/CollapsibleVerticalTabItem.tsx @@ -13,7 +13,7 @@ type CollapsibleVerticalTabItemProps = { } -const ArrowIcon = ({ is_open }: { is_open: boolean }) => @@ -26,7 +26,7 @@ export const CollapsibleVerticalTabItem = ({ className, iconClassName, }: CollapsibleVerticalTabItemProps) => { - const selectedSubItemSelected = item?.subItems?.find((subItem) => subItem?.title === selectedTab) + const selectedSubItemSelected = item?.subItems?.find((subItem) => subItem.title === selectedTab) const [open, setOpen] = useState(selectedSubItemSelected ? true : false); const onClickHandler = () => { @@ -37,20 +37,20 @@ export const CollapsibleVerticalTabItem = ({ return (
-
+
onClickHandler()} > - {item?.icon} - {item?.title} + {item?.icon} + {item.title}
{open &&
{item?.subItems?.map((subItem) => { return ( - onSelectItemHandler(subItem?.title)} /> + onSelectItemHandler(subItem.title)} /> ) })}
} diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index 4708f3f1..a5381e43 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -59,7 +59,7 @@ flex:1; } - &__pane { + &__panel { flex: 2; } diff --git a/lib/components/VerticalTab/VerticalTab.tsx b/lib/components/VerticalTab/VerticalTab.tsx index 9e33bdd1..0ed2c73b 100644 --- a/lib/components/VerticalTab/VerticalTab.tsx +++ b/lib/components/VerticalTab/VerticalTab.tsx @@ -11,7 +11,7 @@ export const VerticalTab = memo(({ children }: React.PropsWithChildren) => { return ( -
+
{children}
); diff --git a/lib/components/VerticalTab/VerticalTabItem.tsx b/lib/components/VerticalTab/VerticalTabItem.tsx index 0eacc7d0..96e3a74b 100644 --- a/lib/components/VerticalTab/VerticalTabItem.tsx +++ b/lib/components/VerticalTab/VerticalTabItem.tsx @@ -26,14 +26,16 @@ export const VerticalTabItem = ({ tab, onClick, className, selectedTab }: Vertic return (
!tab.is_disabled && onClick(tab.title)} > - {tab?.icon} + {tab?.icon && ( + {tab?.icon} + )} {tab.title}
) diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index 684dcb00..4b1f3b70 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -36,12 +36,10 @@ type VerticalTabItemsProps = { * subItems: [ * { * title: 'Item 2.1', - * icon: Icon, * panel:
Item 2.1 pane
* }, * { * title: 'Item 2.2', - * icon: Icon, * is_disabled: true, * panel:
Item 2.2 pane
* }, @@ -81,12 +79,12 @@ export const VerticalTabItems = memo(({ const findActiveTab = (title: string) => { for (const item of items) { if (item?.subItems) { - const foundItem = item?.subItems.find((subItem) => subItem?.title === title); + const foundItem = item?.subItems.find((subItem) => subItem.title === title); if (foundItem) { return foundItem; } } else { - if (item?.title === title) { + if (item.title === title) { return item; } } @@ -106,12 +104,12 @@ export const VerticalTabItems = memo(({ {items.map((item) => { if (!item?.subItems) { return ( - onSelectItemHandler(item?.title)} /> + onSelectItemHandler(item.title)} /> ) } else { return ( -
+
{findActiveTab(selectedTab)?.panel}
From 8d33af7e7da61b924f111d3c86b7e96c49dbba1a Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Fri, 9 Feb 2024 17:07:12 +0800 Subject: [PATCH 10/11] chore: made the right panel optional --- lib/components/VerticalTab/VerticalTabItems.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/components/VerticalTab/VerticalTabItems.tsx b/lib/components/VerticalTab/VerticalTabItems.tsx index 4b1f3b70..b2890532 100644 --- a/lib/components/VerticalTab/VerticalTabItems.tsx +++ b/lib/components/VerticalTab/VerticalTabItems.tsx @@ -10,6 +10,7 @@ type VerticalTabItemsProps = { panelClassName?: string; itemClassName?: string; items: TabItem[]; + should_have_panel?: boolean; } /** @@ -20,6 +21,7 @@ type VerticalTabItemsProps = { * @param {string} itemClassName - it applies the classname to the each items whether it's sub-item or single item * @param {string} activeTab - indicates the active tab. you can pass the title of the tab * @param {Function} onSelectItem - callback to handle selecting each tab item + * @param {boolean} should_have_panel - indicates whether the panel should be displayed or not * @returns {React.JSX.Element} - returns the vertical tab component * * @example @@ -68,6 +70,7 @@ export const VerticalTabItems = memo(({ wrapperClassName, itemClassName, activeTab, + should_have_panel = true, onSelectItem }: VerticalTabItemsProps) => { const [selectedTab, setSelectedTab] = useState(activeTab); useEffect(() => { @@ -119,9 +122,10 @@ export const VerticalTabItems = memo(({ } })}
-
+ {should_have_panel &&
{findActiveTab(selectedTab)?.panel} -
+
} ); }) + From 49d57a7b7aee578d9367d459e418aaf8e053e0b4 Mon Sep 17 00:00:00 2001 From: shayan khaleghparast Date: Fri, 9 Feb 2024 17:40:21 +0800 Subject: [PATCH 11/11] chore: removed unused classnames --- lib/components/VerticalTab/VerticalTab.scss | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/lib/components/VerticalTab/VerticalTab.scss b/lib/components/VerticalTab/VerticalTab.scss index a5381e43..a4e02012 100644 --- a/lib/components/VerticalTab/VerticalTab.scss +++ b/lib/components/VerticalTab/VerticalTab.scss @@ -92,16 +92,3 @@ } } - -.test-1{ - background-color: purple; -} -.test-2{ - background-color: forestgreen; -} -.test-3{ - background-color: hotpink; -} -.test-item{ - background-color: yellow; -}