@laser-ui/components 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
4
4
 
5
+ # [2.6.0](https://github.com/laser-ui/laser-ui/compare/v2.5.0...v2.6.0) (2026-04-08)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **components:** fix number input cant enter `0.01` ([483f7f0](https://github.com/laser-ui/laser-ui/commit/483f7f099a25d68a89ba3899bc07fcd380513531))
10
+
11
+ # [2.5.0](https://github.com/laser-ui/laser-ui/compare/v2.4.0...v2.5.0) (2026-04-03)
12
+
13
+ ### Features
14
+
15
+ - **components:** cascader support `onScrollBottom` event ([19508bb](https://github.com/laser-ui/laser-ui/commit/19508bbd77fabdd3b884b40e77005d8f596985ac))
16
+
5
17
  # [2.4.0](https://github.com/laser-ui/laser-ui/compare/v2.3.5...v2.4.0) (2026-03-27)
6
18
 
7
19
  ### Bug Fixes
@@ -27,7 +27,7 @@ import { TREE_NODE_KEY } from '../tree/vars';
27
27
  import { getVerticalSidePosition, isPrintableCharacter, mergeCS } from '../utils';
28
28
  import { TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../vars';
29
29
  export function Cascader(props) {
30
- const _a = useComponentProps('Cascader', props), { ref, styleOverrides, styleProvider, formControl, list, model, defaultModel, visible: visibleProp, defaultVisible, placeholder, multiple = false, searchable = false, searchValue: searchValueProp, defaultSearchValue, onlyLeafSelectable = true, clearable: clearableProp = false, loading = false, size: sizeProp, disabled: disabledProp = false, virtual = false, escClosable = true, customItem, customSelected, customSearch, inputProps, popupRender, onModelChange, onVisibleChange, onSearch, onClear, onFirstFocus, afterVisibleChange } = _a, restProps = __rest(_a, ["ref", "styleOverrides", "styleProvider", "formControl", "list", "model", "defaultModel", "visible", "defaultVisible", "placeholder", "multiple", "searchable", "searchValue", "defaultSearchValue", "onlyLeafSelectable", "clearable", "loading", "size", "disabled", "virtual", "escClosable", "customItem", "customSelected", "customSearch", "inputProps", "popupRender", "onModelChange", "onVisibleChange", "onSearch", "onClear", "onFirstFocus", "afterVisibleChange"]);
30
+ const _a = useComponentProps('Cascader', props), { ref, styleOverrides, styleProvider, formControl, list, model, defaultModel, visible: visibleProp, defaultVisible, placeholder, multiple = false, searchable = false, searchValue: searchValueProp, defaultSearchValue, onlyLeafSelectable = true, clearable: clearableProp = false, loading = false, size: sizeProp, disabled: disabledProp = false, virtual = false, escClosable = true, customItem, customSelected, customSearch, inputProps, popupRender, onModelChange, onVisibleChange, onSearch, onClear, onFirstFocus, afterVisibleChange, onScrollBottom } = _a, restProps = __rest(_a, ["ref", "styleOverrides", "styleProvider", "formControl", "list", "model", "defaultModel", "visible", "defaultVisible", "placeholder", "multiple", "searchable", "searchValue", "defaultSearchValue", "onlyLeafSelectable", "clearable", "loading", "size", "disabled", "virtual", "escClosable", "customItem", "customSelected", "customSearch", "inputProps", "popupRender", "onModelChange", "onVisibleChange", "onSearch", "onClear", "onFirstFocus", "afterVisibleChange", "onScrollBottom"]);
31
31
  const namespace = useNamespace();
32
32
  const styled = useStyled(CLASSES, { cascader: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.cascader, 'cascader-popup': styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider['cascader-popup'] }, styleOverrides);
33
33
  const { t } = useTranslation();
@@ -482,12 +482,16 @@ export function Cascader(props) {
482
482
  }, namespace: namespace, styled: styled, id: listId, list: searchList, customItem: customItem, itemId: getItemId, itemFocused: itemFocusedWithSearch, multiple: multiple, onlyLeafSelectable: onlyLeafSelectable, virtual: virtual, focusVisible: focusVisible, onClick: (item) => {
483
483
  changeItemFocusedWithSearch(item);
484
484
  changeSelectedByClickWithSearch(item);
485
+ }, onScrollBottom: () => {
486
+ onScrollBottom === null || onScrollBottom === void 0 ? void 0 : onScrollBottom([]);
485
487
  } })) : (_jsx(CascaderPanel, { ref: (instance) => {
486
488
  focusRef.current = instance;
487
489
  return () => {
488
490
  focusRef.current = null;
489
491
  };
490
- }, namespace: namespace, styled: styled, id: listId, list: nodes, customItem: customItem, itemId: getItemId, itemSelected: !multiple && hasSelected ? nodesMap.get(selected) : undefined, itemFocused: itemFocusedWithoutSearch, multiple: multiple, virtual: virtual, focusVisible: focusVisible, onFocus: changeItemFocusedWithoutSearch, onClick: changeSelectedByClickWithoutSearch }))] })));
492
+ }, namespace: namespace, styled: styled, id: listId, list: nodes, customItem: customItem, itemId: getItemId, itemSelected: !multiple && hasSelected ? nodesMap.get(selected) : undefined, itemFocused: itemFocusedWithoutSearch, multiple: multiple, virtual: virtual, focusVisible: focusVisible, onFocus: changeItemFocusedWithoutSearch, onClick: changeSelectedByClickWithoutSearch, onScrollBottom: (ancestors) => {
493
+ onScrollBottom === null || onScrollBottom === void 0 ? void 0 : onScrollBottom(ancestors);
494
+ } }))] })));
491
495
  return popupRender ? popupRender(el) : el;
492
496
  })() }))) }) })] }));
493
497
  }
@@ -17,6 +17,7 @@ interface CascaderPanelProps<V extends React.Key, T extends CascaderItem<V>> {
17
17
  focusVisible: boolean;
18
18
  onFocus: (item: AbstractTreeNode<V, T>) => void;
19
19
  onClick: (item: AbstractTreeNode<V, T>) => void;
20
+ onScrollBottom: (ancestors: V[]) => void;
20
21
  }
21
22
  export declare function CascaderPanel<V extends React.Key, T extends CascaderItem<V>>(props: CascaderPanelProps<V, T>): React.ReactElement | null;
22
23
  export {};
@@ -11,7 +11,7 @@ import { Empty } from '../../empty';
11
11
  import { Icon } from '../../icon';
12
12
  import { VirtualScroll } from '../../virtual-scroll';
13
13
  export function CascaderPanel(props) {
14
- const { ref, namespace, styled, id, list, customItem, itemId, itemSelected, itemFocused, multiple, virtual, focusVisible, onFocus, onClick, _root = true, } = props;
14
+ const { ref, namespace, styled, id, list, customItem, itemId, itemSelected, itemFocused, multiple, virtual, focusVisible, onFocus, onClick, onScrollBottom, _root = true, } = props;
15
15
  const listRef = useRef(null);
16
16
  const vsRef = useRef(null);
17
17
  const focusRef = useRef(null);
@@ -135,7 +135,9 @@ export function CascaderPanel(props) {
135
135
  } }) }))),
136
136
  _jsx("div", Object.assign({}, styled('cascader__option-content'), { children: customItem ? customItem(item.origin) : item.origin.label })),
137
137
  !item.isLeaf && (_jsx("div", Object.assign({}, styled('cascader__option-icon'), { children: _jsx(Icon, { children: item.origin.loading ? _jsx(CircularProgress, {}) : _jsx(KeyboardArrowRightOutlined, {}) }) })))));
138
- }, itemFocused: nodeFocused === null || nodeFocused === void 0 ? void 0 : nodeFocused.id, placeholder: "li", children: (vsList, onScroll) => (_jsx("ul", Object.assign({}, styled('cascader__list', 'cascader__list--inline'), { ref: (instance) => {
138
+ }, itemFocused: nodeFocused === null || nodeFocused === void 0 ? void 0 : nodeFocused.id, placeholder: "li", onScrollEnd: () => {
139
+ onScrollBottom([]);
140
+ }, children: (vsList, onScroll) => (_jsx("ul", Object.assign({}, styled('cascader__list', 'cascader__list--inline'), { ref: (instance) => {
139
141
  listRef.current = instance;
140
142
  return () => {
141
143
  listRef.current = null;
@@ -145,5 +147,7 @@ export function CascaderPanel(props) {
145
147
  return () => {
146
148
  focusRef.current = null;
147
149
  };
148
- }, id: undefined, list: nodeFocused.children })))] }));
150
+ }, id: undefined, list: nodeFocused.children, onScrollBottom: (ancestors) => {
151
+ onScrollBottom([nodeFocused.id].concat(ancestors));
152
+ } })))] }));
149
153
  }
@@ -16,6 +16,7 @@ interface CascaderSearchPanelProps<V extends React.Key, T extends CascaderItem<V
16
16
  virtual: boolean | number;
17
17
  focusVisible: boolean;
18
18
  onClick: (item: CascaderSearchPanelItem<V, T>) => void;
19
+ onScrollBottom: () => void;
19
20
  }
20
21
  export declare function CascaderSearchPanel<V extends React.Key, T extends CascaderItem<V>>(props: CascaderSearchPanelProps<V, T>): React.ReactElement | null;
21
22
  export {};
@@ -10,7 +10,7 @@ import { getTreeNodeLabel } from '../../tree/utils';
10
10
  import { TREE_NODE_KEY } from '../../tree/vars';
11
11
  import { VirtualScroll } from '../../virtual-scroll';
12
12
  export function CascaderSearchPanel(props) {
13
- const { ref, namespace, styled, id, list, customItem, itemId, itemFocused, multiple, onlyLeafSelectable, virtual, focusVisible, onClick, } = props;
13
+ const { ref, namespace, styled, id, list, customItem, itemId, itemFocused, multiple, onlyLeafSelectable, virtual, focusVisible, onClick, onScrollBottom, } = props;
14
14
  const listRef = useRef(null);
15
15
  const vsRef = useRef(null);
16
16
  const handleKeyDown = useEventCallback((code) => {
@@ -73,7 +73,7 @@ export function CascaderSearchPanel(props) {
73
73
  focusVisible && (itemFocused === null || itemFocused === void 0 ? void 0 : itemFocused.value) === item.value && _jsx("div", { className: `${namespace}-focus-outline` }),
74
74
  multiple && (_jsx("div", Object.assign({}, styled('cascader__option-prefix'), { children: _jsx(Checkbox, { model: node.checked, disabled: node.disabled }) }))),
75
75
  _jsx("div", Object.assign({}, styled('cascader__option-content'), { children: customItem ? customItem(node.origin) : getTreeNodeLabel(node) }))));
76
- }, itemFocused: itemFocused === null || itemFocused === void 0 ? void 0 : itemFocused.value, placeholder: "li", children: (vsList, onScroll) => (_jsx("ul", Object.assign({}, styled('cascader__list'), { ref: (instance) => {
76
+ }, itemFocused: itemFocused === null || itemFocused === void 0 ? void 0 : itemFocused.value, placeholder: "li", onScrollEnd: onScrollBottom, children: (vsList, onScroll) => (_jsx("ul", Object.assign({}, styled('cascader__list'), { ref: (instance) => {
77
77
  listRef.current = instance;
78
78
  return () => {
79
79
  listRef.current = null;
@@ -45,5 +45,6 @@ export interface CascaderProps<V extends React.Key, T extends CascaderItem<V>> e
45
45
  onSearch?: (value: string) => void;
46
46
  onClear?: () => void;
47
47
  onFirstFocus?: (value: V, origin: T) => void;
48
+ onScrollBottom?: (ancestors: V[]) => void;
48
49
  afterVisibleChange?: (visible: boolean) => void;
49
50
  }
@@ -1,13 +1,13 @@
1
1
  import { __rest } from "tslib";
2
2
  import { createElement as _createElement } from "react";
3
3
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
4
- import { useAsync, useEventCallback, useForceUpdate, useImmer, useIsomorphicLayoutEffect, useResize } from '@laser-ui/hooks';
4
+ import { useAsync, useEventCallback, useImmer, useIsomorphicLayoutEffect, useResize } from '@laser-ui/hooks';
5
5
  import { setRef } from '@laser-ui/utils';
6
6
  import CancelFilled from '@material-design-icons/svg/filled/cancel.svg?react';
7
7
  import CalendarTodayOutlined from '@material-design-icons/svg/outlined/calendar_today.svg?react';
8
8
  import SwapHorizOutlined from '@material-design-icons/svg/outlined/swap_horiz.svg?react';
9
9
  import { isArray, isBoolean, isNull, isUndefined } from 'lodash';
10
- import { useEffect, useImperativeHandle, useRef } from 'react';
10
+ import { useImperativeHandle, useRef } from 'react';
11
11
  import { DatePickerPanel } from './internal/DatePickerPanel';
12
12
  import { CLASSES } from './vars';
13
13
  import { BaseInput } from '../base-input';
@@ -23,8 +23,8 @@ import { Transition } from '../transition';
23
23
  import { getVerticalSidePosition, mergeCS } from '../utils';
24
24
  import { TTANSITION_DURING_POPUP, WINDOW_SPACE } from '../vars';
25
25
  export function DatePicker(props) {
26
- var _a, _b;
27
- const _c = useComponentProps('DatePicker', props), { ref, styleOverrides, styleProvider, formControl, model, defaultModel, visible: visibleProp, defaultVisible, placeholder, range = false, format: formatProp, order: orderProp = 'ascend', clearable: clearableProp = false, size: sizeProp, disabled: disabledProp = false, presetDate, config, showTime = false, escClosable = true, inputProps, onModelChange, onVisibleChange, onClear, afterVisibleChange } = _c, restProps = __rest(_c, ["ref", "styleOverrides", "styleProvider", "formControl", "model", "defaultModel", "visible", "defaultVisible", "placeholder", "range", "format", "order", "clearable", "size", "disabled", "presetDate", "config", "showTime", "escClosable", "inputProps", "onModelChange", "onVisibleChange", "onClear", "afterVisibleChange"]);
26
+ var _a;
27
+ const _b = useComponentProps('DatePicker', props), { ref, styleOverrides, styleProvider, formControl, model, defaultModel, visible: visibleProp, defaultVisible, placeholder, range = false, format: formatProp, order: orderProp = 'ascend', clearable: clearableProp = false, size: sizeProp, disabled: disabledProp = false, presetDate, config, showTime = false, escClosable = true, inputProps, onModelChange, onVisibleChange, onClear, afterVisibleChange } = _b, restProps = __rest(_b, ["ref", "styleOverrides", "styleProvider", "formControl", "model", "defaultModel", "visible", "defaultVisible", "placeholder", "range", "format", "order", "clearable", "size", "disabled", "presetDate", "config", "showTime", "escClosable", "inputProps", "onModelChange", "onVisibleChange", "onClear", "afterVisibleChange"]);
28
28
  const namespace = useNamespace();
29
29
  const styled = useStyled(CLASSES, {
30
30
  'date-picker': styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider['date-picker'],
@@ -32,87 +32,130 @@ export function DatePicker(props) {
32
32
  'date-picker-popup': styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider['date-picker-popup'],
33
33
  }, styleOverrides);
34
34
  const { t } = useTranslation();
35
- const forceUpdate = useForceUpdate();
36
35
  const async = useAsync();
37
36
  const { contentResizeRef } = useLayout();
38
37
  const boxRef = useRef(null);
39
38
  const popupRef = useRef(null);
40
- const inputLeftRef = useRef(null);
41
- const inputRightRef = useRef(null);
39
+ const inputStartRef = useRef(null);
40
+ const inputEndRef = useRef(null);
42
41
  const indicatorRef = useRef(null);
43
42
  const panelRef = useRef(null);
44
43
  const timePickerPanelRef = useRef(null);
45
44
  const updatePanel = (date) => {
46
45
  var _a, _b;
47
- (_a = panelRef.current) === null || _a === void 0 ? void 0 : _a.call(panelRef, date);
48
- (_b = timePickerPanelRef.current) === null || _b === void 0 ? void 0 : _b.call(timePickerPanelRef, date);
46
+ if (visible) {
47
+ (_a = panelRef.current) === null || _a === void 0 ? void 0 : _a.call(panelRef, date);
48
+ (_b = timePickerPanelRef.current) === null || _b === void 0 ? void 0 : _b.call(timePickerPanelRef, date);
49
+ }
49
50
  };
50
- const dataRef = useRef({
51
- latestFocused: 'start',
52
- onceVisible: false,
53
- focusAnother: false,
54
- inputValue: [undefined, undefined],
55
- rangeDate: [null, null],
56
- });
51
+ const dataRef = useRef({ focusWithoutUser: false });
57
52
  const format = isUndefined(formatProp) ? (showTime ? 'YYYY-MM-DD HH:mm:ss' : `YYYY-MM-DD`) : formatProp;
58
- const order = (date) => orderDate(date, orderProp, showTime ? undefined : 'date');
59
53
  const [visible, changeVisible] = useControlled(defaultVisible !== null && defaultVisible !== void 0 ? defaultVisible : false, visibleProp, onVisibleChange);
60
54
  const [focused, setFocused] = useImmer([false, false]);
61
- if (focused[0]) {
62
- dataRef.current.latestFocused = 'start';
63
- }
64
- if (focused[1]) {
65
- dataRef.current.latestFocused = 'end';
66
- }
67
- const [_value, _changeValue] = useControlled(defaultModel !== null && defaultModel !== void 0 ? defaultModel : null, model, onModelChange, (a, b) => deepCompareDate(a, b, format), formControl === null || formControl === void 0 ? void 0 : formControl.control);
68
- let [valueLeft, valueRight = null] = range ? ((_a = _value) !== null && _a !== void 0 ? _a : [null, null]) : [_value, null];
69
- if (range) {
70
- if (isNull(_value)) {
71
- [valueLeft, valueRight] = dataRef.current.rangeDate;
55
+ const [value, _changeValue] = useControlled(defaultModel !== null && defaultModel !== void 0 ? defaultModel : null, model, onModelChange, (a, b) => deepCompareDate(a, b, format), formControl === null || formControl === void 0 ? void 0 : formControl.control);
56
+ const [placeholderValues, setPlaceholderValues] = useImmer(() => {
57
+ let values = ['', ''];
58
+ if (value) {
59
+ if (range) {
60
+ values = value.map((v) => dayjs(v).format(format));
61
+ }
62
+ else {
63
+ values[0] = dayjs(value).format(format);
64
+ }
65
+ }
66
+ return values;
67
+ });
68
+ const newPlaceholderValues = (() => {
69
+ if (focused.some((f) => f)) {
70
+ return;
71
+ }
72
+ if (isNull(value)) {
73
+ if (placeholderValues.some((p) => p)) {
74
+ return ['', ''];
75
+ }
72
76
  }
73
77
  else {
74
- dataRef.current.rangeDate = [null, null];
78
+ if (isArray(value)) {
79
+ const currentPlaceholder = value.map((v) => dayjs(v).format(format));
80
+ if (currentPlaceholder.some((p, i) => p !== placeholderValues[i])) {
81
+ return currentPlaceholder;
82
+ }
83
+ }
84
+ else {
85
+ const currentPlaceholder = dayjs(value).format(format);
86
+ if (currentPlaceholder !== placeholderValues[0]) {
87
+ return [currentPlaceholder, ''];
88
+ }
89
+ }
75
90
  }
91
+ })();
92
+ if (!isUndefined(newPlaceholderValues)) {
93
+ setPlaceholderValues(newPlaceholderValues);
76
94
  }
77
- const inputValue = [0, 1].map((index) => focused[index] && !isUndefined(dataRef.current.inputValue[index])
78
- ? dataRef.current.inputValue[index]
79
- : (() => {
80
- const value = index === 0 ? valueLeft : valueRight;
81
- return isNull(value) ? '' : dayjs(value).format(format);
82
- })());
95
+ const placeholderDates = placeholderValues.map((v) => (v && dayjs(v, format, true).isValid() ? dayjs(v, format).toDate() : null));
83
96
  const changeValue = (date) => {
84
- const index = focused.findIndex((f) => f);
85
- if (range) {
86
- if (isNull(_value)) {
87
- dataRef.current.rangeDate[index] = date;
88
- if (dataRef.current.rangeDate.every((v) => !isNull(v))) {
89
- dataRef.current.focusAnother = order(dataRef.current.rangeDate);
90
- if (dataRef.current.focusAnother) {
91
- dataRef.current.rangeDate.reverse();
97
+ if (isNull(date)) {
98
+ _changeValue(null);
99
+ setPlaceholderValues(['', '']);
100
+ }
101
+ else {
102
+ if (range) {
103
+ let newValue = [...placeholderDates];
104
+ if (isArray(date)) {
105
+ newValue = date;
106
+ }
107
+ else {
108
+ newValue[focused[0] ? 0 : 1] = date;
109
+ }
110
+ if (newValue.every((v) => !isNull(v))) {
111
+ const reverse = orderDate(newValue, orderProp, showTime ? undefined : 'date');
112
+ if (reverse) {
113
+ newValue.reverse();
114
+ const inputEl = focused[0] ? inputEndRef.current : inputStartRef.current;
115
+ if (inputEl) {
116
+ dataRef.current.focusWithoutUser = true;
117
+ inputEl.focus({ preventScroll: true });
118
+ }
92
119
  }
93
- dataRef.current.inputValue = [undefined, undefined];
94
- _changeValue(dataRef.current.rangeDate);
120
+ _changeValue(newValue);
95
121
  }
122
+ setPlaceholderValues(newValue.map((v) => (v ? dayjs(v).format(format) : '')));
96
123
  }
97
124
  else {
98
- dataRef.current.inputValue = [undefined, undefined];
99
- _changeValue((draft) => {
100
- draft[index] = date;
101
- dataRef.current.focusAnother = order(draft);
102
- if (dataRef.current.focusAnother) {
103
- draft.reverse();
104
- }
105
- });
125
+ _changeValue(date);
126
+ setPlaceholderValues([dayjs(date).format(format), '']);
106
127
  }
107
128
  }
129
+ };
130
+ const handleEnter = (date) => {
131
+ if (isArray(date)) {
132
+ updatePanel(date[focused[0] ? 0 : 1]);
133
+ changeVisible(false);
134
+ dataRef.current.lastVisible = focused[0] ? 'start' : 'end';
135
+ }
108
136
  else {
109
- dataRef.current.inputValue = [undefined, undefined];
110
- _changeValue(date);
137
+ updatePanel(date);
138
+ if (range) {
139
+ if (placeholderDates[focused[0] ? 1 : 0]) {
140
+ changeVisible(false);
141
+ dataRef.current.lastVisible = focused[0] ? 'start' : 'end';
142
+ }
143
+ else {
144
+ const inputEl = focused[0] ? inputEndRef.current : inputStartRef.current;
145
+ if (inputEl) {
146
+ dataRef.current.focusWithoutUser = true;
147
+ inputEl.focus({ preventScroll: true });
148
+ }
149
+ }
150
+ }
151
+ else {
152
+ changeVisible(false);
153
+ dataRef.current.lastVisible = 'start';
154
+ }
111
155
  }
112
- forceUpdate();
113
156
  };
114
- const [placeholderLeft = t('DatePicker', range ? 'Start date' : 'Select date'), placeholderRight = t('DatePicker', 'End date')] = range
115
- ? ((_b = placeholder) !== null && _b !== void 0 ? _b : [])
157
+ const [placeholderStart = t('DatePicker', range ? 'Start date' : 'Select date'), placeholderEnd = t('DatePicker', 'End date')] = range
158
+ ? ((_a = placeholder) !== null && _a !== void 0 ? _a : [])
116
159
  : [placeholder];
117
160
  const { size, disabled } = useScopedProps({ size: sizeProp, disabled: disabledProp || (formControl === null || formControl === void 0 ? void 0 : formControl.control.disabled) });
118
161
  const zIndexValue = useZIndex(visible);
@@ -132,6 +175,24 @@ export function DatePicker(props) {
132
175
  popupRef.current.style.maxWidth = maxWidth + 'px';
133
176
  }
134
177
  });
178
+ const updatePanelWhenEnter = useEventCallback(() => {
179
+ const update = () => {
180
+ const date = placeholderDates[focused[0] ? 0 : 1];
181
+ if (date) {
182
+ updatePanel(date);
183
+ }
184
+ };
185
+ if (range) {
186
+ if ((focused[0] ? 'start' : 'end') !== dataRef.current.lastVisible) {
187
+ update();
188
+ }
189
+ }
190
+ else {
191
+ if (dataRef.current.lastVisible !== 'start') {
192
+ update();
193
+ }
194
+ }
195
+ });
135
196
  useContainerScrolling(boxRef, updatePosition, !visible);
136
197
  useResize(boxRef, updatePosition, undefined, !visible);
137
198
  useResize(popupRef, updatePosition, undefined, !visible);
@@ -143,13 +204,13 @@ export function DatePicker(props) {
143
204
  if (boxRef.current && indicatorRef.current) {
144
205
  let focus = false;
145
206
  const boxRect = boxRef.current.getBoundingClientRect();
146
- if (inputLeftRef.current && document.activeElement === inputLeftRef.current) {
147
- const rect = inputLeftRef.current.getBoundingClientRect();
207
+ if (inputStartRef.current && document.activeElement === inputStartRef.current) {
208
+ const rect = inputStartRef.current.getBoundingClientRect();
148
209
  indicatorRef.current.style.cssText = `left:${rect.left - boxRect.left}px;width:${rect.width}px;opacity:1;`;
149
210
  focus = true;
150
211
  }
151
- if (inputRightRef.current && document.activeElement === inputRightRef.current) {
152
- const rect = inputRightRef.current.getBoundingClientRect();
212
+ if (inputEndRef.current && document.activeElement === inputEndRef.current) {
213
+ const rect = inputEndRef.current.getBoundingClientRect();
153
214
  indicatorRef.current.style.cssText = `left:${rect.left - boxRect.left}px;width:${rect.width}px;opacity:1;`;
154
215
  focus = true;
155
216
  }
@@ -158,43 +219,11 @@ export function DatePicker(props) {
158
219
  }
159
220
  }
160
221
  });
161
- useEffect(() => {
162
- if (dataRef.current.focusAnother && document.activeElement) {
163
- const el = document.activeElement.parentElement;
164
- for (let index = 0; index < el.childElementCount; index++) {
165
- const element = el.children.item(index);
166
- if (element.tagName.toLowerCase() === 'input' && element !== document.activeElement) {
167
- element.focus({ preventScroll: true });
168
- break;
169
- }
170
- }
171
- }
172
- dataRef.current.focusAnother = false;
173
- });
174
- const handleEnter = (date) => {
175
- if (range) {
176
- const index = focused.findIndex((f) => f);
177
- if (isNull(index === 0 ? valueRight : valueLeft)) {
178
- dataRef.current.focusAnother = true;
179
- forceUpdate();
180
- }
181
- else {
182
- changeVisible(false);
183
- }
184
- }
185
- else {
186
- changeVisible(false);
187
- }
188
- if (!dataRef.current.focusAnother) {
189
- updatePanel(date);
190
- }
191
- };
192
- const clearable = clearableProp && !isNull(_value) && !visible && !disabled;
193
- const inputNode = (isLeft) => {
222
+ const clearable = clearableProp && !disabled && !visible && placeholderValues.some((p) => p);
223
+ const inputNode = (isStart) => {
194
224
  var _a, _b;
195
- const index = isLeft ? 0 : 1;
196
- const value = isLeft ? valueLeft : valueRight;
197
- const inputRef = isLeft ? inputLeftRef : inputRightRef;
225
+ const index = isStart ? 0 : 1;
226
+ const inputRef = isStart ? inputStartRef : inputEndRef;
198
227
  return (_jsx(BaseInput, Object.assign({}, inputProps === null || inputProps === void 0 ? void 0 : inputProps[index], mergeCS(styled('date-picker__input'), {
199
228
  className: (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps[index]) === null || _a === void 0 ? void 0 : _a.className,
200
229
  style: (_b = inputProps === null || inputProps === void 0 ? void 0 : inputProps[index]) === null || _b === void 0 ? void 0 : _b.style,
@@ -206,13 +235,29 @@ export function DatePicker(props) {
206
235
  inputRef.current = null;
207
236
  ret();
208
237
  };
209
- }, type: "text", autoComplete: "off", value: inputValue[index], size: 22, placeholder: isLeft ? placeholderLeft : placeholderRight, disabled: disabled, onValueChange: (val) => {
210
- forceUpdate();
211
- dataRef.current.inputValue[index] = val;
212
- if (dayjs(val, format, true).isValid()) {
213
- const date = dayjs(val, format).toDate();
214
- changeValue(date);
215
- updatePanel(date);
238
+ }, type: "text", autoComplete: "off", value: placeholderValues[index], size: 22, placeholder: isStart ? placeholderStart : placeholderEnd, disabled: disabled, onValueChange: (val) => {
239
+ const values = [...placeholderValues];
240
+ values[index] = val;
241
+ setPlaceholderValues(values);
242
+ if (range) {
243
+ if (values.every((v) => !v)) {
244
+ _changeValue(null);
245
+ }
246
+ else if (values.every((v) => v && dayjs(v, format, true).isValid())) {
247
+ const dates = values.map((v) => dayjs(v, format).toDate());
248
+ _changeValue(dates);
249
+ updatePanel(dates[index]);
250
+ }
251
+ }
252
+ else {
253
+ if (!values[index]) {
254
+ _changeValue(null);
255
+ }
256
+ else if (values[index] && dayjs(values[index], format, true).isValid()) {
257
+ const date = dayjs(values[index], format).toDate();
258
+ _changeValue(date);
259
+ updatePanel(date);
260
+ }
216
261
  }
217
262
  }, onKeyDown: (e) => {
218
263
  var _a, _b;
@@ -222,12 +267,14 @@ export function DatePicker(props) {
222
267
  e.stopPropagation();
223
268
  e.preventDefault();
224
269
  changeVisible(false);
270
+ dataRef.current.lastVisible = isStart ? 'start' : 'end';
225
271
  }
226
272
  }
227
- else if (e.code === 'Enter' && inputValue[index] && dayjs(inputValue[index], format, true).isValid()) {
228
- e.preventDefault();
229
- const date = dayjs(inputValue[index], format).toDate();
230
- handleEnter(date);
273
+ else if (e.code === 'Enter') {
274
+ if (placeholderDates[index]) {
275
+ e.preventDefault();
276
+ handleEnter(placeholderDates[index]);
277
+ }
231
278
  }
232
279
  }, onFocus: (e) => {
233
280
  var _a, _b, _c, _d;
@@ -235,25 +282,26 @@ export function DatePicker(props) {
235
282
  (_d = (_c = dataRef.current).clearTid) === null || _d === void 0 ? void 0 : _d.call(_c);
236
283
  setFocused((draft) => {
237
284
  draft.fill(false);
238
- draft[isLeft ? 0 : 1] = true;
285
+ draft[index] = true;
239
286
  });
240
- dataRef.current.inputValue = [undefined, undefined];
241
- if (visible && range && value) {
242
- updatePanel(value);
287
+ if (range && !dataRef.current.focusWithoutUser && placeholderDates[index]) {
288
+ updatePanel(placeholderDates[index]);
243
289
  }
290
+ dataRef.current.focusWithoutUser = false;
244
291
  }, onBlur: (e) => {
245
292
  var _a, _b;
246
293
  (_b = (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps[index]) === null || _a === void 0 ? void 0 : _a.onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, e);
247
294
  dataRef.current.clearTid = async.setTimeout(() => {
248
295
  setFocused([false, false]);
249
296
  changeVisible(false);
297
+ dataRef.current.lastVisible = isStart ? 'start' : 'end';
250
298
  }, 20);
251
299
  } })));
252
300
  };
253
301
  const preventBlur = (e) => {
254
- if ((document.activeElement === inputLeftRef.current || document.activeElement === inputRightRef.current) &&
255
- e.target !== inputLeftRef.current &&
256
- e.target !== inputRightRef.current &&
302
+ if ((document.activeElement === inputStartRef.current || document.activeElement === inputEndRef.current) &&
303
+ e.target !== inputStartRef.current &&
304
+ e.target !== inputEndRef.current &&
257
305
  e.button === 0) {
258
306
  e.preventDefault();
259
307
  }
@@ -281,7 +329,8 @@ export function DatePicker(props) {
281
329
  var _a, _b;
282
330
  (_a = restProps.onClick) === null || _a === void 0 ? void 0 : _a.call(restProps, e);
283
331
  if (!focused.some((f) => f)) {
284
- (_b = inputLeftRef.current) === null || _b === void 0 ? void 0 : _b.focus({ preventScroll: true });
332
+ dataRef.current.focusWithoutUser = true;
333
+ (_b = inputStartRef.current) === null || _b === void 0 ? void 0 : _b.focus({ preventScroll: true });
285
334
  }
286
335
  changeVisible(true);
287
336
  }, children: [inputNode(true), range && (_jsxs(_Fragment, { children: [_jsx("div", Object.assign({}, styled('date-picker__indicator'), { ref: (instance) => {
@@ -291,8 +340,7 @@ export function DatePicker(props) {
291
340
  };
292
341
  } })), _jsx("div", Object.assign({}, styled('date-picker__separator'), { children: _jsx(Icon, { children: _jsx(SwapHorizOutlined, {}) }) })), inputNode(false)] })), clearable && (_jsx("div", Object.assign({}, styled('date-picker__clear'), { role: "button", "aria-label": t('Clear'), onClick: (e) => {
293
342
  e.stopPropagation();
294
- dataRef.current.inputValue = [undefined, undefined];
295
- _changeValue(null);
343
+ changeValue(null);
296
344
  onClear === null || onClear === void 0 ? void 0 : onClear();
297
345
  }, children: _jsx(Icon, { children: _jsx(CancelFilled, {}) }) }))), _jsx("div", Object.assign({}, mergeCS(styled('date-picker__icon'), {
298
346
  style: { visibility: clearable ? 'hidden' : undefined },
@@ -306,34 +354,10 @@ export function DatePicker(props) {
306
354
  return el;
307
355
  }, children: _jsx(Transition, { enter: visible, name: `${namespace}-popup-down`, duration: TTANSITION_DURING_POPUP, onSkipEnter: () => {
308
356
  updatePosition();
309
- const cb = () => {
310
- const value = focused[0] ? valueLeft : valueRight;
311
- if (value) {
312
- updatePanel(value);
313
- }
314
- };
315
- if (range) {
316
- cb();
317
- }
318
- else if (!dataRef.current.onceVisible) {
319
- dataRef.current.onceVisible = true;
320
- cb();
321
- }
357
+ updatePanelWhenEnter();
322
358
  }, onBeforeEnter: () => {
323
359
  updatePosition();
324
- const cb = () => {
325
- const value = focused[0] ? valueLeft : valueRight;
326
- if (value) {
327
- updatePanel(value);
328
- }
329
- };
330
- if (range) {
331
- cb();
332
- }
333
- else if (!dataRef.current.onceVisible) {
334
- dataRef.current.onceVisible = true;
335
- cb();
336
- }
360
+ updatePanelWhenEnter();
337
361
  }, onAfterEnter: () => {
338
362
  afterVisibleChange === null || afterVisibleChange === void 0 ? void 0 : afterVisibleChange(true);
339
363
  }, onAfterLeave: () => {
@@ -351,32 +375,16 @@ export function DatePicker(props) {
351
375
  preventBlur(e);
352
376
  }, onMouseUp: (e) => {
353
377
  preventBlur(e);
354
- }, children: [presetDate && (_jsx("ul", Object.assign({}, styled('date-picker__preset'), { children: Object.keys(presetDate).map((name) => {
355
- const handleClick = () => {
378
+ }, children: [presetDate && (_jsx("ul", Object.assign({}, styled('date-picker__preset'), { children: Object.keys(presetDate).map((name) => (_createElement("li", Object.assign({}, styled('date-picker__preset-option'), { key: name, role: "button", onClick: () => {
356
379
  const date = presetDate[name]();
357
- dataRef.current.inputValue = [undefined, undefined];
358
- if (range) {
359
- if (isArray(date)) {
360
- _changeValue(date);
361
- changeVisible(false);
362
- }
363
- else {
364
- changeValue(date);
365
- handleEnter(date);
366
- }
367
- }
368
- else {
369
- _changeValue(date);
370
- handleEnter(date);
371
- }
372
- };
373
- return (_createElement("li", Object.assign({}, styled('date-picker__preset-option'), { key: name, role: "button", onClick: handleClick }), name));
374
- }) }))), _jsxs("div", Object.assign({}, styled('date-picker__panel-wrapper'), { children: [_jsx(DatePickerPanel, { ref: (instance) => {
380
+ changeValue(date);
381
+ handleEnter(date);
382
+ } }), name))) }))), _jsxs("div", Object.assign({}, styled('date-picker__panel-wrapper'), { children: [_jsx(DatePickerPanel, { ref: (instance) => {
375
383
  panelRef.current = instance;
376
384
  return () => {
377
385
  panelRef.current = null;
378
386
  };
379
- }, styled: styled, currentSelected: dataRef.current.latestFocused === 'start' ? valueLeft : valueRight, anotherSelected: dataRef.current.latestFocused === 'start' ? valueRight : valueLeft, config: config ? (...args) => config(...args, dataRef.current.latestFocused, [valueLeft, valueRight]) : undefined, range: range, onDateChange: (date) => {
387
+ }, styled: styled, currentSelected: placeholderDates[focused[0] ? 0 : 1], anotherSelected: placeholderDates[focused[0] ? 1 : 0], config: config ? (...args) => config(...args, focused[0] ? 'start' : 'end', placeholderDates) : undefined, range: range, onDateChange: (date) => {
380
388
  changeValue(date);
381
389
  if (!showTime) {
382
390
  handleEnter(date);
@@ -386,11 +394,11 @@ export function DatePicker(props) {
386
394
  return () => {
387
395
  timePickerPanelRef.current = null;
388
396
  };
389
- }, styled: styled, time: dataRef.current.latestFocused === 'start' ? valueLeft : valueRight, format: format, config: (() => {
397
+ }, styled: styled, time: placeholderDates[focused[0] ? 0 : 1], format: format, config: (() => {
390
398
  if (showTime && !isBoolean(showTime)) {
391
399
  const fn = showTime.config;
392
400
  if (fn) {
393
- return (...args) => fn(...args, dataRef.current.latestFocused, [valueLeft, valueRight]);
401
+ return (...args) => fn(...args, focused[0] ? 'start' : 'end', placeholderDates);
394
402
  }
395
403
  }
396
404
  })(), inDatePicker: true, onTimeChange: (time) => {