import React from 'react';
import { StoryMetaType } from '@lg-tools/storybook-utils';
import { type StoryObj } from '@storybook/react';
import { within } from '@storybook/test';
import startCase from 'lodash/startCase';
import { css, cx } from '@leafygreen-ui/emotion';
import { Theme } from '@leafygreen-ui/lib';
import { palette } from '@leafygreen-ui/palette';
import { scrollbarColor } from './scrollbars';
import {
addOverflowShadow,
borderRadius,
boxShadows,
color,
focusRing,
fontFamilies,
hoverRing,
type ShadowKey,
Side,
spacing,
transitionDuration,
typeScales,
Variant,
} from '.';
const DemoCard = ({
children,
darkMode,
className,
...rest
}: {
children: React.ReactNode;
darkMode: boolean;
className?: string;
[key: string]: any;
}) => {
const theme = darkMode ? Theme.Dark : Theme.Light;
return (
{children}
);
};
const meta: StoryMetaType = {
title: 'Internal/Tokens',
component: null,
parameters: { default: 'Spacing' },
};
export default meta;
type HoverRingColor = keyof typeof hoverRing.dark;
type TypeScale = keyof typeof typeScales;
type FontFamily = keyof typeof fontFamilies;
const gutter = css`
margin-left: ${spacing[400]}px;
`;
const spacingBlockVariants = Object.keys(spacing)
.filter(num => Number(num) === 0 || Number(num) > 25)
.reduce((acc: Partial>, index) => {
const key = index as PropertyKey as keyof typeof spacing;
acc[key] = css`
background-color: ${palette.purple.light2};
width: ${spacing[key]}px;
height: ${spacing[key]}px;
`;
return acc;
}, {});
function SpacingBlock({ space }: { space: keyof typeof spacing }) {
return (
spacing[{space}]: {spacing[space]}
);
}
export const OverflowShadows = () => {
return (
{Object.values(Theme).map((theme: Theme) => {
const isDarkMode = theme === Theme.Dark;
const backgroundColor = isDarkMode ? palette.gray.dark4 : palette.white;
return (
{Object.values(Side).map(side => (
Inside {side} shadow
))}
{Object.values(Side).map(side => (
Outside {side} shadow
))}
);
})}
);
};
const shadowMap: Record> = {
[Theme.Light]: boxShadows.light,
[Theme.Dark]: boxShadows.dark,
};
const excludeKeys: Array = ['overflow'];
export const Shadows = () => (
{Object.entries(shadowMap).map(([theme, shadows]) => (
{theme}
{Object.entries(shadows).map(
([key, value]) =>
!excludeKeys.includes(key as keyof typeof boxShadows.light) && (
{key}
),
)}
))}
);
export const Spacing = () => (
Spacing
{Object.keys(spacing)
.filter(num => Number(num) === 0 || Number(num) > 25)
.map(space => (
))}
);
export const TypeScales = () => {
return (
Typescales
{Object.keys(typeScales).map((_scale: string) => {
const scale = _scale as TypeScale;
return (
);
})}
);
};
export const FontFamilies = () => (
Font Families
{Object.keys(fontFamilies).map((_family: string) => {
const family = _family as FontFamily;
return (
);
})}
);
const generateTable = (theme: Theme) => {
const isDarkMode = !!(theme === Theme.Dark);
return (
{theme} Mode
{Object.keys(color[theme]).map(type => (
{type}
|
default
|
hover
|
focus
|
{/* @ts-expect-error */}
{Object.keys(color[theme][type]).map(variant => (
{variant}
|
{/* @ts-expect-error */}
{Object.keys(color[theme][type][variant]).map(state => (
|
))}
))}
))}
);
};
export const Colors = {
render: () => {
return (
Color Tokens
{Object.values(Theme).map(theme => generateTable(theme))}
);
},
parameters: {
chromatic: {
disableSnapshot: true,
},
},
};
export const Scrollbars: StoryObj = {
parameters: {
chromatic: {
// TODO: skipping for now until we can get Chromatic to snapshot the scrollbars
// https://github.com/storybookjs/storybook/discussions/31691#discussion-8425494
disableSnapshot: true,
},
},
render: () => {
return (
{Object.values(Theme).map((theme: Theme) => {
const isDarkMode = theme === Theme.Dark;
return [Variant.Primary, Variant.Secondary].map(variant => {
const thumbColor = scrollbarColor[theme].thumb[variant].default;
const trackColor = scrollbarColor[theme].track[variant].default;
return (
);
});
})}
);
},
play: async ({ canvasElement }) => {
const cards = within(canvasElement).getAllByTestId('demo-card');
cards.forEach(card => {
const scrollable = within(card).getByTestId('scrollable');
scrollable.scrollTo({
top: 12,
left: 12,
behavior: 'smooth',
});
});
},
};
export const InteractionRings = () => {
const invertTheme = (theme: Theme): Theme =>
theme === 'dark' ? 'light' : 'dark';
const themeWrapper = (theme: Theme) => css`
display: flex;
gap: ${spacing[200]}px;
color: ${theme === 'dark' ? palette.white : palette.black};
background-color: ${theme === 'dark' ? palette.black : palette.white};
border: 1px solid
${theme === 'dark' ? palette.gray.light3 : palette.gray.dark3};
border-radius: ${spacing[400]}px;
padding: ${spacing[600]}px;
margin: ${spacing[400]}px 0;
`;
const buttonBase = css`
font-family: ${fontFamilies.default};
font-size: ${typeScales.body2.fontSize}px;
outline: none;
background-color: unset;
border: unset;
padding: ${spacing[200]}px;
border-radius: ${spacing[100]}px;
cursor: pointer;
transition: box-shadow ${transitionDuration.faster}ms ease-in-out;
`;
return (
Interaction States
{Object.values(Theme).map((theme: Theme) => (
{Object.keys(hoverRing[theme]).map(_color => {
const color = _color as HoverRingColor;
return (
);
})}
))}
);
};
InteractionRings.parameters = {
chromatic: {
disableSnapshot: true,
},
};