Migrate to a monorepo structure (#2909)
This commit is contained in:
@ -0,0 +1,160 @@
|
||||
import { ComponentProps, JSX } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { isNumber, isString } from '@sniptt/guards';
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
const StyledColumnTitle = styled.h1`
|
||||
font-size: ${({ theme }) => theme.font.size.lg};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledRowsTitle = styled.h2`
|
||||
color: ${({ theme }) => theme.font.color.secondary};
|
||||
font-size: ${({ theme }) => theme.font.size.md};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin: ${({ theme }) => theme.spacing(2)};
|
||||
width: 100px;
|
||||
`;
|
||||
|
||||
const StyledRowTitle = styled.h3`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
font-size: ${({ theme }) => theme.font.size.md};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin: ${({ theme }) => theme.spacing(2)};
|
||||
width: 100px;
|
||||
`;
|
||||
|
||||
const StyledElementTitle = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
margin-bottom: ${({ theme }) => theme.spacing(1)};
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
`;
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
`;
|
||||
|
||||
const StyledColumnContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledRowsContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledRowContainer = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledElementContainer = styled.div<{ width: number }>`
|
||||
display: flex;
|
||||
${({ width }) => width && `min-width: ${width}px;`}
|
||||
`;
|
||||
|
||||
const StyledCellContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const emptyDimension = {
|
||||
name: '',
|
||||
values: [undefined],
|
||||
props: () => ({}),
|
||||
} as CatalogDimension;
|
||||
|
||||
const isStringOrNumber = (term: unknown): term is string | number =>
|
||||
isString(term) || isNumber(term);
|
||||
|
||||
export type CatalogDimension<
|
||||
ComponentType extends React.ElementType = () => JSX.Element,
|
||||
> = {
|
||||
name: string;
|
||||
values: any[];
|
||||
props: (value: any) => Partial<ComponentProps<ComponentType>>;
|
||||
labels?: (value: any) => string;
|
||||
};
|
||||
|
||||
export type CatalogOptions = {
|
||||
elementContainer?: {
|
||||
width?: number;
|
||||
};
|
||||
};
|
||||
|
||||
export const CatalogDecorator: Decorator = (Story, context) => {
|
||||
const {
|
||||
catalog: { dimensions, options },
|
||||
} = context.parameters;
|
||||
|
||||
const [
|
||||
dimension1,
|
||||
dimension2 = emptyDimension,
|
||||
dimension3 = emptyDimension,
|
||||
dimension4 = emptyDimension,
|
||||
] = dimensions as CatalogDimension[];
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
{dimension4.values.map((value4: any) => (
|
||||
<StyledColumnContainer key={value4}>
|
||||
<StyledColumnTitle>
|
||||
{dimension4.labels?.(value4) ??
|
||||
(isStringOrNumber(value4) ? value4 : '')}
|
||||
</StyledColumnTitle>
|
||||
{dimension3.values.map((value3: any) => (
|
||||
<StyledRowsContainer key={value3}>
|
||||
<StyledRowsTitle>
|
||||
{dimension3.labels?.(value3) ??
|
||||
(isStringOrNumber(value3) ? value3 : '')}
|
||||
</StyledRowsTitle>
|
||||
{dimension2.values.map((value2: any) => (
|
||||
<StyledRowContainer key={value2}>
|
||||
<StyledRowTitle>
|
||||
{dimension2.labels?.(value2) ??
|
||||
(isStringOrNumber(value2) ? value2 : '')}
|
||||
</StyledRowTitle>
|
||||
{dimension1.values.map((value1: any) => {
|
||||
return (
|
||||
<StyledCellContainer key={value1} id={value1}>
|
||||
<StyledElementTitle>
|
||||
{dimension1.labels?.(value1) ??
|
||||
(isStringOrNumber(value1) ? value1 : '')}
|
||||
</StyledElementTitle>
|
||||
<StyledElementContainer
|
||||
width={options?.elementContainer?.width}
|
||||
>
|
||||
<Story
|
||||
args={{
|
||||
...context.args,
|
||||
...dimension1.props(value1),
|
||||
...dimension2.props(value2),
|
||||
...dimension3.props(value3),
|
||||
...dimension4.props(value4),
|
||||
}}
|
||||
/>
|
||||
</StyledElementContainer>
|
||||
</StyledCellContainer>
|
||||
);
|
||||
})}
|
||||
</StyledRowContainer>
|
||||
))}
|
||||
</StyledRowsContainer>
|
||||
))}
|
||||
</StyledColumnContainer>
|
||||
))}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,13 @@
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
|
||||
|
||||
export const ComponentDecorator: Decorator = (Story, context) => {
|
||||
const { container } = context.parameters;
|
||||
|
||||
return (
|
||||
<ComponentStorybookLayout width={container?.width}>
|
||||
<Story />
|
||||
</ComponentStorybookLayout>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,14 @@
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
|
||||
export const ComponentWithRecoilScopeDecorator: Decorator = (
|
||||
Story,
|
||||
context,
|
||||
) => (
|
||||
<RecoilScope
|
||||
CustomRecoilScopeContext={context.parameters.customRecoilScopeContext}
|
||||
>
|
||||
<Story />
|
||||
</RecoilScope>
|
||||
);
|
||||
@ -0,0 +1,12 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
|
||||
|
||||
export const ComponentWithRouterDecorator: Decorator = (Story) => (
|
||||
<ComponentStorybookLayout>
|
||||
<MemoryRouter>
|
||||
<Story />
|
||||
</MemoryRouter>
|
||||
</ComponentStorybookLayout>
|
||||
);
|
||||
@ -0,0 +1,9 @@
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
|
||||
|
||||
export const ObjectMetadataItemsDecorator: Decorator = (Story) => (
|
||||
<ObjectMetadataItemsProvider>
|
||||
<Story />
|
||||
</ObjectMetadataItemsProvider>
|
||||
);
|
||||
@ -0,0 +1,59 @@
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
import { Decorator } from '@storybook/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
|
||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||
import { ClientConfigProvider } from '~/modules/client-config/components/ClientConfigProvider';
|
||||
import { DefaultLayout } from '~/modules/ui/layout/page/DefaultLayout';
|
||||
import { UserProvider } from '~/modules/users/components/UserProvider';
|
||||
|
||||
import { FullHeightStorybookLayout } from '../FullHeightStorybookLayout';
|
||||
|
||||
export type PageDecoratorArgs = {
|
||||
routePath: string;
|
||||
routeParams: RouteParams;
|
||||
};
|
||||
|
||||
type RouteParams = {
|
||||
[param: string]: string;
|
||||
};
|
||||
|
||||
const computeLocation = (routePath: string, routeParams: RouteParams) => {
|
||||
return {
|
||||
pathname: routePath.replace(
|
||||
/:(\w+)/g,
|
||||
(paramName) => routeParams[paramName] ?? '',
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
export const PageDecorator: Decorator<{
|
||||
routePath: string;
|
||||
routeParams: RouteParams;
|
||||
}> = (Story, { args }) => (
|
||||
<RecoilRoot>
|
||||
<UserProvider>
|
||||
<ClientConfigProvider>
|
||||
<MemoryRouter
|
||||
initialEntries={[computeLocation(args.routePath, args.routeParams)]}
|
||||
>
|
||||
<FullHeightStorybookLayout>
|
||||
<HelmetProvider>
|
||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||
<RelationPickerScope relationPickerScopeId="relation-picker">
|
||||
<DefaultLayout>
|
||||
<Routes>
|
||||
<Route path={args.routePath} element={<Story />} />
|
||||
</Routes>
|
||||
</DefaultLayout>
|
||||
</RelationPickerScope>
|
||||
</SnackBarProviderScope>
|
||||
</HelmetProvider>
|
||||
</FullHeightStorybookLayout>
|
||||
</MemoryRouter>
|
||||
</ClientConfigProvider>
|
||||
</UserProvider>
|
||||
</RecoilRoot>
|
||||
);
|
||||
@ -0,0 +1,9 @@
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
|
||||
|
||||
export const RelationPickerDecorator: Decorator = (Story) => (
|
||||
<RelationPickerScope relationPickerScopeId="relation-picker">
|
||||
<Story />
|
||||
</RelationPickerScope>
|
||||
);
|
||||
@ -0,0 +1,19 @@
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import { Decorator } from '@storybook/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { ApolloMetadataClientProvider } from '@/object-metadata/components/ApolloMetadataClientProvider';
|
||||
|
||||
import { InitializeHotkeyStorybookHookEffect } from '../InitializeHotkeyStorybookHook';
|
||||
import { mockedClient } from '../mockedClient';
|
||||
|
||||
export const RootDecorator: Decorator = (Story) => (
|
||||
<RecoilRoot>
|
||||
<ApolloProvider client={mockedClient}>
|
||||
<ApolloMetadataClientProvider>
|
||||
<InitializeHotkeyStorybookHookEffect />
|
||||
<Story />
|
||||
</ApolloMetadataClientProvider>
|
||||
</ApolloProvider>
|
||||
</RecoilRoot>
|
||||
);
|
||||
@ -0,0 +1,9 @@
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||
|
||||
export const SnackBarDecorator: Decorator = (Story) => (
|
||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||
<Story />
|
||||
</SnackBarProviderScope>
|
||||
);
|
||||
Reference in New Issue
Block a user