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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ render(<Picker />, mountNode);
| onOpenChange | Function(open:boolean) | | called when open/close picker |
| onFocus | (evnet:React.FocusEventHandler<HTMLInputElement>) => void | | called like input's on focus |
| onBlur | (evnet:React.FocusEventHandler<HTMLInputElement>) => void | | called like input's on blur |
| direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. |

### PickerPanel

Expand All @@ -99,6 +100,7 @@ render(<Picker />, mountNode);
| onSelect | Function(date: moment) | | a callback function, can be executed when the selected time |
| onPanelChange | Function(value: moment, mode) | | callback when picker panel mode is changed |
| onMouseDown | (evnet:React.MouseEventHandler<HTMLInputElement>) => void | | callback when executed onMouseDown evnent |
| direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. |

### RangePicker

Expand All @@ -125,6 +127,7 @@ render(<Picker />, mountNode);
| disabled | Boolean | false | whether the range picker is disabled |
| onChange | Function(value:[moment], formatString: [string, string]) | | a callback function, can be executed when the selected time is changing |
| onCalendarChange | Function(value:[moment], formatString: [string, string]) | | a callback function, can be executed when the start time or the end time of the range is changing |
| direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. |

### showTime-options

Expand Down
44 changes: 40 additions & 4 deletions assets/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
.@{prefix-cls} {
display: inline-flex;

&-rtl {
direction: rtl;
}

&-focused {
border: 1px solid blue;
}

&-panel {
border: 1px solid #666;
background: @background-color;
Expand All @@ -18,6 +21,10 @@
&-focused {
border-color: blue;
}

&-rtl {
direction: rtl;
}
}

// ===================== Shared Panel =====================
Expand Down Expand Up @@ -237,6 +244,11 @@
display: block;
width: 100%;
text-align: left;

.@{prefix-cls}-panel-rtl & {
padding: 0 12px 0 0;
text-align: right;
}
}
}
}
Expand Down Expand Up @@ -274,6 +286,10 @@
display: inline-flex;
width: 100%;

.@{prefix-cls}-rtl & {
text-align: right;
}

> input {
width: 100%;
}
Expand All @@ -285,6 +301,11 @@
top: 0;
cursor: pointer;

.@{prefix-cls}-rtl & {
right: auto;
left: 4px;
}

&-btn::after {
content: '×';
}
Expand All @@ -306,13 +327,15 @@
// Panel
@arrow-size: 10px;

&-placement-topLeft {
&-placement-topLeft,
&-placement-topRight {
.@{prefix-cls}-range-arrow {
bottom: @arrow-size / 2 + 1px;
transform: rotate(135deg);
}
}
&-placement-bottomLeft {
&-placement-bottomLeft,
&-placement-bottomright {
.@{prefix-cls}-range-arrow {
top: @arrow-size / 2 + 1px;
transform: rotate(-45deg);
Expand All @@ -326,7 +349,14 @@
z-index: 1;
left: @arrow-size;
margin-left: 10px;
transition: left 0.3s;
transition: all 0.3s;

.@{prefix-cls}-dropdown-rtl& {
right: @arrow-size;
left: auto;
margin-left: 0;
margin-right: 10px;
}

&::before,
&::after {
Expand All @@ -336,6 +366,12 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

.@{prefix-cls}-dropdown-rtl& {
right: 50%;
left: auto;
transform: translate(50%, -50%);
}
}

&::before {
Expand Down
216 changes: 216 additions & 0 deletions examples/rtl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import React from 'react';
import moment, { Moment } from 'moment';
import Picker from '../src/Picker';
import RangePicker from '../src/RangePicker';
import PickerPanel from '../src/PickerPanel';
import momentGenerateConfig from '../src/generate/moment';
import zhCN from '../src/locale/zh_CN';
import enUS from '../src/locale/en_US';
import jaJP from '../src/locale/ja_JP';
import '../assets/index.less';

const defaultValue = moment('2019-11-28 01:02:03');

function formatDate(date: Moment | null) {
return date ? date.format('YYYY-MM-DD HH:mm:ss') : 'null';
}

export default () => {
const [value, setValue] = React.useState<Moment | null>(defaultValue);

const weekRef = React.useRef<Picker<Moment>>(null);

const onSelect = (newValue: Moment) => {
console.log('Select:', newValue);
};

const onChange = (newValue: Moment | null, formatString?: string) => {
console.log('Change:', newValue, formatString);
setValue(newValue);
};

const sharedProps = {
generateConfig: momentGenerateConfig,
value,
onSelect,
onChange,
direction: 'rtl',
};

const rangePickerRef = React.useRef<RangePicker<Moment>>(null);

return (
<div dir="rtl">
<h2>
Value:{' '}
{value ? `${formatDate(value[0])} ~ ${formatDate(value[1])}` : 'null'}
</h2>

<div style={{ display: 'flex', flexWrap: 'wrap' }}>
<div style={{ margin: '0 8px' }}>
<h3>Basic</h3>
<PickerPanel<Moment> {...sharedProps} locale={zhCN} />
</div>

<div style={{ margin: '0 8px' }}>
<h3>Uncontrolled</h3>
<PickerPanel<Moment>
generateConfig={momentGenerateConfig}
locale={zhCN}
onChange={onChange}
defaultValue={moment('2000-01-01', 'YYYY-MM-DD')}
/>
</div>

<div style={{ margin: '0 8px' }}>
<h3>1 Month earlier</h3>
<PickerPanel<Moment>
{...sharedProps}
defaultPickerValue={defaultValue.clone().subtract(1, 'month')}
locale={enUS}
/>
</div>

<div style={{ margin: '0 8px' }}>
<h3>Week Picker CN</h3>
<PickerPanel<Moment> {...sharedProps} locale={zhCN} picker="week" />
</div>

<div style={{ margin: '0 8px' }}>
<h3>Month Picker</h3>
<PickerPanel<Moment> {...sharedProps} locale={zhCN} picker="month" />
</div>

<div style={{ margin: '0 8px' }}>
<h3>Week Picker US</h3>
<PickerPanel<Moment> {...sharedProps} locale={enUS} picker="week" />
</div>

<div style={{ margin: '0 8px' }}>
<h3>Time</h3>
<PickerPanel<Moment> {...sharedProps} locale={jaJP} mode="time" />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Time AM/PM</h3>
<PickerPanel<Moment>
{...sharedProps}
locale={jaJP}
mode="time"
showTime={{
use12Hours: true,
showSecond: false,
format: 'hh:mm A',
}}
/>
</div>
<div style={{ margin: '0 8px' }}>
<h3>Datetime</h3>
<PickerPanel<Moment> {...sharedProps} locale={zhCN} showTime />
</div>
</div>

<div style={{ display: 'flex' }}>
<div style={{ margin: '0 8px' }}>
<h3>Basic</h3>
<Picker<Moment> {...sharedProps} locale={zhCN} />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Uncontrolled</h3>
<Picker<Moment>
generateConfig={momentGenerateConfig}
locale={zhCN}
allowClear
/>
</div>
<div style={{ margin: '0 8px' }}>
<h3>Datetime</h3>
<Picker<Moment>
{...sharedProps}
locale={zhCN}
defaultPickerValue={defaultValue.clone().subtract(1, 'month')}
showTime={{
showSecond: false,
defaultValue: moment('11:28:39', 'HH:mm:ss'),
}}
showToday
disabledTime={date => {
if (date && date.isSame(defaultValue, 'date')) {
return {
disabledHours: () => [1, 3, 5, 7, 9, 11],
};
}
return {};
}}
/>
</div>
<div style={{ margin: '0 8px' }}>
<h3>Uncontrolled Datetime</h3>
<Picker<Moment> generateConfig={momentGenerateConfig} locale={zhCN} />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Week</h3>
<Picker<Moment>
{...sharedProps}
locale={zhCN}
format="YYYY-Wo"
allowClear
picker="week"
renderExtraFooter={() => 'I am footer!!!'}
ref={weekRef}
/>

<button
type="button"
onClick={() => {
if (weekRef.current) {
weekRef.current.focus();
}
}}
>
Focus
</button>
</div>
<div style={{ margin: '0 8px' }}>
<h3>Week</h3>
<Picker<Moment>
generateConfig={momentGenerateConfig}
locale={zhCN}
picker="week"
/>
</div>
<div style={{ margin: '0 8px' }}>
<h3>Time</h3>
<Picker<Moment> {...sharedProps} locale={zhCN} picker="time" />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Time 12</h3>
<Picker<Moment>
{...sharedProps}
locale={zhCN}
picker="time"
use12Hours
/>
</div>
<div style={{ margin: '0 8px' }}>
<h3>Year</h3>
<Picker<Moment> {...sharedProps} locale={zhCN} picker="year" />
</div>
</div>

<div style={{ display: 'flex', flexWrap: 'wrap' }}>
<div style={{ margin: '0 8px' }}>
<h3>Basic RangePicker</h3>
<RangePicker<Moment>
{...sharedProps}
value={undefined}
locale={zhCN}
allowClear
ref={rangePickerRef}
defaultValue={[moment('1990-09-03'), moment('1989-11-28')]}
placeholder={['start...', 'end...']}
/>
</div>
</div>
</div>
);
};
8 changes: 8 additions & 0 deletions src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export interface PickerSharedProps<DateType> extends React.AriaAttributes {
// WAI-ARIA
role?: string;
name?: string;

direction?: 'ltr' | 'rtl';
}

type OmitPanelProps<Props> = Omit<
Expand Down Expand Up @@ -158,6 +160,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
onMouseLeave,
onContextMenu,
onClick,
direction,
} = props as MergedPickerProps<DateType>;

const inputRef = React.useRef<HTMLInputElement>(null);
Expand Down Expand Up @@ -357,6 +360,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
locale={locale}
tabIndex={-1}
onChange={setSelectedValue}
direction={direction}
/>
</div>
);
Expand Down Expand Up @@ -394,6 +398,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
triggerOpen(false, true);
}
};
const popupPlacement = direction === 'rtl' ? 'bottomRight' : 'bottomLeft';

return (
<PanelContext.Provider
Expand All @@ -414,11 +419,14 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
dropdownAlign={dropdownAlign}
getPopupContainer={getPopupContainer}
transitionName={transitionName}
popupPlacement={popupPlacement}
direction={direction}
>
<div
className={classNames(prefixCls, className, {
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-focused`]: focused,
[`${prefixCls}-rtl`]: direction === 'rtl',
})}
style={style}
onMouseDown={onMouseDown}
Expand Down
Loading