DEV;Fix calendar and make doc for button

This commit is contained in:
Roman Jaroš 2021-07-05 22:24:48 +02:00 committed by romanjaros
parent 29d2e14be2
commit a2b87d77ce
24 changed files with 122 additions and 555 deletions

View file

@ -0,0 +1,34 @@
const path = require('path');
module.exports.append = (config) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
include: [path.join(__dirname, '../../packages'), path.join(__dirname, '../../stories')],
use: [
{
loader: require.resolve('awesome-typescript-loader'),
options: {
configFileName: 'tsconfig.json',
},
},
{
loader: require.resolve('react-docgen-typescript-loader'),
},
],
});
config.resolve.extensions.push('.ts', '.tsx', '.mdx', '.json');
config.resolve.alias = {
...config.resolve.alias,
'@treejs/components': path.join(__dirname, '../../packages/components/src'),
'@treejs/api': path.join(__dirname, '../../packages/api/src'),
'@treejs/auth': path.join(__dirname, '../../packages/auth/src'),
'@treejs/constants': path.join(__dirname, '../../packages/constants/src'),
'@treejs/forms': path.join(__dirname, '../../packages/forms/src'),
'@treejs/hooks': path.join(__dirname, '../../packages/hooks/src'),
'@treejs/localization': path.join(__dirname, '../../packages/localization/src'),
'@treejs/styles': path.join(__dirname, '../../packages/styles/src'),
'@treejs/types': path.join(__dirname, '../../packages/types/src'),
'@treejs/utils': path.join(__dirname, '../../packages/utils/src'),
};
return config;
};

View file

@ -1,7 +1,12 @@
const appendWebpackConfig = require('./webpack.config').append;
const appendWebpackConfig = require('./helpers/webpack.config').append;
module.exports = {
stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-postcss'],
addons: [
'@storybook/addon-links',
'@storybook/addon-docs',
'@storybook/addon-essentials',
'@storybook/addon-postcss',
],
webpackFinal: (config) => appendWebpackConfig(config),
};

View file

@ -0,0 +1 @@
<link href="https://fonts.googleapis.com/css?family=Ubuntu:400,700&amp;subset=cyrillic-ext" rel="stylesheet">

View file

@ -1,11 +1,9 @@
import '../packages/styles/src/global.css';
import './helpers/icons';
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
actions: {
argTypesRegex: '^on[A-Z].*',
},
};

View file

@ -1,34 +0,0 @@
const path = require('path');
module.exports.append = (config) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
include: [path.join(__dirname, '../packages'), path.join(__dirname, '../stories')],
use: [
{
loader: require.resolve('awesome-typescript-loader'),
options: {
configFileName: 'tsconfig.json',
},
},
{
loader: require.resolve('react-docgen-typescript-loader'),
},
],
});
config.resolve.extensions.push('.ts', '.tsx', '.json');
config.resolve.alias = {
...config.resolve.alias,
'@treejs/components': path.join(__dirname, '../packages/components/src'),
'@treejs/api': path.join(__dirname, '../packages/api/src'),
'@treejs/auth': path.join(__dirname, '../packages/auth/src'),
'@treejs/constants': path.join(__dirname, '../packages/constants/src'),
'@treejs/forms': path.join(__dirname, '../packages/forms/src'),
'@treejs/hooks': path.join(__dirname, '../packages/hooks/src'),
'@treejs/localization': path.join(__dirname, '../packages/localization/src'),
'@treejs/styles': path.join(__dirname, '../packages/styles/src'),
'@treejs/types': path.join(__dirname, '../packages/types/src'),
'@treejs/utils': path.join(__dirname, '../packages/utils/src'),
};
return config;
};

View file

@ -56,6 +56,7 @@
"devDependencies": {
"@babel/core": "^7.13.14",
"@storybook/addon-actions": "^6.3.2",
"@storybook/addon-docs": "^6.3.2",
"@storybook/addon-essentials": "^6.3.2",
"@storybook/addon-links": "^6.3.2",
"@storybook/addon-postcss": "^2.0.0",

View file

@ -1,4 +1,4 @@
import React, { useCallback } from 'react';
import React, { ReactNode, useCallback } from 'react';
import cx from 'classnames';
@ -6,7 +6,7 @@ import { STATUS } from '@treejs/types/common';
export type ButtonType = {
disabled?: boolean;
label: string | React.ReactElement;
label: string | ReactNode;
onClick?: () => void;
/**
* Define color

View file

@ -17,7 +17,7 @@ export type CalendarType = {
/**
* Custom component for show detail, used for view
*/
detailComponent?: React.FunctionComponent<DetailComponentProps>;
detail?: React.FunctionComponent<DetailComponentProps>;
/**
* Show color when mouse cursor move over cell
*/
@ -26,7 +26,7 @@ export type CalendarType = {
/**
* When type is WEEK, then use this prop for time column on left side
*/
timeColumnComponent?: React.FunctionComponent;
timeColumn?: React.FunctionComponent;
title?: string;
type?: CALENDAR_VIEW;
value?: Date;
@ -35,7 +35,7 @@ export type CalendarType = {
const todayDate: Date = new Date();
const Calendar: React.FC<CalendarType> = (props) => {
const { value, onChange, type = CALENDAR_VIEW.MONTH, title, detailComponent, timeColumnComponent, hover } = props;
const { value, onChange, type = CALENDAR_VIEW.MONTH, title, detail, timeColumn, hover } = props;
const [currentDate, setCurrentDate] = useState<Date>(isValid(new Date(value)) ? new Date(value) : todayDate);
@ -68,6 +68,7 @@ const Calendar: React.FC<CalendarType> = (props) => {
}, [todayDate]);
const handleClickDay = useCallback((date) => {
setCurrentDate(date);
if (!isNilOrEmpty(onChange)) {
onChange(date);
}
@ -102,7 +103,7 @@ const Calendar: React.FC<CalendarType> = (props) => {
>
<div className="table-row-group">
<div className="table-row">
{type === CALENDAR_VIEW.WEEK && timeColumnComponent && <div className="table-cell" />}
{type === CALENDAR_VIEW.WEEK && timeColumn && <div className="table-cell" />}
{WEEK_DAYS_SHORT.map((day, i) => (
<div className="table-cell uppercase pb-1.5 text-center font-bold" key={i}>
{day}
@ -112,16 +113,16 @@ const Calendar: React.FC<CalendarType> = (props) => {
{range(weekStart, weekEnd).map((i: number) => (
<React.Fragment key={i}>
<div className="table-row">
{type === CALENDAR_VIEW.WEEK &&
timeColumnComponent &&
React.createElement(timeColumnComponent)}
{type === CALENDAR_VIEW.WEEK && timeColumn
? React.createElement(timeColumn)
: null}
<CalendarView
row={i}
type={type}
hover={hover}
detailComponent={detailComponent}
detailComponent={detail}
onChange={handleClickDay}
value={value}
value={currentDate}
todayDate={todayDate}
currentDate={currentDate}
/>

View file

@ -25,7 +25,7 @@ const CalendarCell: React.FC<IProps> = (props) => {
return (
<div
className={cx('table-cell text-center align-top', {
className={cx('table-cell text-center align-top p-1', {
'hover:bg-focus cursor-pointer': hover && hasValue,
'border border-whitespace': hasValue && border,
'bg-primary-light': isToday,

View file

@ -55,7 +55,6 @@ const CalendarView: React.FC<IProps> = (props) => {
if (!isNilOrEmpty(day)) {
newDate = setDate(currentDate, day);
}
setValue(newDate);
if (!isNilOrEmpty(onChange)) {
onChange(newDate);
}

View file

@ -1,151 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`(component) ButtonPage should match snapshot 1`] = `
<Fragment>
<Title
size={4}
space={
Object {
"y": 5,
}
}
>
Button
</Title>
<Code
code="import Button from '@treejs/components/Button';"
language="js"
/>
<Section
title="Default"
>
<Grid
cols={4}
>
<GridCol>
<Code
language="html"
>
<Button
label="Send"
onClick={[Function]}
/>
</Code>
</GridCol>
</Grid>
</Section>
<Section
title="Status"
>
<Grid
cols={4}
>
<GridCol>
<Code
language="html"
>
<Button
label="Send"
onClick={[Function]}
status="info"
/>
</Code>
</GridCol>
<GridCol>
<Code
language="html"
>
<Button
label="Send"
onClick={[Function]}
status="success"
/>
</Code>
</GridCol>
<GridCol>
<Code
language="html"
>
<Button
label="Send"
onClick={[Function]}
status="warning"
/>
</Code>
</GridCol>
<GridCol>
<Code
language="html"
>
<Button
label="Send"
onClick={[Function]}
status="error"
/>
</Code>
</GridCol>
</Grid>
</Section>
<Section
title="Disabled"
>
<Grid
cols={4}
>
<GridCol>
<Code
language="html"
>
<Button
disabled={true}
label="Send"
onClick={[Function]}
/>
</Code>
</GridCol>
</Grid>
</Section>
<API
propDefinition={
Array [
Object {
"comment": Array [],
"isOptional": true,
"name": "disabled",
"type": "boolean",
},
Object {
"comment": Array [],
"isOptional": undefined,
"name": "label",
"type": "\\"string\\" | \\"ReactElement\\"",
},
Object {
"comment": Array [
"Callback for click event",
],
"isOptional": true,
"name": "onClick",
"type": "(): void",
},
Object {
"comment": Array [
"Define color",
],
"isOptional": true,
"name": "status",
"type": "STATUS",
},
Object {
"comment": Array [
"Type when is in form",
],
"isOptional": true,
"name": "type",
"type": "\\"submit\\" | \\"reset\\" | \\"button\\"",
},
]
}
/>
</Fragment>
`;

View file

@ -1,11 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import ButtonPage from '../';
describe('(component) ButtonPage', () => {
it('should match snapshot', () => {
expect(shallow(<ButtonPage />)).toMatchSnapshot();
});
});

View file

@ -1,89 +0,0 @@
import React from 'react';
import Button from '@treejs/components/Button';
import { Grid, GridCol } from '@treejs/components/Grid';
import Section from '@treejs/components/Section';
import Title from '@treejs/components/Title';
import { TITLE_SPACE_ENUM } from '@treejs/components/Title/types';
import { getMessage } from '@treejs/localization/message';
import { STATUS } from '@treejs/types/common';
import { noop } from '@treejs/utils';
import API from 'documentation/components/API';
import Code from 'documentation/components/Code';
import { ButtonLocalization } from 'documentation/localization/button';
import { MenuLocalization } from 'documentation/localization/menu';
import { generateDocumentationObject } from 'documentation/utils/documentation';
import { children, groups } from '../typedoc.json';
const propDefinition = generateDocumentationObject(groups, children);
const ButtonPage = (): React.ReactElement => {
return (
<>
<Title size={4} space={{ [TITLE_SPACE_ENUM.Y]: 5 }}>
{getMessage(MenuLocalization.button)}
</Title>
<Code code={`import Button from '@treejs/components/Button';`} language="js" />
<Section title={getMessage(ButtonLocalization.default)}>
<Grid cols={4}>
<GridCol>
<Code language="html">
<Button label={getMessage(ButtonLocalization.send)} onClick={noop} />
</Code>
</GridCol>
</Grid>
</Section>
<Section title={getMessage(ButtonLocalization.status)}>
<Grid cols={4}>
<GridCol>
<Code language="html">
<Button label={getMessage(ButtonLocalization.send)} onClick={noop} status={STATUS.info} />
</Code>
</GridCol>
<GridCol>
<Code language="html">
<Button
label={getMessage(ButtonLocalization.send)}
onClick={noop}
status={STATUS.success}
/>
</Code>
</GridCol>
<GridCol>
<Code language="html">
<Button
label={getMessage(ButtonLocalization.send)}
onClick={noop}
status={STATUS.warning}
/>
</Code>
</GridCol>
<GridCol>
<Code language="html">
<Button label={getMessage(ButtonLocalization.send)} onClick={noop} status={STATUS.error} />
</Code>
</GridCol>
</Grid>
</Section>
<Section title={getMessage(ButtonLocalization.disabled)}>
<Grid cols={4}>
<GridCol>
<Code language="html">
<Button label={getMessage(ButtonLocalization.send)} onClick={noop} disabled />
</Code>
</GridCol>
</Grid>
</Section>
<API propDefinition={propDefinition} />
</>
);
};
export default ButtonPage;

View file

@ -1,102 +0,0 @@
import React, { useCallback, useState } from 'react';
import Calendar from '@treejs/components/Calendar/components/Calendar';
import { CALENDAR_VIEW } from '@treejs/components/Calendar/types';
import { Grid, GridCol } from '@treejs/components/Grid';
import { GRID_SIZE_ENUM } from '@treejs/components/Grid/types';
import Section from '@treejs/components/Section';
import Title from '@treejs/components/Title';
import { TITLE_SPACE_ENUM } from '@treejs/components/Title/types';
import { getMessage } from '@treejs/localization/message';
import API from 'documentation/components/API';
import Code from 'documentation/components/Code';
import { MenuLocalization } from 'documentation/localization/menu';
import { CustomDayInWeek } from 'documentation/pages/CalendarPage/components/CustomDayInWeek';
import { generateDocumentationObject } from 'documentation/utils/documentation';
import { children, groups } from '../typedoc.json';
import CalendarTimeColumn from './CalendarTimeColumn';
import { CustomDayInMonth } from './CustomDayInMonth';
const propDefinition = generateDocumentationObject(groups, children);
const customDetailPropDefinition = generateDocumentationObject(groups, children, 'DetailComponentProps');
const CalendarPage = (): React.ReactElement => {
const [calendar, setCalendar] = useState(new Date());
const handleChangeCalendar = useCallback((value) => {
setCalendar(value);
}, []);
return (
<>
<Title size={4} space={{ [TITLE_SPACE_ENUM.Y]: 5 }}>
{getMessage(MenuLocalization.calendar)}
</Title>
<Grid>
<GridCol>
<Code code={`import Calendar from '@treejs/components/Calendar';`} language="js" />
</GridCol>
</Grid>
<Section title={'Mini'}>
<Grid cols={{ [GRID_SIZE_ENUM.SM]: 4 }}>
<GridCol>
<Code language="html">
<Calendar key="mini" title="Kalendář" onChange={setCalendar} value={calendar} hover />
</Code>
</GridCol>
</Grid>
</Section>
<Section title={'Vlastní komponenta'}>
<Grid
cols={{
[GRID_SIZE_ENUM.LG]: 2,
}}
>
<GridCol>
<Section>
<Code language="html">
<Calendar
key="month"
title="Měsíční"
onChange={handleChangeCalendar}
value={calendar}
detailComponent={CustomDayInMonth}
type={CALENDAR_VIEW.MONTH}
/>
</Code>
</Section>
</GridCol>
</Grid>
<Grid>
<GridCol>
<Section>
<Code language="html">
<Calendar
key="month"
title="Týdenní"
onChange={handleChangeCalendar}
value={calendar}
detailComponent={CustomDayInWeek}
timeColumnComponent={CalendarTimeColumn}
type={CALENDAR_VIEW.WEEK}
hover
/>
</Code>
</Section>
</GridCol>
</Grid>
</Section>
<API propDefinition={customDetailPropDefinition} title="DetailComponent API" />
<API propDefinition={propDefinition} />
</>
);
};
export default CalendarPage;

View file

@ -1,21 +0,0 @@
import React from 'react';
import cx from 'classnames';
type IProps = {
children?: any;
className?: string;
onClick?: (event: any) => void;
value: Date;
};
const CalendarHourCell: React.FC<IProps> = (props) => {
const { className, onClick, children } = props;
return (
<div className={cx('h-8 pt-0.5 ml-0.5 align-top select-none', className)} onClick={onClick}>
{children}
</div>
);
};
export default CalendarHourCell;

View file

@ -1,26 +0,0 @@
import React from 'react';
import { times } from 'ramda';
import { addMinutes, format } from 'date-fns';
import CalendarHourCell from './CalendarHourCell';
const CalendarTimeColumn: React.FC = () => {
return (
<div className="table-cell w-2">
<div className="h-4" />
{times(
(i) => (
<CalendarHourCell key={i} value={null} className="text-right text-xs mr-3">
{format(addMinutes(new Date(0, 0, 0, 8, 0), 30 * i), 'kk:mm')}
<br />
<br />
</CalendarHourCell>
),
16
)}
</div>
);
};
export default CalendarTimeColumn;

View file

@ -1,34 +0,0 @@
import React, { useMemo } from 'react';
import { times } from 'ramda';
import { format } from 'date-fns';
import CalendarCell from '@treejs/components/Calendar/components/CalendarCell';
import { DetailComponentProps } from '@treejs/components/Calendar/types';
export const CustomDayInMonth: React.FC<DetailComponentProps> = (props) => {
const { value, isToday, isSelected, onClick } = props;
const todayDay = format(value, 'dd');
const agenda = useMemo<{ [key: string]: React.ReactElement }>(() => {
const list: { [key: string]: React.ReactElement } = {};
times((i) => {
list[todayDay] = (
<div key={i} className="text-left m-1">
<div className="bg-primary p-1 my-1">todo</div>
</div>
);
}, Math.round(Math.random()));
return list;
}, [todayDay, todayDay]);
return (
<CalendarCell isToday={isToday} isSelected={isSelected} onClick={onClick} hasValue hover value={value} border>
<div className="p-1 h-24">
<div className="text-right text-sm">{format(value, 'dd')}</div>
{agenda[todayDay]}
</div>
</CalendarCell>
);
};

View file

@ -1,55 +0,0 @@
import React, { useCallback, useMemo } from 'react';
import { times } from 'ramda';
import cx from 'classnames';
import { addMinutes, format } from 'date-fns';
import CalendarCell from '@treejs/components/Calendar/components/CalendarCell';
import { DetailComponentProps } from '@treejs/components/Calendar/types';
import { isNilOrEmpty } from '@treejs/utils';
import CalendarHourCell from 'documentation/pages/CalendarPage/components/CalendarHourCell';
export const CustomDayInWeek: React.FC<DetailComponentProps> = (props) => {
const { value, isToday, onClick, hover } = props;
const handleClick = useCallback(
(value) => () => {
if (!isNilOrEmpty(onClick)) {
onClick(value);
}
},
[onClick]
);
const agenda = useMemo(() => {
return times((i) => {
const value = addMinutes(new Date(props.value).setHours(8, 0, 0, 0), 30 * i);
if (Math.round(Math.random())) {
return (
<CalendarHourCell
key={i}
value={value}
onClick={handleClick(value)}
className={cx({
'hover:bg-focus': hover,
})}
/>
);
} else {
return (
<CalendarHourCell key={i} value={value} className="text-left">
<div className="bg-primary h-full mt-0.5 p-1">event</div>
</CalendarHourCell>
);
}
}, 16);
}, [props.value]);
return (
<CalendarCell isToday={isToday} isSelected={false} hover={false} hasValue>
{format(value, 'dd')}
{agenda}
</CalendarCell>
);
};

View file

@ -1,4 +1,4 @@
import { Meta } from '@storybook/addon-docs/blocks';
import { Meta } from "@storybook/addon-docs/blocks";
<Meta title="Introduction" />

View file

@ -0,0 +1,41 @@
import Button from "@treejs/components/Button";
import { STATUS } from "@treejs/types/common";
import { ArgsTable, Story, Preview, Primary } from "@storybook/addon-docs";
import { action } from "@storybook/addon-actions";
<Meta
title={'Components/Button'}
component={Button}
parameters={{
layout: 'centered',
}}
/>
# Button
`import Button from '@treejs/components/Button';`
export const Template = (args) => <Button {...args} />
## Default Button
We can write the documentation related to the Default Button
<Preview withToolbar>
<Story name="Default Button" args={{
label: 'Default Button'
}}>
{Template.bind({})}
</Story>
</Preview>
## Large Button
We are writing sample docs for two stories, you can write rest of them
<Preview withToolbar>
<Story name="Large Button" args={{
label: "Large Button",
}}>
{Template.bind({})}
</Story>
</Preview>
<ArgsTable />

View file

@ -1,19 +1,31 @@
import React from 'react';
import { action } from '@storybook/addon-actions';
import { Meta, Story } from '@storybook/react';
import Button, { ButtonType } from '@treejs/components/Button';
import { STATUS } from '@treejs/types/common';
const Template: Story<ButtonType> = (args) => <Button {...args} />;
export const Default = Template.bind({});
Default.args = {
label: 'Button',
status: STATUS.none,
onClick: action('clicked'),
};
export const WithElement = Template.bind({});
WithElement.args = {
label: <b>Element</b>,
onClick: action('clicked'),
};
export default {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
docs: {
page: require('./Button.stories.mdx').default,
},
},
} as Meta;

View file

@ -13,26 +13,23 @@ const Template: Story<CalendarType> = (args) => <Calendar {...args} />;
export const Mini = Template.bind({});
Mini.args = {
key: 'mini',
title: 'Mini calendar',
hover: true,
};
export const Month = Template.bind({});
Month.args = {
key: 'month',
title: 'Month calendar',
detailComponent: CustomDayInMonth,
detail: CustomDayInMonth,
type: CALENDAR_VIEW.MONTH,
hover: true,
};
export const Week = Template.bind({});
Week.args = {
key: 'week',
title: 'Week calendar',
detailComponent: CustomDayInWeek,
timeColumnComponent: CalendarTimeColumn,
detail: CustomDayInWeek,
timeColumn: CalendarTimeColumn,
type: CALENDAR_VIEW.WEEK,
hover: true,
};

View file

@ -29,12 +29,13 @@
},
"types": [
"node",
"jest"
"jest",
]
},
"include": [
"./**/*.ts",
"./**/*.tsx"
"./**/*.tsx",
"./**/*.mdx"
],
"exclude": [
"node_modules",