@linzjs/step-ag-grid 8.4.1 → 8.4.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/src/lui/TextAreaInput.d.ts +1 -0
- package/dist/src/lui/TextInputFormatted.d.ts +1 -0
- package/dist/src/react-menu3/components/FocusableItem.d.ts +1 -1
- package/dist/src/react-menu3/components/MenuItem.d.ts +3 -1
- package/dist/src/react-menu3/components/SubMenu.d.ts +1 -1
- package/dist/src/react-menu3/utils/withHovering.d.ts +2 -2
- package/dist/step-ag-grid.esm.js +46 -54
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/gridForm/GridFormDropDown.tsx +11 -13
- package/src/components/gridForm/GridFormMultiSelect.tsx +20 -24
- package/src/components/gridForm/GridFormPopoverMenu.tsx +18 -22
- package/src/components/gridForm/GridFormSubComponentTextArea.tsx +1 -0
- package/src/components/gridForm/GridFormSubComponentTextInput.tsx +1 -0
- package/src/components/gridForm/GridFormTextArea.tsx +1 -1
- package/src/components/gridForm/GridFormTextInput.tsx +1 -1
- package/src/lui/TextAreaInput.tsx +2 -0
- package/src/lui/TextInputFormatted.tsx +2 -0
- package/src/react-menu3/components/MenuItem.tsx +1 -1
- package/src/react-menu3/utils/withHovering.tsx +3 -3
- package/src/stories/grid/GridPopoutEditDropDown.stories.tsx +10 -2
- package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +128 -0
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +92 -0
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +91 -0
- package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +171 -0
- package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +78 -0
- package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +85 -0
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormDropDown.stories.tsx +1 -1
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormEditBearing.stories.tsx +1 -1
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormEditBearingCorrection.stories.tsx +1 -1
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormMessage.stories.tsx +1 -1
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormMultiSelect.stories.tsx +1 -1
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormPopoverMenu.stories.tsx +1 -1
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormTextArea.stories.tsx +1 -1
- package/src/stories/grid/{gridForm → gridFormStatic}/GridFormTextInput.stories.tsx +1 -1
package/package.json
CHANGED
|
@@ -7,8 +7,8 @@ import debounce from "debounce-promise";
|
|
|
7
7
|
import { CellEditorCommon } from "../GridCell";
|
|
8
8
|
import { useGridPopoverHook } from "../GridPopoverHook";
|
|
9
9
|
import { useGridPopoverContext } from "../../contexts/GridPopoverContext";
|
|
10
|
-
import { GridSubComponentContext } from "contexts/GridSubComponentContext";
|
|
11
|
-
import { ClickEvent
|
|
10
|
+
import { GridSubComponentContext } from "../../contexts/GridSubComponentContext";
|
|
11
|
+
import { ClickEvent } from "../../react-menu3/types";
|
|
12
12
|
import { FormError } from "../../lui/FormError";
|
|
13
13
|
import { isNotEmpty } from "../../utils/util";
|
|
14
14
|
|
|
@@ -270,19 +270,17 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDro
|
|
|
270
270
|
title={item.disabled && typeof item.disabled !== "boolean" ? item.disabled : ""}
|
|
271
271
|
value={item.value}
|
|
272
272
|
onFocus={() => {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
subComponentIsValid.current = true;
|
|
276
|
-
subComponentInitialValue.current = null;
|
|
277
|
-
} else {
|
|
273
|
+
if (selectedItem !== item) {
|
|
274
|
+
setSelectedItem(item);
|
|
278
275
|
setSubSelectedValue(null);
|
|
279
276
|
subComponentIsValid.current = true;
|
|
277
|
+
if (item.subComponent) {
|
|
278
|
+
subComponentInitialValue.current = null;
|
|
279
|
+
}
|
|
280
280
|
}
|
|
281
281
|
}}
|
|
282
282
|
onClick={(e: ClickEvent) => {
|
|
283
|
-
|
|
284
|
-
e.keepOpen = true;
|
|
285
|
-
}
|
|
283
|
+
e.keepOpen = !!item.subComponent;
|
|
286
284
|
}}
|
|
287
285
|
>
|
|
288
286
|
{item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)}
|
|
@@ -291,7 +289,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDro
|
|
|
291
289
|
|
|
292
290
|
{item.subComponent && selectedItem === item && (
|
|
293
291
|
<FocusableItem className={"LuiDeprecatedForms"} key={`${item.label}_subcomponent`}>
|
|
294
|
-
{(
|
|
292
|
+
{() => (
|
|
295
293
|
<GridSubComponentContext.Provider
|
|
296
294
|
value={{
|
|
297
295
|
context: { options },
|
|
@@ -308,13 +306,13 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDro
|
|
|
308
306
|
subComponentIsValid.current = valid;
|
|
309
307
|
},
|
|
310
308
|
triggerSave: async () => {
|
|
311
|
-
|
|
309
|
+
// empty
|
|
312
310
|
},
|
|
313
311
|
}}
|
|
314
312
|
>
|
|
315
313
|
{item.subComponent && (
|
|
316
314
|
<div className={"subComponent"}>
|
|
317
|
-
<item.subComponent
|
|
315
|
+
<item.subComponent />
|
|
318
316
|
</div>
|
|
319
317
|
)}
|
|
320
318
|
</GridSubComponentContext.Provider>
|
|
@@ -18,7 +18,7 @@ import { useGridPopoverHook } from "../GridPopoverHook";
|
|
|
18
18
|
import { MenuSeparatorString } from "./GridFormDropDown";
|
|
19
19
|
import { CellEditorCommon } from "../GridCell";
|
|
20
20
|
import { ClickEvent } from "../../react-menu3/types";
|
|
21
|
-
import { GridSubComponentContext } from "contexts/GridSubComponentContext";
|
|
21
|
+
import { GridSubComponentContext } from "../../contexts/GridSubComponentContext";
|
|
22
22
|
import { useGridPopoverContext } from "../../contexts/GridPopoverContext";
|
|
23
23
|
import { FormError } from "../../lui/FormError";
|
|
24
24
|
import { textMatch } from "../../utils/textMatcher";
|
|
@@ -397,29 +397,25 @@ const MenuSubComponent = (props: {
|
|
|
397
397
|
const { data, item, options, setOptions, subComponentIsValid, triggerSave } = props;
|
|
398
398
|
return (
|
|
399
399
|
<FocusableItem className={"LuiDeprecatedForms"} key={`${item.value}_subcomponent`}>
|
|
400
|
-
{(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
>
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
</div>
|
|
420
|
-
</GridSubComponentContext.Provider>
|
|
421
|
-
)
|
|
422
|
-
}
|
|
400
|
+
{() => (
|
|
401
|
+
<GridSubComponentContext.Provider
|
|
402
|
+
value={{
|
|
403
|
+
context: { options },
|
|
404
|
+
data,
|
|
405
|
+
value: item.subValue,
|
|
406
|
+
setValue: (value: any) => {
|
|
407
|
+
item.subValue = value;
|
|
408
|
+
setOptions([...options]);
|
|
409
|
+
},
|
|
410
|
+
setValid: (valid: boolean) => {
|
|
411
|
+
subComponentIsValid[`${item.value}`] = valid;
|
|
412
|
+
},
|
|
413
|
+
triggerSave,
|
|
414
|
+
}}
|
|
415
|
+
>
|
|
416
|
+
<div className={"subComponent"}>{item.subComponent && <item.subComponent />}</div>
|
|
417
|
+
</GridSubComponentContext.Provider>
|
|
418
|
+
)}
|
|
423
419
|
</FocusableItem>
|
|
424
420
|
);
|
|
425
421
|
};
|
|
@@ -143,28 +143,24 @@ export const GridFormPopoverMenu = <RowType extends GridBaseRow>(props: GridForm
|
|
|
143
143
|
</MenuItem>
|
|
144
144
|
{item.subComponent && subComponentSelected === item && (
|
|
145
145
|
<FocusableItem className={"LuiDeprecatedForms"} key={`${item.label}_subcomponent`}>
|
|
146
|
-
{(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
</div>
|
|
165
|
-
</GridSubComponentContext.Provider>
|
|
166
|
-
)
|
|
167
|
-
}
|
|
146
|
+
{() => (
|
|
147
|
+
<GridSubComponentContext.Provider
|
|
148
|
+
value={{
|
|
149
|
+
context: {},
|
|
150
|
+
data,
|
|
151
|
+
value: subSelectedValue,
|
|
152
|
+
setValue: (value: any) => {
|
|
153
|
+
setSubSelectedValue(value);
|
|
154
|
+
},
|
|
155
|
+
setValid: (valid: boolean) => {
|
|
156
|
+
subComponentIsValid.current = valid;
|
|
157
|
+
},
|
|
158
|
+
triggerSave,
|
|
159
|
+
}}
|
|
160
|
+
>
|
|
161
|
+
<div className={"subComponent"}>{item.subComponent && <item.subComponent />}</div>
|
|
162
|
+
</GridSubComponentContext.Provider>
|
|
163
|
+
)}
|
|
168
164
|
</FocusableItem>
|
|
169
165
|
)}
|
|
170
166
|
</Fragment>
|
|
@@ -55,7 +55,7 @@ export const GridFormTextArea = <RowType extends GridBaseRow>(props: GridFormTex
|
|
|
55
55
|
value={value}
|
|
56
56
|
onChange={(e) => setValue(e.target.value)}
|
|
57
57
|
error={invalid()}
|
|
58
|
-
placeholder={props.placeholder}
|
|
58
|
+
placeholder={props.placeholder ?? "Type here"}
|
|
59
59
|
helpText={helpText}
|
|
60
60
|
/>
|
|
61
61
|
</div>,
|
|
@@ -57,7 +57,7 @@ export const GridFormTextInput = <RowType extends GridBaseRow>(props: GridFormTe
|
|
|
57
57
|
error={invalid()}
|
|
58
58
|
formatted={props.units}
|
|
59
59
|
style={{ width: props.width ?? 240 }}
|
|
60
|
-
placeholder={props.placeholder}
|
|
60
|
+
placeholder={props.placeholder ?? "Type here"}
|
|
61
61
|
helpText={helpText}
|
|
62
62
|
/>
|
|
63
63
|
</div>,
|
|
@@ -18,6 +18,7 @@ export interface LuiTextAreaInputProps extends InputHTMLAttributes<HTMLTextAreaE
|
|
|
18
18
|
mandatory?: boolean;
|
|
19
19
|
helpText?: string;
|
|
20
20
|
error?: JSX.Element | string | boolean | null;
|
|
21
|
+
allowTabToSave?: boolean;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export const TextAreaInput = (props: LuiTextAreaInputProps) => {
|
|
@@ -50,6 +51,7 @@ export const TextAreaInput = (props: LuiTextAreaInputProps) => {
|
|
|
50
51
|
}
|
|
51
52
|
props.onMouseEnter && props.onMouseEnter(e);
|
|
52
53
|
}}
|
|
54
|
+
data-allowtabtosave={props.allowTabToSave}
|
|
53
55
|
>
|
|
54
56
|
{props.value}
|
|
55
57
|
</textarea>
|
|
@@ -14,6 +14,7 @@ export interface LuiTextInputProps extends DetailedHTMLProps<InputHTMLAttributes
|
|
|
14
14
|
helpText?: string;
|
|
15
15
|
error?: JSX.Element | string | boolean | null;
|
|
16
16
|
formatted?: string;
|
|
17
|
+
allowTabToSave?: boolean;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export const TextInputFormatted = (props: LuiTextInputProps): JSX.Element => {
|
|
@@ -31,6 +32,7 @@ export const TextInputFormatted = (props: LuiTextInputProps): JSX.Element => {
|
|
|
31
32
|
e.currentTarget.focus();
|
|
32
33
|
props.onMouseEnter && props.onMouseEnter(e);
|
|
33
34
|
}}
|
|
35
|
+
data-allowtabtosave={props.allowTabToSave}
|
|
34
36
|
/>
|
|
35
37
|
<span className={"LuiTextInput-formatted"}>{props.formatted}</span>
|
|
36
38
|
</span>
|
|
@@ -128,7 +128,7 @@ const MenuItemFr = ({
|
|
|
128
128
|
};
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
|
-
* Keyboard events are triggered on up, otherwise
|
|
131
|
+
* Keyboard events are triggered on up, otherwise subcomponents get spaces and enters typed in them
|
|
132
132
|
*/
|
|
133
133
|
const handleKeyUp = (e: KeyboardEvent) => {
|
|
134
134
|
if (!isHovering) return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { memo, forwardRef, useContext, useRef, MutableRefObject } from "react";
|
|
1
|
+
import { memo, forwardRef, useContext, useRef, MutableRefObject, PropsWithRef } from "react";
|
|
2
2
|
import { HoverItemContext } from "../contexts/HoverItemContext";
|
|
3
3
|
|
|
4
4
|
export interface withHoveringResultProps {
|
|
@@ -7,9 +7,9 @@ export interface withHoveringResultProps {
|
|
|
7
7
|
menuItemRef?: MutableRefObject<any>;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export const withHovering = (name: string, WrappedComponent: (
|
|
10
|
+
export const withHovering = <T,>(name: string, WrappedComponent: (props: T) => JSX.Element) => {
|
|
11
11
|
const Component = memo(WrappedComponent);
|
|
12
|
-
const WithHovering = forwardRef
|
|
12
|
+
const WithHovering = forwardRef((props: PropsWithRef<T>, ref) => {
|
|
13
13
|
const menuItemRef = useRef<any>(null);
|
|
14
14
|
return (
|
|
15
15
|
<Component
|
|
@@ -14,6 +14,7 @@ import { ColDefT, GridCell } from "../../components/GridCell";
|
|
|
14
14
|
import { GridPopoverEditDropDown } from "../../components/gridPopoverEdit/GridPopoverEditDropDown";
|
|
15
15
|
import { GridFormSubComponentTextInput } from "../../components/gridForm/GridFormSubComponentTextInput";
|
|
16
16
|
import { GridPopoverMenu } from "../../components/gridPopoverEdit/GridPopoverMenu";
|
|
17
|
+
import { GridFormSubComponentTextArea } from "../../components/gridForm/GridFormSubComponentTextArea";
|
|
17
18
|
|
|
18
19
|
export default {
|
|
19
20
|
title: "Components / Grids",
|
|
@@ -234,9 +235,16 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
|
|
|
234
235
|
},
|
|
235
236
|
{
|
|
236
237
|
value: "oth",
|
|
237
|
-
label: "Other",
|
|
238
|
+
label: "Other text input",
|
|
238
239
|
subComponent: () => (
|
|
239
|
-
<GridFormSubComponentTextInput placeholder={"Other..."} defaultValue={""} required={true} />
|
|
240
|
+
<GridFormSubComponentTextInput placeholder={"Other..."} defaultValue={"a"} required={true} />
|
|
241
|
+
),
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
value: "oth",
|
|
245
|
+
label: "Other text area",
|
|
246
|
+
subComponent: () => (
|
|
247
|
+
<GridFormSubComponentTextArea placeholder={"Other..."} defaultValue={"b"} required={true} />
|
|
240
248
|
),
|
|
241
249
|
},
|
|
242
250
|
];
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import "@linzjs/lui/dist/scss/base.scss";
|
|
2
|
+
import "@linzjs/lui/dist/fonts";
|
|
3
|
+
|
|
4
|
+
import { useRef } from "react";
|
|
5
|
+
import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
|
|
6
|
+
import {
|
|
7
|
+
GridFormDropDown,
|
|
8
|
+
GridFormDropDownProps,
|
|
9
|
+
GridPopoutEditDropDownSelectedItem,
|
|
10
|
+
} from "../../../components/gridForm/GridFormDropDown";
|
|
11
|
+
import { GridContextProvider } from "../../../contexts/GridContextProvider";
|
|
12
|
+
import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
|
|
13
|
+
import { GridFormSubComponentTextInput } from "../../../components/gridForm/GridFormSubComponentTextInput";
|
|
14
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
15
|
+
import { expect, jest } from "@storybook/jest";
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
title: "GridForm / Interactions",
|
|
19
|
+
component: GridFormDropDown,
|
|
20
|
+
args: {},
|
|
21
|
+
} as ComponentMeta<typeof GridFormDropDown>;
|
|
22
|
+
|
|
23
|
+
const updateValue = jest
|
|
24
|
+
.fn<void, [saveFn: (selectedRows: any[]) => Promise<boolean>, _tabDirection: 1 | 0 | -1]>()
|
|
25
|
+
.mockImplementation((saveFn: (selectedRows: any[]) => Promise<boolean>, _tabDirection: 1 | 0 | -1) => saveFn([]));
|
|
26
|
+
|
|
27
|
+
const onSelectedItem = jest.fn<Promise<void>, [GridPopoutEditDropDownSelectedItem<any>]>().mockResolvedValue(undefined);
|
|
28
|
+
|
|
29
|
+
const Template: ComponentStory<typeof GridFormDropDown> = (props) => {
|
|
30
|
+
const config: GridFormDropDownProps<any> = {
|
|
31
|
+
filtered: "local",
|
|
32
|
+
onSelectedItem,
|
|
33
|
+
options: [
|
|
34
|
+
{ label: "Enabled", value: 1 },
|
|
35
|
+
{ label: "Disabled", value: 0, disabled: true },
|
|
36
|
+
{
|
|
37
|
+
label: "Sub menu",
|
|
38
|
+
value: 0,
|
|
39
|
+
subComponent: () => (
|
|
40
|
+
<GridFormSubComponentTextInput placeholder={"Text input"} maxLength={5} required defaultValue={""} />
|
|
41
|
+
),
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
const anchorRef = useRef<HTMLHeadingElement>(null);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className={"react-menu-inline-test"}>
|
|
49
|
+
<GridContextProvider>
|
|
50
|
+
<div>
|
|
51
|
+
<h6 ref={anchorRef}>Interaction test</h6>
|
|
52
|
+
<GridPopoverContext.Provider
|
|
53
|
+
value={
|
|
54
|
+
{
|
|
55
|
+
anchorRef: anchorRef,
|
|
56
|
+
updateValue,
|
|
57
|
+
data: { value: "" },
|
|
58
|
+
value: "",
|
|
59
|
+
field: "value",
|
|
60
|
+
selectedRows: [],
|
|
61
|
+
} as any as GridPopoverContextType<any>
|
|
62
|
+
}
|
|
63
|
+
>
|
|
64
|
+
<GridFormDropDown {...props} {...config} />
|
|
65
|
+
</GridPopoverContext.Provider>
|
|
66
|
+
</div>
|
|
67
|
+
</GridContextProvider>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const GridFormDropDownInteractions_ = Template.bind({});
|
|
73
|
+
GridFormDropDownInteractions_.play = async ({ canvasElement }) => {
|
|
74
|
+
const canvas = within(canvasElement);
|
|
75
|
+
|
|
76
|
+
const getOption = (name: string) => canvas.findByRole("menuitem", { name });
|
|
77
|
+
|
|
78
|
+
// Check enabled menu handles click
|
|
79
|
+
const enabledMenuOption = await getOption("Enabled");
|
|
80
|
+
expect(enabledMenuOption).toBeInTheDocument();
|
|
81
|
+
|
|
82
|
+
userEvent.click(enabledMenuOption);
|
|
83
|
+
expect(updateValue).toHaveBeenCalled();
|
|
84
|
+
expect(onSelectedItem).toHaveBeenCalled();
|
|
85
|
+
|
|
86
|
+
// Check disabled menu ignores click
|
|
87
|
+
updateValue.mockClear();
|
|
88
|
+
onSelectedItem.mockClear();
|
|
89
|
+
const disabledMenuOption = await getOption("Disabled");
|
|
90
|
+
userEvent.click(disabledMenuOption);
|
|
91
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
92
|
+
expect(onSelectedItem).not.toHaveBeenCalled();
|
|
93
|
+
|
|
94
|
+
// Check sub menu works
|
|
95
|
+
const subTextInput = await getOption("Sub menu...");
|
|
96
|
+
expect(subTextInput).toBeInTheDocument();
|
|
97
|
+
|
|
98
|
+
expect(canvas.queryByPlaceholderText("Text input")).not.toBeInTheDocument();
|
|
99
|
+
|
|
100
|
+
userEvent.click(subTextInput);
|
|
101
|
+
const textInput = await canvas.findByPlaceholderText("Text input");
|
|
102
|
+
expect(textInput).toBeInTheDocument();
|
|
103
|
+
expect(await canvas.findByText("Must not be empty")).toBeInTheDocument();
|
|
104
|
+
|
|
105
|
+
userEvent.type(textInput, "Hello");
|
|
106
|
+
expect(await canvas.findByText("Press enter or tab to save")).toBeInTheDocument();
|
|
107
|
+
|
|
108
|
+
// Test tab to save
|
|
109
|
+
updateValue.mockClear();
|
|
110
|
+
userEvent.tab();
|
|
111
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
112
|
+
|
|
113
|
+
// Test shift+tab to save
|
|
114
|
+
updateValue.mockClear();
|
|
115
|
+
userEvent.tab({ shift: true });
|
|
116
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
117
|
+
|
|
118
|
+
// Test escape to not save
|
|
119
|
+
updateValue.mockClear();
|
|
120
|
+
userEvent.type(textInput, "{Escape}");
|
|
121
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
122
|
+
|
|
123
|
+
// Test invalid value doesn't save
|
|
124
|
+
updateValue.mockClear();
|
|
125
|
+
userEvent.clear(textInput);
|
|
126
|
+
userEvent.type(textInput, "{Enter}");
|
|
127
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
128
|
+
};
|
package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import "@linzjs/lui/dist/scss/base.scss";
|
|
2
|
+
import "@linzjs/lui/dist/fonts";
|
|
3
|
+
|
|
4
|
+
import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
|
|
5
|
+
import { GridFormEditBearing } from "../../../components/gridForm/GridFormEditBearing";
|
|
6
|
+
import { GridContextProvider } from "../../../contexts/GridContextProvider";
|
|
7
|
+
import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
|
|
8
|
+
import { useRef } from "react";
|
|
9
|
+
import { GridPopoverEditBearingCorrectionEditorParams } from "../../../components/gridPopoverEdit/GridPopoverEditBearing";
|
|
10
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
11
|
+
import { expect, jest } from "@storybook/jest";
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
title: "GridForm / Interactions",
|
|
15
|
+
component: GridFormEditBearing,
|
|
16
|
+
args: {},
|
|
17
|
+
} as ComponentMeta<typeof GridFormEditBearing>;
|
|
18
|
+
|
|
19
|
+
const updateValue = jest.fn();
|
|
20
|
+
|
|
21
|
+
const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
|
|
22
|
+
const anchorRef = useRef<HTMLHeadingElement>(null);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className={"react-menu-inline-test"}>
|
|
26
|
+
<GridContextProvider>
|
|
27
|
+
<h6 ref={anchorRef}>Test</h6>
|
|
28
|
+
<GridPopoverContext.Provider
|
|
29
|
+
value={
|
|
30
|
+
{
|
|
31
|
+
anchorRef,
|
|
32
|
+
value: null,
|
|
33
|
+
updateValue,
|
|
34
|
+
} as any as GridPopoverContextType<any>
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
<GridFormEditBearing {...props} {...GridPopoverEditBearingCorrectionEditorParams} />
|
|
38
|
+
</GridPopoverContext.Provider>
|
|
39
|
+
</GridContextProvider>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const GridFormEditBearingCorrectionInteractions_ = Template.bind({});
|
|
45
|
+
GridFormEditBearingCorrectionInteractions_.play = async ({ canvasElement }) => {
|
|
46
|
+
const canvas = within(canvasElement);
|
|
47
|
+
|
|
48
|
+
expect(await canvas.findByText("Press enter or tab to save")).toBeInTheDocument();
|
|
49
|
+
|
|
50
|
+
const inputField = canvas.getByPlaceholderText("Enter bearing correction");
|
|
51
|
+
|
|
52
|
+
// Test formatting null
|
|
53
|
+
expect(await canvas.findByText("–")).toBeInTheDocument();
|
|
54
|
+
|
|
55
|
+
// Test formatting a bearing
|
|
56
|
+
expect(inputField).toBeInTheDocument();
|
|
57
|
+
userEvent.type(inputField, "1.2345");
|
|
58
|
+
expect(await canvas.findByText("+1° 23' 45.0\"")).toBeInTheDocument();
|
|
59
|
+
|
|
60
|
+
// Test enter to save
|
|
61
|
+
updateValue.mockClear();
|
|
62
|
+
userEvent.type(inputField, "{Enter}");
|
|
63
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 0); // 0 = Enter
|
|
64
|
+
|
|
65
|
+
// Test tab to save
|
|
66
|
+
updateValue.mockClear();
|
|
67
|
+
userEvent.tab();
|
|
68
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
69
|
+
|
|
70
|
+
// Test shift+tab to save
|
|
71
|
+
updateValue.mockClear();
|
|
72
|
+
userEvent.tab({ shift: true });
|
|
73
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
74
|
+
|
|
75
|
+
// Test escape not to save
|
|
76
|
+
updateValue.mockClear();
|
|
77
|
+
userEvent.type(inputField, "{Escape}");
|
|
78
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
79
|
+
|
|
80
|
+
// Test invalid value doesn't save
|
|
81
|
+
updateValue.mockClear();
|
|
82
|
+
userEvent.type(inputField, "xxx");
|
|
83
|
+
expect(await canvas.findByText("?")).toBeInTheDocument();
|
|
84
|
+
|
|
85
|
+
expect(canvas.getByText("Bearing must be a number in D.MMSSS format")).toBeInTheDocument();
|
|
86
|
+
userEvent.type(inputField, "{Enter}");
|
|
87
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
88
|
+
userEvent.tab();
|
|
89
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
90
|
+
userEvent.tab({ shift: true });
|
|
91
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
92
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import "@linzjs/lui/dist/scss/base.scss";
|
|
2
|
+
import "@linzjs/lui/dist/fonts";
|
|
3
|
+
|
|
4
|
+
import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
|
|
5
|
+
import { GridFormEditBearing } from "../../../components/gridForm/GridFormEditBearing";
|
|
6
|
+
import { GridContextProvider } from "../../../contexts/GridContextProvider";
|
|
7
|
+
import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
|
|
8
|
+
import { useRef } from "react";
|
|
9
|
+
import { GridPopoverEditBearingEditorParams } from "../../../components/gridPopoverEdit/GridPopoverEditBearing";
|
|
10
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
11
|
+
import { expect, jest } from "@storybook/jest";
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
title: "GridForm / Interactions",
|
|
15
|
+
component: GridFormEditBearing,
|
|
16
|
+
args: {},
|
|
17
|
+
} as ComponentMeta<typeof GridFormEditBearing>;
|
|
18
|
+
|
|
19
|
+
const updateValue = jest.fn();
|
|
20
|
+
|
|
21
|
+
const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
|
|
22
|
+
const anchorRef = useRef<HTMLHeadingElement>(null);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className={"react-menu-inline-test"}>
|
|
26
|
+
<GridContextProvider>
|
|
27
|
+
<h6 ref={anchorRef}>Test</h6>
|
|
28
|
+
<GridPopoverContext.Provider
|
|
29
|
+
value={
|
|
30
|
+
{
|
|
31
|
+
anchorRef,
|
|
32
|
+
value: null,
|
|
33
|
+
updateValue,
|
|
34
|
+
} as any as GridPopoverContextType<any>
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
<GridFormEditBearing {...props} {...GridPopoverEditBearingEditorParams} />
|
|
38
|
+
</GridPopoverContext.Provider>
|
|
39
|
+
</GridContextProvider>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const GridFormEditBearingInteractions_ = Template.bind({});
|
|
45
|
+
GridFormEditBearingInteractions_.play = async ({ canvasElement }) => {
|
|
46
|
+
const canvas = within(canvasElement);
|
|
47
|
+
|
|
48
|
+
expect(await canvas.findByText("Press enter or tab to save")).toBeInTheDocument();
|
|
49
|
+
|
|
50
|
+
const inputField = canvas.getByPlaceholderText("Enter bearing");
|
|
51
|
+
|
|
52
|
+
// Test formatting null
|
|
53
|
+
expect(await canvas.findByText("–")).toBeInTheDocument();
|
|
54
|
+
|
|
55
|
+
// Test formatting a bearing
|
|
56
|
+
expect(inputField).toBeInTheDocument();
|
|
57
|
+
userEvent.type(inputField, "1.2345");
|
|
58
|
+
expect(await canvas.findByText("1° 23' 45\"")).toBeInTheDocument();
|
|
59
|
+
|
|
60
|
+
// Test enter to save
|
|
61
|
+
updateValue.mockClear();
|
|
62
|
+
userEvent.type(inputField, "{Enter}");
|
|
63
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 0); // 0 = Enter
|
|
64
|
+
|
|
65
|
+
// Test tab to save
|
|
66
|
+
updateValue.mockClear();
|
|
67
|
+
userEvent.tab();
|
|
68
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
69
|
+
|
|
70
|
+
// Test shift+tab to save
|
|
71
|
+
updateValue.mockClear();
|
|
72
|
+
userEvent.tab({ shift: true });
|
|
73
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
74
|
+
|
|
75
|
+
// Test escape not to save
|
|
76
|
+
updateValue.mockClear();
|
|
77
|
+
userEvent.type(inputField, "{Escape}");
|
|
78
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
79
|
+
|
|
80
|
+
// Test invalid value doesn't save
|
|
81
|
+
updateValue.mockClear();
|
|
82
|
+
userEvent.type(inputField, "xxx");
|
|
83
|
+
expect(await canvas.findByText("?")).toBeInTheDocument();
|
|
84
|
+
expect(canvas.getByText("Bearing must be a number in D.MMSSS format")).toBeInTheDocument();
|
|
85
|
+
userEvent.type(inputField, "{Enter}");
|
|
86
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
87
|
+
userEvent.tab();
|
|
88
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
89
|
+
userEvent.tab({ shift: true });
|
|
90
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
91
|
+
};
|