Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.8.0]

### Added

- Added chart to `SummaryCard` component.
- Added `Statistic` component.
- Added `Grid.useBreakpoint()` hooks.
- Added `sidebarMode` for sidebarProps for `DashboardTemplate`.
- Support responsive for `DashboardTemplate`.
- Added `LineChart` component.

## [1.7.0]

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "1byte-react-design",
"version": "1.7.1",
"version": "1.8.0",
"description": "A simple React UI library",
"main": "dist/index.js",
"module": "dist/index.js",
Expand Down
6 changes: 6 additions & 0 deletions src/molecules/Grid/Grid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { RdGridComponent } from './types';
import { useBreakpoint } from './useBreakpoint';

export const Grid: RdGridComponent = {
useBreakpoint: useBreakpoint,
};
1 change: 1 addition & 0 deletions src/molecules/Grid/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './Col';
export * from './Grid';
export * from './Row';
export * from './types';
6 changes: 5 additions & 1 deletion src/molecules/Grid/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Col, GetProps, Row } from 'antd';
import { Col, GetProps, Grid, Row } from 'antd';
import { ComponentToken as GridComponentTokenAntd } from 'antd/es/grid/style';

//#region Define Ant Design types
type ColPropsAntd = GetProps<typeof Col>;
type RowPropsAntd = GetProps<typeof Row>;
type GridPropsAntd = GetProps<typeof Grid>;
//#endregion

//#region Define extended component tokens
Expand All @@ -13,11 +14,13 @@ type GridComponentTokenExtend = {};
//#region Define extended types
type ColPropsExtend = {};
type RowPropsExtend = {};
type GridPropsExtend = {};
//#endregion

//#region Export types
export type RdColProps = ColPropsAntd & ColPropsExtend;
export type RdRowProps = RowPropsAntd & RowPropsExtend;
export type RdGridProps = GridPropsAntd & GridPropsExtend;

export type RdGridComponentToken = GridComponentTokenAntd & GridComponentTokenExtend;
//#endregion
Expand All @@ -29,4 +32,5 @@ export type RdColComponent = React.ForwardRefExoticComponent<
export type RdRowComponent = React.ForwardRefExoticComponent<
RdRowProps & React.RefAttributes<HTMLDivElement>
>;
export type RdGridComponent = RdGridProps;
//#endregion
3 changes: 3 additions & 0 deletions src/molecules/Grid/useBreakpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Grid } from 'antd';

export const useBreakpoint = Grid.useBreakpoint;
42 changes: 42 additions & 0 deletions src/molecules/LineChart/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { LineConfig } from '@ant-design/plots';
import { formatDate } from '../../utils/datetime';
import { Empty } from '../Empty';
import { LineChartWrapper } from './styles';
import { LineChartProps } from './types';

export const LineChart: React.FC<LineChartProps> = props => {
const { data, valueLabel = 'value' } = props;

if (!data?.length) return <Empty />;

const lineProps: LineConfig = {
data,
xField: 'date' as keyof LineChartProps['data'][0],
yField: 'value' as keyof LineChartProps['data'][0],
point: {
shapeField: 'square',
sizeField: 4,
},
interaction: {
tooltip: {
marker: false,
},
},
style: {
lineWidth: 2,
},
tooltip: {
title: ({ date }) => {
return formatDate(date);
},
items: [
{
channel: 'y',
name: valueLabel,
},
],
},
};

return <LineChartWrapper {...lineProps} />;
};
4 changes: 4 additions & 0 deletions src/molecules/LineChart/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Line } from '@ant-design/plots';
import styled from '@emotion/styled'

export const LineChartWrapper = styled(Line)``;
14 changes: 14 additions & 0 deletions src/molecules/LineChart/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Line } from '@ant-design/plots/es/core/plots/line';
import { GetProps } from 'antd';

export interface LineDataItem {
date: Date | string;
value: number;
}

type LineChartPropsAntd = GetProps<Line>;

export interface LineChartProps extends Partial<LineChartPropsAntd> {
data: LineDataItem[];
valueLabel?: string;
}
13 changes: 13 additions & 0 deletions src/molecules/Statistic/Statistic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { forwardRef } from 'react';
import { StatisticStyled } from './styles';
import { Timer } from './Timer';
import { RdStatisticComponent, RdStatisticCompoundedComponent } from './types';

export const InternalStatistic: RdStatisticComponent = forwardRef((props, ref) => {
return <StatisticStyled {...props} ref={ref} />;
});

export const Statistic: RdStatisticCompoundedComponent =
InternalStatistic as RdStatisticCompoundedComponent;

Statistic.Timer = Timer;
6 changes: 6 additions & 0 deletions src/molecules/Statistic/Timer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { TimerStyled } from './styles';
import { RdStatisticTimerComponent } from './types';

export const Timer: RdStatisticTimerComponent = props => {
return <TimerStyled {...props} />;
};
2 changes: 2 additions & 0 deletions src/molecules/Statistic/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Statistic';
export * from './types';
7 changes: 7 additions & 0 deletions src/molecules/Statistic/styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styled from '@emotion/styled';
import { Statistic } from 'antd';
import { RdStatisticProps } from './types';

export const StatisticStyled = styled(Statistic as React.FC<RdStatisticProps>)``;

export const TimerStyled = styled(Statistic.Timer)``;
71 changes: 71 additions & 0 deletions src/molecules/Statistic/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Statistic, GetProps } from 'antd';
import { ComponentToken as StatisticComponentTokenAntd } from 'antd/es/drawer/style';
import { StatisticRef } from 'antd/es/statistic/Statistic';
import { ComponentProps } from 'react';

//#region Define Ant Design types
/**
* 📝 Explanation:
*
* Normally, when styling an Ant Design component, we can simply write:
* type StatisticPropsAntd = GetProps<typeof Statistic>;
*
* But Statistic is a special case:
* - Ant Design does NOT export a public interface for Statistic props (it relies on an internal type `StatisticReactProps`).
* - Because of this, when exporting styled(Statistic), TypeScript tries to expose `StatisticReactProps` and throws:
* ts(4023): "Exported variable '...' has or is using name 'StatisticReactProps' but cannot be named".
*
* 🚑 Workaround:
* - Instead of using `GetProps<typeof Statistic>`, we clone the props using a mapped type to create a "public" type:
* StatisticPublicProps = { [K in keyof ComponentProps<typeof Statistic>]: ComponentProps<typeof Statistic>[K] }
* - Then we wrap it in a `StatisticBase` component so that styled() only sees our public type,
* avoiding any reference to the internal Ant Design type.
*
* 🔮 Note:
* - If Ant Design exports a proper `StatisticProps` type in the future, we can remove this workaround
* and go back to the shorter version:
* type StatisticPropsAntd = GetProps<typeof Statistic>;
*/
type StatisticPropsAntd = {
[K in keyof ComponentProps<typeof Statistic>]: ComponentProps<typeof Statistic>[K];
};
type TimerPropsAntd = GetProps<typeof Statistic.Timer>;

type StatisticRefAntd = StatisticRef;

//#endregion

//#region Define extended component tokens
type StatisticComponentTokenExtend = {};
//#endregion

//#region Define extended types
type StatisticPropsExtend = {};
type TimerPropsExtend = {};

type StatisticRefExtend = {};
//#endregion

//#region Export types
export type RdStatisticProps = StatisticPropsAntd & StatisticPropsExtend;
export type RdStatisticTimerProps = TimerPropsAntd & TimerPropsExtend;
export type RdStatisticRef = StatisticRefAntd & StatisticRefExtend;
export type RdStatisticComponentToken = StatisticComponentTokenAntd & StatisticComponentTokenExtend;
//#endregion

//#region Define component types
// export type RdStatisticComponent = React.FC<RdStatisticProps>;
export type RdStatisticComponent = React.ForwardRefExoticComponent<
React.AriaAttributes & {
[key: `data-${string}`]: unknown;
} & Pick<React.HTMLAttributes<HTMLDivElement>, 'role'> &
RdStatisticProps &
React.RefAttributes<RdStatisticRef>
>;

export type RdStatisticTimerComponent = React.FC<RdStatisticTimerProps>;

export type RdStatisticCompoundedComponent = RdStatisticComponent & {
Timer: RdStatisticTimerComponent;
};
//#endregion
1 change: 1 addition & 0 deletions src/molecules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export * from './Skeleton';
export * from './Slider';
export * from './Space';
export * from './Spin';
export * from './Statistic';
export * from './Steps';
export * from './Switch';
export * from './Table';
Expand Down
2 changes: 1 addition & 1 deletion src/organisms/SummaryCard/styles.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import Statistic from 'antd/es/statistic/Statistic';
import { Card } from '../../molecules';
import { Statistic } from '../../molecules/Statistic';

export const SummaryCardWrapper = styled(Card)``;

Expand Down
69 changes: 59 additions & 10 deletions src/templates/DashboardTemplate/DashboardTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef } from 'react';
import { forwardRef, useState } from 'react';
import { Layout } from '../../molecules';
import DashboardTemplateFooter from './Footer';
import DashboardTemplateHeader from './Header';
Expand All @@ -18,25 +18,74 @@ const DashboardTemplateInternal: RdDashboardTemplateComponent = forwardRef((prop
fitScreen = false,
...restProps
} = props;
const [collapsed, setCollapsed] = useState(false);

return (
<DashboardTemplateStyles ref={ref} fitScreen={fitScreen} {...restProps}>
{headerProps && <DashboardTemplateHeader {...headerProps} />}

<Layout hasSider={Boolean(siderProps)}>
{siderProps && <DashboardTemplateSider {...siderProps} />}
const handleToggleSider = () => {
setCollapsed(!collapsed);
};

const renderFullHeightLayout = () => (
<DashboardTemplateStyles
ref={ref}
fitScreen={fitScreen}
hasSider={Boolean(siderProps)}
{...restProps}
>
{siderProps && (
<DashboardTemplateSider
collapsed={collapsed}
toggleSider={handleToggleSider}
{...siderProps}
/>
)}
<Layout>
{headerProps && (
<DashboardTemplateHeader
collapsed={collapsed}
toggleSider={handleToggleSider}
{...headerProps}
/>
)}
<DashboardTemplateSkeletonLayout>
<DashboardTemplateContent fitScreen={fitScreen}>
{props.children}
</DashboardTemplateContent>
{footerProps && (
<DashboardTemplateFooter {...footerProps}></DashboardTemplateFooter>
)}
{footerProps && <DashboardTemplateFooter {...footerProps} />}
</DashboardTemplateSkeletonLayout>
</Layout>
</DashboardTemplateStyles>
);

const renderContentHeightLayout = () => (
<DashboardTemplateStyles ref={ref} fitScreen={fitScreen} {...restProps}>
{headerProps && (
<DashboardTemplateHeader
collapsed={collapsed}
toggleSider={handleToggleSider}
{...headerProps}
/>
)}
<Layout>
{siderProps && (
<DashboardTemplateSider
collapsed={collapsed}
toggleSider={handleToggleSider}
{...siderProps}
/>
)}
<DashboardTemplateSkeletonLayout hasSider={Boolean(siderProps)}>
<DashboardTemplateContent fitScreen={fitScreen}>
{props.children}
</DashboardTemplateContent>
{footerProps && <DashboardTemplateFooter {...footerProps} />}
</DashboardTemplateSkeletonLayout>
</Layout>
</DashboardTemplateStyles>
);

const sidebarMode = props.siderProps?.sidebarMode; // 'fullHeight' | 'contentHeight';

return sidebarMode === 'fullHeight' ? renderFullHeightLayout() : renderContentHeightLayout();
});

export const DashboardTemplate =
Expand Down
6 changes: 3 additions & 3 deletions src/templates/DashboardTemplate/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { forwardRef } from 'react';
import { DashboardTemplateHeaderStyles } from './styles';
import { DashboardTemplateHeaderContent, DashboardTemplateHeaderStyles } from './styles';
import { RdDashboardTemplateHeaderComponent } from './types';

export const DashboardTemplateHeader: RdDashboardTemplateHeaderComponent = forwardRef(
(props, ref) => {
const { children, render, ...restProps } = props;
const { children, render, collapsed, toggleSider, ...restProps } = props;

if (render) {
return render({ children, ...restProps });
}

return (
<DashboardTemplateHeaderStyles ref={ref} {...restProps}>
{children}
<DashboardTemplateHeaderContent flex={1}>{children}</DashboardTemplateHeaderContent>
</DashboardTemplateHeaderStyles>
);
}
Expand Down
Loading