Skip to content

Commit

Permalink
feat(timePicker): timePicker =< staticTimePicker, add new timePicker (#…
Browse files Browse the repository at this point in the history
…1430)

Co-authored-by: ZhaoChen <ittisennsinn@gmail.com>
  • Loading branch information
itiiss and itiisennsinn committed Nov 8, 2021
1 parent 012f195 commit b58df1d
Show file tree
Hide file tree
Showing 19 changed files with 395 additions and 144 deletions.
2 changes: 1 addition & 1 deletion src/locales/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import dateSelectorLocale from '../date-selector/locales/en-US';
import emptyLocale from '../empty/locales/en-US';
import listPickerLocale from '../list-picker/locales/en-US';
import modalLocale from '../legacy/modal/locales/en-US';
import timePickerLocale from '../time-picker/locales/en-US';
import timePickerLocale from '../static-time-picker/locales/en-US';
import timeSelectorLocale from '../time-selector/locales/en-US';
import searchBarLocale from '../legacy/search-bar/locales/en-US';
import cascaderLocale from '../legacy/cascader/locales/en-US';
Expand Down
29 changes: 29 additions & 0 deletions src/static-time-picker/StaticTimePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import classnames from 'classnames';
import PickerPanel from 'rc-picker/lib/PickerPanel';
import generateDateFns from 'rc-picker/lib/generate/dateFns';
import { useLocale, usePrefixCls } from '@gio-design/utils';
import defaultLocale from './locales/zh-CN';
import { StaticTimePickerProps } from './interfaces';

function StaticTimePicker({ className, showSecond = false, renderFooter, ...restProps }: StaticTimePickerProps) {
const prefixCls = usePrefixCls('new-time-picker');
const locale = useLocale('StaticTimePicker') || defaultLocale;

return (
<PickerPanel<Date>
{...restProps}
className={classnames({ [`${prefixCls}--three-columns`]: showSecond }, className)}
hideHeader
locale={locale}
prefixCls={prefixCls}
picker="time"
generateConfig={generateDateFns}
showNow={false}
showSecond={showSecond}
renderExtraFooter={renderFooter}
/>
);
}

export default StaticTimePicker;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { Basic, ShowSecond } from '../demos/TimePicker.stories';
import { Basic, ShowSecond } from '../demos/StaticTimePicker.stories';

describe('TimePicker', () => {
describe('StaticTimePicker', () => {
it('renders with default', () => {
render(<Basic />);
expect(screen.getAllByText('00')).toHaveLength(2);
Expand Down
28 changes: 28 additions & 0 deletions src/static-time-picker/demos/StaticTimePicker.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Subtitle, ArgsTable, Story, Canvas } from '@storybook/addon-docs';
import StaticTimePicker from '../StaticTimePicker';

# StaticTimePicker 时间选择器

<Subtitle>当用户需要一个时间,可以在面板中进行选择。</Subtitle>

## 代码演示

### 基本样式

最简单的用法,在面板中可以选择时间。

<Canvas>
<Story id="components-StaticTimePicker--basic" />
</Canvas>

### 显示秒

通过 `showSecond` 选项提供秒选择列。

<Canvas>
<Story id="components-StaticTimePicker--show-second" />
</Canvas>

## 参数说明

<ArgsTable of={StaticTimePicker} />
32 changes: 32 additions & 0 deletions src/static-time-picker/demos/StaticTimePicker.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { Story, Meta } from '@storybook/react/types-6-0';
import StaticTimePicker from '../StaticTimePicker';
import { StaticTimePickerProps } from '../interfaces';
import Docs from './StaticTimePicker.mdx';

import '../style';

export default {
title: 'Upgraded/StaticTimePicker',
component: StaticTimePicker,
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/kP3A6S2fLUGVVMBgDuUx0f/GIO-Components?node-id=4078%3A49236',
allowFullscreen: true,
},
docs: {
page: Docs,
},
},
} as Meta;

const Template: Story<StaticTimePickerProps> = (args) => <StaticTimePicker {...args} />;

export const Basic = Template.bind({});
Basic.args = {};

export const ShowSecond = Template.bind({});
ShowSecond.args = {
showSecond: true,
};
48 changes: 48 additions & 0 deletions src/static-time-picker/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { PanelMode, Locale } from 'rc-picker/lib/interface';
import { CommonProps } from '@gio-design/utils';

export type StaticTimePickerLocale = Omit<Locale, 'locale'>;

export interface StaticTimePickerProps extends CommonProps {
/**
* 自定义 CSS 样式名
*/
className?: string;
/**
* 默认选择的时间
*/
defaultValue?: Date;
/**
* 国际化配置
*/
locale?: StaticTimePickerLocale;
/**
* 日历面板切换的回调
*
* @param value - 当前时间 `Date`
* @param mode - 当前模式,目前只会是 `date` 模式
*/
onPanelChange?: (value: Date, mode: PanelMode) => void;
/**
* 时间发生变化时的回调
*
* @param value - 选择的时间 `Date`
*/
onSelect?: (value: Date) => void;
/**
* 自定义面板底部
*/
renderFooter?: (mode: PanelMode) => React.ReactNode;
/**
* 显示秒
*/
showSecond?: boolean;
/**
* 选择的时间
*/
value?: Date;
/**
* 可见日历中的时间
*/
viewDate?: Date;
}
5 changes: 5 additions & 0 deletions src/static-time-picker/locales/en-US.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import rcPickerLocale from 'rc-picker/lib/locale/en_US';

export default {
...rcPickerLocale,
};
5 changes: 5 additions & 0 deletions src/static-time-picker/locales/zh-CN.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import rcPickerLocale from 'rc-picker/lib/locale/zh_CN';

export default {
...rcPickerLocale,
};
84 changes: 84 additions & 0 deletions src/static-time-picker/style/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@import '../../stylesheet/index.less';

@new-time-picker-prefix-cls: ~'@{component-prefix}-new-time-picker';

.@{new-time-picker-prefix-cls} {
&-panel {
display: flex;
flex-direction: column;
width: fit-content;
height: fit-content;
padding-top: 4px;
background-color: @palette-white;
filter: drop-shadow(0 8px 24px rgba(36, 46, 89, 0.1));
}
&--three-columns {
.@{new-time-picker-prefix-cls}-time-panel-column {
padding-right: 10px;
padding-left: 10px;
}
}

&-content {
display: flex;
flex-direction: row;
width: fit-content;
}

&-time-panel {
&-column {
width: 40px;
height: 240px;
margin: 0;
padding: 8px 20px;
overflow: hidden scroll;
list-style-type: none;
border-right: 1px solid @palette-gray-3;

.scrollbar();
}
&-column:last-child {
border-right: none;
}

&-cell {
margin-top: 4px;
padding: 4px 12px;
color: @palette-black-6;
.font();
line-height: 22px;
list-style-type: none;
background-color: @palette-white;
border-radius: 4px;
cursor: pointer;

&:hover {
background-color: @palette-gray-3;
}

&-selected,
&:active {
color: @palette-blue-5;
font-weight: 500;
background-color: @palette-gray-1;
}

&-inner {
display: inline-block;
}
}
}

&-footer {
border-top: 1px solid @palette-gray-3;

&-extra {
display: flex;
justify-content: space-between;
padding: 12px;
}
}
&-ranges {
display: none;
}
}
1 change: 1 addition & 0 deletions src/static-time-picker/style/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './index.less';
125 changes: 106 additions & 19 deletions src/time-picker/TimePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,116 @@
import React from 'react';
import classnames from 'classnames';
import PickerPanel from 'rc-picker/lib/PickerPanel';
import generateDateFns from 'rc-picker/lib/generate/dateFns';
import { useLocale, usePrefixCls } from '@gio-design/utils';
import defaultLocale from './locales/zh-CN';
import { StopWatchOutlined } from '@gio-design/icons';
import { useLocale, useControlledState, usePrefixCls } from '@gio-design/utils';
import { format } from 'date-fns';
import Button from '../button';
import Popover from '../popover';
import { InputButton } from '../input';
import StaticTimePicker from '../static-time-picker/StaticTimePicker';
import { TimePickerProps } from './interfaces';
import { TIME_FORMAT, TIME_WITH_SECOND_FORMAT } from './constant';
import defaultLocale from './locales/zh-CN';

function TimePicker({ className, showSecond = false, renderFooter, ...restProps }: TimePickerProps) {
const prefixCls = usePrefixCls('new-time-picker');
const locale = useLocale('TimePicker') || defaultLocale;
export const TimePicker: React.FC<TimePickerProps> = (props: TimePickerProps) => {
const {
defaultValue,
onSelect,
visible: popoverVisible,
placeholder,
showSecond = false,
value,
trigger,
disabled,
allowClear,
overlayClassName,
size,
prefix,
hidePrefix,
suffix,
locale: customizeLocale,
onVisibleChange,
...restProps
} = props;
const [visible, setVisible] = useControlledState(popoverVisible, false);
const [controlledValue, setControlledValue] = useControlledState(value, defaultValue);
const [time, setTime] = React.useState<Date | undefined>(controlledValue);
const prefixCls = usePrefixCls('time-picker-new');
const locale = useLocale('TimePicker');
const coalescedLocale = customizeLocale ?? locale ?? defaultLocale;
const { now, ok, timeSelect } = coalescedLocale;
const overlayCls = classnames(`${prefixCls}-overlay`, overlayClassName);

return (
<PickerPanel<Date>
{...restProps}
className={classnames({ [`${prefixCls}--three-columns`]: showSecond }, className)}
hideHeader
locale={locale}
prefixCls={prefixCls}
picker="time"
generateConfig={generateDateFns}
showNow={false}
const formatTime = (date: Date) => format(date, showSecond ? TIME_WITH_SECOND_FORMAT : TIME_FORMAT);

const handleOnPickerSelect = (currentValue: Date) => {
setTime(currentValue);
};

const handleOnOk = () => {
setControlledValue(time);
setVisible(false);
onSelect?.(time as Date, formatTime(time as Date));
};

const handleVisibleChange = (current: boolean) => {
setVisible(current);
onVisibleChange?.(current);
};

const handleOnNow = () => {
setTime(new Date());
};

const overlay = (
<StaticTimePicker
onSelect={handleOnPickerSelect}
locale={coalescedLocale}
renderFooter={() => (
<>
<Button type="text" size="small" onClick={handleOnNow}>
{now}
</Button>
<Button disabled={!time} type="primary" size="small" onClick={handleOnOk}>
{ok}
</Button>
</>
)}
showSecond={showSecond}
renderExtraFooter={renderFooter}
value={time}
/>
);
}

function renderTrigger() {
if (trigger) {
return <div>{trigger}</div>;
}
return (
<InputButton
prefix={prefix || <StopWatchOutlined />}
disabled={disabled}
allowClear={allowClear}
value={time && formatTime(time)}
placeholder={placeholder ?? timeSelect}
size={size}
suffix={suffix}
hidePrefix={hidePrefix}
/>
);
}

return (
<Popover
content={overlay}
trigger={['click', 'focus']}
visible={visible}
placement="bottomLeft"
overlayClassName={overlayCls}
onVisibleChange={handleVisibleChange}
{...restProps}
>
{renderTrigger()}
</Popover>
);
};

export default TimePicker;

1 comment on commit b58df1d

@vercel
Copy link

@vercel vercel bot commented on b58df1d Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.