@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.
@@ -27,11 +27,7 @@ export function Dropdown(props) {
27
27
  const updateSubPosition = useRef(new Map());
28
28
  const [focusVisible, focusVisibleProps] = useFocusVisible((code) => code.startsWith('Arrow') || ['Home', 'End', 'Enter', 'Space'].includes(code));
29
29
  const [visible, changeVisible] = useControlled(defaultVisible !== null && defaultVisible !== void 0 ? defaultVisible : false, visibleProp, onVisibleChange);
30
- const { popupIdsRef, setPopupIds, addPopupId, removePopupId } = useNestedPopup();
31
- if (!visible) {
32
- popupIdsRef.current = [];
33
- }
34
- const popupIds = popupIdsRef.current;
30
+ const { popupIds, setPopupIds, addPopupId, removePopupId } = useNestedPopup(visible);
35
31
  const [focusIds, setFocusIds] = useState([]);
36
32
  const focusId = (() => {
37
33
  var _a;
@@ -1,11 +1,10 @@
1
- import type { DraftFunction } from '@laser-ui/hooks/useImmer';
2
1
  interface PopupId<ID> {
3
2
  id: ID;
4
3
  visible: boolean;
5
4
  }
6
- export declare function useNestedPopup<ID>(): {
7
- popupIdsRef: import("react").RefObject<PopupId<ID>[]>;
8
- setPopupIds: (value: PopupId<ID>[] | DraftFunction<PopupId<ID>[]>) => void;
5
+ export declare function useNestedPopup<ID>(visible?: boolean): {
6
+ popupIds: PopupId<ID>[];
7
+ setPopupIds: import("@laser-ui/hooks/useImmer").Updater<PopupId<ID>[]>;
9
8
  addPopupId: (id: ID) => void;
10
9
  removePopupId: (id: ID) => void;
11
10
  };
@@ -1,16 +1,11 @@
1
- import { useForceUpdate } from '@laser-ui/hooks';
2
- import { freeze, produce } from 'immer';
3
- import { isFunction } from 'lodash';
4
- import { useRef } from 'react';
5
- export function useNestedPopup() {
6
- const forceUpdate = useForceUpdate();
7
- const popupIdsRef = useRef([]);
8
- const setPopupIds = (value) => {
9
- popupIdsRef.current = isFunction(value) ? produce(popupIdsRef.current, value) : freeze(value);
10
- forceUpdate();
11
- };
1
+ import { useImmer } from '@laser-ui/hooks';
2
+ export function useNestedPopup(visible = true) {
3
+ const [popupIds, setPopupIds] = useImmer([]);
4
+ if (!visible && popupIds.length > 0) {
5
+ setPopupIds([]);
6
+ }
12
7
  return {
13
- popupIdsRef,
8
+ popupIds,
14
9
  setPopupIds,
15
10
  addPopupId: (id) => {
16
11
  setPopupIds((draft) => {
package/image/Image.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { __rest } from "tslib";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useForceUpdate } from '@laser-ui/hooks';
4
3
  import { checkNodeExist } from '@laser-ui/utils';
5
4
  import { has } from 'lodash';
6
- import { Fragment, useRef } from 'react';
5
+ import { Fragment, useState } from 'react';
7
6
  import { ImageAction } from './ImageAction';
8
7
  import { ImageLoader } from './ImageLoader';
9
8
  import { ImagePreview } from './ImagePreview';
@@ -13,42 +12,37 @@ import { mergeCS } from '../utils';
13
12
  export const Image = (props) => {
14
13
  const _a = useComponentProps('Image', props), { styleOverrides, styleProvider, loading, error, actions, imgProps } = _a, restProps = __rest(_a, ["styleOverrides", "styleProvider", "loading", "error", "actions", "imgProps"]);
15
14
  const styled = useStyled(CLASSES, { image: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.image }, styleOverrides);
16
- const forceUpdate = useForceUpdate();
17
- const dataRef = useRef({
18
- isLoading: true,
19
- isError: false,
20
- });
21
- if (imgProps.src !== dataRef.current.prevSrc) {
22
- dataRef.current.prevSrc = imgProps.src;
23
- dataRef.current.isLoading = true;
24
- dataRef.current.isError = false;
15
+ const [previousSrc, setPreviousSrc] = useState(imgProps.src);
16
+ const [isLoading, setIsLoading] = useState(true);
17
+ const [isError, setIsError] = useState(false);
18
+ if (imgProps.src !== previousSrc) {
19
+ setPreviousSrc(imgProps.src);
20
+ setIsLoading(true);
21
+ setIsError(false);
25
22
  }
26
23
  return (_jsxs("div", Object.assign({}, restProps, mergeCS(styled('image'), {
27
24
  className: restProps.className,
28
25
  style: restProps.style,
29
- }), { children: [dataRef.current.isLoading && checkNodeExist(loading) && loading, dataRef.current.isError && checkNodeExist(error) && error, actions && (_jsx("div", Object.assign({}, styled('image__actions'), { children: actions.map((node, index) => {
26
+ }), { children: [isLoading && checkNodeExist(loading) && loading, isError && checkNodeExist(error) && error, actions && (_jsx("div", Object.assign({}, styled('image__actions'), { children: actions.map((node, index) => {
30
27
  const { id, action } = (has(node, ['id', 'action']) ? node : { id: index, action: node });
31
28
  return _jsx(Fragment, { children: action }, id);
32
29
  }) }))), _jsx("img", Object.assign({}, imgProps, mergeCS(styled('image__img'), {
33
30
  className: imgProps === null || imgProps === void 0 ? void 0 : imgProps.className,
34
- style: Object.assign(Object.assign({}, imgProps === null || imgProps === void 0 ? void 0 : imgProps.style), { display: (dataRef.current.isLoading && loading) || (dataRef.current.isError && error) ? 'none' : undefined }),
31
+ style: Object.assign(Object.assign({}, imgProps === null || imgProps === void 0 ? void 0 : imgProps.style), { display: (isLoading && loading) || (isError && error) ? 'none' : undefined }),
35
32
  }), { onLoadStart: (e) => {
36
33
  var _a;
37
34
  // https://bugs.chromium.org/p/chromium/issues/detail?id=458851
38
35
  (_a = imgProps === null || imgProps === void 0 ? void 0 : imgProps.onLoadStart) === null || _a === void 0 ? void 0 : _a.call(imgProps, e);
39
- dataRef.current.isLoading = true;
40
- forceUpdate();
36
+ setIsLoading(true);
41
37
  }, onLoad: (e) => {
42
38
  var _a;
43
39
  (_a = imgProps === null || imgProps === void 0 ? void 0 : imgProps.onLoad) === null || _a === void 0 ? void 0 : _a.call(imgProps, e);
44
- dataRef.current.isLoading = false;
45
- forceUpdate();
40
+ setIsLoading(false);
46
41
  }, onError: (e) => {
47
42
  var _a;
48
43
  (_a = imgProps === null || imgProps === void 0 ? void 0 : imgProps.onError) === null || _a === void 0 ? void 0 : _a.call(imgProps, e);
49
- dataRef.current.isLoading = false;
50
- dataRef.current.isError = true;
51
- forceUpdate();
44
+ setIsLoading(false);
45
+ setIsError(true);
52
46
  } }))] })));
53
47
  };
54
48
  Image.Loader = ImageLoader;
@@ -1,46 +1,52 @@
1
1
  import { __rest } from "tslib";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useAsync, useEvent, useForceUpdate, useRefExtra } from '@laser-ui/hooks';
3
+ import { useAsync, useEvent, useRefExtra } from '@laser-ui/hooks';
4
4
  import { checkNodeExist, setRef } from '@laser-ui/utils';
5
5
  import CancelFilled from '@material-design-icons/svg/filled/cancel.svg?react';
6
6
  import KeyboardArrowDownOutlined from '@material-design-icons/svg/outlined/keyboard_arrow_down.svg?react';
7
7
  import KeyboardArrowUpOutlined from '@material-design-icons/svg/outlined/keyboard_arrow_up.svg?react';
8
8
  import { isNull, isUndefined } from 'lodash';
9
- import { useRef } from 'react';
9
+ import { useRef, useState } from 'react';
10
10
  import { CLASSES } from './vars';
11
11
  import { BaseInput } from '../base-input';
12
12
  import { useComponentProps, useControlled, useDesign, useScopedProps, useStyled, useTranslation } from '../hooks';
13
13
  import { Icon } from '../icon';
14
14
  import { mergeCS } from '../utils';
15
+ function syncValueToPlaceholder(value, placeholder) {
16
+ if (isNull(value)) {
17
+ if (placeholder) {
18
+ return '';
19
+ }
20
+ }
21
+ else {
22
+ if (value !== Number(placeholder)) {
23
+ return value.toString();
24
+ }
25
+ }
26
+ }
15
27
  export function InputNumber(props) {
16
28
  const _a = useComponentProps('InputNumber', props), { styleOverrides, styleProvider, formControl, model, defaultModel, max, min, step = 1, integer = false, prefix, suffix, clearable, placeholder, size: sizeProp, numberButton = true, disabled: disabledProp = false, inputProps, onModelChange, onClear } = _a, restProps = __rest(_a, ["styleOverrides", "styleProvider", "formControl", "model", "defaultModel", "max", "min", "step", "integer", "prefix", "suffix", "clearable", "placeholder", "size", "numberButton", "disabled", "inputProps", "onModelChange", "onClear"]);
17
29
  const styled = useStyled(CLASSES, { input: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.input }, styleOverrides);
18
30
  const async = useAsync();
19
31
  const { t } = useTranslation();
20
- const forceUpdate = useForceUpdate();
21
- const dataRef = useRef({
22
- inputFocused: false,
23
- });
32
+ const dataRef = useRef({});
24
33
  const windowRef = useRefExtra(() => window);
25
34
  const inputRef = useRef(null);
26
35
  const [value, _changeValue] = useControlled(defaultModel !== null && defaultModel !== void 0 ? defaultModel : null, model, onModelChange, undefined, formControl === null || formControl === void 0 ? void 0 : formControl.control);
27
- const inputValue = dataRef.current.inputFocused && !isUndefined(dataRef.current.inputValue)
28
- ? dataRef.current.inputValue
29
- : isNull(value)
30
- ? ''
31
- : value.toString();
36
+ const [placeholderValue, setPlaceholderValue] = useState(() => (isNull(value) ? '' : value.toString()));
37
+ const newPlaceholderValue = syncValueToPlaceholder(value, placeholderValue);
38
+ if (!isUndefined(newPlaceholderValue)) {
39
+ setPlaceholderValue(newPlaceholderValue);
40
+ }
32
41
  const changeValue = (val) => {
33
- if ((isNull(val) ? '' : val.toString()) !== inputValue) {
34
- forceUpdate();
35
- }
36
- dataRef.current.inputValue = undefined;
37
42
  _changeValue(val);
43
+ setPlaceholderValue(isNull(val) ? '' : val.toString());
38
44
  };
39
45
  const { size, disabled } = useScopedProps({ size: sizeProp, disabled: disabledProp || (formControl === null || formControl === void 0 ? void 0 : formControl.control.disabled) });
40
46
  const getValue = (val) => { var _a, _b; return Number(Math.max(min !== null && min !== void 0 ? min : -Infinity, Math.min(max !== null && max !== void 0 ? max : Infinity, val)).toFixed((_b = (_a = step.toString().split('.')[1]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0)); };
41
47
  const handleNumberButtonMouseDown = (increase = true) => {
42
- changeValue(getValue((() => {
43
- let val = inputValue.length > 0 ? Number(inputValue) : null;
48
+ const val = getValue((() => {
49
+ let val = placeholderValue.length > 0 ? Number(placeholderValue) : null;
44
50
  if (isNull(val)) {
45
51
  return 0;
46
52
  }
@@ -48,13 +54,14 @@ export function InputNumber(props) {
48
54
  val = Math.round(val);
49
55
  }
50
56
  return increase ? val + step : val - step;
51
- })()));
57
+ })());
58
+ changeValue(val);
52
59
  const loop = (prev) => {
53
60
  const val = getValue(increase ? prev + step : prev - step);
54
61
  changeValue(val);
55
62
  dataRef.current.clearLoop = async.setTimeout(() => loop(val), 50);
56
63
  };
57
- dataRef.current.clearTid = async.setTimeout(() => loop(Number(inputValue)), 400);
64
+ dataRef.current.clearTid = async.setTimeout(() => loop(Number(placeholderValue)), 400);
58
65
  };
59
66
  const handleNumberButtonMouseUp = () => {
60
67
  var _a, _b, _c, _d;
@@ -95,32 +102,26 @@ export function InputNumber(props) {
95
102
  inputRef.current = null;
96
103
  ret();
97
104
  };
98
- }, value: inputValue, max: max, min: min, step: step, type: "number", placeholder: placeholder, disabled: disabled, onValueChange: (val) => {
99
- forceUpdate();
100
- dataRef.current.inputValue = val;
105
+ }, value: placeholderValue, max: max, min: min, step: step, type: "number", placeholder: placeholder, disabled: disabled, onValueChange: (val) => {
106
+ setPlaceholderValue(val);
101
107
  if (val.length === 0) {
102
- changeValue(null);
108
+ _changeValue(null);
103
109
  }
104
110
  else {
105
111
  const num = Number(val);
106
112
  if ((isUndefined(max) || num <= max) && (isUndefined(min) || num >= min) && (!integer || Number.isInteger(num))) {
107
- changeValue(num);
113
+ _changeValue(num);
108
114
  }
109
115
  }
110
- }, onFocus: (e) => {
111
- var _a;
112
- (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
113
- dataRef.current.inputFocused = true;
114
- dataRef.current.inputValue = undefined;
115
116
  }, onBlur: (e) => {
116
117
  var _a;
117
118
  (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
118
- dataRef.current.inputFocused = false;
119
- if (inputValue.length === 0) {
120
- changeValue(null);
119
+ let val = value;
120
+ if (placeholderValue.length === 0) {
121
+ val = null;
121
122
  }
122
123
  else {
123
- let num = Number(inputValue);
124
+ let num = Number(placeholderValue);
124
125
  if (!isUndefined(max) && num > max) {
125
126
  num = max;
126
127
  }
@@ -130,9 +131,12 @@ export function InputNumber(props) {
130
131
  if (integer && !Number.isInteger(num)) {
131
132
  num = Math.round(num);
132
133
  }
133
- changeValue(num);
134
+ val = num;
135
+ }
136
+ if (val !== value) {
137
+ changeValue(val);
134
138
  }
135
- } })), clearable && !disabled && (_jsx("div", Object.assign({}, mergeCS(styled('input__clear'), { style: { opacity: inputValue.length > 0 ? 1 : 0 } }), { role: "button", "aria-label": t('Clear'), onClick: () => {
139
+ } })), clearable && !disabled && (_jsx("div", Object.assign({}, mergeCS(styled('input__clear'), { style: { opacity: placeholderValue.length > 0 ? 1 : 0 } }), { role: "button", "aria-label": t('Clear'), onClick: () => {
136
140
  changeValue(null);
137
141
  onClear === null || onClear === void 0 ? void 0 : onClear();
138
142
  }, children: _jsx(Icon, { children: _jsx(CancelFilled, {}) }) }))), numberButton && !disabled && (_jsxs("div", Object.assign({}, styled('input__number-container'), { children: [_jsx("div", Object.assign({}, styled('input__number'), { role: "button", "aria-label": t('Input', 'Increase number'), onMouseDown: (e) => {
package/menu/Menu.js CHANGED
@@ -73,8 +73,7 @@ export function Menu(props) {
73
73
  onExpandsChange(ids, items);
74
74
  }
75
75
  });
76
- const { popupIdsRef, setPopupIds, addPopupId, removePopupId } = useNestedPopup();
77
- const popupIds = popupIdsRef.current;
76
+ const { popupIds, setPopupIds, addPopupId, removePopupId } = useNestedPopup();
78
77
  const [focusIds, setFocusIds] = useState([]);
79
78
  const focusId = (() => {
80
79
  var _a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laser-ui/components",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "React components.",
5
5
  "keywords": [
6
6
  "ui",
@@ -37,5 +37,5 @@
37
37
  "access": "public",
38
38
  "directory": "../../dist/libs/components"
39
39
  },
40
- "gitHead": "6aa6cb81ee51849b66dddeab0de811cadcb65c60"
40
+ "gitHead": "10832372dcf8eb1ce1a71903333f7abb61325613"
41
41
  }
@@ -1,9 +1,9 @@
1
1
  import { __rest } from "tslib";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useAsync, useForceUpdate } from '@laser-ui/hooks';
3
+ import { useAsync } from '@laser-ui/hooks';
4
4
  import { checkNodeExist } from '@laser-ui/utils';
5
5
  import { isNumber, isUndefined } from 'lodash';
6
- import { useEffect, useRef } from 'react';
6
+ import { useEffect, useRef, useState } from 'react';
7
7
  import { CLASSES } from './vars';
8
8
  import { CircularProgress } from '../circular-progress';
9
9
  import { useComponentProps, useNamespace, useStyled } from '../hooks';
@@ -16,24 +16,22 @@ export function Spinner(props) {
16
16
  const namespace = useNamespace();
17
17
  const styled = useStyled(CLASSES, { spinner: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.spinner }, styleOverrides);
18
18
  const async = useAsync();
19
- const forceUpdate = useForceUpdate();
20
19
  const spinnerRef = useRef(null);
21
- const delayVisible = useRef(false);
22
- if (visibleProp === false) {
23
- delayVisible.current = false;
20
+ const [delayTimeout, setDelayTimeout] = useState(false);
21
+ if (!visibleProp && delayTimeout) {
22
+ setDelayTimeout(false);
24
23
  }
25
- const visible = isUndefined(delay) ? visibleProp : delayVisible.current;
24
+ const visible = isUndefined(delay) ? visibleProp : delayTimeout;
26
25
  useEffect(() => {
27
26
  if (isNumber(delay) && visibleProp) {
28
27
  const clearTid = async.setTimeout(() => {
29
- delayVisible.current = true;
30
- forceUpdate();
28
+ setDelayTimeout(true);
31
29
  }, delay);
32
30
  return () => {
33
31
  clearTid();
34
32
  };
35
33
  }
36
- }, [async, delay, forceUpdate, visibleProp]);
34
+ }, [async, delay, visibleProp]);
37
35
  return (_jsx(Transition, { enter: visible, name: `${namespace}-fade`, duration: TTANSITION_DURING_BASE, onSkipEnter: () => {
38
36
  if (spinnerRef.current) {
39
37
  spinnerRef.current.style.setProperty('--spinner-container-height', `${spinnerRef.current.offsetHeight}px`);