@mezzanine-ui/react 1.0.0-rc.3 → 1.0.0-rc.4

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.
@@ -48,7 +48,7 @@ function isOptionSelected(option, value, isMultiple) {
48
48
  */
49
49
  const AutoComplete = forwardRef(function AutoComplete(props, ref) {
50
50
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
51
- const { addable = false, asyncData = false, className, clearSearchText = true, createSeparators = [',', '+', '\n'], defaultValue, disabled = disabledFromFormControl || false, disabledOptionsFilter = false, emptyText, error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, id, inputPosition = 'outside', inputProps, inputRef, loading = false, loadingText, loadingPosition = 'bottom', menuMaxHeight, mode = 'single', name, onClear: onClearProp, onChange: onChangeProp, onInsert, onSearch, onSearchTextChange, onVisibilityChange, open: openProp, options: optionsProp, overflowStrategy, placeholder = '', prefix, required = requiredFromFormControl || false, searchDebounceTime = 300, searchTextControlRef, size, trimOnCreate = true, value: valueProp, createActionText, createActionTextTemplate = '建立 "{text}"', dropdownZIndex, globalPortal = true, onReachBottom, onLeaveBottom, } = props;
51
+ const { addable = false, asyncData = false, className, clearSearchText = true, createSeparators = [',', '+', '\n'], defaultValue, disabled = disabledFromFormControl || false, disabledOptionsFilter = false, emptyText = '沒有符合的項目', error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, id, inputPosition = 'outside', inputProps, inputRef, loading = false, loadingText = '載入中...', loadingPosition = 'bottom', menuMaxHeight, mode = 'single', name, onClear: onClearProp, onChange: onChangeProp, onInsert, onSearch, onSearchTextChange, onVisibilityChange, open: openProp, options: optionsProp, overflowStrategy, placeholder = '', prefix, required = requiredFromFormControl || false, searchDebounceTime = 300, searchTextControlRef, size, trimOnCreate = true, value: valueProp, createActionText, createActionTextTemplate = '建立 "{text}"', dropdownZIndex, globalPortal = true, onReachBottom, onLeaveBottom, } = props;
52
52
  const shouldClearSearchTextOnBlur = clearSearchText;
53
53
  const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
54
54
  const isMultiple = mode === 'multiple';
@@ -25,7 +25,7 @@ function getElementRef(element) {
25
25
  return propsRef !== null && propsRef !== void 0 ? propsRef : element.ref;
26
26
  }
27
27
  function Dropdown(props) {
28
- const { activeIndex: activeIndexProp, id, children, options = [], type = 'default', toggleCheckedOnClick, maxHeight, disabled = false, showDropdownActions = false, actionCancelText, actionConfirmText, actionText, actionClearText, actionCustomButtonProps, showActionShowTopBar, isMatchInputValue = false, inputPosition = 'outside', placement = 'bottom', customWidth, sameWidth = false, listboxId: listboxIdProp, listboxLabel, onClose, onOpen, open: openProp, onVisibilityChange, onSelect, onActionConfirm, onActionCancel, onActionCustom, onActionClear, onItemHover, zIndex, status, loadingText, emptyText, emptyIcon, loadingPosition = 'full', followText: followTextProp, globalPortal = true, onReachBottom, onLeaveBottom, onScroll, mode, value, scrollbarDefer, scrollbarDisabled, scrollbarMaxWidth, scrollbarOptions, } = props;
28
+ const { activeIndex: activeIndexProp, id, children, options = [], type = 'default', toggleCheckedOnClick, maxHeight, disabled = false, showDropdownActions = false, actionCancelText, actionConfirmText, actionText, actionClearText, actionCustomButtonProps, showActionShowTopBar, isMatchInputValue = false, inputPosition = 'outside', placement = 'bottom-start', customWidth, sameWidth = false, listboxId: listboxIdProp, listboxLabel, onClose, onOpen, open: openProp, onVisibilityChange, onSelect, onActionConfirm, onActionCancel, onActionCustom, onActionClear, onItemHover, zIndex, status, loadingText, emptyText, emptyIcon, loadingPosition = 'full', followText: followTextProp, globalPortal = true, onReachBottom, onLeaveBottom, onScroll, mode, value, scrollbarDefer, scrollbarDisabled, scrollbarMaxWidth, scrollbarOptions, } = props;
29
29
  const isInline = inputPosition === 'inside';
30
30
  const inputId = useId();
31
31
  const defaultListboxId = `${inputId}-listbox`;
@@ -0,0 +1 @@
1
+ export { default } from './Section.js';
package/Stepper/Step.js CHANGED
@@ -35,6 +35,16 @@ const DotStatusIndicator = () => (jsx("span", { className: cx(stepClasses.status
35
35
  */
36
36
  const Step = forwardRef(function Step(props, ref) {
37
37
  const { className, description, index = 0, orientation, status = 'pending', title, type = 'number', error, ...rest } = props;
38
+ const handleKeyDown = rest.onClick
39
+ ? (e) => {
40
+ var _a;
41
+ if (e.key === 'Enter' || e.key === ' ') {
42
+ e.preventDefault();
43
+ e.currentTarget.click();
44
+ }
45
+ (_a = rest.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(rest, e);
46
+ }
47
+ : rest.onKeyDown;
38
48
  return (jsxs("div", { className: cx(stepClasses.host, {
39
49
  // status
40
50
  [stepClasses.processing]: status === 'processing',
@@ -49,8 +59,8 @@ const Step = forwardRef(function Step(props, ref) {
49
59
  [stepClasses.dot]: type === 'dot',
50
60
  [stepClasses.number]: type === 'number',
51
61
  // interactive
52
- [stepClasses.interactive]: rest.onClick,
53
- }, className), ref: ref, ...rest, children: [type === 'number' && (jsx(NumberStatusIndicator, { status: status, indicatorNumber: index + 1, error: error })), type === 'dot' && jsx(DotStatusIndicator, {}), jsxs("div", { className: stepClasses.textContainer, children: [jsxs(Typography, { className: stepClasses.title, variant: "label-primary-highlight", children: [title, jsx("span", { className: stepClasses.titleConnectLine })] }), description && (jsx(Typography, { className: stepClasses.description, variant: "caption", children: description }))] })] }));
62
+ [stepClasses.interactive]: !!rest.onClick,
63
+ }, className), role: rest.onClick ? 'button' : undefined, ref: ref, tabIndex: rest.onClick ? 0 : undefined, ...rest, onKeyDown: handleKeyDown, children: [type === 'number' && (jsx(NumberStatusIndicator, { status: status, indicatorNumber: index + 1, error: error })), type === 'dot' && jsx(DotStatusIndicator, {}), jsxs("div", { className: stepClasses.textContainer, children: [jsxs(Typography, { className: stepClasses.title, variant: "label-primary-highlight", children: [title, jsx("span", { className: stepClasses.titleConnectLine })] }), description && (jsx(Typography, { className: stepClasses.description, variant: "caption", children: description }))] })] }));
54
64
  });
55
65
 
56
66
  export { Step as default };
@@ -35,6 +35,7 @@ const Stepper = forwardRef(function Stepper(props, ref) {
35
35
  var _a;
36
36
  const step = element;
37
37
  return cloneElement(step, {
38
+ ...step.props,
38
39
  index,
39
40
  orientation,
40
41
  ref: (el) => {
@@ -48,7 +49,6 @@ const Stepper = forwardRef(function Stepper(props, ref) {
48
49
  ...step.props.style,
49
50
  },
50
51
  type,
51
- ...step.props,
52
52
  });
53
53
  });
54
54
  useEffect(() => {
package/Tab/Tab.d.ts CHANGED
@@ -24,6 +24,13 @@ export interface TabProps extends Omit<NativeElementPropsWithoutKeyAndRef<'div'>
24
24
  * The change event handler of Tab
25
25
  */
26
26
  onChange?: (activeKey: Key, index: number) => void;
27
+ /**
28
+ * The size of tab, controls padding around the tab group.
29
+ * main: padding-horizontal-spacious + padding-vertical-spacious (top only)
30
+ * sub: no padding
31
+ * @default 'main'
32
+ */
33
+ size?: 'main' | 'sub';
27
34
  }
28
35
  /**
29
36
  * The react component for `mezzanine` tab.
package/Tab/Tab.js CHANGED
@@ -1,18 +1,20 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { forwardRef, useState, useRef, Children, cloneElement, useLayoutEffect } from 'react';
2
+ import { forwardRef, useState, useRef, useMemo, Children, cloneElement, useLayoutEffect } from 'react';
3
3
  import { tabClasses } from '@mezzanine-ui/core/tab';
4
4
  import TabItem from './TabItem.js';
5
+ import { flattenChildren } from '../utils/flatten-children.js';
5
6
  import cx from 'clsx';
6
7
 
7
8
  /**
8
9
  * The react component for `mezzanine` tab.
9
10
  */
10
11
  const Tab = forwardRef(function Tab(props, ref) {
11
- const { activeKey: activeKeyProp, children, className, defaultActiveKey = 0, onChange, direction = 'horizontal', ...rest } = props;
12
+ const { activeKey: activeKeyProp, children, className, defaultActiveKey = 0, direction = 'horizontal', onChange, size = 'main', ...rest } = props;
12
13
  const [activeKeyInternal, setActiveKey] = useState(defaultActiveKey);
13
14
  const activeKey = activeKeyProp !== null && activeKeyProp !== void 0 ? activeKeyProp : activeKeyInternal;
14
15
  const activeTabItemRef = useRef(null);
15
- const tabItems = Children.map(children, (tabItem, index) => {
16
+ const flattenedChildren = useMemo(() => flattenChildren(children), [children]);
17
+ const tabItems = Children.map(flattenedChildren, (tabItem, index) => {
16
18
  var _a;
17
19
  if (!tabItem || tabItem.type !== TabItem) {
18
20
  return null;
@@ -51,6 +53,8 @@ const Tab = forwardRef(function Tab(props, ref) {
51
53
  return (jsxs("div", { ...rest, ref: ref, className: cx(tabClasses.host, {
52
54
  [tabClasses.tabHorizontal]: direction === 'horizontal',
53
55
  [tabClasses.tabVertical]: direction === 'vertical',
56
+ [tabClasses.tabSizeMain]: size === 'main',
57
+ [tabClasses.tabSizeSub]: size === 'sub',
54
58
  }, className), children: [tabItems, jsx("div", { className: tabClasses.tabActiveBar, style: activeBarStyle })] }));
55
59
  });
56
60
 
package/Tab/TabItem.d.ts CHANGED
@@ -15,6 +15,11 @@ export interface TabItemProps extends NativeElementPropsWithoutKeyAndRef<'button
15
15
  * @default false
16
16
  */
17
17
  disabled?: boolean;
18
+ /**
19
+ * Whether the tab item is in error state.
20
+ * @default false
21
+ */
22
+ error?: boolean;
18
23
  /**
19
24
  * The icon to display on the tab item.
20
25
  */
package/Tab/TabItem.js CHANGED
@@ -9,10 +9,11 @@ import cx from 'clsx';
9
9
  * The react component for `mezzanine` tab.
10
10
  */
11
11
  const TabItem = forwardRef(function TabItem(props, ref) {
12
- const { active, badgeCount, children, className, disabled = false, icon, ...rest } = props;
12
+ const { active, badgeCount, children, className, disabled = false, error = false, icon, ...rest } = props;
13
13
  return (jsxs("button", { ...rest, "aria-disabled": disabled, className: cx(tabClasses.tabItem, {
14
14
  [tabClasses.tabItemActive]: active,
15
- }, className), disabled: disabled, ref: ref, type: "button", children: [icon && jsx(Icon, { className: tabClasses.tabItemIcon, icon: icon, size: 16 }), children, badgeCount !== undefined && (jsx(Badge, { className: tabClasses.tabItemBadge, count: badgeCount, variant: active ? 'count-brand' : 'count-inactive' }))] }));
15
+ [tabClasses.tabItemError]: error,
16
+ }, className), disabled: disabled, ref: ref, type: "button", children: [icon && jsx(Icon, { className: tabClasses.tabItemIcon, icon: icon, size: 16 }), children, badgeCount !== undefined && (jsx(Badge, { className: tabClasses.tabItemBadge, count: badgeCount, variant: error ? 'count-alert' : active ? 'count-brand' : 'count-inactive' }))] }));
16
17
  });
17
18
 
18
19
  export { TabItem as default };
@@ -38,7 +38,7 @@ function TableDragOrPinHandleCellInner(props, ref) {
38
38
  return null;
39
39
  }
40
40
  if (loading) {
41
- return jsx(Skeleton, { variant: "body-highlight", width: "100%" });
41
+ return (jsx(Skeleton, { variant: "body-highlight", width: "100%", ...(mode === 'drag' ? dragHandleProps : {}) }));
42
42
  }
43
43
  if (mode === 'drag') {
44
44
  return (jsx("span", { className: tableClasses.dragOrPinHandle, ...dragHandleProps, children: jsx(Icon, { color: "neutral", icon: DotDragVerticalIcon }) }));
@@ -73,7 +73,6 @@ const Fade = forwardRef(function Fade(props, ref) {
73
73
  };
74
74
  return (jsx(Transition, { ...transitionProps, children: children &&
75
75
  ((state) => cloneElement(children, {
76
- ...children.props,
77
76
  ref: composedNodeRef,
78
77
  style: {
79
78
  ...getStyle(state, inProp),
@@ -106,7 +106,6 @@ const Scale = forwardRef(function Scale(props, ref) {
106
106
  };
107
107
  return (jsx(Transition, { ...transitionProps, children: children &&
108
108
  ((state) => cloneElement(children, {
109
- ...children.props,
110
109
  ref: composedNodeRef,
111
110
  style: {
112
111
  visibility: state === 'exited' && !inProp ? 'hidden' : undefined,
@@ -78,7 +78,6 @@ const Slide = forwardRef(function Slide(props, ref) {
78
78
  };
79
79
  return (jsx(Transition, { ...transitionProps, children: children &&
80
80
  ((state) => cloneElement(children, {
81
- ...children.props,
82
81
  ref: composedNodeRef,
83
82
  style: {
84
83
  ...getStyle(state, inProp, from),
@@ -82,7 +82,6 @@ const Translate = forwardRef(function Translate(props, ref) {
82
82
  };
83
83
  return (jsx(Transition, { ...transitionProps, children: children &&
84
84
  ((state) => cloneElement(children, {
85
- ...children.props,
86
85
  ref: composedNodeRef,
87
86
  style: {
88
87
  ...getStyle(state, inProp, from),
@@ -1,8 +1,10 @@
1
- import { useMemo } from 'react';
1
+ import { useRef, useCallback } from 'react';
2
2
  import { composeRefs } from '../utils/composeRefs.js';
3
3
 
4
4
  function useComposeRefs(refs) {
5
- return useMemo(() => composeRefs(refs), [refs]);
5
+ const refsRef = useRef(refs);
6
+ refsRef.current = refs;
7
+ return useCallback((element) => composeRefs(refsRef.current)(element), []);
6
8
  }
7
9
 
8
10
  export { useComposeRefs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mezzanine-ui/react",
3
- "version": "1.0.0-rc.3",
3
+ "version": "1.0.0-rc.4",
4
4
  "description": "React components for mezzanine-ui",
5
5
  "author": "Mezzanine",
6
6
  "repository": {
@@ -31,9 +31,9 @@
31
31
  "@floating-ui/dom": "^1.7.4",
32
32
  "@floating-ui/react-dom": "^2.1.6",
33
33
  "@hello-pangea/dnd": "^18.0.1",
34
- "@mezzanine-ui/core": "1.0.0-rc.3",
35
- "@mezzanine-ui/icons": "1.0.0-rc.3",
36
- "@mezzanine-ui/system": "1.0.0-rc.3",
34
+ "@mezzanine-ui/core": "1.0.0-rc.4",
35
+ "@mezzanine-ui/icons": "1.0.0-rc.4",
36
+ "@mezzanine-ui/system": "1.0.0-rc.4",
37
37
  "@tanstack/react-virtual": "^3.13.13",
38
38
  "@types/react-transition-group": "^4.4.12",
39
39
  "clsx": "^2.1.1",
@@ -17,14 +17,21 @@
17
17
  */
18
18
  function composeRefs(refs) {
19
19
  return (element) => {
20
+ const cleanups = [];
20
21
  refs.forEach((ref) => {
21
22
  if (typeof ref === 'function') {
22
- ref(element);
23
+ const cleanup = ref(element);
24
+ if (typeof cleanup === 'function') {
25
+ cleanups.push(cleanup);
26
+ }
23
27
  }
24
28
  else if (ref) {
25
29
  ref.current = element;
26
30
  }
27
31
  });
32
+ if (cleanups.length > 0) {
33
+ return () => cleanups.forEach((c) => c());
34
+ }
28
35
  };
29
36
  }
30
37
 
@@ -20,8 +20,9 @@ function flattenChildren(children, recursionDepth = -1, keys = []) {
20
20
  }
21
21
  else {
22
22
  if (isValidElement(node)) {
23
+ const rawKey = String(node.key).replace(/^\.\$/, '');
23
24
  acc.push(cloneElement(node, {
24
- key: keys.concat(String(node.key)).join('.'),
25
+ key: keys.length > 0 ? keys.concat(rawKey).join('.') : rawKey,
25
26
  }));
26
27
  }
27
28
  else if (typeof node === 'string' ||