Skip to content

Commit

Permalink
feat: add tablist utilities styles and examples (#171)
Browse files Browse the repository at this point in the history
* feat: add tablist utilities styles and examples
  • Loading branch information
axis-d0op committed Feb 20, 2024
1 parent 11422a8 commit d9cd7a2
Show file tree
Hide file tree
Showing 10 changed files with 538 additions and 55 deletions.
4 changes: 3 additions & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"@vitejs/plugin-react": "^1.3.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "6.21.3",
"react-router-dom": "6.20.1",
"react-syntax-highlighter": "15.5.0",
"scheduler": "0.23.0",
"vite": "^3.0.9"
},
Expand All @@ -46,6 +47,7 @@
"@types/node": "^20.11.5",
"@types/react": "^17.0.67",
"@types/react-dom": "^17.0.21",
"@types/react-syntax-highlighter": "15.5.11",
"eslint": "^8.56.0",
"typescript": "^4.5.5"
},
Expand Down
25 changes: 25 additions & 0 deletions examples/src/components/code-block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import SyntaxHighlighter from "react-syntax-highlighter";
import React from "react";
import {
Accordion,
AccordionHeader,
AccordionItem,
AccordionPanel,
} from "@fluentui/react-components";

export const CodeBlock = (
{ codeString, title }: { codeString: string; title: string }
) => {
return (
<Accordion collapsible>
<AccordionItem value="1">
<AccordionHeader>{title}</AccordionHeader>
<AccordionPanel>
<SyntaxHighlighter language="typescript">
{codeString}
</SyntaxHighlighter>
</AccordionPanel>
</AccordionItem>
</Accordion>
);
};
31 changes: 22 additions & 9 deletions examples/src/routing/route-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {
bundleIcon,
DarkThemeFilled,
DarkThemeRegular,
DocumentCssFilled,
DocumentCssRegular,
EyeFilled,
EyeRegular,
HomeFilled,
Expand All @@ -25,6 +27,7 @@ import { routes, TRoute } from "./routes";
import { SliderPage } from "../stories/slider-page";
import { WelcomePage } from "../landingpage";
import { PasswordInputPage } from "../stories/password-input-page";
import { FluentUiTabStylesPage } from "../stories/tab-list-utilities/tab-list-utilities-page";

const HomeIcon = bundleIcon(HomeFilled, HomeRegular);
const ThemeIcon = bundleIcon(DarkThemeFilled, DarkThemeRegular);
Expand All @@ -34,6 +37,7 @@ const VStepperIcon = bundleIcon(StepsFilled, StepsRegular);
const TableUtilitiesIcon = bundleIcon(TableFilled, TableRegular);
const SliderIcon = bundleIcon(OptionsFilled, OptionsRegular);
const PasswordIcon = bundleIcon(EyeFilled, EyeRegular);
const TabStylesIcon = bundleIcon(DocumentCssFilled, DocumentCssRegular);

export enum RouteGroup {
MISC,
Expand Down Expand Up @@ -93,15 +97,6 @@ export const routeMap: Map<TRoute, TRouteData> = new Map([
group: RouteGroup.STORY,
},
],
[
routes.TableUtilities,
{
label: "Table Utilities",
element: <TableUtilitiesPage />,
icon: <TableUtilitiesIcon />,
group: RouteGroup.STORY,
},
],
[
routes.Slider,
{
Expand All @@ -120,6 +115,24 @@ export const routeMap: Map<TRoute, TRouteData> = new Map([
group: RouteGroup.STORY,
},
],
[
routes.TableUtilities,
{
label: "Table Utilities",
element: <TableUtilitiesPage />,
icon: <TableUtilitiesIcon />,
group: RouteGroup.STORY,
},
],
[
routes.PasswordInput,
{
label: "Tablist utilities",
element: <FluentUiTabStylesPage />,
icon: <TabStylesIcon />,
group: RouteGroup.STORY,
},
],
]);

export const getRouteByGroup = (group: RouteGroup) => {
Expand Down
94 changes: 94 additions & 0 deletions examples/src/stories/tab-list-utilities/tab-list-styled..tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from "react";
import {
Tab,
TabList,
TabListProps,
TabProps,
} from "@fluentui/react-components";
import { bundleIcon, HomeFilled, HomeRegular } from "@fluentui/react-icons";
import {
useTabListStyles,
useTabStyles,
} from "@axiscommunications/fluent-styles";
import { useTabListContext } from "./tab-list-utilities-page";

export const codeBlockStyled = `
...
import {
useTabListStyles,
useTabStyles,
} from "@axiscommunications/fluent-styles";
...
//standard usage
const { rootStyle: tabListStyle } = useTabListStyles({ vertical: true/false });
const { rootStyle: tabStyle } = useTabStyles({ selected: true/false });
<Tab className={tabListStyle} {...TabListProps}>
<Tab className={tabStyle} {...TabProps}>tab1</Tab>
</Tab>
//not happy with style? all styles can be grabbed from styles prop
const { styles } = useTabListStyles();
const newStyle = mergeClasses(styles.root, overrideStyles.root ...)
...
`;

const HomeIcon = bundleIcon(HomeFilled, HomeRegular);

export type TTabListComponent = {
withText?: boolean;
} & TabListProps;

export function StyledTabListComponent(
{ withText = true, ...props }: TTabListComponent
) {
const { selectedTab, setSelectedTab } = useTabListContext();
const { rootStyle } = useTabListStyles({ vertical: props.vertical });

return (
<TabList
selectedValue={selectedTab}
className={rootStyle}
defaultSelectedValue={selectedTab}
onTabSelect={(_, { value }) => {
setSelectedTab(value as unknown as string);
}}
{...props}
>
<StyledTabComponent
icon={<HomeIcon />}
value="tab1"
selected={selectedTab === "tab1"}
>
{withText && "First Tab"}
</StyledTabComponent>
<StyledTabComponent
icon={<HomeIcon />}
value="tab2"
selected={selectedTab === "tab2"}
>
{withText && "First Tab"}
</StyledTabComponent>
<StyledTabComponent
icon={<HomeIcon />}
value="tab3"
selected={selectedTab === "tab3"}
>
{withText && "First Tab"}
</StyledTabComponent>
</TabList>
);
}

export type TStyledTabComponent = {
selected?: boolean;
} & TabProps;

function StyledTabComponent(
{ selected, children, ...props }: TStyledTabComponent
) {
const { rootStyle } = useTabStyles({ selected });

return <Tab className={rootStyle} {...props}>{children}</Tab>;
}
110 changes: 110 additions & 0 deletions examples/src/stories/tab-list-utilities/tab-list-utilities-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { createContext, useContext, useState } from "react";
import {
makeStyles,
mergeClasses,
shorthands,
Tab,
TabList,
tokens,
} from "@fluentui/react-components";
import { PageHeader } from "../../components/page-header";
import { useLayoutStyles, useScrollPageStyle } from "../../styles/page";
import { SectionTitle } from "../../components/section-title";
import { bundleIcon, HomeFilled, HomeRegular } from "@fluentui/react-icons";
import { CodeBlock } from "../../components/code-block";
import {
codeBlockStyled,
StyledTabListComponent,
TTabListComponent,
} from "./tab-list-styled.";

type TTabListContext = {
selectedTab: string;
setSelectedTab: (value: string) => void;
};

const TabListContext = createContext<TTabListContext | null>(null);
export const useTabListContext = () => {
const context = useContext(TabListContext);
if (context === null) {
throw new Error("cant use context outside its provider");
}
return context;
};

const HomeIcon = bundleIcon(HomeFilled, HomeRegular);

const useTabListUtilitiesStyles = makeStyles({
section: {
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
...shorthands.gap(tokens.spacingHorizontalXXL),
},
group: {
display: "flex",
alignItems: "flex-start",
flexDirection: "column",
...shorthands.gap(tokens.spacingHorizontalXS),
},
});

export const FluentUiTabStylesPage = () => {
const styles = useTabListUtilitiesStyles();
const scrollPageStyle = useScrollPageStyle();
const layoutStyles = useLayoutStyles();
const [selectedTab, setSelectedTab] = useState("tab1");

return (
<div className={layoutStyles.grid}>
<TabListContext.Provider value={{ selectedTab, setSelectedTab }}>
<PageHeader className={layoutStyles.header} title="Tablist utilities" />
<div
className={mergeClasses(
layoutStyles.content,
layoutStyles.sections,
scrollPageStyle
)}
>
<div className={styles.section}>
<div className={styles.group}>
<SectionTitle title={"TabList default"} />
<TabListComponent />
<TabListComponent withText={false} />
<TabListComponent vertical />
<TabListComponent withText={false} vertical />
</div>

<div className={styles.group}>
<SectionTitle title={"TabList styled tabs"} />
<StyledTabListComponent />
<StyledTabListComponent withText={false} />
<StyledTabListComponent vertical />
<StyledTabListComponent withText={false} vertical />

<CodeBlock codeString={codeBlockStyled} title={"code"} />
</div>
</div>
</div>
</TabListContext.Provider>
</div>
);
};

function TabListComponent({ withText = true, ...props }: TTabListComponent) {
const { selectedTab, setSelectedTab } = useTabListContext();
return (
<TabList
selectedValue={selectedTab}
defaultSelectedValue={selectedTab}
onTabSelect={(_, { value }) => {
setSelectedTab(value as unknown as string);
}}
{...props}
>
<Tab icon={<HomeIcon />} value="tab1">{withText && "First Tab"}</Tab>
<Tab icon={<HomeIcon />} value="tab2">{withText && "First Tab"}</Tab>
<Tab icon={<HomeIcon />} value="tab3">{withText && "First Tab"}</Tab>
</TabList>
);
}
Loading

0 comments on commit d9cd7a2

Please sign in to comment.