@canlooks/can-ui 0.0.144 → 0.0.146

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.
Files changed (95) hide show
  1. package/dist/cjs/components/app/appActionSheet.js +42 -41
  2. package/dist/cjs/components/app/appDialog.js +31 -32
  3. package/dist/cjs/components/autocomplete/autocomplete.js +10 -5
  4. package/dist/cjs/components/cascade/searchResult.js +2 -2
  5. package/dist/cjs/components/clickAway/clickAway.d.ts +11 -11
  6. package/dist/cjs/components/form/formItem.js +1 -1
  7. package/dist/cjs/components/inputBase/inputBase.style.js +1 -1
  8. package/dist/cjs/components/optionsBase/filterOptions.d.ts +4 -0
  9. package/dist/cjs/components/optionsBase/filterOptions.js +36 -0
  10. package/dist/cjs/components/optionsBase/optionsBase.d.ts +5 -0
  11. package/dist/cjs/components/optionsBase/optionsBase.js +3 -28
  12. package/dist/cjs/components/popper/popper.d.ts +4 -2
  13. package/dist/cjs/components/popper/popper.js +7 -2
  14. package/dist/cjs/components/popper/popper.style.js +4 -1
  15. package/dist/cjs/components/snackbarBase/snackbarBase.js +1 -1
  16. package/dist/cjs/components/upload/upload.js +1 -1
  17. package/dist/cjs/utils/utils.d.ts +2 -8
  18. package/dist/cjs/utils/utils.js +9 -23
  19. package/dist/esm/components/app/appActionSheet.js +38 -37
  20. package/dist/esm/components/app/appDialog.js +27 -28
  21. package/dist/esm/components/autocomplete/autocomplete.js +11 -6
  22. package/dist/esm/components/cascade/searchResult.js +2 -2
  23. package/dist/esm/components/clickAway/clickAway.d.ts +11 -11
  24. package/dist/esm/components/form/formItem.js +2 -2
  25. package/dist/esm/components/inputBase/inputBase.style.js +1 -1
  26. package/dist/esm/components/optionsBase/filterOptions.d.ts +4 -0
  27. package/dist/esm/components/optionsBase/filterOptions.js +33 -0
  28. package/dist/esm/components/optionsBase/optionsBase.d.ts +5 -0
  29. package/dist/esm/components/optionsBase/optionsBase.js +4 -29
  30. package/dist/esm/components/popper/popper.d.ts +4 -2
  31. package/dist/esm/components/popper/popper.js +7 -2
  32. package/dist/esm/components/popper/popper.style.js +4 -1
  33. package/dist/esm/components/snackbarBase/snackbarBase.js +2 -2
  34. package/dist/esm/components/upload/upload.js +2 -2
  35. package/dist/esm/utils/utils.d.ts +2 -8
  36. package/dist/esm/utils/utils.js +8 -21
  37. package/package.json +1 -4
  38. package/documentation/bootstrap.mjs +0 -8
  39. package/documentation/dist/assets/index-DyrGMYuH.js +0 -8115
  40. package/documentation/dist/atom-one-dark.min.css +0 -1
  41. package/documentation/dist/components/accordion.md +0 -38
  42. package/documentation/dist/components/actionSheet.md +0 -49
  43. package/documentation/dist/components/alert.md +0 -38
  44. package/documentation/dist/components/anchorList.md +0 -36
  45. package/documentation/dist/components/autocomplete.md +0 -68
  46. package/documentation/dist/components/avatar.md +0 -79
  47. package/documentation/dist/components/badge.md +0 -33
  48. package/documentation/dist/components/bottomNavigation.md +0 -39
  49. package/documentation/dist/components/breadcrumb.md +0 -28
  50. package/documentation/dist/components/bubbleConfirm.md +0 -34
  51. package/documentation/dist/components/button.md +0 -62
  52. package/documentation/dist/components/card.md +0 -30
  53. package/documentation/dist/components/cascade.md +0 -48
  54. package/documentation/dist/components/checkbox.md +0 -36
  55. package/documentation/dist/components/colorPicker.md +0 -27
  56. package/documentation/dist/components/contextMenu.md +0 -27
  57. package/documentation/dist/components/counter.md +0 -29
  58. package/documentation/dist/components/dataGrid.md +0 -112
  59. package/documentation/dist/components/dateTimePicker.md +0 -35
  60. package/documentation/dist/components/dateTimeRangePicker.md +0 -36
  61. package/documentation/dist/components/descriptions.md +0 -35
  62. package/documentation/dist/components/dialog.md +0 -56
  63. package/documentation/dist/components/divider.md +0 -26
  64. package/documentation/dist/components/drawer.md +0 -40
  65. package/documentation/dist/components/flex.md +0 -20
  66. package/documentation/dist/components/form.md +0 -131
  67. package/documentation/dist/components/formDialog.md +0 -36
  68. package/documentation/dist/components/grid.md +0 -34
  69. package/documentation/dist/components/highlight.md +0 -26
  70. package/documentation/dist/components/image.md +0 -90
  71. package/documentation/dist/components/input.md +0 -39
  72. package/documentation/dist/components/loading.md +0 -46
  73. package/documentation/dist/components/menu.md +0 -85
  74. package/documentation/dist/components/pagination.md +0 -38
  75. package/documentation/dist/components/pickerDialog.md +0 -56
  76. package/documentation/dist/components/placeholder.md +0 -30
  77. package/documentation/dist/components/progress.md +0 -43
  78. package/documentation/dist/components/radio.md +0 -37
  79. package/documentation/dist/components/rating.md +0 -35
  80. package/documentation/dist/components/resizable.md +0 -41
  81. package/documentation/dist/components/scrollbar.md +0 -31
  82. package/documentation/dist/components/segmented.md +0 -57
  83. package/documentation/dist/components/select.md +0 -30
  84. package/documentation/dist/components/skeleton.md +0 -26
  85. package/documentation/dist/components/slidableActions.md +0 -53
  86. package/documentation/dist/guide/appComponent.md +0 -30
  87. package/documentation/dist/guide/globalMethods.md +0 -238
  88. package/documentation/dist/guide/icon.md +0 -57
  89. package/documentation/dist/guide/introduction.md +0 -2
  90. package/documentation/dist/guide/overrideProps.md +0 -0
  91. package/documentation/dist/guide/startup.md +0 -23
  92. package/documentation/dist/guide/theme.md +0 -249
  93. package/documentation/dist/index.html +0 -13
  94. package/documentation/dist/logo.png +0 -0
  95. package/documentation/vite.config.mjs +0 -22
@@ -1,6 +1,8 @@
1
1
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
2
+ import { createElement as _createElement } from "@emotion/react";
2
3
  import { isValidElement, memo, useState } from 'react';
3
4
  import { ActionSheet } from '../actionSheet';
5
+ import { getRandomId } from '../../utils';
4
6
  export class AppActionSheetMethods {
5
7
  async confirm() {
6
8
  }
@@ -9,45 +11,44 @@ export class AppActionSheetMethods {
9
11
  }
10
12
  export const AppActionSheet = memo(({ methods }) => {
11
13
  const [stacks, setStacks] = useState([]);
12
- const defineMethods = (type) => (params, ...args) => new Promise((resolve, reject) => {
13
- const props = typeof params !== 'object' || isValidElement(params)
14
- ? { title: params }
15
- : params;
16
- setStacks(o => [
17
- ...o,
18
- {
19
- ...props,
20
- type,
21
- onAction(action) {
22
- props?.onAction?.(action, ...args);
23
- resolve(action);
24
- },
25
- onConfirm() {
26
- props?.onConfirm?.(...args);
27
- resolve(void 0);
28
- },
29
- onCancel(e) {
30
- props?.onCancel?.(e);
31
- reject();
32
- },
33
- onClosed() {
34
- props?.onClosed?.();
35
- setStacks(_o => {
36
- _o.splice(o.length, 1);
37
- return [..._o];
38
- });
39
- }
40
- }
41
- ]);
42
- });
14
+ const defineMethods = (type) => {
15
+ return (params, ...args) => {
16
+ return new Promise((resolve, reject) => {
17
+ const props = typeof params !== 'object' || isValidElement(params)
18
+ ? { title: params }
19
+ : params;
20
+ const key = getRandomId();
21
+ setStacks(o => [
22
+ ...o,
23
+ {
24
+ ...props,
25
+ key,
26
+ type,
27
+ onAction(action) {
28
+ props?.onAction?.(action, ...args);
29
+ resolve(action);
30
+ },
31
+ onConfirm() {
32
+ props?.onConfirm?.(...args);
33
+ resolve(void 0);
34
+ },
35
+ onCancel(e) {
36
+ props?.onCancel?.(e);
37
+ reject();
38
+ },
39
+ onClosed() {
40
+ props?.onClosed?.();
41
+ setStacks(stacks => stacks.filter(stack => stack.key !== key));
42
+ }
43
+ }
44
+ ]);
45
+ });
46
+ };
47
+ };
43
48
  methods.confirm = defineMethods('confirm');
44
49
  methods.open = defineMethods('open');
45
- return stacks.map((p, i) => _jsx(AppActionSheetStack, { ...p }, i));
50
+ return stacks.map(p => _createElement(AppActionSheetStack, { ...p, key: p.key }));
46
51
  });
47
52
  const AppActionSheetStack = memo(({ type, ...props }) => {
48
- const [open, setOpen] = useState(true);
49
- return (_jsx(ActionSheet, { showConfirm: type === 'confirm', ...props, open: open, onClose: reason => {
50
- props.onClose?.(reason);
51
- setOpen(false);
52
- } }));
53
+ return (_jsx(ActionSheet, { showConfirm: type === 'confirm', defaultOpen: true, ...props }));
53
54
  });
@@ -1,7 +1,9 @@
1
1
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
2
+ import { createElement as _createElement } from "@emotion/react";
2
3
  import { memo, useState } from 'react';
3
4
  import { Dialog } from '../dialog';
4
5
  import { StatusIcon } from '../status';
6
+ import { getRandomId } from '../../utils';
5
7
  export class AppDialogMethods {
6
8
  async info(props, ...args) {
7
9
  }
@@ -19,28 +21,29 @@ export const AppDialog = memo(({ methods }) => {
19
21
  const defineMethod = (type) => {
20
22
  return (props, ...args) => {
21
23
  return new Promise((resolve, reject) => {
22
- setStacks(o => [
23
- ...o,
24
- {
25
- ...props,
26
- type,
27
- async onConfirm() {
28
- await props.onConfirm?.(...args);
29
- resolve();
30
- },
31
- onCancel() {
32
- props.onCancel?.(...args);
33
- reject();
34
- },
35
- onClosed() {
36
- props.onClosed?.();
37
- setStacks(_o => {
38
- _o.splice(o.length, 1);
39
- return [..._o];
40
- });
24
+ const key = getRandomId();
25
+ setStacks(o => {
26
+ return [
27
+ ...o,
28
+ {
29
+ ...props,
30
+ key,
31
+ type,
32
+ onConfirm: async () => {
33
+ await props.onConfirm?.(...args);
34
+ resolve();
35
+ },
36
+ onCancel: () => {
37
+ props.onCancel?.(...args);
38
+ reject();
39
+ },
40
+ onClosed: () => {
41
+ props.onClosed?.();
42
+ setStacks(stacks => stacks.filter(stack => stack.key !== key));
43
+ }
41
44
  }
42
- }
43
- ]);
45
+ ];
46
+ });
44
47
  });
45
48
  };
46
49
  };
@@ -49,14 +52,10 @@ export const AppDialog = memo(({ methods }) => {
49
52
  methods.warning = defineMethod('warning');
50
53
  methods.error = defineMethod('error');
51
54
  methods.confirm = defineMethod('confirm');
52
- return stacks.map((p, i) => {
53
- return _jsx(AppDialogStack, { ...p }, i);
55
+ return stacks.map(p => {
56
+ return _createElement(AppDialogStack, { ...p, key: p.key });
54
57
  });
55
58
  });
56
59
  const AppDialogStack = memo(({ type, content, ...props }) => {
57
- const [open, setOpen] = useState(true);
58
- return (_jsx(Dialog, { width: 360, maskClosable: false, icon: _jsx(StatusIcon, { status: type }), showCancel: type === 'confirm', showClose: false, confirmText: type === 'confirm' ? void 0 : '知道了', ...props, open: open, onClose: reason => {
59
- props.onClose?.(reason);
60
- setOpen(false);
61
- }, children: content }));
60
+ return (_jsx(Dialog, { width: 360, maskClosable: false, icon: _jsx(StatusIcon, { status: type }), showCancel: type === 'confirm', showClose: false, confirmText: type === 'confirm' ? void 0 : '知道了', defaultOpen: true, ...props, children: content }));
62
61
  });
@@ -1,11 +1,12 @@
1
1
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
2
- import { Children, isValidElement, memo, useCallback, useMemo, useRef, useState } from 'react';
2
+ import { isValidElement, memo, useCallback, useMemo, useRef, useState } from 'react';
3
3
  import { Popper } from '../popper';
4
4
  import { OptionsBase } from '../optionsBase';
5
5
  import { Input } from '../input';
6
6
  import { isUnset, useControlled, useDerivedState, useLoading, useSync, mergeComponentProps, useStrictEffect } from '../../utils';
7
7
  import { classes } from './autocomplete.style';
8
8
  import { popperStyle } from '../popper/popper.style';
9
+ import { useFilterOptions } from '../optionsBase/filterOptions';
9
10
  export const Autocomplete = memo(({ children, loading, options, loadOptions, primaryKey = 'value', labelKey = 'label', onSelect, renderInput, popperProps, popperRef, defaultValue = '', value, onChange, ...props }) => {
10
11
  const [focused, _setFocused] = useState(false);
11
12
  const setFocused = (focused) => {
@@ -33,7 +34,12 @@ export const Autocomplete = memo(({ children, loading, options, loadOptions, pri
33
34
  * ------------------------------------------------------------------
34
35
  * 合并最终选项
35
36
  */
36
- const actualOptions = innerOptions || options || Children.map(children, c => isValidElement(c) ? c.props : c) || void 0;
37
+ const actualOptions = useFilterOptions({
38
+ searchValue: innerValue.current,
39
+ options: innerOptions || options,
40
+ children,
41
+ labelKey
42
+ }).map(opt => isValidElement(opt) ? opt.props : opt);
37
43
  const optionsMap = useMemo(() => {
38
44
  const map = new Map();
39
45
  actualOptions?.forEach(opt => {
@@ -46,7 +52,7 @@ export const Autocomplete = memo(({ children, loading, options, loadOptions, pri
46
52
  }, [actualOptions, primaryKey]);
47
53
  const [open, _setOpen] = useDerivedState(() => {
48
54
  return focused && !!optionsMap.size;
49
- }, [focused, optionsMap.size]);
55
+ }, [focused, optionsMap]);
50
56
  const setOpen = (open) => {
51
57
  if (!props.disabled && !props.readOnly && (!open || optionsMap.size)) {
52
58
  // 必须有选项才能打开下拉框
@@ -72,8 +78,6 @@ export const Autocomplete = memo(({ children, loading, options, loadOptions, pri
72
78
  loading: innerLoading.current,
73
79
  value: innerValue.current,
74
80
  onChange: changeHandler,
75
- onInput: () => setOpen(true),
76
- onClick: () => setOpen(true),
77
81
  onFocus: () => setFocused(true),
78
82
  onBlur: () => setFocused(false)
79
83
  });
@@ -81,7 +85,8 @@ export const Autocomplete = memo(({ children, loading, options, loadOptions, pri
81
85
  placement: 'bottom',
82
86
  variant: 'collapse',
83
87
  trigger: false,
84
- content: (_jsx(OptionsBase, { onToggleSelected: optionSelectHandler, loading: innerLoading.current, options: actualOptions, labelKey: labelKey, primaryKey: primaryKey, children: children }))
88
+ animation: false,
89
+ content: (_jsx(OptionsBase, { onToggleSelected: optionSelectHandler, loading: innerLoading.current, options: actualOptions, labelKey: labelKey, primaryKey: primaryKey, searchValue: innerValue.current, _optionsAlreadyFilter: true, children: children }))
85
90
  }, popperProps, {
86
91
  css: popperStyle,
87
92
  open: open.current,
@@ -39,9 +39,9 @@ export const SearchResult = memo(({ primaryKey, labelKey, childrenKey, searchTok
39
39
  if (!searchValue) {
40
40
  return flattedOptions;
41
41
  }
42
- const splited = searchValue.split(' ');
42
+ const split = searchValue.split(' ');
43
43
  return flattedOptions.filter(({ searchToken }) => {
44
- return splited.some(k => {
44
+ return split.some(k => {
45
45
  return k && searchToken.toLowerCase().includes(k.toLowerCase());
46
46
  });
47
47
  });
@@ -140,18 +140,18 @@ export declare function ClickAway({ ref, container, eventType, onClickAway, disa
140
140
  onFocusCapture: import("react").FocusEventHandler<HTMLDivElement>;
141
141
  onBlur: import("react").FocusEventHandler<HTMLDivElement>;
142
142
  onBlurCapture: import("react").FocusEventHandler<HTMLDivElement>;
143
- onChange: import("react").FormEventHandler<HTMLDivElement>;
144
- onChangeCapture: import("react").FormEventHandler<HTMLDivElement>;
143
+ onChange: import("react").ChangeEventHandler<HTMLDivElement, Element>;
144
+ onChangeCapture: import("react").ChangeEventHandler<HTMLDivElement, Element>;
145
145
  onBeforeInput: import("react").InputEventHandler<HTMLDivElement>;
146
- onBeforeInputCapture: import("react").FormEventHandler<HTMLDivElement>;
147
- onInput: import("react").FormEventHandler<HTMLDivElement>;
148
- onInputCapture: import("react").FormEventHandler<HTMLDivElement>;
149
- onReset: import("react").FormEventHandler<HTMLDivElement>;
150
- onResetCapture: import("react").FormEventHandler<HTMLDivElement>;
151
- onSubmit: import("react").FormEventHandler<HTMLDivElement>;
152
- onSubmitCapture: import("react").FormEventHandler<HTMLDivElement>;
153
- onInvalid: import("react").FormEventHandler<HTMLDivElement>;
154
- onInvalidCapture: import("react").FormEventHandler<HTMLDivElement>;
146
+ onBeforeInputCapture: import("react").InputEventHandler<HTMLDivElement>;
147
+ onInput: import("react").InputEventHandler<HTMLDivElement>;
148
+ onInputCapture: import("react").InputEventHandler<HTMLDivElement>;
149
+ onReset: import("react").ReactEventHandler<HTMLDivElement>;
150
+ onResetCapture: import("react").ReactEventHandler<HTMLDivElement>;
151
+ onSubmit: import("react").SubmitEventHandler<HTMLDivElement>;
152
+ onSubmitCapture: import("react").SubmitEventHandler<HTMLDivElement>;
153
+ onInvalid: import("react").ReactEventHandler<HTMLDivElement>;
154
+ onInvalidCapture: import("react").ReactEventHandler<HTMLDivElement>;
155
155
  onLoad: import("react").ReactEventHandler<HTMLDivElement>;
156
156
  onLoadCapture: import("react").ReactEventHandler<HTMLDivElement>;
157
157
  onError: import("react").ReactEventHandler<HTMLDivElement>;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { cloneElement, isValidElement, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
3
3
  import { useFormContext, useFormStyleContext, useFormValueContext } from './form';
4
- import { clsx, getValueOnChange, queryDeep, stringifyField, useDerivedState, toArray, getShortID, isUnset, useStrictMemo } from '../../utils';
4
+ import { clsx, getValueOnChange, queryDeep, stringifyField, useDerivedState, toArray, getRandomId, isUnset, useStrictMemo } from '../../utils';
5
5
  import { DescriptionItem } from '../descriptions';
6
6
  import { classes } from './form.style';
7
7
  import { Collapse } from '../transitionBase';
@@ -134,7 +134,7 @@ export const FormItem = ({ ref, wrapperRef, field, initialValue, label = '', rul
134
134
  }, [rules, required]);
135
135
  const [randomKey] = useDerivedState(prev => {
136
136
  // fieldValue变为undefined时,需要更新key以强制重渲染组件
137
- return !prev || typeof fieldValue === 'undefined' ? getShortID() : prev;
137
+ return !prev || typeof fieldValue === 'undefined' ? getRandomId() : prev;
138
138
  }, [fieldValue]);
139
139
  const renderedChildren = useMemo(() => {
140
140
  if (typeof children === 'function') {
@@ -74,7 +74,7 @@ export function useStyle({ color }) {
74
74
  }
75
75
 
76
76
  &:not(:has([data-read-only=true]))[data-focused=true],
77
- &:not(:has([data-read-only=true])):has(:focus) {
77
+ &:not(:has([data-read-only=true])):focus-within {
78
78
  &::before, &::after {
79
79
  display: block;
80
80
  animation: ${borderAnim} .4s ${easing.easeOut} forwards;
@@ -0,0 +1,4 @@
1
+ import { ReactNode } from 'react';
2
+ import { Id } from '../../types';
3
+ import { MenuOptionType, OptionsBaseProps } from './optionsBase';
4
+ export declare function useFilterOptions<O extends MenuOptionType<V>, V extends Id = Id>({ searchValue, options, children, filterPredicate, labelKey, searchTokenKey, _optionsAlreadyFilter }: Pick<OptionsBaseProps<O, V>, 'searchValue' | 'children' | 'options' | 'filterPredicate' | 'labelKey' | 'searchTokenKey' | '_optionsAlreadyFilter'>): (O | ReactNode)[];
@@ -0,0 +1,33 @@
1
+ import { Children, isValidElement, useMemo } from 'react';
2
+ export function useFilterOptions({ searchValue, options, children, filterPredicate, labelKey = 'label', searchTokenKey = 'searchToken', _optionsAlreadyFilter }) {
3
+ return useMemo(() => {
4
+ if (_optionsAlreadyFilter) {
5
+ return options || Children.toArray(children);
6
+ }
7
+ const trimmedSearchValue = searchValue?.trim();
8
+ if (!trimmedSearchValue) {
9
+ return options || Children.toArray(children);
10
+ }
11
+ const splitValue = trimmedSearchValue.split(' ');
12
+ const filterFn = (opt, index) => {
13
+ let ret = false;
14
+ if (filterPredicate) {
15
+ ret = filterPredicate(trimmedSearchValue, opt, index);
16
+ }
17
+ else {
18
+ const searchToken = typeof opt[labelKey] === 'string' ? opt[labelKey] : opt[searchTokenKey];
19
+ if (typeof searchToken === 'string') {
20
+ ret = splitValue.some(k => {
21
+ return k && searchToken.toLowerCase().includes(k.toLowerCase());
22
+ });
23
+ }
24
+ }
25
+ return ret;
26
+ };
27
+ return options
28
+ ? options.filter(filterFn)
29
+ : Children.toArray(children).filter((c, index) => {
30
+ return isValidElement(c) && filterFn(c.props, index);
31
+ });
32
+ }, [searchValue, filterPredicate, options, children, labelKey, searchTokenKey, _optionsAlreadyFilter]);
33
+ }
@@ -27,5 +27,10 @@ export interface OptionsBaseProps<O extends MenuOptionType<V>, V extends Id = Id
27
27
  searchValue?: string;
28
28
  selectedValue?: V | V[];
29
29
  onToggleSelected?(value: V, e: KeyboardEvent | React.MouseEvent<HTMLDivElement>): void;
30
+ /**
31
+ * @private
32
+ * 内部使用,传入的选项是否已经经过筛选
33
+ */
34
+ _optionsAlreadyFilter?: boolean;
30
35
  }
31
36
  export declare const OptionsBase: <O extends MenuOptionType<V>, V extends Id = Id>(props: OptionsBaseProps<O, V>) => ReactElement;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
2
- import { useMemo, memo, Children, isValidElement, cloneElement, useRef } from 'react';
2
+ import { useMemo, memo, isValidElement, cloneElement, useRef } from 'react';
3
3
  import { Highlight } from '../highlight';
4
4
  import { MenuItem } from '../menuItem';
5
5
  import { Placeholder } from '../placeholder';
@@ -7,39 +7,14 @@ import { clsx, isSelected, mergeComponentProps, useKeyboard, useSync } from '../
7
7
  import { classes, style } from './optionsBase.style';
8
8
  import { Loading } from '../loading';
9
9
  import { usePopperContext, useScrollToTarget } from '../popper';
10
+ import { useFilterOptions } from './filterOptions';
10
11
  export const OptionsBase = memo(({
11
12
  // 共享属性
12
13
  showCheckbox, loading, options, children, labelKey = 'label', primaryKey = 'value', searchTokenKey = 'searchToken', filterPredicate,
13
14
  // 以下为非共享属性
14
- searchValue, selectedValue, onToggleSelected, ...props }) => {
15
+ searchValue, selectedValue, onToggleSelected, _optionsAlreadyFilter, ...props }) => {
15
16
  const { open, setOpen } = usePopperContext();
16
- const filteredOptions = useMemo(() => {
17
- const trimmedSearchValue = searchValue?.trim();
18
- if (!trimmedSearchValue) {
19
- return options || Children.toArray(children);
20
- }
21
- const splitedValue = trimmedSearchValue.split(' ');
22
- const filterFn = (opt, index) => {
23
- let ret = false;
24
- if (filterPredicate) {
25
- ret = filterPredicate(trimmedSearchValue, opt, index);
26
- }
27
- else {
28
- const searchToken = typeof opt[labelKey] === 'string' ? opt[labelKey] : opt[searchTokenKey];
29
- if (typeof searchToken === 'string') {
30
- ret = splitedValue.some(k => {
31
- return k && searchToken.toLowerCase().includes(k.toLowerCase());
32
- });
33
- }
34
- }
35
- return ret;
36
- };
37
- return options
38
- ? options.filter(filterFn)
39
- : Children.toArray(children).filter((c, index) => {
40
- return isValidElement(c) && filterFn(c.props, index);
41
- });
42
- }, [searchValue, filterPredicate, options, children, labelKey, searchTokenKey]);
17
+ const filteredOptions = useFilterOptions({ searchValue, filterPredicate, options, children, labelKey, searchTokenKey, _optionsAlreadyFilter });
43
18
  /**
44
19
  * ------------------------------------------------------------------
45
20
  * 键盘控制
@@ -28,7 +28,7 @@ export interface PopperProps extends Omit<DivProps, 'content' | 'children'> {
28
28
  sizeAdaptable?: boolean;
29
29
  /** trigger{@link trigger}包含"hover"时,鼠标移入移的延迟时间,默认为`150(ms)` */
30
30
  mouseEnterDelay?: number;
31
- /**默认为`150(ms)` */
31
+ /** 默认为`150(ms)` */
32
32
  mouseLeaveDelay?: number;
33
33
  defaultOpen?: boolean;
34
34
  open?: boolean;
@@ -43,6 +43,8 @@ export interface PopperProps extends Omit<DivProps, 'content' | 'children'> {
43
43
  * @enum {undefined} 第一次打开时渲染,跟随父组件销毁。
44
44
  */
45
45
  forceRender?: boolean;
46
+ /** 打开与关闭是否渲染过度动画,默认为`true` */
47
+ animation?: boolean;
46
48
  children?: ReactElement<any>;
47
49
  }
48
50
  export interface PopperRef extends HTMLDivElement {
@@ -51,4 +53,4 @@ export interface PopperRef extends HTMLDivElement {
51
53
  openAnimation?: boolean;
52
54
  }, beforeOpen?: () => void): void;
53
55
  }
54
- export declare function Popper({ ref, popperRef, anchorElement, container, effectContainer, content, offset, trigger, clickToClose, placement, variant, sizeAdaptable, mouseEnterDelay, mouseLeaveDelay, defaultOpen, open, onOpenChange, onOpenChangeEnd, disabled, autoClose, forceRender, children, ...props }: PopperProps): import("@emotion/react/jsx-runtime").JSX.Element;
56
+ export declare function Popper({ ref, popperRef, anchorElement, container, effectContainer, content, offset, trigger, clickToClose, placement, variant, sizeAdaptable, mouseEnterDelay, mouseLeaveDelay, defaultOpen, open, onOpenChange, onOpenChangeEnd, disabled, autoClose, forceRender, animation, children, ...props }: PopperProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -19,7 +19,7 @@ const getAttemptOrder = (placement) => {
19
19
  }
20
20
  return order;
21
21
  };
22
- export function Popper({ ref, popperRef, anchorElement, container, effectContainer, content, offset, trigger = 'hover', clickToClose, placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 150, mouseLeaveDelay = 150, defaultOpen = false, open, onOpenChange, onOpenChangeEnd, disabled, autoClose = false, forceRender, children, ...props }) {
22
+ export function Popper({ ref, popperRef, anchorElement, container, effectContainer, content, offset, trigger = 'hover', clickToClose, placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 150, mouseLeaveDelay = 150, defaultOpen = false, open, onOpenChange, onOpenChangeEnd, disabled, autoClose = false, forceRender, animation = true, children, ...props }) {
23
23
  const { spacing } = useTheme();
24
24
  offset ??= spacing[2];
25
25
  useImperativeHandle(popperRef, () => {
@@ -52,6 +52,8 @@ export function Popper({ ref, popperRef, anchorElement, container, effectContain
52
52
  if (newOpen || openHolding.current === 0) {
53
53
  _setInnerOpen(newOpen);
54
54
  }
55
+ // 不渲染动画时,需要手动触发onTransitionEnd
56
+ !animation && transitionEndHandler();
55
57
  };
56
58
  const { onChildrenOpenChange: tellParentOpenChange } = usePopperContext();
57
59
  useUpdateEffect(() => {
@@ -82,6 +84,9 @@ export function Popper({ ref, popperRef, anchorElement, container, effectContain
82
84
  const animating = useRef(false);
83
85
  const onTransitionEnd = (e) => {
84
86
  props.onTransitionEnd?.(e);
87
+ transitionEndHandler();
88
+ };
89
+ const transitionEndHandler = () => {
85
90
  onOpenChangeEnd?.(innerOpen.current);
86
91
  if (forceRender === false && !innerOpen.current) {
87
92
  renderedOnce.current = false;
@@ -538,5 +543,5 @@ export function Popper({ ref, popperRef, anchorElement, container, effectContain
538
543
  transform: 'scale(1)'
539
544
  },
540
545
  ...props.style
541
- }, "data-open": innerOpen.current, "data-variant": variant, "data-place-a": placeA.current, "data-place-b": placeB.current, onTransitionEnd: onTransitionEnd, children: _jsx(PopperContext, { value: contextValue, children: content }) }) }), containerEl.current)] }));
546
+ }, "data-open": innerOpen.current, "data-variant": variant, "data-place-a": placeA.current, "data-place-b": placeB.current, "data-animation": animation, onTransitionEnd: onTransitionEnd, children: _jsx(PopperContext, { value: contextValue, children: content }) }) }), containerEl.current)] }));
542
547
  }
@@ -16,7 +16,10 @@ export const style = defineCss(theme => {
16
16
  left: 0;
17
17
  z-index: ${zIndex.popper};
18
18
  transition-property: transform, opacity;
19
- transition-duration: .25s;
19
+
20
+ &[data-animation=true] {
21
+ transition-duration: .25s;
22
+ }
20
23
 
21
24
  &[data-open=true] {
22
25
  transition-timing-function: ${easing.bounce}, ${easing.easeOut};
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { createElement as _createElement } from "@emotion/react";
3
3
  import { isValidElement, memo, useRef, useState } from 'react';
4
4
  import { Collapse, Slide } from '../transitionBase';
5
- import { clsx, getEasyID, useColor, useContainer, useUnmounted } from '../../utils';
5
+ import { clsx, getRandomId, useColor, useContainer, useUnmounted } from '../../utils';
6
6
  import { classes, style } from './snackbarBase.style';
7
7
  import { TransitionGroup } from 'react-transition-group';
8
8
  import { StatusIcon, statusMapToIconDefinition } from '../status';
@@ -43,7 +43,7 @@ export const SnackbarBase = memo(({ methods, useTo, max = useTo === 'message' ?
43
43
  : { content: props };
44
44
  const { placement = useTo === 'message' ? 'top' : 'topRight', duration = useTo === 'message' ? 3000 : 5000, ...restProps } = propsObject;
45
45
  const index = placementToIndex[placement];
46
- let id = getEasyID('snackbar');
46
+ let id = getRandomId();
47
47
  const onCloseButtonClick = () => {
48
48
  !isUnmounted.current && setStacks(o => {
49
49
  o[index] = o[index].filter(s => s.id !== id);
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { memo, useImperativeHandle, useRef } from 'react';
3
3
  import { classes, style } from './upload.style';
4
- import { clsx, getShortID, onDndDragEnd, useControlled, useDndSensors, mergeComponentProps } from '../../utils';
4
+ import { clsx, getRandomId, onDndDragEnd, useControlled, useDndSensors, mergeComponentProps } from '../../utils';
5
5
  import { Button } from '../button';
6
6
  import { FileItem } from './fileItem';
7
7
  import { TransitionGroup } from 'react-transition-group';
@@ -17,7 +17,7 @@ import { faUpload } from '@fortawesome/free-solid-svg-icons/faUpload';
17
17
  const markFileId = (files) => {
18
18
  if (files) {
19
19
  for (const file of files) {
20
- file.id ||= getShortID();
20
+ file.id ||= getRandomId();
21
21
  }
22
22
  }
23
23
  };
@@ -1,15 +1,9 @@
1
1
  import { Ref, ReactNode, ElementType, ComponentProps } from 'react';
2
2
  import { Id, Obj } from '../types';
3
3
  /**
4
- * 生成最简易的随机ID
5
- * @param namespace
4
+ * 获取UUID
6
5
  */
7
- export declare function getEasyID(namespace?: string): string;
8
- /**
9
- * 获取任意长度由随机字母组成的ID
10
- * @param length
11
- */
12
- export declare function getShortID(length?: number): string;
6
+ export declare function getRandomId(): `${string}-${string}-${string}-${string}-${string}`;
13
7
  /**
14
8
  * 拼接元素的类名
15
9
  * @param classes
@@ -1,22 +1,8 @@
1
1
  /**
2
- * 生成最简易的随机ID
3
- * @param namespace
2
+ * 获取UUID
4
3
  */
5
- export function getEasyID(namespace = '') {
6
- return `${namespace}${Date.now()}${Math.random()}`;
7
- }
8
- const randomIdAlphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
9
- /**
10
- * 获取任意长度由随机字母组成的ID
11
- * @param length
12
- */
13
- export function getShortID(length = 8) {
14
- const { length: alphabetLength } = randomIdAlphabet;
15
- let id = '';
16
- while (length--) {
17
- id += randomIdAlphabet[Math.floor(Math.random() * alphabetLength)];
18
- }
19
- return id;
4
+ export function getRandomId() {
5
+ return crypto.randomUUID();
20
6
  }
21
7
  /**
22
8
  * 拼接元素的类名
@@ -387,11 +373,12 @@ export function mergeComponentProps(...props) {
387
373
  target.style = { ...source.style, ...target.style };
388
374
  continue;
389
375
  default:
390
- const v = source[p];
391
- if (typeof v === 'function') {
376
+ const sourceFn = source[p];
377
+ if (typeof sourceFn === 'function') {
378
+ const targetFn = target[p];
392
379
  target[p] = (...args) => {
393
- target[p](...args);
394
- v(...args);
380
+ targetFn(...args);
381
+ sourceFn(...args);
395
382
  };
396
383
  continue;
397
384
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canlooks/can-ui",
3
- "version": "0.0.144",
3
+ "version": "0.0.146",
4
4
  "author": "C.CanLiang <canlooks@gmail.com>",
5
5
  "description": "My ui framework",
6
6
  "license": "MIT",
@@ -20,9 +20,6 @@
20
20
  "url": "https://github.com/canlooks/canui/issues",
21
21
  "email": "canlooks@gmail.com"
22
22
  },
23
- "bin": {
24
- "can-ui-doc": "documentation/bootstrap.mjs"
25
- },
26
23
  "main": "dist/cjs/index.js",
27
24
  "module": "dist/esm/index.js",
28
25
  "types": "dist/esm/index.d.ts",
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
- import { preview } from 'vite';
3
- import inlineConfig from './vite.config.mjs';
4
- (async () => {
5
- const server = await preview(inlineConfig);
6
- server.printUrls();
7
- server.bindCLIShortcuts({ print: true });
8
- })();