Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 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
8 changes: 8 additions & 0 deletions docs/demo/focus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: focus
nav:
title: Demo
path: /demo
---

<code src="../examples/focus.tsx"></code>
55 changes: 55 additions & 0 deletions docs/examples/focus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { useLayoutEffect, useRef, useState } from 'react';
import '../../assets/index.less';
import { Picker, RangePicker, type PickerRef } from '../../src';
import momentGenerateConfig from '../../src/generate/moment';
import zhCN from '../../src/locale/zh_CN';
import type { RangePickerRef } from '../../src/interface';

const MyPicker = () => {
const ref = useRef<PickerRef>(null);
useLayoutEffect(() => {
if (ref.current) {
ref.current.focus({ preventScroll: true });
}
}, []);

return (
<div>
<Picker open locale={zhCN} generateConfig={momentGenerateConfig} ref={ref} />
</div>
);
};

const MyRangePicker = () => {
const ref = useRef<RangePickerRef>(null);
useLayoutEffect(() => {
if (ref.current) {
ref.current.focus({ preventScroll: true, index: 1 });
}
}, []);

return (
<div>
<RangePicker open locale={zhCN} generateConfig={momentGenerateConfig} ref={ref} />
</div>
);
};

const Demo = () => {
const [open, setOpen] = useState(false);
const [open2, setOpen2] = useState(false);
return (
<div>
<div style={{ height: '50vh' }} />
<a onClick={() => setOpen(!open)}>picker {`${open}`}</a>
<br />
<a onClick={() => setOpen2(!open2)}>rangePicker {`${open2}`}</a>
<div style={{ height: '80vh' }} />
{open && <MyPicker />}
{open2 && <MyRangePicker />}
<div style={{ height: '30vh' }} />
</div>
);
};

export default Demo;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"gh-pages": "npm run build && father doc deploy",
"prepublishOnly": "npm run compile && np --yolo --no-publish",
"lint": "eslint src/ --ext .ts,.tsx,.jsx,.js,.md",
"lint:tsc": "tsc -p tsconfig.json --noEmit",
"prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
"test": "rc-test",
"coverage": "father test --coverage",
Expand Down
12 changes: 6 additions & 6 deletions src/PickerInput/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
OnOpenChange,
OpenConfig,
PanelMode,
PickerRef,
RangePickerRef,
RangeTimeProps,
SelectorProps,
SharedHTMLAttrs,
Expand All @@ -26,7 +26,7 @@ import useCellRender from './hooks/useCellRender';
import useFieldsInvalidate from './hooks/useFieldsInvalidate';
import useFilledProps from './hooks/useFilledProps';
import useOpen from './hooks/useOpen';
import { usePickerRef } from './hooks/usePickerRef';
import usePickerRef from './hooks/usePickerRef';
import usePresets from './hooks/usePresets';
import useRangeActive from './hooks/useRangeActive';
import useRangeDisabledDate from './hooks/useRangeDisabledDate';
Expand Down Expand Up @@ -136,7 +136,7 @@ function getActiveRange(activeIndex: number) {

function RangePicker<DateType extends object = any>(
props: RangePickerProps<DateType>,
ref: React.Ref<PickerRef>,
ref: React.Ref<RangePickerRef>,
) {
// ========================= Prop =========================
const [filledProps, internalPicker, complexPicker, formatList, maskFormat, isInvalidateDate] =
Expand Down Expand Up @@ -412,7 +412,7 @@ function RangePicker<DateType extends object = any>(
if (nextIndex === null) {
triggerOpen(false, { force: true });
} else if (!skipFocus) {
selectorRef.current.focus(nextIndex);
selectorRef.current.focus({ index: nextIndex });
}
};

Expand All @@ -422,7 +422,7 @@ function RangePicker<DateType extends object = any>(
// Click to focus the enabled input
const enabledIndex = disabled.findIndex((d) => !d);
if (enabledIndex >= 0) {
selectorRef.current.focus(enabledIndex);
selectorRef.current.focus({ index: enabledIndex });
}
}

Expand Down Expand Up @@ -754,7 +754,7 @@ function RangePicker<DateType extends object = any>(
}

const RefRangePicker = React.forwardRef(RangePicker) as <DateType extends object = any>(
props: RangePickerProps<DateType> & React.RefAttributes<PickerRef>,
props: RangePickerProps<DateType> & React.RefAttributes<RangePickerRef>,
) => React.ReactElement;

if (process.env.NODE_ENV !== 'production') {
Expand Down
10 changes: 4 additions & 6 deletions src/PickerInput/Selector/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import useLockEffect from '../hooks/useLockEffect';
import Icon from './Icon';
import MaskFormat from './MaskFormat';
import { getMaskRange } from './util';
import type { PickerRef } from '../../interface';

// Format logic
//
Expand All @@ -22,11 +23,8 @@ import { getMaskRange } from './util';
// 2. Re-selection the mask cell
// 3. If `cacheValue` match the limit length or cell format (like 1 ~ 12 month), go to next cell

export interface InputRef {
nativeElement: HTMLDivElement;
export interface InputRef extends PickerRef {
inputElement: HTMLInputElement;
focus: VoidFunction;
blur: VoidFunction;
}

export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
Expand Down Expand Up @@ -97,8 +95,8 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
React.useImperativeHandle(ref, () => ({
nativeElement: holderRef.current,
inputElement: inputRef.current,
focus: () => {
inputRef.current.focus();
focus: (options) => {
inputRef.current.focus(options);
},
blur: () => {
inputRef.current.blur();
Expand Down
13 changes: 9 additions & 4 deletions src/PickerInput/Selector/RangeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import classNames from 'classnames';
import ResizeObserver from 'rc-resize-observer';
import { useEvent } from 'rc-util';
import * as React from 'react';
import type { SelectorProps, SelectorRef } from '../../interface';
import type { RangePickerRef, SelectorProps } from '../../interface';
import PickerContext from '../context';
import useInputProps from './hooks/useInputProps';
import useRootProps from './hooks/useRootProps';
Expand Down Expand Up @@ -46,7 +46,7 @@ export interface RangeSelectorProps<DateType = any> extends SelectorProps<DateTy

function RangeSelector<DateType extends object = any>(
props: RangeSelectorProps<DateType>,
ref: React.Ref<SelectorRef>,
ref: React.Ref<RangePickerRef>,
) {
const {
id,
Expand Down Expand Up @@ -138,8 +138,13 @@ function RangeSelector<DateType extends object = any>(

React.useImperativeHandle(ref, () => ({
nativeElement: rootRef.current,
focus: (index = 0) => {
getInput(index)?.focus();
focus: (options) => {
if (typeof options === 'object') {
const { index = 0, ...rest } = options || {};
getInput(index)?.focus(rest);
} else {
getInput(options ?? 0)?.focus();
}
},
blur: () => {
getInput(0)?.blur();
Expand Down
8 changes: 4 additions & 4 deletions src/PickerInput/Selector/SingleSelector/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import classNames from 'classnames';
import * as React from 'react';
import type { InternalMode, SelectorProps, SelectorRef } from '../../../interface';
import type { InternalMode, PickerRef, SelectorProps } from '../../../interface';
import { isSame } from '../../../utils/dateUtil';
import PickerContext from '../../context';
import type { PickerProps } from '../../SinglePicker';
Expand Down Expand Up @@ -36,7 +36,7 @@ export interface SingleSelectorProps<DateType extends object = any>

function SingleSelector<DateType extends object = any>(
props: SingleSelectorProps<DateType>,
ref: React.Ref<SelectorRef>,
ref: React.Ref<PickerRef>,
) {
const {
id,
Expand Down Expand Up @@ -116,8 +116,8 @@ function SingleSelector<DateType extends object = any>(

React.useImperativeHandle(ref, () => ({
nativeElement: rootRef.current,
focus: () => {
inputRef.current?.focus();
focus: (options) => {
inputRef.current?.focus(options);
},
blur: () => {
inputRef.current?.blur();
Expand Down
2 changes: 1 addition & 1 deletion src/PickerInput/SinglePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import useCellRender from './hooks/useCellRender';
import useFieldsInvalidate from './hooks/useFieldsInvalidate';
import useFilledProps from './hooks/useFilledProps';
import useOpen from './hooks/useOpen';
import { usePickerRef } from './hooks/usePickerRef';
import usePickerRef from './hooks/usePickerRef';
import usePresets from './hooks/usePresets';
import useRangeActive from './hooks/useRangeActive';
import useRangePickerValue from './hooks/useRangePickerValue';
Expand Down
16 changes: 11 additions & 5 deletions src/PickerInput/hooks/usePickerRef.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import * as React from 'react';
import type { PickerRef, SelectorRef } from '../../interface';
import type { PickerRef } from '../../interface';

export function usePickerRef(ref: React.Ref<PickerRef>) {
const selectorRef = React.useRef<SelectorRef>();
type BaseRefType = Omit<PickerRef, 'focus'>;
type Focus<OptionType> = (options?: OptionType) => void;
type PickerRefType<OptionType> = BaseRefType & {
focus: Focus<OptionType>;
};

export default function usePickerRef<OptionType>(ref: React.Ref<PickerRefType<OptionType>>) {
const selectorRef = React.useRef<PickerRefType<OptionType>>();

React.useImperativeHandle(ref, () => ({
nativeElement: selectorRef.current?.nativeElement,
focus: () => {
selectorRef.current?.focus();
focus: (options) => {
selectorRef.current?.focus(options);
},
blur: () => {
selectorRef.current?.blur();
Expand Down
14 changes: 7 additions & 7 deletions src/interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -432,12 +432,18 @@ export interface SharedPickerProps<DateType extends object = any>
renderExtraFooter?: (mode: PanelMode) => React.ReactNode;
}

// picker
export interface PickerRef {
nativeElement: HTMLDivElement;
focus: VoidFunction;
focus: (options?: FocusOptions) => void;
blur: VoidFunction;
}

// rangePicker
export interface RangePickerRef extends Omit<PickerRef, 'focus'> {
focus: (index?: number | (FocusOptions & { index?: number })) => void;
}

// ======================== Selector ========================
export interface OpenConfig {
index?: number;
Expand Down Expand Up @@ -506,12 +512,6 @@ export interface SelectorProps<DateType = any> extends SharedHTMLAttrs {
inputReadOnly?: boolean;
}

export interface SelectorRef {
nativeElement: HTMLDivElement;
focus: (index?: number) => void;
blur: VoidFunction;
}

// ========================== MISC ==========================
// https://stackoverflow.com/a/39495173; need TypeScript >= 4.5
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
Expand Down
20 changes: 5 additions & 15 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,10 @@
"skipLibCheck": true,
"esModuleInterop": true,
"paths": {
"@/*": [
"src/*"
],
"@@/*": [
".dumi/tmp/*"
],
"rc-picker": [
"src/index.tsx"
]
"@/*": ["src/*"],
"@@/*": [".dumi/tmp/*"],
"rc-picker": ["src/index.tsx"]
}
},
"include": [
".dumirc.ts",
"**/*.ts",
"**/*.tsx"
]
}
"include": [".dumirc.ts", "src/**/*.ts", "src/**/*.tsx", "docs/examples/focus.tsx"]
}