@mezzanine-ui/react 0.8.0 → 0.8.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.
|
@@ -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,
|
|
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
|
-
|
|
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
|
|
package/Table/TableBodyRow.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { forwardRef, useContext, useState, useMemo, useCallback, Fragment } from 'react';
|
|
3
3
|
import { tableClasses } 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';
|
|
6
7
|
import TableRowSelection from './rowSelection/TableRowSelection.js';
|
|
@@ -53,9 +54,9 @@ const TableBodyRow = forwardRef(function TableBodyRow(props, ref) {
|
|
|
53
54
|
expanding ? (jsx(TableExpandable, { expandable: isExpandable, expanded: expanded, role: "gridcell", setExpanded: setExpanded }, void 0)) : null,
|
|
54
55
|
(columns !== null && columns !== void 0 ? columns : []).map((column, index) => {
|
|
55
56
|
var _a, _b, _c, _d;
|
|
56
|
-
const ellipsis = !!(rowData
|
|
57
|
-
const tooltipTitle = ((_c = (_b = column.renderTooltipTitle) === null || _b === void 0 ? void 0 : _b.call(column, rowData)) !== null && _c !== void 0 ? _c : rowData
|
|
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
|
|
57
|
+
const ellipsis = !!(get(rowData, column.dataIndex)) && ((_a = column.ellipsis) !== null && _a !== void 0 ? _a : true);
|
|
58
|
+
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));
|
|
59
|
+
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)) || get(rowData, column.dataIndex) }), void 0) }), void 0) }), `${column.dataIndex}-${column.title}`));
|
|
59
60
|
})] }), void 0),
|
|
60
61
|
renderedExpandedContent ? (jsx(AccordionDetails, Object.assign({ className: expanding.className, expanded: expanded }, { children: renderedExpandedContent }), void 0)) : null] }, void 0));
|
|
61
62
|
});
|
|
@@ -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
|
|
|
@@ -70,7 +71,7 @@ function useTableSorting(props) {
|
|
|
70
71
|
// sort by given sorter
|
|
71
72
|
newSource = newSource.sort((a, b) => (
|
|
72
73
|
// reverse result when sorted type is ascending
|
|
73
|
-
(sorter(a
|
|
74
|
+
(sorter(get(a, dataIndex), get(b, dataIndex))) * (nextSortedType === 'asc' ? -1 : 1)));
|
|
74
75
|
// map back the data source
|
|
75
76
|
onMappingSources(newSource);
|
|
76
77
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mezzanine-ui/react",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.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.
|
|
35
|
+
"@mezzanine-ui/core": "^0.8.1",
|
|
36
36
|
"@mezzanine-ui/icons": "^0.7.3",
|
|
37
37
|
"@mezzanine-ui/system": "^0.7.0",
|
|
38
38
|
"@popperjs/core": "^2.9.2",
|