@axinom/mosaic-ui 0.68.1 → 0.68.3
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.
- package/dist/components/Buttons/Button/Button.d.ts.map +1 -1
- package/dist/components/Buttons/Button.model.d.ts +2 -0
- package/dist/components/Buttons/Button.model.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.d.ts +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.d.ts +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/renderers.model.d.ts +2 -0
- package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/renderers.model.d.ts.map +1 -1
- package/dist/components/Explorer/BulkEdit/FormFieldsConfigConverter.d.ts.map +1 -1
- package/dist/components/Explorer/BulkEdit/helpers/FieldWrapper.d.ts.map +1 -1
- package/dist/components/FieldSelection/FieldSelection.d.ts +1 -0
- package/dist/components/FieldSelection/FieldSelection.d.ts.map +1 -1
- package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +1 -1
- package/dist/components/InfoPanel/hooks/useCollapse.d.ts.map +1 -1
- package/dist/index.es.js +3 -3
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Buttons/Button/Button.tsx +4 -0
- package/src/components/Buttons/Button.model.ts +2 -0
- package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.tsx +38 -20
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.tsx +2 -0
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.tsx +2 -0
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/renderers.model.ts +2 -0
- package/src/components/Explorer/BulkEdit/FormFieldsConfigConverter.tsx +1 -0
- package/src/components/Explorer/BulkEdit/helpers/FieldWrapper.scss +1 -0
- package/src/components/Explorer/BulkEdit/helpers/FieldWrapper.tsx +1 -0
- package/src/components/FieldSelection/FieldSelection.scss +1 -1
- package/src/components/FieldSelection/FieldSelection.tsx +6 -2
- package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +5 -3
- package/src/components/Icons/Icons.tsx +1 -1
- package/src/components/InfoPanel/InfoPanel.scss +2 -0
- package/src/components/InfoPanel/hooks/useCollapse.ts +9 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-ui",
|
|
3
|
-
"version": "0.68.
|
|
3
|
+
"version": "0.68.3",
|
|
4
4
|
"description": "UI components for building Axinom Mosaic applications",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -112,5 +112,5 @@
|
|
|
112
112
|
"publishConfig": {
|
|
113
113
|
"access": "public"
|
|
114
114
|
},
|
|
115
|
-
"gitHead": "
|
|
115
|
+
"gitHead": "496e5fc981424ef5a5a4eb2a6b4bfb55cd5f7019"
|
|
116
116
|
}
|
|
@@ -69,6 +69,7 @@ const ContextButtonElement = React.forwardRef<
|
|
|
69
69
|
className = '',
|
|
70
70
|
customIcon,
|
|
71
71
|
dataTestId,
|
|
72
|
+
title,
|
|
72
73
|
onButtonClicked = noop,
|
|
73
74
|
onBlur,
|
|
74
75
|
}: ContextButtonProps,
|
|
@@ -93,6 +94,7 @@ const ContextButtonElement = React.forwardRef<
|
|
|
93
94
|
disabled={disabled}
|
|
94
95
|
onBlur={onBlur}
|
|
95
96
|
data-test-id={dataTestId ?? 'button'}
|
|
97
|
+
title={title}
|
|
96
98
|
>
|
|
97
99
|
{customIcon ? customIcon : <Icons icon={icon} />}
|
|
98
100
|
</button>
|
|
@@ -113,6 +115,7 @@ const NavigationButtonElement = React.forwardRef<
|
|
|
113
115
|
dataTestId = undefined,
|
|
114
116
|
disabled = false,
|
|
115
117
|
openInNewTab = false,
|
|
118
|
+
title,
|
|
116
119
|
}: NavigationButtonProps,
|
|
117
120
|
ref: ForwardedRef<HTMLAnchorElement>,
|
|
118
121
|
) {
|
|
@@ -132,6 +135,7 @@ const NavigationButtonElement = React.forwardRef<
|
|
|
132
135
|
style={{ height, width }}
|
|
133
136
|
data-test-id={dataTestId ?? 'button'}
|
|
134
137
|
target={openInNewTab ? '_blank' : undefined}
|
|
138
|
+
title={title}
|
|
135
139
|
>
|
|
136
140
|
{customIcon ? customIcon : <Icons icon={icon ? icon : defaultIcon} />}
|
|
137
141
|
</Link>
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
PropsWithChildren,
|
|
4
|
+
ReactElement,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react';
|
|
3
9
|
import { ValidationError } from 'yup';
|
|
4
10
|
import { OptionalObjectSchema } from 'yup/lib/object';
|
|
5
11
|
import { noop } from '../../../helpers/utils';
|
|
@@ -105,29 +111,41 @@ export const DynamicListDataEntry = <T extends Data>({
|
|
|
105
111
|
const [isDirty, setIsDirty] = useState<boolean>(false);
|
|
106
112
|
const [error, setError] = useState<Record<string, string>>({});
|
|
107
113
|
|
|
108
|
-
const validateSchema =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
const validateSchema = useCallback(
|
|
115
|
+
async (data: T): Promise<boolean> => {
|
|
116
|
+
if (!rowValidationSchema) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
112
119
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
120
|
+
try {
|
|
121
|
+
await rowValidationSchema.validate(data, { abortEarly: false });
|
|
122
|
+
setError({});
|
|
123
|
+
|
|
124
|
+
return true;
|
|
125
|
+
} catch (e) {
|
|
126
|
+
const newErrors: Record<string, string> = {};
|
|
127
|
+
(e as ValidationError).inner.forEach((validationError) => {
|
|
128
|
+
const path = validationError.path;
|
|
129
|
+
if (path !== undefined && newErrors?.[path] === undefined) {
|
|
130
|
+
newErrors[path] = validationError.message;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
setError(newErrors);
|
|
116
134
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (path !== undefined && newErrors?.[path] === undefined) {
|
|
123
|
-
newErrors[path] = validationError.message;
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
setError(newErrors);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
[rowValidationSchema],
|
|
139
|
+
);
|
|
127
140
|
|
|
128
|
-
|
|
141
|
+
// Input errors should be cleared when the field is disabled
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (disabled) {
|
|
144
|
+
setError({});
|
|
145
|
+
} else if (isDirty) {
|
|
146
|
+
validateSchema(state);
|
|
129
147
|
}
|
|
130
|
-
};
|
|
148
|
+
}, [disabled, state, isDirty, validateSchema]);
|
|
131
149
|
|
|
132
150
|
/**
|
|
133
151
|
* Updates new data object with supplied key/value pair
|
|
@@ -14,6 +14,7 @@ export const createInputRenderer = ({
|
|
|
14
14
|
name = '',
|
|
15
15
|
placeholder,
|
|
16
16
|
type = 'text',
|
|
17
|
+
autofocus = false,
|
|
17
18
|
transform = (value: string) => value,
|
|
18
19
|
}: CreateInputRendererConfig = {}): DynamicListDataEntryRenderer => {
|
|
19
20
|
const inputRenderer = (
|
|
@@ -38,6 +39,7 @@ export const createInputRenderer = ({
|
|
|
38
39
|
error={error}
|
|
39
40
|
className={classes.container}
|
|
40
41
|
value={(currentValue as string) ?? ''}
|
|
42
|
+
autoFocus={autofocus}
|
|
41
43
|
/>
|
|
42
44
|
);
|
|
43
45
|
};
|
|
@@ -22,6 +22,7 @@ export const createSelectRenderer = ({
|
|
|
22
22
|
options = [],
|
|
23
23
|
defaultValue,
|
|
24
24
|
transform = (value: string) => value,
|
|
25
|
+
autofocus = false,
|
|
25
26
|
}: CreateSelectRendererConfig = {}): DynamicListDataEntryRenderer => {
|
|
26
27
|
const selectRenderer = (
|
|
27
28
|
currentValue: unknown,
|
|
@@ -49,6 +50,7 @@ export const createSelectRenderer = ({
|
|
|
49
50
|
className={classes.container}
|
|
50
51
|
value={(currentValue as string) ?? ''}
|
|
51
52
|
options={options}
|
|
53
|
+
autoFocus={autofocus}
|
|
52
54
|
/>
|
|
53
55
|
);
|
|
54
56
|
};
|
|
@@ -9,6 +9,8 @@ export interface BaseRendererConfig {
|
|
|
9
9
|
placeholder?: string;
|
|
10
10
|
/** Optional transformer that will change the final value to match the return value */
|
|
11
11
|
transform?: (value: string) => unknown;
|
|
12
|
+
/** Optional autofocus on render (default: false) */
|
|
13
|
+
autofocus?: boolean;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export interface CreateInputRendererConfig extends BaseRendererConfig {
|
|
@@ -9,6 +9,7 @@ import { IconName } from '../Icons';
|
|
|
9
9
|
import classes from './FieldSelection.scss';
|
|
10
10
|
|
|
11
11
|
interface FieldSelectionProps {
|
|
12
|
+
name?: string;
|
|
12
13
|
className?: string;
|
|
13
14
|
onFieldAdded?: (field: string) => void;
|
|
14
15
|
onFieldRemoved?: (field: string) => void;
|
|
@@ -22,6 +23,7 @@ interface FieldDefinition {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export const FieldSelection: React.FC<FieldSelectionProps> = ({
|
|
26
|
+
name,
|
|
25
27
|
className,
|
|
26
28
|
onFieldAdded = noop,
|
|
27
29
|
onFieldRemoved = noop,
|
|
@@ -62,6 +64,7 @@ export const FieldSelection: React.FC<FieldSelectionProps> = ({
|
|
|
62
64
|
expandedByDefault={true}
|
|
63
65
|
header={
|
|
64
66
|
<FieldSelectionHeader
|
|
67
|
+
name={name}
|
|
65
68
|
fields={availableFields}
|
|
66
69
|
onAddField={(value) => {
|
|
67
70
|
const newField = availableFields.find(
|
|
@@ -108,9 +111,10 @@ export const FieldSelection: React.FC<FieldSelectionProps> = ({
|
|
|
108
111
|
};
|
|
109
112
|
|
|
110
113
|
const FieldSelectionHeader: React.FC<{
|
|
114
|
+
name?: string;
|
|
111
115
|
fields: SelectOption[];
|
|
112
116
|
onAddField: (value: string) => void;
|
|
113
|
-
}> = ({ fields, onAddField }) => {
|
|
117
|
+
}> = ({ name, fields, onAddField }) => {
|
|
114
118
|
const [value, setValue] = React.useState<string>();
|
|
115
119
|
|
|
116
120
|
useEffect(() => {
|
|
@@ -124,7 +128,7 @@ const FieldSelectionHeader: React.FC<{
|
|
|
124
128
|
<div className={classes.selectionHeader}>
|
|
125
129
|
<Select
|
|
126
130
|
label="Field"
|
|
127
|
-
name=
|
|
131
|
+
name={name ?? 'field'}
|
|
128
132
|
placeholder="Select Field"
|
|
129
133
|
options={fields}
|
|
130
134
|
disabled={fields.length === 0}
|
|
@@ -40,7 +40,7 @@ export const FormStationHeader: React.FC<
|
|
|
40
40
|
},
|
|
41
41
|
setValidationError,
|
|
42
42
|
}) => {
|
|
43
|
-
const { dirty, submitForm, resetForm,
|
|
43
|
+
const { dirty, submitForm, resetForm, validateForm } =
|
|
44
44
|
useFormikContext<FormikValues>();
|
|
45
45
|
const quickEditContext = useContext(QuickEditContext);
|
|
46
46
|
const bulkEditContext = useContext(BulkEditContext);
|
|
@@ -74,10 +74,12 @@ export const FormStationHeader: React.FC<
|
|
|
74
74
|
if (quickEditContext?.isQuickEditMode) {
|
|
75
75
|
quickEditContext.refresh();
|
|
76
76
|
} else if (bulkEditContext?.isBulkEditMode) {
|
|
77
|
-
|
|
77
|
+
const errors = await validateForm();
|
|
78
|
+
if (Object.keys(errors).length > 0) {
|
|
78
79
|
setValidationError();
|
|
79
80
|
return;
|
|
80
81
|
}
|
|
82
|
+
|
|
81
83
|
await submitForm();
|
|
82
84
|
history.replace(history.location.pathname);
|
|
83
85
|
} else {
|
|
@@ -128,7 +130,6 @@ export const FormStationHeader: React.FC<
|
|
|
128
130
|
cancelNavigationUrl,
|
|
129
131
|
dirty,
|
|
130
132
|
history,
|
|
131
|
-
isValid,
|
|
132
133
|
quickEditContext,
|
|
133
134
|
resetForm,
|
|
134
135
|
saveHeaderActionConfig.icon,
|
|
@@ -136,6 +137,7 @@ export const FormStationHeader: React.FC<
|
|
|
136
137
|
setValidationError,
|
|
137
138
|
showSaveHeaderAction,
|
|
138
139
|
submitForm,
|
|
140
|
+
validateForm,
|
|
139
141
|
]);
|
|
140
142
|
|
|
141
143
|
return (
|
|
@@ -175,7 +175,7 @@ const ClearAllIcon: React.FC<SvgElementProps> = (props) => (
|
|
|
175
175
|
<SvgElement {...props}>
|
|
176
176
|
<path
|
|
177
177
|
{...DEFAULT_PATH_PROPS}
|
|
178
|
-
d="
|
|
178
|
+
d="M28.6,33.7H11.2l-7.2-7.2L24.2,6.3l11.8,11.8-15.6,15.6M18.6,11.9l11.8,11.8M31.9,33.7h3.7"
|
|
179
179
|
/>
|
|
180
180
|
</SvgElement>
|
|
181
181
|
);
|
|
@@ -180,13 +180,15 @@ export const useCollapse = ({
|
|
|
180
180
|
userExpandedRef.current = true;
|
|
181
181
|
autoCollapsedRef.current = false;
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
183
|
+
// TODO: Temporarily disable auto-scrolling to prevent jarring experience when collapsing/expanding panels in smaller screens.
|
|
184
|
+
// to be revisited with https://dev.azure.com/axinom/CMS/_workitems/edit/53479/
|
|
185
|
+
// setTimeout(() => {
|
|
186
|
+
// containerRef.current?.scrollIntoView({
|
|
187
|
+
// behavior: 'smooth',
|
|
188
|
+
// block: 'nearest',
|
|
189
|
+
// inline: 'end',
|
|
190
|
+
// });
|
|
191
|
+
// }, 350);
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
onCollapseChange?.(newState);
|