Skip to content

Commit

Permalink
feat(ui): add date-picker component
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Jun 27, 2022
1 parent d70e541 commit 83a33a7
Show file tree
Hide file tree
Showing 53 changed files with 1,760 additions and 515 deletions.
3 changes: 2 additions & 1 deletion packages/site/src/app/styles/_app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ h3 {
'Radio': 'radio',
'Input': 'input',
'Switch': 'switch',
'Time-picker': 'time-picker'
'Time-picker': 'time-picker',
'Date-picker': 'date-picker'
)
{
section[id^='#{$id}'] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,30 @@ import {
useElement,
useUpdatePosition,
} from '../../hooks';
import { ClockCircleOutlined, CloseCircleFilled, SwapRightOutlined } from '../../icons';
import { CloseCircleFilled, SwapRightOutlined } from '../../icons';
import { getClassName, getNoTransformSize, getVerticalSidePosition } from '../../utils';
import { ICON_SIZE } from '../../utils/global';
import { DBaseDesign } from '../_base-design';
import { DBaseInput } from '../_base-input';
import { DTransition } from '../_transition';

export type DExtendsTimeInputProps = Pick<
DTimeInputProps,
'dFormControl' | 'dPlacement' | 'dSize' | 'dRange' | 'dClearable' | 'dDisabled' | 'onClear' | 'onVisibleChange'
>;

export interface DTimeInputRef {
export interface DDateInputRef {
updatePosition: () => void;
}

export interface DTimeInputRenderProps {
tiStyle: React.CSSProperties;
'data-time-input-popupid': string;
tiOnMouseDown: React.MouseEventHandler;
tiOnMouseUp: React.MouseEventHandler;
export interface DDateInputRenderProps {
diStyle: React.CSSProperties;
'data-date-input-popupid': string;
diOnMouseDown: React.MouseEventHandler;
diOnMouseUp: React.MouseEventHandler;
}

export interface DTimeInputProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
children: (props: DTimeInputRenderProps) => JSX.Element | null;
export interface DDateInputProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
children: (props: DDateInputRenderProps) => JSX.Element | null;
dFormControl?: DFormControl;
dVisible?: boolean;
dPlacement?: 'top' | 'top-left' | 'top-right' | 'bottom' | 'bottom-left' | 'bottom-right';
dSuffix?: React.ReactNode;
dSize?: DSize;
dRange?: boolean;
dClearable?: boolean;
Expand All @@ -54,16 +50,17 @@ export interface DTimeInputProps extends Omit<React.HTMLAttributes<HTMLDivElemen
}

const TTANSITION_DURING = 116;
function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef>) {
function DateInput(props: DDateInputProps, ref: React.ForwardedRef<DDateInputRef>) {
const {
children,
dFormControl,
dVisible = false,
dVisible,
dSuffix,
dPlacement = 'bottom-left',
dSize,
dRange = false,
dClearable = false,
dDisabled = false,
dRange,
dClearable,
dDisabled,
dInputProps,
dInputRef,
onVisibleChange,
Expand Down Expand Up @@ -117,10 +114,10 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
const clearable = dClearable && !dVisible && !dDisabled;

const containerEl = useElement(() => {
let el = document.getElementById(`${dPrefix}time-input-root`);
let el = document.getElementById(`${dPrefix}date-input-root`);
if (!el) {
el = document.createElement('div');
el.id = `${dPrefix}time-input-root`;
el.id = `${dPrefix}date-input-root`;
document.body.appendChild(el);
}
return el;
Expand All @@ -134,7 +131,7 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
});
const [transformOrigin, setTransformOrigin] = useState<string>();
const updatePosition = useEventCallback(() => {
const popupEl = document.querySelector(`[data-time-input-popupid="${uniqueId}"]`) as HTMLElement | null;
const popupEl = document.querySelector(`[data-date-input-popupid="${uniqueId}"]`) as HTMLElement | null;
if (boxRef.current && popupEl) {
const { width, height } = getNoTransformSize(popupEl);
const { top, left, transformOrigin } = getVerticalSidePosition(boxRef.current, { width, height }, dPlacement, 8);
Expand All @@ -155,7 +152,7 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
});
}

const popupEl = document.querySelector(`[data-time-input-popupid="${uniqueId}"]`) as HTMLElement | null;
const popupEl = document.querySelector(`[data-date-input-popupid="${uniqueId}"]`) as HTMLElement | null;
if (popupEl) {
asyncGroup.onResize(popupEl, () => {
updatePosition();
Expand Down Expand Up @@ -221,7 +218,7 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
<DBaseInput
{...inputProps}
ref={isLeft ? combineInputRefLeft : combineInputRefRight}
className={getClassName(inputProps?.className, `${dPrefix}time-input__input`)}
className={getClassName(inputProps?.className, `${dPrefix}date-input__input`)}
type="text"
autoComplete="off"
disabled={dDisabled}
Expand Down Expand Up @@ -271,8 +268,8 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
<div
{...restProps}
ref={boxRef}
className={getClassName(className, `${dPrefix}time-input`, {
[`${dPrefix}time-input--${dSize}`]: dSize,
className={getClassName(className, `${dPrefix}date-input`, {
[`${dPrefix}date-input--${dSize}`]: dSize,
'is-disabled': dDisabled,
'is-focus': isFocus,
})}
Expand All @@ -298,14 +295,14 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
{getInputNode(true)}
{dRange && (
<>
<div ref={indicatorRef} className={`${dPrefix}time-input__indicator`}></div>
<SwapRightOutlined className={`${dPrefix}time-input__separator`} />
<div ref={indicatorRef} className={`${dPrefix}date-input__indicator`}></div>
<SwapRightOutlined className={`${dPrefix}date-input__separator`} />
{getInputNode(false)}
</>
)}
{clearable && (
<button
className={getClassName(`${dPrefix}icon-button`, `${dPrefix}time-input__clear`)}
className={getClassName(`${dPrefix}icon-button`, `${dPrefix}date-input__clear`)}
style={{ width: iconSize, height: iconSize }}
aria-label={t('Common', 'Clear')}
onClick={(e) => {
Expand All @@ -317,7 +314,11 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
<CloseCircleFilled dSize={iconSize} />
</button>
)}
<ClockCircleOutlined className={`${dPrefix}time-input__icon`} style={{ opacity: clearable ? 0 : 1 }} dSize={iconSize} />
{dSuffix && (
<div className={`${dPrefix}date-input__icon`} style={{ opacity: clearable ? 0 : 1, fontSize: iconSize }}>
{dSuffix}
</div>
)}
</div>
</DBaseDesign>
{containerEl &&
Expand Down Expand Up @@ -355,14 +356,14 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
}

return children({
tiStyle: {
diStyle: {
...popupPositionStyle,
...transitionStyle,
zIndex: maxZIndex,
},
'data-time-input-popupid': uniqueId,
tiOnMouseDown: preventBlur,
tiOnMouseUp: preventBlur,
'data-date-input-popupid': uniqueId,
diOnMouseDown: preventBlur,
diOnMouseUp: preventBlur,
});
}}
</DTransition>,
Expand All @@ -372,4 +373,4 @@ function TimeInput(props: DTimeInputProps, ref: React.ForwardedRef<DTimeInputRef
);
}

export const DTimeInput = React.forwardRef(TimeInput);
export const DDateInput = React.forwardRef(DateInput);
1 change: 1 addition & 0 deletions packages/ui/src/components/_date-input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DateInput';
13 changes: 4 additions & 9 deletions packages/ui/src/components/_popup/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import { filter } from 'rxjs';

import { useAsync, useElement, useEventCallback, usePrefixConfig, useUpdatePosition } from '../../hooks';

export type DExtendsPopupProps = Pick<
DPopupProps,
'dDisabled' | 'dTrigger' | 'dMouseEnterDelay' | 'dMouseLeaveDelay' | 'dEscClosable' | 'onVisibleChange'
>;

export interface DPopupPopupRenderProps {
'data-popup-popupid': string;
pOnMouseEnter?: React.MouseEventHandler;
Expand All @@ -31,7 +26,7 @@ export interface DPopupProps {
dVisible: boolean;
dPopup: (props: DPopupPopupRenderProps) => JSX.Element | null;
dContainer?: HTMLElement | null;
dTrigger?: 'hover' | 'focus' | 'click';
dTrigger: 'hover' | 'focus' | 'click';
dDisabled?: boolean;
dEscClosable?: boolean;
dMouseEnterDelay?: number;
Expand All @@ -46,9 +41,9 @@ export function DPopup(props: DPopupProps) {
dVisible,
dPopup,
dContainer,
dTrigger = 'hover',
dDisabled = false,
dEscClosable = true,
dTrigger,
dDisabled,
dEscClosable,
dMouseEnterDelay = 150,
dMouseLeaveDelay = 200,
onVisibleChange,
Expand Down
25 changes: 5 additions & 20 deletions packages/ui/src/components/_selectbox/Selectbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,6 @@ import { DBaseInput } from '../_base-input';
import { DFocusVisible } from '../_focus-visible';
import { DTransition } from '../_transition';

export type DExtendsSelectboxProps = Pick<
DSelectboxProps,
| 'dFormControl'
| 'dPlaceholder'
| 'dSize'
| 'dLoading'
| 'dSearchable'
| 'dClearable'
| 'dDisabled'
| 'dInputProps'
| 'dInputRef'
| 'onClear'
| 'onVisibleChange'
>;

export interface DSelectboxRef {
updatePosition: () => void;
}
Expand Down Expand Up @@ -76,16 +61,16 @@ function Selectbox(props: DSelectboxProps, ref: React.ForwardedRef<DSelectboxRef
const {
children,
dFormControl,
dVisible = false,
dVisible,
dContent,
dContentTitle,
dPlaceholder,
dSuffix,
dSize,
dLoading = false,
dSearchable = false,
dClearable = false,
dDisabled = false,
dLoading,
dSearchable,
dClearable,
dDisabled,
dInputProps,
dInputRef,
onUpdatePosition,
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/components/_time-input/index.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/ui/src/components/_transition/Transition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const [T_ENTER, T_ENTERING, T_ENTERED, T_LEAVE, T_LEAVING, T_LEAVED] = [

export interface DTransitionProps {
children: (state: DTransitionState) => JSX.Element | null;
dIn: boolean;
dIn?: boolean;
dDuring: number | { enter: number; leave: number };
dMountBeforeFirstEnter?: boolean;
dSkipFirstTransition?: boolean | [boolean, boolean];
Expand All @@ -27,7 +27,7 @@ export interface DTransitionProps {
export function DTransition(props: DTransitionProps) {
const {
children,
dIn,
dIn = false,
dDuring,
dMountBeforeFirstEnter = true,
dSkipFirstTransition = true,
Expand Down
42 changes: 28 additions & 14 deletions packages/ui/src/components/cascader/Cascader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { DId, DNestedChildren } from '../../utils/global';
import type { DExtendsSelectboxProps } from '../_selectbox';
import type { DId, DNestedChildren, DSize } from '../../utils/global';
import type { DDropdownOption } from '../dropdown';
import type { DFormControl } from '../form';
import type { DSelectOption } from '../select';
import type { AbstractTreeNode } from '../tree';

Expand Down Expand Up @@ -34,12 +34,17 @@ export interface DCascaderOption<V extends DId> {
disabled?: boolean;
}

export interface DCascaderProps<V extends DId, T extends DCascaderOption<V>>
extends React.HTMLAttributes<HTMLDivElement>,
DExtendsSelectboxProps {
export interface DCascaderProps<V extends DId, T extends DCascaderOption<V>> extends React.HTMLAttributes<HTMLDivElement> {
dFormControl?: DFormControl;
dModel?: V | null | V[];
dOptions: DNestedChildren<T>[];
dVisible?: boolean;
dPlaceholder?: string;
dSize?: DSize;
dLoading?: boolean;
dSearchable?: boolean;
dClearable?: boolean;
dDisabled?: boolean;
dMultiple?: boolean;
dOnlyLeafSelectable?: boolean;
dCustomOption?: (option: DNestedChildren<T>) => React.ReactNode;
Expand All @@ -49,35 +54,41 @@ export interface DCascaderProps<V extends DId, T extends DCascaderOption<V>>
sort?: (a: DNestedChildren<T>, b: DNestedChildren<T>) => number;
};
dPopupClassName?: string;
dInputProps?: React.InputHTMLAttributes<HTMLInputElement>;
dInputRef?: React.Ref<HTMLInputElement>;
onModelChange?: (value: any, option: any) => void;
onVisibleChange?: (visible: boolean) => void;
onSearch?: (value: string) => void;
onClear?: () => void;
onFocusChange?: (value: V, option: DNestedChildren<T>) => void;
}

const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DCascader' });
function Cascader<V extends DId, T extends DCascaderOption<V>>(props: DCascaderProps<V, T>, ref: React.ForwardedRef<DCascaderRef>) {
const {
dFormControl,
dModel,
dOptions,
dVisible,
dPlaceholder,
dSize,
dLoading = false,
dSearchable = false,
dClearable = false,
dDisabled = false,
dMultiple = false,
dOnlyLeafSelectable = true,
dCustomOption,
dCustomSelected,
dCustomSearch,
dPopupClassName,
onModelChange,
onSearch,
onFocusChange,

dFormControl,
dLoading,
dSearchable,
dDisabled,
dSize,
dInputProps,
dInputRef,
onModelChange,
onVisibleChange,
onSearch,
onClear,
onFocusChange,

className,
...restProps
Expand Down Expand Up @@ -348,10 +359,12 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(props: DCascaderP
dVisible={visible}
dContent={hasSelected && selectedNode}
dContentTitle={selectedLabel}
dPlaceholder={dPlaceholder}
dSuffix={suffixNode}
dSize={size}
dLoading={dLoading}
dSearchable={dSearchable}
dClearable={dClearable}
dDisabled={disabled}
dInputProps={{
...dInputProps,
Expand All @@ -374,6 +387,7 @@ function Cascader<V extends DId, T extends DCascaderOption<V>>(props: DCascaderP
}
},
}}
dInputRef={dInputRef}
onUpdatePosition={(boxEl) => {
const popupEl = popupRef.current;
if (popupEl) {
Expand Down
Loading

0 comments on commit 83a33a7

Please sign in to comment.