@mezzanine-ui/react 0.8.0 → 0.9.1

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.
@@ -18,7 +18,7 @@ import { FormControlContext } from '../Form/FormControlContext.js';
18
18
  const DatePicker = forwardRef(function DatePicker(props, ref) {
19
19
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
20
20
  const { defaultDateFormat, getNow, } = useCalendarContext();
21
- const { calendarProps, className, clearable, defaultValue, disableOnNext, disableOnPrev, disabled = disabledFromFormControl || false, displayMonthLocale, error = severity === 'error' || false, fadeProps, format = defaultDateFormat, fullWidth = fullWidthFromFormControl || false, inputProps, isDateDisabled, isMonthDisabled, isYearDisabled, mode = 'day', onCalendarToggle: onCalendarToggleProp, onChange: onChangeProp, placeholder, popperProps, prefix, readOnly, referenceDate: referenceDateProp, required = requiredFromFormControl || false, size, value: valueProp, ...restTriggerProps } = props;
21
+ const { calendarProps, className, clearable = true, defaultValue, disableOnNext, disableOnPrev, disabled = disabledFromFormControl || false, displayMonthLocale, error = severity === 'error' || false, fadeProps, format = defaultDateFormat, fullWidth = fullWidthFromFormControl || false, inputProps, isDateDisabled, isMonthDisabled, isYearDisabled, mode = 'day', onCalendarToggle: onCalendarToggleProp, onChange: onChangeProp, placeholder, popperProps, prefix, readOnly, referenceDate: referenceDateProp, required = requiredFromFormControl || false, size, value: valueProp, ...restTriggerProps } = props;
22
22
  const { onBlur: onBlurProp, onKeyDown: onKeyDownProp, onFocus: onFocusProp, size: inputSize = format.length + 2, ...restInputProp } = inputProps || {};
23
23
  const formats = useMemo(() => [
24
24
  format,
@@ -18,7 +18,7 @@ import { FormControlContext } from '../Form/FormControlContext.js';
18
18
  const DateRangePicker = forwardRef(function DateRangePicker(props, ref) {
19
19
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
20
20
  const { defaultDateFormat, getNow, isBetween, } = useCalendarContext();
21
- const { calendarProps, className, clearable, defaultValue, disabled = disabledFromFormControl || false, displayMonthLocale, error = severity === 'error' || false, fadeProps, format = defaultDateFormat, fullWidth = fullWidthFromFormControl || false, inputFromPlaceholder, inputFromProps, inputToPlaceholder, inputToProps, isDateDisabled, isMonthDisabled, isYearDisabled, mode = 'day', onCalendarToggle: onCalendarToggleProp, onChange: onChangeProp, popperProps, prefix, readOnly, referenceDate: referenceDateProp, required = requiredFromFormControl || false, size, value: valueProp, } = props;
21
+ const { calendarProps, className, clearable = true, defaultValue, disabled = disabledFromFormControl || false, displayMonthLocale, error = severity === 'error' || false, fadeProps, format = defaultDateFormat, fullWidth = fullWidthFromFormControl || false, inputFromPlaceholder, inputFromProps, inputToPlaceholder, inputToProps, isDateDisabled, isMonthDisabled, isYearDisabled, mode = 'day', onCalendarToggle: onCalendarToggleProp, onChange: onChangeProp, popperProps, prefix, readOnly, referenceDate: referenceDateProp, required = requiredFromFormControl || false, size, value: valueProp, } = props;
22
22
  const { onBlur: onFromBlurProp, onKeyDown: onFromKeyDownProp, onFocus: onFromFocusProp, ...restInputFromProps } = inputFromProps || {};
23
23
  const { onBlur: onToBlurProp, onKeyDown: onToKeyDownProp, onFocus: onToFocusProp, ...restInputToProps } = inputToProps || {};
24
24
  const formats = useMemo(() => [
@@ -156,7 +156,9 @@ const DateRangePicker = forwardRef(function DateRangePicker(props, ref) {
156
156
  const [from, to] = internalValue;
157
157
  if (from && to) {
158
158
  const newValue = onChange([from, to]);
159
- onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp(newValue);
159
+ if (onChangeProp) {
160
+ onChangeProp(newValue);
161
+ }
160
162
  }
161
163
  else {
162
164
  onChange(valueProp);
@@ -18,7 +18,7 @@ const DateTimePicker = forwardRef(function DateTimePicker(props, ref) {
18
18
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
19
19
  const { defaultDateFormat, defaultTimeFormat, getNow, startOf, } = useCalendarContext();
20
20
  const defaultFormat = `${defaultDateFormat} ${defaultTimeFormat}`;
21
- const { calendarProps, className, clearable, confirmText, defaultValue, disableOnNext, disableOnPrev, disabled = disabledFromFormControl, displayMonthLocale, error = severity === 'error' || false, fadeProps, format = defaultFormat, fullWidth = fullWidthFromFormControl, hideHour, hideMinute, hideSecond, hourPrefix, hourStep, inputProps, isDateDisabled, isMonthDisabled, isYearDisabled, minutePrefix, minuteStep, onChange: onChangeProp, onPanelToggle: onPanelToggleProp, placeholder, popperProps, prefix, readOnly, referenceDate: referenceDateProp, required = requiredFromFormControl, secondPrefix, secondStep, size: sizeProp, value: valueProp, } = props;
21
+ const { calendarProps, className, clearable = true, confirmText, defaultValue, disableOnNext, disableOnPrev, disabled = disabledFromFormControl, displayMonthLocale, error = severity === 'error' || false, fadeProps, format = defaultFormat, fullWidth = fullWidthFromFormControl, hideHour, hideMinute, hideSecond, hourPrefix, hourStep, inputProps, isDateDisabled, isMonthDisabled, isYearDisabled, minutePrefix, minuteStep, onChange: onChangeProp, onPanelToggle: onPanelToggleProp, placeholder, popperProps, prefix, readOnly, referenceDate: referenceDateProp, required = requiredFromFormControl, secondPrefix, secondStep, size: sizeProp, value: valueProp, } = props;
22
22
  const { onBlur: onBlurProp, onKeyDown: onKeyDownProp, onFocus: onFocusProp, size: inputSize = format.length + 2, ...restInputProp } = inputProps || {};
23
23
  const formats = useMemo(() => [format, defaultFormat], [defaultFormat, format]);
24
24
  /** Panel open control */
@@ -0,0 +1,37 @@
1
+ import { ChangeEvent, KeyboardEvent, RefObject } from 'react';
2
+ import { UseInputControlValueProps } from './useInputControlValue';
3
+ export declare type TagsType = string[] | number[];
4
+ export interface UseInputWithTagsModeValueProps<E extends HTMLInputElement | HTMLTextAreaElement> extends UseInputControlValueProps<E> {
5
+ /**
6
+ * The value of initial tags
7
+ */
8
+ initialTagsValue?: string[];
9
+ /**
10
+ * Maximum permitted length of the tags
11
+ * @default 3
12
+ */
13
+ maxTagsLength?: number;
14
+ /**
15
+ * The change event handler of tags
16
+ */
17
+ onTagsChange?: (tags: TagsType) => void;
18
+ /**
19
+ * The ref object of input element
20
+ */
21
+ ref: RefObject<E>;
22
+ /**
23
+ * Will skip `onKeyDown` calling if `true`
24
+ * @default false
25
+ */
26
+ skip?: boolean;
27
+ /**
28
+ * Maximum length of value on each tag
29
+ * @default 8
30
+ */
31
+ tagValueMaxLength?: number;
32
+ }
33
+ export declare function useInputWithTagsModeValue<E extends HTMLInputElement | HTMLTextAreaElement>(props: Omit<UseInputWithTagsModeValueProps<E>, 'onChange'>): readonly [{
34
+ readonly tags: string[];
35
+ readonly typingValue: string;
36
+ readonly tagsReachedMax: boolean;
37
+ }, (event: ChangeEvent<E> | null) => void, () => void, (tag: string) => void, (e: KeyboardEvent) => void];
@@ -0,0 +1,88 @@
1
+ import { useRef, useState, useCallback } from 'react';
2
+ import { useInputControlValue } from './useInputControlValue.js';
3
+
4
+ function useInputWithTagsModeValue(props) {
5
+ var _a;
6
+ const { defaultValue, initialTagsValue = [], maxTagsLength, onTagsChange: onChangeProp, ref, skip = false, tagValueMaxLength = 8, } = props;
7
+ const canActive = !skip;
8
+ const activeMaxTagsLength = maxTagsLength || Math.max(3, initialTagsValue.length);
9
+ const tagsSetRef = useRef(new Set(initialTagsValue.map((initialTag) => initialTag.trim())));
10
+ const inputTypeIsNumber = useRef(((_a = ref.current) === null || _a === void 0 ? void 0 : _a.type) === 'number');
11
+ const tagValueTransform = (tag) => (tag.slice(0, tagValueMaxLength).trim());
12
+ const transformNumberTags = (tags) => (tags.map((tag) => Number(tag)));
13
+ const generateUniqueTags = () => (Array
14
+ .from(tagsSetRef.current.values())
15
+ .map((initialTag) => tagValueTransform(initialTag)));
16
+ const [value, setValue] = useInputControlValue({
17
+ defaultValue: canActive ? defaultValue : undefined,
18
+ });
19
+ const [tags, setTags] = useState(generateUniqueTags()
20
+ .slice(0, activeMaxTagsLength));
21
+ const tagsWillOverflow = useCallback(() => (tagsSetRef.current.size === activeMaxTagsLength), []);
22
+ const clearTypingFieldValue = () => {
23
+ if (!canActive)
24
+ return;
25
+ const target = ref.current;
26
+ if (target) {
27
+ const changeEvent = Object.create({});
28
+ changeEvent.target = target;
29
+ changeEvent.currentTarget = target;
30
+ target.value = '';
31
+ setValue(changeEvent);
32
+ }
33
+ };
34
+ const onClear = () => {
35
+ if (!canActive)
36
+ return;
37
+ clearTypingFieldValue();
38
+ tagsSetRef.current.clear();
39
+ setTags([]);
40
+ onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp([]);
41
+ };
42
+ const onChange = (event) => {
43
+ if (canActive && event) {
44
+ setValue(event);
45
+ }
46
+ };
47
+ const onRemove = (tag) => {
48
+ tagsSetRef.current.delete(tag);
49
+ const numberTag = inputTypeIsNumber.current;
50
+ const newTags = generateUniqueTags();
51
+ setTags(newTags);
52
+ onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp(numberTag ? transformNumberTags(newTags) : newTags);
53
+ };
54
+ const onKeyDown = useCallback((e) => {
55
+ var _a;
56
+ if (!canActive)
57
+ return;
58
+ const element = ref.current;
59
+ if (element && (element === null || element === void 0 ? void 0 : element.value) &&
60
+ (e.key === 'Enter' || e.code === 'Enter') &&
61
+ !e.nativeEvent.isComposing &&
62
+ !tagsWillOverflow()) {
63
+ e.preventDefault();
64
+ inputTypeIsNumber.current = ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.type) === 'number';
65
+ const tagsSet = tagsSetRef.current;
66
+ const isNumber = inputTypeIsNumber.current;
67
+ const newTagValue = tagValueTransform(element.value);
68
+ tagsSet.add(newTagValue);
69
+ const newTags = generateUniqueTags();
70
+ setTags(newTags);
71
+ onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp(isNumber ? transformNumberTags(newTags) : newTags);
72
+ clearTypingFieldValue();
73
+ }
74
+ }, [tagsWillOverflow]);
75
+ return [
76
+ {
77
+ tags,
78
+ typingValue: value,
79
+ tagsReachedMax: tagsWillOverflow(),
80
+ },
81
+ onChange,
82
+ onClear,
83
+ onRemove,
84
+ onKeyDown,
85
+ ];
86
+ }
87
+
88
+ export { useInputWithTagsModeValue };
package/Icon/Icon.js CHANGED
@@ -11,6 +11,7 @@ const Icon = forwardRef(function Icon(props, ref) {
11
11
  const { definition } = icon;
12
12
  const cssVars = toIconCssVars({ color, size });
13
13
  const style = {
14
+ '--mzn-icon-cursor': props.onClick || props.onMouseOver ? 'pointer' : 'inherit',
14
15
  ...cssVars,
15
16
  ...styleProp,
16
17
  };
package/Input/Input.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Ref, ChangeEventHandler } from 'react';
2
2
  import { InputSize } from '@mezzanine-ui/core/input';
3
3
  import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
4
+ import type { TagsType } from '../Form/useInputWithTagsModeValue';
4
5
  import { TextFieldProps } from '../TextField';
5
6
  export interface InputProps extends Omit<TextFieldProps, 'active' | 'children' | 'onClear' | 'onKeyDown'> {
6
7
  /**
@@ -15,6 +16,11 @@ export interface InputProps extends Omit<TextFieldProps, 'active' | 'children' |
15
16
  * The other native props for input element.
16
17
  */
17
18
  inputProps?: Omit<NativeElementPropsWithoutKeyAndRef<'input'>, 'defaultValue' | 'disabled' | 'onChange' | 'placeholder' | 'readOnly' | 'required' | 'value' | `aria-${'disabled' | 'multiline' | 'readonly' | 'required'}`>;
19
+ /**
20
+ * The input value mode
21
+ * @default 'default'
22
+ */
23
+ mode?: 'default' | 'tags';
18
24
  /**
19
25
  * The change event handler of input element.
20
26
  */
@@ -38,6 +44,28 @@ export interface InputProps extends Omit<TextFieldProps, 'active' | 'children' |
38
44
  * @default 'medium'
39
45
  */
40
46
  size?: InputSize;
47
+ /**
48
+ * The props for input element with tags mode.
49
+ */
50
+ tagsProps?: {
51
+ /**
52
+ * The initial value of tags
53
+ */
54
+ initialTagsValue?: string[];
55
+ /**
56
+ * The position of input field on tags mode
57
+ * @default 'bottom''
58
+ */
59
+ inputPosition?: 'top' | 'bottom';
60
+ /**
61
+ * Maximum permitted length of the tags
62
+ */
63
+ maxTagsLength?: number;
64
+ /**
65
+ * The change event handler of input tags value.
66
+ */
67
+ onTagsChange?: (tags: TagsType) => void;
68
+ };
41
69
  /**
42
70
  * The value of input.
43
71
  */
package/Input/Input.js CHANGED
@@ -1,9 +1,12 @@
1
- import { jsx } from 'react/jsx-runtime';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef, useContext, useRef } from 'react';
3
3
  import { inputClasses } from '@mezzanine-ui/core/input';
4
+ import { selectClasses } from '@mezzanine-ui/core/select';
4
5
  import { useComposeRefs } from '../hooks/useComposeRefs.js';
5
6
  import { useInputWithClearControlValue } from '../Form/useInputWithClearControlValue.js';
7
+ import { useInputWithTagsModeValue } from '../Form/useInputWithTagsModeValue.js';
6
8
  import TextField from '../TextField/TextField.js';
9
+ import Tag from '../Tag/Tag.js';
7
10
  import { FormControlContext } from '../Form/FormControlContext.js';
8
11
  import cx from 'clsx';
9
12
 
@@ -12,7 +15,9 @@ import cx from 'clsx';
12
15
  */
13
16
  const Input = forwardRef(function Input(props, ref) {
14
17
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
15
- const { className, clearable = false, defaultValue, disabled = disabledFromFormControl || false, error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, inputRef: inputRefProp, inputProps, onChange: onChangeProp, placeholder, prefix, readOnly = false, required = requiredFromFormControl || false, size = 'medium', suffix, value: valueProp, } = props;
18
+ const { className, clearable = false, defaultValue, disabled = disabledFromFormControl || false, error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, inputProps, inputRef: inputRefProp, mode = 'default', onChange: onChangeProp, placeholder, prefix, readOnly = false, required = requiredFromFormControl || false, size = 'medium', suffix, tagsProps, value: valueProp, } = props;
19
+ const { initialTagsValue, inputPosition = 'bottom', maxTagsLength, onTagsChange, } = tagsProps || {};
20
+ const tagsMode = mode === 'tags';
16
21
  const inputRef = useRef(null);
17
22
  const [value, onChange, onClear,] = useInputWithClearControlValue({
18
23
  defaultValue,
@@ -20,9 +25,27 @@ const Input = forwardRef(function Input(props, ref) {
20
25
  ref: inputRef,
21
26
  value: valueProp,
22
27
  });
28
+ const [{ tags, tagsReachedMax, }, tagsModeOnChange, tagsModeOnClear, tagsModeOnRemove, onKeyDown,] = useInputWithTagsModeValue({
29
+ defaultValue,
30
+ initialTagsValue,
31
+ maxTagsLength,
32
+ onTagsChange,
33
+ ref: inputRef,
34
+ skip: !tagsMode,
35
+ tagValueMaxLength: inputProps === null || inputProps === void 0 ? void 0 : inputProps.maxLength,
36
+ value: valueProp,
37
+ });
23
38
  const composedInputRef = useComposeRefs([inputRefProp, inputRef]);
39
+ const maxLength = () => (tagsMode
40
+ ? Math.min((inputProps === null || inputProps === void 0 ? void 0 : inputProps.maxLength) || 8, 8)
41
+ : inputProps === null || inputProps === void 0 ? void 0 : inputProps.maxLength);
24
42
  const active = !!value;
25
- return (jsx(TextField, Object.assign({ ref: ref, active: active, className: cx(inputClasses.host, className), clearable: clearable, disabled: disabled, error: error, fullWidth: fullWidth, onClear: onClear, prefix: prefix, size: size, suffix: suffix }, { children: jsx("input", Object.assign({}, inputProps, { ref: composedInputRef, "aria-disabled": disabled, "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, onChange: onChange, placeholder: placeholder, readOnly: readOnly, required: required, value: value }), void 0) }), void 0));
43
+ const mountInput = !tagsMode || !tagsReachedMax;
44
+ return (jsxs(TextField, Object.assign({ ref: ref, active: active, className: cx(inputClasses.host, tagsMode && inputClasses.tagsMode, inputPosition === 'top' && inputClasses.tagsModeInputOnTop, className), clearable: clearable, disabled: disabled, error: error, fullWidth: fullWidth, onClear: tagsMode ? tagsModeOnClear : onClear, prefix: mountInput ? prefix : undefined, suffix: mountInput ? suffix : undefined, size: size }, { children: [tagsMode && (jsx("div", Object.assign({ className: selectClasses.triggerTags }, { children: tags.map((tag) => (jsx(Tag, Object.assign({ closable: true, disabled: disabled, size: size, onClose: (e) => {
45
+ e.stopPropagation();
46
+ tagsModeOnRemove(tag);
47
+ } }, { children: tag }), tag))) }), void 0)),
48
+ mountInput && (jsx("input", Object.assign({}, inputProps, { "aria-disabled": disabled, "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, maxLength: maxLength(), onChange: tagsMode ? tagsModeOnChange : onChange, onKeyDown: tagsMode ? onKeyDown : inputProps === null || inputProps === void 0 ? void 0 : inputProps.onKeyDown, placeholder: placeholder, readOnly: readOnly, ref: composedInputRef, required: required, value: tagsMode ? undefined : value }), void 0))] }), void 0));
26
49
  });
27
50
  var Input$1 = Input;
28
51
 
@@ -22,7 +22,7 @@ const TableBody = forwardRef(function TableBody(props, ref) {
22
22
  const currentStartCount = (paginationOptions === null || paginationOptions === void 0 ? void 0 : paginationOptions.pageSize) && currentPage ? ((paginationOptions.pageSize) * (currentPage - 1)) : 0;
23
23
  const currentEndCount = (paginationOptions === null || paginationOptions === void 0 ? void 0 : paginationOptions.pageSize) && currentPage && total ? (Math.min(((paginationOptions.pageSize) * currentPage), total)) : 0;
24
24
  const currentDataSource = pagination && !disableAutoSlicing ? (dataSource.slice(currentStartCount, currentEndCount)) : dataSource;
25
- return (jsxs("div", Object.assign({}, rest, { ref: composedRefs, className: cx(tableClasses.body, className), onScroll: tableBody.onScroll, role: "rowgroup" }, { children: [currentDataSource.length ? currentDataSource.map((rowData) => (jsx(TableBodyRow, { className: rowClassName, rowData: rowData }, (rowData.key || rowData.id)))) : (jsx(Empty, Object.assign({}, restEmptyProps, { className: cx(tableClasses.bodyEmpty, emptyComponentClassName), fullHeight: emptyComponentFullHeight }, { children: emptyComponentChildren }), void 0)),
25
+ return (jsxs("div", Object.assign({}, rest, { ref: composedRefs, className: cx(tableClasses.body, className), onScroll: tableBody.onScroll, role: "rowgroup" }, { children: [currentDataSource.length ? currentDataSource.map((rowData, index) => (jsx(TableBodyRow, { className: rowClassName, rowData: rowData, rowIndex: index }, (rowData.key || rowData.id)))) : (jsx(Empty, Object.assign({}, restEmptyProps, { className: cx(tableClasses.bodyEmpty, emptyComponentClassName), fullHeight: emptyComponentFullHeight }, { children: emptyComponentChildren }), void 0)),
26
26
  (fetchMore === null || fetchMore === void 0 ? void 0 : fetchMore.isFetching) ? (jsx("div", Object.assign({ className: tableClasses.bodyFetchMore }, { children: jsx(Loading, { loading: true }, void 0) }), void 0)) : null,
27
27
  jsx("div", Object.assign({ ref: scrollElement.ref, onMouseDown: scrollElement.onMouseDown, onMouseUp: scrollElement.onMouseUp, onMouseEnter: scrollElement.onMouseEnter, onMouseLeave: scrollElement.onMouseLeave, role: "button", style: scrollElement.style, tabIndex: -1 }, { children: jsx("div", { style: {
28
28
  width: `${scrollBarSize}px`,
@@ -6,6 +6,7 @@ export interface TableBodyRowProps extends NativeElementPropsWithoutKeyAndRef<'d
6
6
  * table body row dataSource
7
7
  */
8
8
  rowData: TableDataSource;
9
+ rowIndex: number;
9
10
  }
10
11
  declare const TableBodyRow: import("react").ForwardRefExoticComponent<TableBodyRowProps & import("react").RefAttributes<HTMLDivElement>>;
11
12
  export default TableBodyRow;
@@ -1,8 +1,10 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { forwardRef, useContext, useState, useMemo, useCallback, Fragment } from 'react';
3
- import { tableClasses } from '@mezzanine-ui/core/table';
1
+ import { jsxs, jsx, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
+ import { forwardRef, useContext, useState, useMemo, Fragment } from 'react';
3
+ import { tableClasses, getColumnStyle, getCellStyle } from '@mezzanine-ui/core/table';
4
+ import get from 'lodash/get';
4
5
  import { TableContext, TableDataContext } from './TableContext.js';
5
6
  import TableCell from './TableCell.js';
7
+ import TableExpandedTable from './TableExpandedTable.js';
6
8
  import TableRowSelection from './rowSelection/TableRowSelection.js';
7
9
  import TableExpandable from './expandable/TableExpandable.js';
8
10
  import TableEditRenderWrapper from './editable/TableEditRenderWrapper.js';
@@ -10,7 +12,7 @@ import AccordionDetails from '../Accordion/AccordionDetails.js';
10
12
  import cx from 'clsx';
11
13
 
12
14
  const TableBodyRow = forwardRef(function TableBodyRow(props, ref) {
13
- const { className, rowData, ...rest } = props;
15
+ const { className, rowData, rowIndex, ...rest } = props;
14
16
  const { rowSelection, expanding, } = useContext(TableContext) || {};
15
17
  const { columns, } = useContext(TableDataContext) || {};
16
18
  /** Feature rowSelection */
@@ -25,39 +27,17 @@ const TableBodyRow = forwardRef(function TableBodyRow(props, ref) {
25
27
  var _a, _b;
26
28
  return ((_b = (_a = expanding === null || expanding === void 0 ? void 0 : expanding.expandedRowRender) === null || _a === void 0 ? void 0 : _a.call(expanding, rowData)) !== null && _b !== void 0 ? _b : null);
27
29
  }, [expanding, rowData]);
28
- /** styling */
29
- const getColumnStyle = useCallback((column) => {
30
- let style = {};
31
- if (column.width) {
32
- style = {
33
- ...style,
34
- width: column.width,
35
- maxWidth: column.width,
36
- };
37
- }
38
- return style;
39
- }, []);
40
- const getCellStyle = useCallback((column) => {
41
- let style = {};
42
- if (column.align) {
43
- style = {
44
- ...style,
45
- justifyContent: column.align === 'center' ? column.align : `flex-${column.align}`,
46
- };
47
- }
48
- return style;
49
- }, []);
50
30
  return (jsxs(Fragment, { children: [jsxs("div", Object.assign({}, rest, { ref: ref, className: cx(tableClasses.bodyRow, {
51
31
  [tableClasses.bodyRowHighlight]: selected || expanded,
52
32
  }, className), role: "row" }, { children: [rowSelection ? (jsx(TableRowSelection, { role: "gridcell", rowKey: (rowData.key || rowData.id), setChecked: (status) => setSelected(status), showDropdownIcon: false }, void 0)) : null,
53
- expanding ? (jsx(TableExpandable, { expandable: isExpandable, expanded: expanded, role: "gridcell", setExpanded: setExpanded }, void 0)) : null,
54
- (columns !== null && columns !== void 0 ? columns : []).map((column, index) => {
33
+ expanding ? (jsx(TableExpandable, { expandable: isExpandable, expanded: expanded, role: "gridcell", setExpanded: setExpanded, onExpand: (status) => { var _a; return (_a = expanding.onExpand) === null || _a === void 0 ? void 0 : _a.call(expanding, rowData, status); } }, void 0)) : null,
34
+ (columns !== null && columns !== void 0 ? columns : []).map((column) => {
55
35
  var _a, _b, _c, _d;
56
- const ellipsis = !!(rowData[column.dataIndex]) && ((_a = column.ellipsis) !== null && _a !== void 0 ? _a : true);
57
- const tooltipTitle = ((_c = (_b = column.renderTooltipTitle) === null || _b === void 0 ? void 0 : _b.call(column, rowData)) !== null && _c !== void 0 ? _c : rowData[column.dataIndex]);
58
- return (jsx("div", Object.assign({ className: cx(tableClasses.bodyRowCellWrapper, column.bodyClassName), style: getColumnStyle(column) }, { children: jsx(TableEditRenderWrapper, Object.assign({}, column, { rowData: rowData }, { children: jsx(TableCell, Object.assign({ ellipsis: ellipsis, forceShownTooltipWhenHovered: column.forceShownTooltipWhenHovered, style: getCellStyle(column), tooltipTitle: tooltipTitle }, { children: ((_d = column.render) === null || _d === void 0 ? void 0 : _d.call(column, column, rowData, index)) || rowData[column.dataIndex] }), void 0) }), void 0) }), `${column.dataIndex}-${column.title}`));
36
+ const ellipsis = !!(get(rowData, column.dataIndex)) && ((_a = column.ellipsis) !== null && _a !== void 0 ? _a : true);
37
+ const tooltipTitle = ((_c = (_b = column.renderTooltipTitle) === null || _b === void 0 ? void 0 : _b.call(column, rowData)) !== null && _c !== void 0 ? _c : get(rowData, column.dataIndex));
38
+ return (jsx("div", Object.assign({ className: cx(tableClasses.bodyRowCellWrapper, column.bodyClassName), style: getColumnStyle(column) }, { children: jsx(TableEditRenderWrapper, Object.assign({}, column, { rowData: rowData }, { children: jsx(TableCell, Object.assign({ ellipsis: ellipsis, forceShownTooltipWhenHovered: column.forceShownTooltipWhenHovered, style: getCellStyle(column), tooltipTitle: tooltipTitle }, { children: ((_d = column.render) === null || _d === void 0 ? void 0 : _d.call(column, column, rowData, rowIndex)) || get(rowData, column.dataIndex) }), void 0) }), void 0) }), `${column.dataIndex}-${column.title}`));
59
39
  })] }), void 0),
60
- renderedExpandedContent ? (jsx(AccordionDetails, Object.assign({ className: expanding.className, expanded: expanded }, { children: renderedExpandedContent }), void 0)) : null] }, void 0));
40
+ renderedExpandedContent ? (jsx(Fragment$1, { children: typeof renderedExpandedContent === 'string' ? (jsx(AccordionDetails, Object.assign({ className: expanding.className, expanded: expanded }, { children: renderedExpandedContent }), void 0)) : (jsx(Fragment$1, { children: renderedExpandedContent.dataSource.length > 0 ? (jsx(AccordionDetails, Object.assign({ className: cx(expanding.className, tableClasses.bodyRowExpandedTableWrapper), expanded: expanded }, { children: jsx(TableExpandedTable, { renderedExpandedContent: renderedExpandedContent }, void 0) }), void 0)) : null }, void 0)) }, void 0)) : null] }, void 0));
61
41
  });
62
42
  var TableBodyRow$1 = TableBodyRow;
63
43
 
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ import { TableDataSource, ExpandedTableColumn } from '@mezzanine-ui/core/table';
3
+ import { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
4
+ export interface TableExpandedTableProps extends NativeElementPropsWithoutKeyAndRef<'div'> {
5
+ renderedExpandedContent: {
6
+ dataSource: TableDataSource[];
7
+ columns?: ExpandedTableColumn[];
8
+ };
9
+ }
10
+ declare const TableExpandedTable: import("react").ForwardRefExoticComponent<TableExpandedTableProps & import("react").RefAttributes<HTMLDivElement>>;
11
+ export default TableExpandedTable;
@@ -0,0 +1,27 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { forwardRef, useContext } from 'react';
3
+ import { tableClasses, getColumnStyle, getCellStyle } from '@mezzanine-ui/core/table';
4
+ import get from 'lodash/get';
5
+ import { TableDataContext } from './TableContext.js';
6
+ import TableCell from './TableCell.js';
7
+ import TableExpandable from './expandable/TableExpandable.js';
8
+ import cx from 'clsx';
9
+
10
+ const TableExpandedTable = forwardRef(function TableExpandedTable(props, ref) {
11
+ const { renderedExpandedContent, } = props;
12
+ const { columns, } = useContext(TableDataContext) || {};
13
+ return (jsx("div", Object.assign({ className: tableClasses.bodyRowExpandedTable }, { children: renderedExpandedContent.dataSource.map((source, sourceIndex) => {
14
+ var _a;
15
+ return (jsxs("div", Object.assign({ ref: ref, className: cx(tableClasses.bodyRow, tableClasses.bodyRowExpandedTableRow), role: "row" }, { children: [jsx(TableExpandable, { showIcon: false }, void 0),
16
+ ((_a = (renderedExpandedContent.columns || columns)) !== null && _a !== void 0 ? _a : [])
17
+ .map((column, index) => {
18
+ var _a, _b, _c, _d;
19
+ const ellipsis = !!(get(source, column.dataIndex)) && ((_a = column.ellipsis) !== null && _a !== void 0 ? _a : true);
20
+ const tooltipTitle = ((_c = (_b = column.renderTooltipTitle) === null || _b === void 0 ? void 0 : _b.call(column, source)) !== null && _c !== void 0 ? _c : get(source, column.dataIndex));
21
+ return (jsx("div", Object.assign({ className: cx(tableClasses.bodyRowCellWrapper, column.bodyClassName), style: getColumnStyle((columns !== null && columns !== void 0 ? columns : [])[index]) }, { children: jsx(TableCell, Object.assign({ ellipsis: ellipsis, forceShownTooltipWhenHovered: column.forceShownTooltipWhenHovered, style: getCellStyle((columns !== null && columns !== void 0 ? columns : [])[index]), tooltipTitle: tooltipTitle || '' }, { children: ((_d = column.render) === null || _d === void 0 ? void 0 : _d.call(column, column, source, sourceIndex)) || get(source, column.dataIndex) }), void 0) }), `${column.dataIndex}-${index}`));
22
+ })] }), (source.key || source.id)));
23
+ }) }), void 0));
24
+ });
25
+ var TableExpandedTable$1 = TableExpandedTable;
26
+
27
+ export { TableExpandedTable$1 as default };
@@ -1,6 +1,6 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { forwardRef, useContext, useCallback } from 'react';
3
- import { tableClasses } from '@mezzanine-ui/core/table';
2
+ import { forwardRef, useContext } from 'react';
3
+ import { tableClasses, getColumnStyle, getCellStyle } from '@mezzanine-ui/core/table';
4
4
  import { TableContext, TableDataContext } from './TableContext.js';
5
5
  import { SELECTED_ALL_KEY } from './rowSelection/useTableRowSelection.js';
6
6
  import TableCell from './TableCell.js';
@@ -13,34 +13,12 @@ const TableHeader = forwardRef(function TableHeader(props, ref) {
13
13
  const { className, ...rest } = props;
14
14
  const { rowSelection, expanding, } = useContext(TableContext) || {};
15
15
  const { columns, } = useContext(TableDataContext) || {};
16
- /** styling */
17
- const getColumnStyle = useCallback((column) => {
18
- let style = {};
19
- if (column.width) {
20
- style = {
21
- ...style,
22
- width: column.width,
23
- maxWidth: column.width,
24
- };
25
- }
26
- return style;
27
- }, []);
28
- const getCellStyle = useCallback((column) => {
29
- let style = {};
30
- if (column.align) {
31
- style = {
32
- ...style,
33
- justifyContent: column.align === 'center' ? column.align : `flex-${column.align}`,
34
- };
35
- }
36
- return style;
37
- }, []);
38
16
  return (jsxs("div", Object.assign({ ref: ref }, rest, { className: cx(tableClasses.header, className), role: "rowgroup" }, { children: [rowSelection ? (jsx(TableRowSelection, { rowKey: SELECTED_ALL_KEY, showDropdownIcon: true }, void 0)) : null,
39
17
  expanding && !rowSelection ? (jsx(TableExpandable, { showIcon: false }, void 0)) : null,
40
18
  (columns !== null && columns !== void 0 ? columns : []).map((column) => {
41
19
  var _a;
42
20
  return (jsx("div", Object.assign({ className: cx(tableClasses.headerCellWrapper, column.headerClassName), style: getColumnStyle(column) }, { children: jsxs(TableCell, Object.assign({ ellipsis: false, role: "columnheader", style: getCellStyle(column) }, { children: [((_a = column.renderTitle) === null || _a === void 0 ? void 0 : _a.call(column, tableClasses)) || column.title,
43
- typeof column.sorter === 'function' ? (jsx(TableSortingIcon, { column: column }, void 0)) : null] }), void 0) }), `${column.dataIndex}-${column.title}`));
21
+ typeof column.sorter === 'function' || typeof column.onSorted === 'function' ? (jsx(TableSortingIcon, { column: column }, void 0)) : null] }), void 0) }), `${column.dataIndex}-${column.title}`));
44
22
  })] }), void 0));
45
23
  });
46
24
  var TableHeader$1 = TableHeader;
@@ -10,6 +10,10 @@ export interface TableExpandableProps extends NativeElementPropsWithoutKeyAndRef
10
10
  * whether is expanded or not
11
11
  */
12
12
  expanded?: boolean;
13
+ /**
14
+ * Invoked by expanded status changed.
15
+ */
16
+ onExpand?(status: boolean): void;
13
17
  /**
14
18
  * toggle expanded
15
19
  */
@@ -6,10 +6,19 @@ import Icon from '../../Icon/Icon.js';
6
6
  import cx from 'clsx';
7
7
 
8
8
  const TableExpandable = forwardRef(function TableExpandable(props, ref) {
9
- const { className, expandable = true, expanded, setExpanded, showIcon = true, ...rest } = props;
9
+ const { className, expandable = true, expanded, onExpand, setExpanded, showIcon = true, ...rest } = props;
10
+ const onClick = () => {
11
+ if (expandable) {
12
+ const nextStatus = !expanded;
13
+ setExpanded === null || setExpanded === void 0 ? void 0 : setExpanded(nextStatus);
14
+ if (onExpand) {
15
+ onExpand(nextStatus);
16
+ }
17
+ }
18
+ };
10
19
  return (jsx("div", Object.assign({}, rest, { ref: ref, className: cx(tableClasses.collapseAction, className) }, { children: jsx("div", Object.assign({ className: tableClasses.icon }, { children: showIcon ? (jsx(Icon, { className: cx(tableClasses.icon, {
11
20
  [tableClasses.iconClickable]: expandable,
12
- }), color: expandable ? 'primary' : 'disabled', icon: ChevronDownIcon, onClick: () => expandable && (setExpanded === null || setExpanded === void 0 ? void 0 : setExpanded(!expanded)), style: { transform: `rotate(${expanded ? '180deg' : '0'})` } }, void 0)) : null }), void 0) }), void 0));
21
+ }), color: expandable ? 'primary' : 'disabled', icon: ChevronDownIcon, onClick: onClick, style: { transform: `rotate(${expanded ? '180deg' : '0'})` } }, void 0)) : null }), void 0) }), void 0));
13
22
  });
14
23
  var TableExpandable$1 = TableExpandable;
15
24
 
@@ -1,5 +1,6 @@
1
1
  import { useState, useCallback } from 'react';
2
2
  import isEqual from 'lodash/isEqual';
3
+ import get from 'lodash/get';
3
4
  import { useControlValueState } from '../../Form/useControlValueState.js';
4
5
  import { useLastCallback } from '../../hooks/useLastCallback.js';
5
6
 
@@ -50,15 +51,15 @@ function useTableSorting(props) {
50
51
  }, []);
51
52
  const onChange = useLastCallback((opts) => {
52
53
  const { dataIndex, sorter, onSorted } = opts;
54
+ const isChosenFromOneToAnother = sortedOn && dataIndex !== sortedOn;
55
+ const nextSortedType = getNextSortedType(isChosenFromOneToAnother ? 'none' : sortedType);
53
56
  const onMappingSources = (sources) => {
54
57
  setDataSource(sources);
55
- onSorted === null || onSorted === void 0 ? void 0 : onSorted(sources);
58
+ onSorted === null || onSorted === void 0 ? void 0 : onSorted(dataIndex, nextSortedType);
56
59
  };
57
60
  // only apply changes when column sorter is given
58
- if (typeof sorter === 'function') {
61
+ if (typeof sorter === 'function' || typeof onSorted === 'function') {
59
62
  // should update next sorted type first
60
- const isChosenFromOneToAnother = sortedOn && dataIndex !== sortedOn;
61
- const nextSortedType = getNextSortedType(isChosenFromOneToAnother ? 'none' : sortedType);
62
63
  setSortedType(nextSortedType);
63
64
  switch (nextSortedType) {
64
65
  case 'desc':
@@ -67,10 +68,12 @@ function useTableSorting(props) {
67
68
  setSortedOn(dataIndex);
68
69
  // getting new source instance (when switch between sorter, should use origin dataSource)
69
70
  let newSource = (isChosenFromOneToAnother ? dataSourceProp : dataSource).slice(0);
70
- // sort by given sorter
71
- newSource = newSource.sort((a, b) => (
72
- // reverse result when sorted type is ascending
73
- (sorter(a[dataIndex], b[dataIndex])) * (nextSortedType === 'asc' ? -1 : 1)));
71
+ if (typeof sorter === 'function') {
72
+ // sort by given sorter
73
+ newSource = newSource.sort((a, b) => (
74
+ // reverse result when sorted type is ascending
75
+ (sorter(get(a, dataIndex), get(b, dataIndex))) * (nextSortedType === 'asc' ? -1 : 1)));
76
+ }
74
77
  // map back the data source
75
78
  onMappingSources(newSource);
76
79
  break;
@@ -1,26 +1,10 @@
1
1
  import { useState, useEffect } from 'react';
2
- import { useWindowWidth } from '../hooks/useWindowWidth.js';
3
2
 
4
3
  function useTabsOverflow(tabsRef) {
5
4
  const [isOverflowing, setIsOverflowing] = useState(false);
6
5
  const [scrollState, setScrollState] = useState('begin');
7
6
  const isScrollToBegin = scrollState === 'begin';
8
7
  const isScrollToEnd = scrollState === 'end';
9
- const windowWidth = useWindowWidth();
10
- function handleScrollState() {
11
- if (tabsRef.current) {
12
- const offsetRight = tabsRef.current.scrollWidth - tabsRef.current.clientWidth;
13
- if (tabsRef.current.scrollLeft === 0) {
14
- setScrollState('begin');
15
- }
16
- else if (tabsRef.current.scrollLeft >= offsetRight) {
17
- setScrollState('end');
18
- }
19
- else {
20
- setScrollState('middle');
21
- }
22
- }
23
- }
24
8
  function scrollToLeft() {
25
9
  if (tabsRef.current) {
26
10
  tabsRef.current.scrollTo(0, 0);
@@ -34,16 +18,35 @@ function useTabsOverflow(tabsRef) {
34
18
  }
35
19
  useEffect(() => {
36
20
  if (tabsRef.current) {
37
- const isXOverflowing = tabsRef.current.scrollWidth > tabsRef.current.clientWidth;
38
- if (isOverflowing !== isXOverflowing) {
39
- setIsOverflowing(isXOverflowing);
40
- }
41
- }
42
- }, [isOverflowing, windowWidth]);
43
- useEffect(() => {
44
- if (tabsRef.current) {
21
+ const handleOverflowingState = () => {
22
+ if (tabsRef.current) {
23
+ setIsOverflowing(tabsRef.current.scrollWidth > tabsRef.current.clientWidth);
24
+ }
25
+ };
26
+ const handleScrollState = () => {
27
+ if (tabsRef.current) {
28
+ const offsetRight = tabsRef.current.scrollWidth - tabsRef.current.clientWidth;
29
+ if (tabsRef.current.scrollLeft === 0) {
30
+ setScrollState('begin');
31
+ }
32
+ else if (tabsRef.current.scrollLeft >= offsetRight) {
33
+ setScrollState('end');
34
+ }
35
+ else {
36
+ setScrollState('middle');
37
+ }
38
+ }
39
+ };
40
+ // init isOverflowing when mounting
41
+ handleOverflowingState();
42
+ window.addEventListener('resize', handleOverflowingState);
45
43
  tabsRef.current.addEventListener('scroll', handleScrollState);
46
- return () => { var _a; return (_a = tabsRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('scroll', handleScrollState); };
44
+ return () => {
45
+ if (tabsRef.current) {
46
+ window.removeEventListener('resize', handleOverflowingState);
47
+ tabsRef.current.removeEventListener('scroll', handleScrollState);
48
+ }
49
+ };
47
50
  }
48
51
  }, [tabsRef.current]);
49
52
  return {
@@ -20,12 +20,13 @@ const TimePanelColumn = forwardRef(function TimePanelColumn(props, ref) {
20
20
  };
21
21
  const prevetSmoothScrollTo = useRef(true);
22
22
  useEffect(() => {
23
- var _a;
24
23
  const activeIndex = units.findIndex(({ value }) => value === activeUnit);
25
- (_a = cellsRef.current) === null || _a === void 0 ? void 0 : _a.scrollTo({
26
- top: activeIndex * cellHeight,
27
- behavior: prevetSmoothScrollTo.current ? 'auto' : 'smooth',
28
- });
24
+ if (cellsRef.current) {
25
+ cellsRef.current.scrollTo({
26
+ top: activeIndex * cellHeight,
27
+ behavior: prevetSmoothScrollTo.current ? 'auto' : 'smooth',
28
+ });
29
+ }
29
30
  prevetSmoothScrollTo.current = false;
30
31
  }, [activeUnit, cellHeight, units]);
31
32
  return (jsxs("div", Object.assign({ ref: ref, className: timePanelClasses.column }, { children: [prefix && jsx("div", Object.assign({ className: timePanelClasses.columnPrefix }, { children: prefix }), void 0),
@@ -17,7 +17,7 @@ import { FormControlContext } from '../Form/FormControlContext.js';
17
17
  const TimePicker = forwardRef(function TimePicker(props, ref) {
18
18
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
19
19
  const { defaultTimeFormat, } = useCalendarContext();
20
- const { className, clearable, confirmText, defaultValue, disabled = disabledFromFormControl, error = severity === 'error' || false, format = defaultTimeFormat, fullWidth = fullWidthFromFormControl, hideHour, hideMinute, hideSecond, hourPrefix, hourStep, inputProps, minutePrefix, minuteStep, onChange: onChangeProp, onPanelToggle: onPanelToggleProp, placeholder, popperProps, prefix, readOnly, required = requiredFromFormControl, secondPrefix, secondStep, size: sizeProp, value: valueProp, } = props;
20
+ const { className, clearable = true, confirmText, defaultValue, disabled = disabledFromFormControl, error = severity === 'error' || false, format = defaultTimeFormat, fullWidth = fullWidthFromFormControl, hideHour, hideMinute, hideSecond, hourPrefix, hourStep, inputProps, minutePrefix, minuteStep, onChange: onChangeProp, onPanelToggle: onPanelToggleProp, placeholder, popperProps, prefix, readOnly, required = requiredFromFormControl, secondPrefix, secondStep, size: sizeProp, value: valueProp, } = props;
21
21
  const { onBlur: onBlurProp, onKeyDown: onKeyDownProp, onFocus: onFocusProp, size: inputSize = format.length + 2, ...restInputProp } = inputProps || {};
22
22
  const formats = useMemo(() => [format], [format]);
23
23
  /** Panel open control */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mezzanine-ui/react",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "React components for mezzanine-ui",
5
5
  "author": "Mezzanine",
6
6
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "react-dom": "^17.0.1"
33
33
  },
34
34
  "dependencies": {
35
- "@mezzanine-ui/core": "^0.7.3",
35
+ "@mezzanine-ui/core": "^0.9.0",
36
36
  "@mezzanine-ui/icons": "^0.7.3",
37
37
  "@mezzanine-ui/system": "^0.7.0",
38
38
  "@popperjs/core": "^2.9.2",