@linzjs/step-ag-grid 8.4.2 → 9.0.0
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/README.md +4 -4
- package/dist/index.css +3 -0
- package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +5 -4
- 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/src/utils/textMatcher.d.ts +1 -1
- package/dist/src/utils/textMatcher.test.d.ts +1 -0
- package/dist/step-ag-grid.esm.js +502 -735
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +42 -42
- package/src/components/Grid.tsx +29 -27
- package/src/components/gridForm/GridFormDropDown.tsx +12 -14
- package/src/components/gridForm/GridFormMultiSelect.tsx +31 -29
- package/src/components/gridForm/GridFormPopoverMenu.tsx +18 -22
- package/src/components/gridForm/GridFormSubComponentTextArea.tsx +1 -1
- package/src/components/gridForm/GridFormSubComponentTextInput.tsx +1 -1
- package/src/components/gridForm/GridFormTextArea.tsx +1 -1
- package/src/components/gridForm/GridFormTextInput.tsx +1 -1
- package/src/lui/TextAreaInput.tsx +3 -1
- package/src/lui/TextInputFormatted.tsx +3 -1
- package/src/react-menu3/components/ControlledMenu.tsx +19 -6
- package/src/react-menu3/components/MenuItem.tsx +1 -1
- package/src/react-menu3/utils/withHovering.tsx +3 -3
- package/src/stories/grid/GridKeyboardInteractions.stories.tsx +261 -0
- package/src/stories/grid/{GridPopoutBearing.stories.tsx → GridPopoverEditBearing.stories.tsx} +4 -4
- package/src/stories/grid/{GridPopoutEditDropDown.stories.tsx → GridPopoverEditDropDown.stories.tsx} +10 -2
- package/src/stories/grid/{GridPopoutEditMultiSelect.stories.tsx → GridPopoverEditMultiSelect.stories.tsx} +0 -0
- package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +137 -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/GridFormMultiSelectInteraction.stories.tsx +153 -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/src/stories/react-menu/ReactMenu.stories.tsx +66 -3
- package/src/styles/Grid.scss +3 -0
- package/src/utils/testUtil.ts +1 -0
- package/src/utils/textMatcher.test.ts +38 -0
- package/src/utils/textMatcher.ts +9 -2
|
@@ -0,0 +1,153 @@
|
|
|
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
|
+
GridFormMultiSelect,
|
|
8
|
+
GridFormMultiSelectProps,
|
|
9
|
+
GridFormMultiSelectSaveProps,
|
|
10
|
+
MultiSelectOption,
|
|
11
|
+
} from "../../../components/gridForm/GridFormMultiSelect";
|
|
12
|
+
import { GridContextProvider } from "../../../contexts/GridContextProvider";
|
|
13
|
+
import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
|
|
14
|
+
import { GridFormSubComponentTextInput } from "../../../components/gridForm/GridFormSubComponentTextInput";
|
|
15
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
16
|
+
import { expect, jest } from "@storybook/jest";
|
|
17
|
+
import { wait } from "../../../utils/util";
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
title: "GridForm / Interactions",
|
|
21
|
+
component: GridFormMultiSelect,
|
|
22
|
+
args: {},
|
|
23
|
+
} as ComponentMeta<typeof GridFormMultiSelect>;
|
|
24
|
+
|
|
25
|
+
const updateValue = jest
|
|
26
|
+
.fn<void, [saveFn: (selectedRows: any[]) => Promise<boolean>, _tabDirection: 1 | 0 | -1]>()
|
|
27
|
+
.mockImplementation((saveFn: (selectedRows: any[]) => Promise<boolean>, _tabDirection: 1 | 0 | -1) => saveFn([]));
|
|
28
|
+
|
|
29
|
+
const onSave = jest.fn<Promise<boolean>, [GridFormMultiSelectSaveProps<any>]>().mockImplementation(async () => true);
|
|
30
|
+
|
|
31
|
+
const options = Object.freeze([
|
|
32
|
+
{ label: "Zero", value: 0 },
|
|
33
|
+
{ label: "One", value: 1 },
|
|
34
|
+
{
|
|
35
|
+
label: "Sub component",
|
|
36
|
+
value: 2,
|
|
37
|
+
subComponent: () => (
|
|
38
|
+
<GridFormSubComponentTextInput placeholder={"Text input"} maxLength={5} required defaultValue={""} />
|
|
39
|
+
),
|
|
40
|
+
},
|
|
41
|
+
{ label: "Other", value: 3 },
|
|
42
|
+
]) as MultiSelectOption[];
|
|
43
|
+
|
|
44
|
+
const Template: ComponentStory<typeof GridFormMultiSelect> = (props) => {
|
|
45
|
+
const config: GridFormMultiSelectProps<any> = {
|
|
46
|
+
filtered: true,
|
|
47
|
+
onSave,
|
|
48
|
+
options,
|
|
49
|
+
};
|
|
50
|
+
const anchorRef = useRef<HTMLHeadingElement>(null);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className={"react-menu-inline-test"}>
|
|
54
|
+
<GridContextProvider>
|
|
55
|
+
<div>
|
|
56
|
+
<h6 ref={anchorRef}>Interaction test</h6>
|
|
57
|
+
<GridPopoverContext.Provider
|
|
58
|
+
value={
|
|
59
|
+
{
|
|
60
|
+
anchorRef: anchorRef,
|
|
61
|
+
updateValue,
|
|
62
|
+
data: { value: "" },
|
|
63
|
+
value: "",
|
|
64
|
+
field: "value",
|
|
65
|
+
selectedRows: [],
|
|
66
|
+
} as any as GridPopoverContextType<any>
|
|
67
|
+
}
|
|
68
|
+
>
|
|
69
|
+
<GridFormMultiSelect {...props} {...config} />
|
|
70
|
+
</GridPopoverContext.Provider>
|
|
71
|
+
</div>
|
|
72
|
+
</GridContextProvider>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const GridFormMultiSelectInteractions_ = Template.bind({});
|
|
78
|
+
GridFormMultiSelectInteractions_.play = async ({ canvasElement }) => {
|
|
79
|
+
const canvas = within(canvasElement);
|
|
80
|
+
|
|
81
|
+
const getOption = (name: RegExp | string) => canvas.findByRole("menuitem", { name });
|
|
82
|
+
|
|
83
|
+
// Check enabled menu handles click
|
|
84
|
+
const zeroMenuOption = await getOption(/Zero/);
|
|
85
|
+
expect(zeroMenuOption).toBeInTheDocument();
|
|
86
|
+
|
|
87
|
+
userEvent.click(zeroMenuOption);
|
|
88
|
+
userEvent.keyboard("{Tab}");
|
|
89
|
+
expect(updateValue).toHaveBeenCalled();
|
|
90
|
+
expect(onSave).toHaveBeenCalledWith({ selectedOptions: [options[0]], selectedRows: [] });
|
|
91
|
+
|
|
92
|
+
// Check sub menu works
|
|
93
|
+
const subTextInput = await getOption(/Sub component/);
|
|
94
|
+
expect(subTextInput).toBeInTheDocument();
|
|
95
|
+
|
|
96
|
+
expect(canvas.queryByPlaceholderText("Text input")).not.toBeInTheDocument();
|
|
97
|
+
|
|
98
|
+
userEvent.click(subTextInput);
|
|
99
|
+
const textInput = await canvas.findByPlaceholderText("Text input");
|
|
100
|
+
expect(textInput).toBeInTheDocument();
|
|
101
|
+
expect(await canvas.findByText("Must not be empty")).toBeInTheDocument();
|
|
102
|
+
|
|
103
|
+
userEvent.click(textInput);
|
|
104
|
+
userEvent.type(textInput, "Hello");
|
|
105
|
+
expect(await canvas.findByText("Press enter or tab to save")).toBeInTheDocument();
|
|
106
|
+
|
|
107
|
+
// Test tab to save
|
|
108
|
+
updateValue.mockClear();
|
|
109
|
+
onSave.mockClear();
|
|
110
|
+
userEvent.tab();
|
|
111
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
112
|
+
expect(onSave).toHaveBeenCalledWith({
|
|
113
|
+
selectedRows: [],
|
|
114
|
+
selectedOptions: [
|
|
115
|
+
{ label: "Zero", value: 0, checked: true },
|
|
116
|
+
{ label: "Sub component", value: 2, checked: true, subValue: "Hello", subComponent: expect.anything() },
|
|
117
|
+
],
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Test shift+tab to save
|
|
121
|
+
updateValue.mockClear();
|
|
122
|
+
onSave.mockClear();
|
|
123
|
+
userEvent.tab({ shift: true });
|
|
124
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
125
|
+
expect(onSave).toHaveBeenCalled();
|
|
126
|
+
|
|
127
|
+
// Test escape to not save
|
|
128
|
+
updateValue.mockClear();
|
|
129
|
+
onSave.mockClear();
|
|
130
|
+
userEvent.type(textInput, "{Escape}");
|
|
131
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
132
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
133
|
+
|
|
134
|
+
// Test invalid value doesn't save
|
|
135
|
+
updateValue.mockClear();
|
|
136
|
+
onSave.mockClear();
|
|
137
|
+
userEvent.clear(textInput);
|
|
138
|
+
userEvent.type(textInput, "{Enter}");
|
|
139
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
140
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
141
|
+
|
|
142
|
+
// Test filter
|
|
143
|
+
const filterText = await canvas.findByPlaceholderText("Filter...");
|
|
144
|
+
userEvent.type(filterText, "o");
|
|
145
|
+
await wait(500);
|
|
146
|
+
expect(canvas.queryByText("One")).toBeInTheDocument();
|
|
147
|
+
expect(canvas.queryByText("Other")).toBeInTheDocument();
|
|
148
|
+
userEvent.type(filterText, "n");
|
|
149
|
+
expect(canvas.queryByText("One")).toBeInTheDocument();
|
|
150
|
+
expect(canvas.queryByText("Zero")).not.toBeInTheDocument();
|
|
151
|
+
expect(canvas.queryByText("Sub component")).not.toBeInTheDocument();
|
|
152
|
+
expect(canvas.queryByText("Other")).not.toBeInTheDocument();
|
|
153
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
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 {
|
|
6
|
+
GridFormPopoverMenu,
|
|
7
|
+
PopoutMenuSeparator,
|
|
8
|
+
SelectedMenuOptionResult,
|
|
9
|
+
} from "../../../components/gridForm/GridFormPopoverMenu";
|
|
10
|
+
import { GridContextProvider } from "../../../contexts/GridContextProvider";
|
|
11
|
+
import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
|
|
12
|
+
import { useRef } from "react";
|
|
13
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
14
|
+
import { expect, jest } from "@storybook/jest";
|
|
15
|
+
import { GridBaseRow } from "../../../components/Grid";
|
|
16
|
+
import { GridFormSubComponentTextInput } from "../../../components/gridForm/GridFormSubComponentTextInput";
|
|
17
|
+
import { GridFormSubComponentTextArea } from "../../../components/gridForm/GridFormSubComponentTextArea";
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
title: "GridForm / Interactions",
|
|
21
|
+
component: GridFormPopoverMenu,
|
|
22
|
+
args: {},
|
|
23
|
+
} as ComponentMeta<typeof GridFormPopoverMenu>;
|
|
24
|
+
|
|
25
|
+
const updateValue = jest
|
|
26
|
+
.fn<void, [saveFn: (selectedRows: any[]) => Promise<boolean>, _tabDirection: 1 | 0 | -1]>()
|
|
27
|
+
.mockImplementation(async (saveFn: (selectedRows: any[]) => Promise<boolean>, _tabDirection: 1 | 0 | -1) => {
|
|
28
|
+
await saveFn([]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const enabledAction = jest
|
|
32
|
+
.fn<Promise<void>, [{ selectedRows: GridBaseRow[]; menuOption: SelectedMenuOptionResult<GridBaseRow> }]>()
|
|
33
|
+
.mockResolvedValue(undefined);
|
|
34
|
+
|
|
35
|
+
const disabledAction = jest
|
|
36
|
+
.fn<Promise<void>, [{ selectedRows: GridBaseRow[]; menuOption: SelectedMenuOptionResult<GridBaseRow> }]>()
|
|
37
|
+
.mockResolvedValue(undefined);
|
|
38
|
+
|
|
39
|
+
const Template: ComponentStory<typeof GridFormPopoverMenu> = (props) => {
|
|
40
|
+
const anchorRef = useRef<HTMLHeadingElement>(null);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className={"react-menu-inline-test"}>
|
|
44
|
+
<GridContextProvider>
|
|
45
|
+
<h6 ref={anchorRef}>Interaction Test</h6>
|
|
46
|
+
<GridPopoverContext.Provider
|
|
47
|
+
value={
|
|
48
|
+
{
|
|
49
|
+
anchorRef,
|
|
50
|
+
value: null,
|
|
51
|
+
updateValue,
|
|
52
|
+
} as any as GridPopoverContextType<any>
|
|
53
|
+
}
|
|
54
|
+
>
|
|
55
|
+
<GridFormPopoverMenu
|
|
56
|
+
{...props}
|
|
57
|
+
options={async () => [
|
|
58
|
+
{ label: "Enabled", value: 1, action: enabledAction },
|
|
59
|
+
PopoutMenuSeparator,
|
|
60
|
+
{ label: "Disabled", value: 0, disabled: true, action: disabledAction },
|
|
61
|
+
{
|
|
62
|
+
label: "Sub text input",
|
|
63
|
+
value: 0,
|
|
64
|
+
subComponent: () => (
|
|
65
|
+
<GridFormSubComponentTextInput placeholder={"Text input"} maxLength={5} required defaultValue={""} />
|
|
66
|
+
),
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
label: "Sub text area",
|
|
70
|
+
value: 0,
|
|
71
|
+
subComponent: () => (
|
|
72
|
+
<GridFormSubComponentTextArea placeholder={"Text area"} maxLength={5} required defaultValue={""} />
|
|
73
|
+
),
|
|
74
|
+
},
|
|
75
|
+
{ label: "ERROR! this should be hidden", value: 3, hidden: true },
|
|
76
|
+
]}
|
|
77
|
+
/>
|
|
78
|
+
</GridPopoverContext.Provider>
|
|
79
|
+
</GridContextProvider>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const GridFormPopoverMenuInteractions_ = Template.bind({});
|
|
85
|
+
GridFormPopoverMenuInteractions_.play = async ({ canvasElement }) => {
|
|
86
|
+
const canvas = within(canvasElement);
|
|
87
|
+
|
|
88
|
+
const getOption = (name: string) => canvas.findByRole("menuitem", { name });
|
|
89
|
+
|
|
90
|
+
const enabledMenuOption = await getOption("Enabled");
|
|
91
|
+
expect(enabledMenuOption).toBeInTheDocument();
|
|
92
|
+
userEvent.click(enabledMenuOption);
|
|
93
|
+
expect(enabledAction).toHaveBeenCalled();
|
|
94
|
+
|
|
95
|
+
enabledAction.mockClear();
|
|
96
|
+
const disabledMenuOption = await getOption("Disabled");
|
|
97
|
+
expect(disabledMenuOption).toBeInTheDocument();
|
|
98
|
+
userEvent.click(disabledMenuOption);
|
|
99
|
+
expect(disabledAction).not.toHaveBeenCalled();
|
|
100
|
+
|
|
101
|
+
// Sub input tests
|
|
102
|
+
const subTextInput = await getOption("Sub text input");
|
|
103
|
+
expect(subTextInput).toBeInTheDocument();
|
|
104
|
+
expect(canvas.queryByPlaceholderText("Text input")).not.toBeInTheDocument();
|
|
105
|
+
|
|
106
|
+
const subTextArea = await getOption("Sub text area");
|
|
107
|
+
expect(subTextArea).toBeInTheDocument();
|
|
108
|
+
expect(canvas.queryByPlaceholderText("Text area")).not.toBeInTheDocument();
|
|
109
|
+
|
|
110
|
+
userEvent.click(subTextInput);
|
|
111
|
+
const textInput = await canvas.findByPlaceholderText("Text input");
|
|
112
|
+
expect(textInput).toBeInTheDocument();
|
|
113
|
+
expect(await canvas.findByText("Must not be empty")).toBeInTheDocument();
|
|
114
|
+
expect(canvas.queryByPlaceholderText("Text area")).not.toBeInTheDocument();
|
|
115
|
+
|
|
116
|
+
userEvent.type(textInput, "Hello");
|
|
117
|
+
expect(await canvas.findByText("Press enter or tab to save")).toBeInTheDocument();
|
|
118
|
+
|
|
119
|
+
// Test tab to save
|
|
120
|
+
updateValue.mockClear();
|
|
121
|
+
userEvent.tab();
|
|
122
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
123
|
+
|
|
124
|
+
// Test shift+tab to save
|
|
125
|
+
updateValue.mockClear();
|
|
126
|
+
userEvent.tab({ shift: true });
|
|
127
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
128
|
+
|
|
129
|
+
// Test escape to not save
|
|
130
|
+
updateValue.mockClear();
|
|
131
|
+
userEvent.type(textInput, "{Escape}");
|
|
132
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
133
|
+
|
|
134
|
+
// Test invalid value doesn't save
|
|
135
|
+
updateValue.mockClear();
|
|
136
|
+
userEvent.clear(textInput);
|
|
137
|
+
userEvent.type(textInput, "{Enter}");
|
|
138
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
139
|
+
|
|
140
|
+
// Sub text area tests
|
|
141
|
+
subTextArea.click();
|
|
142
|
+
|
|
143
|
+
const textArea = await canvas.findByPlaceholderText("Text area");
|
|
144
|
+
expect(textArea).toBeInTheDocument();
|
|
145
|
+
expect(await canvas.findByText("Must not be empty")).toBeInTheDocument();
|
|
146
|
+
expect(canvas.queryByPlaceholderText("Text input")).not.toBeInTheDocument();
|
|
147
|
+
|
|
148
|
+
userEvent.type(textArea, "Hello");
|
|
149
|
+
expect(await canvas.findByText("Press tab to save")).toBeInTheDocument();
|
|
150
|
+
|
|
151
|
+
// Test tab to save
|
|
152
|
+
updateValue.mockClear();
|
|
153
|
+
userEvent.tab();
|
|
154
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
155
|
+
|
|
156
|
+
// Test shift+tab to save
|
|
157
|
+
updateValue.mockClear();
|
|
158
|
+
userEvent.tab({ shift: true });
|
|
159
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
160
|
+
|
|
161
|
+
// Test escape to not save
|
|
162
|
+
updateValue.mockClear();
|
|
163
|
+
userEvent.type(textArea, "{Escape}");
|
|
164
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
165
|
+
|
|
166
|
+
// Test invalid value doesn't save
|
|
167
|
+
updateValue.mockClear();
|
|
168
|
+
userEvent.clear(textArea);
|
|
169
|
+
userEvent.type(textArea, "{Enter}");
|
|
170
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
171
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
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 { GridFormTextArea } from "../../../components/gridForm/GridFormTextArea";
|
|
6
|
+
import { GridContextProvider } from "../../../contexts/GridContextProvider";
|
|
7
|
+
import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
|
|
8
|
+
import { useRef } from "react";
|
|
9
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
10
|
+
import { expect, jest } from "@storybook/jest";
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
title: "GridForm / Interactions",
|
|
14
|
+
component: GridFormTextArea,
|
|
15
|
+
args: {},
|
|
16
|
+
} as ComponentMeta<typeof GridFormTextArea>;
|
|
17
|
+
|
|
18
|
+
const updateValue = jest.fn();
|
|
19
|
+
|
|
20
|
+
const Template: ComponentStory<typeof GridFormTextArea> = (props) => {
|
|
21
|
+
const anchorRef = useRef<HTMLHeadingElement>(null);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className={"react-menu-inline-test"}>
|
|
25
|
+
<GridContextProvider>
|
|
26
|
+
<h6 ref={anchorRef}>Interaction Test</h6>
|
|
27
|
+
<GridPopoverContext.Provider
|
|
28
|
+
value={
|
|
29
|
+
{
|
|
30
|
+
anchorRef,
|
|
31
|
+
value: null,
|
|
32
|
+
updateValue,
|
|
33
|
+
} as any as GridPopoverContextType<any>
|
|
34
|
+
}
|
|
35
|
+
>
|
|
36
|
+
<GridFormTextArea {...props} required={true} />
|
|
37
|
+
</GridPopoverContext.Provider>
|
|
38
|
+
</GridContextProvider>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const GridFormTextAreaInteractions_ = Template.bind({});
|
|
44
|
+
GridFormTextAreaInteractions_.play = async ({ canvasElement }) => {
|
|
45
|
+
const canvas = within(canvasElement);
|
|
46
|
+
|
|
47
|
+
expect(await canvas.findByText("Must not be empty")).toBeInTheDocument();
|
|
48
|
+
|
|
49
|
+
const inputField = canvas.getByPlaceholderText("Type here");
|
|
50
|
+
userEvent.type(inputField, "Hello");
|
|
51
|
+
|
|
52
|
+
expect(await canvas.findByText("Press tab to save")).toBeInTheDocument();
|
|
53
|
+
|
|
54
|
+
// Test tab to save
|
|
55
|
+
updateValue.mockClear();
|
|
56
|
+
userEvent.tab();
|
|
57
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
58
|
+
|
|
59
|
+
// Test shift+tab to save
|
|
60
|
+
updateValue.mockClear();
|
|
61
|
+
userEvent.tab({ shift: true });
|
|
62
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
63
|
+
|
|
64
|
+
// Test escape not to save
|
|
65
|
+
updateValue.mockClear();
|
|
66
|
+
userEvent.type(inputField, "{Escape}");
|
|
67
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
68
|
+
|
|
69
|
+
// Test invalid value doesn't save
|
|
70
|
+
updateValue.mockClear();
|
|
71
|
+
userEvent.clear(inputField);
|
|
72
|
+
|
|
73
|
+
expect(canvas.getByText("Must not be empty")).toBeInTheDocument();
|
|
74
|
+
userEvent.tab();
|
|
75
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
76
|
+
userEvent.tab({ shift: true });
|
|
77
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
78
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
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 { GridFormTextInput } from "../../../components/gridForm/GridFormTextInput";
|
|
6
|
+
import { GridContextProvider } from "../../../contexts/GridContextProvider";
|
|
7
|
+
import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
|
|
8
|
+
import { useRef } from "react";
|
|
9
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
10
|
+
import { expect, jest } from "@storybook/jest";
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
title: "GridForm / Interactions",
|
|
14
|
+
component: GridFormTextInput,
|
|
15
|
+
args: {},
|
|
16
|
+
} as ComponentMeta<typeof GridFormTextInput>;
|
|
17
|
+
|
|
18
|
+
const updateValue = jest.fn();
|
|
19
|
+
|
|
20
|
+
const Template: ComponentStory<typeof GridFormTextInput> = (props) => {
|
|
21
|
+
const anchorRef = useRef<HTMLHeadingElement>(null);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className={"react-menu-inline-test"}>
|
|
25
|
+
<GridContextProvider>
|
|
26
|
+
<h6 ref={anchorRef}>Interaction Test</h6>
|
|
27
|
+
<GridPopoverContext.Provider
|
|
28
|
+
value={
|
|
29
|
+
{
|
|
30
|
+
anchorRef,
|
|
31
|
+
value: null,
|
|
32
|
+
updateValue,
|
|
33
|
+
} as any as GridPopoverContextType<any>
|
|
34
|
+
}
|
|
35
|
+
>
|
|
36
|
+
<GridFormTextInput {...props} required={true} />
|
|
37
|
+
</GridPopoverContext.Provider>
|
|
38
|
+
</GridContextProvider>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const GridFormTextInputInteractions_ = Template.bind({});
|
|
44
|
+
GridFormTextInputInteractions_.play = async ({ canvasElement }) => {
|
|
45
|
+
const canvas = within(canvasElement);
|
|
46
|
+
|
|
47
|
+
expect(await canvas.findByText("Must not be empty")).toBeInTheDocument();
|
|
48
|
+
|
|
49
|
+
const inputField = canvas.getByPlaceholderText("Type here");
|
|
50
|
+
userEvent.type(inputField, "Hello");
|
|
51
|
+
|
|
52
|
+
expect(canvas.getByText("Press enter or tab to save")).toBeInTheDocument();
|
|
53
|
+
|
|
54
|
+
// Test enter to save
|
|
55
|
+
updateValue.mockClear();
|
|
56
|
+
userEvent.type(inputField, "{Enter}");
|
|
57
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 0); // 0 = Enter
|
|
58
|
+
|
|
59
|
+
// Test tab to save
|
|
60
|
+
updateValue.mockClear();
|
|
61
|
+
userEvent.tab();
|
|
62
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), 1); // 1 = Tab
|
|
63
|
+
|
|
64
|
+
// Test shift+tab to save
|
|
65
|
+
updateValue.mockClear();
|
|
66
|
+
userEvent.tab({ shift: true });
|
|
67
|
+
expect(updateValue).toHaveBeenCalledWith(expect.anything(), -1); // -1 = Shift + tab
|
|
68
|
+
|
|
69
|
+
// Test escape not to save
|
|
70
|
+
updateValue.mockClear();
|
|
71
|
+
userEvent.type(inputField, "{Escape}");
|
|
72
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
73
|
+
|
|
74
|
+
// Test invalid value doesn't save
|
|
75
|
+
updateValue.mockClear();
|
|
76
|
+
userEvent.clear(inputField);
|
|
77
|
+
|
|
78
|
+
expect(canvas.getByText("Must not be empty")).toBeInTheDocument();
|
|
79
|
+
userEvent.type(inputField, "{Enter}");
|
|
80
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
81
|
+
userEvent.tab();
|
|
82
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
83
|
+
userEvent.tab({ shift: true });
|
|
84
|
+
expect(updateValue).not.toHaveBeenCalled();
|
|
85
|
+
};
|
|
@@ -9,7 +9,7 @@ import { useRef } from "react";
|
|
|
9
9
|
import { GridBaseRow } from "../../../components/Grid";
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: "GridForm /
|
|
12
|
+
title: "GridForm / Static Tests",
|
|
13
13
|
component: GridFormDropDown,
|
|
14
14
|
args: {},
|
|
15
15
|
} as ComponentMeta<typeof GridFormDropDown>;
|
|
@@ -9,7 +9,7 @@ import { useRef } from "react";
|
|
|
9
9
|
import { GridPopoverEditBearingEditorParams } from "../../../components/gridPopoverEdit/GridPopoverEditBearing";
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: "GridForm /
|
|
12
|
+
title: "GridForm / Static Tests",
|
|
13
13
|
component: GridFormEditBearing,
|
|
14
14
|
args: {},
|
|
15
15
|
} as ComponentMeta<typeof GridFormEditBearing>;
|
package/src/stories/grid/{gridForm → gridFormStatic}/GridFormEditBearingCorrection.stories.tsx
RENAMED
|
@@ -9,7 +9,7 @@ import { useRef } from "react";
|
|
|
9
9
|
import { GridPopoverEditBearingCorrectionEditorParams } from "../../../components/gridPopoverEdit/GridPopoverEditBearing";
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: "GridForm /
|
|
12
|
+
title: "GridForm / Static Tests",
|
|
13
13
|
component: GridFormEditBearing,
|
|
14
14
|
args: {},
|
|
15
15
|
} as ComponentMeta<typeof GridFormEditBearing>;
|
|
@@ -8,7 +8,7 @@ import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopover
|
|
|
8
8
|
import { useRef } from "react";
|
|
9
9
|
|
|
10
10
|
export default {
|
|
11
|
-
title: "GridForm /
|
|
11
|
+
title: "GridForm / Static Tests",
|
|
12
12
|
component: GridFormMessage,
|
|
13
13
|
args: {},
|
|
14
14
|
} as ComponentMeta<typeof GridFormMessage>;
|
|
@@ -9,7 +9,7 @@ import { useRef } from "react";
|
|
|
9
9
|
import { GridBaseRow } from "../../../components/Grid";
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: "GridForm /
|
|
12
|
+
title: "GridForm / Static Tests",
|
|
13
13
|
component: GridFormMultiSelect,
|
|
14
14
|
args: {},
|
|
15
15
|
} as ComponentMeta<typeof GridFormMultiSelect>;
|
|
@@ -13,7 +13,7 @@ import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopover
|
|
|
13
13
|
import { GridBaseRow } from "../../../components/Grid";
|
|
14
14
|
|
|
15
15
|
export default {
|
|
16
|
-
title: "GridForm /
|
|
16
|
+
title: "GridForm / Static Tests",
|
|
17
17
|
component: GridFormPopoverMenu,
|
|
18
18
|
args: {},
|
|
19
19
|
} as ComponentMeta<typeof GridFormPopoverMenu>;
|
|
@@ -9,7 +9,7 @@ import { useRef } from "react";
|
|
|
9
9
|
import { GridBaseRow } from "../../../components/Grid";
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: "GridForm /
|
|
12
|
+
title: "GridForm / Static Tests",
|
|
13
13
|
component: GridFormTextArea,
|
|
14
14
|
args: {},
|
|
15
15
|
} as ComponentMeta<typeof GridFormTextArea>;
|
|
@@ -9,7 +9,7 @@ import { useRef } from "react";
|
|
|
9
9
|
import { GridBaseRow } from "../../../components/Grid";
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: "GridForm /
|
|
12
|
+
title: "GridForm / Static Tests",
|
|
13
13
|
component: GridFormTextInput,
|
|
14
14
|
args: {},
|
|
15
15
|
} as ComponentMeta<typeof GridFormTextInput>;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
|
|
2
2
|
import { Grid } from "../../components/Grid";
|
|
3
|
-
import { Menu,
|
|
3
|
+
import { Menu, MenuButton, MenuDivider, MenuItem, SubMenu } from "../../react-menu3";
|
|
4
|
+
import { userEvent, within } from "@storybook/testing-library";
|
|
5
|
+
import { wait } from "../../utils/util";
|
|
6
|
+
import { expect, jest } from "@storybook/jest";
|
|
4
7
|
|
|
5
8
|
export default {
|
|
6
9
|
title: "Components / React-menu",
|
|
@@ -11,11 +14,14 @@ export default {
|
|
|
11
14
|
},
|
|
12
15
|
} as ComponentMeta<typeof Grid>;
|
|
13
16
|
|
|
17
|
+
const menuItemClickAction = jest.fn();
|
|
18
|
+
const newFileAction = jest.fn();
|
|
19
|
+
|
|
14
20
|
const ReactMenuTemplate: ComponentStory<typeof Grid> = () => {
|
|
15
21
|
return (
|
|
16
22
|
<>
|
|
17
|
-
<Menu menuButton={<MenuButton>Open menu</MenuButton>}>
|
|
18
|
-
<MenuItem>New File</MenuItem>
|
|
23
|
+
<Menu menuButton={<MenuButton>Open menu</MenuButton>} onItemClick={menuItemClickAction}>
|
|
24
|
+
<MenuItem onClick={newFileAction}>New File</MenuItem>
|
|
19
25
|
<MenuItem>Save</MenuItem>
|
|
20
26
|
<SubMenu label="Edit">
|
|
21
27
|
<MenuItem>Cut</MenuItem>
|
|
@@ -31,3 +37,60 @@ const ReactMenuTemplate: ComponentStory<typeof Grid> = () => {
|
|
|
31
37
|
};
|
|
32
38
|
|
|
33
39
|
export const ReactMenuControlled = ReactMenuTemplate.bind({});
|
|
40
|
+
ReactMenuControlled.play = async ({ canvasElement }) => {
|
|
41
|
+
const canvas = within(canvasElement);
|
|
42
|
+
|
|
43
|
+
const keyboard = async (key: string) => {
|
|
44
|
+
userEvent.keyboard(key);
|
|
45
|
+
await wait(100); // Wait for debounce
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const menuButton = await canvas.findByRole("button");
|
|
49
|
+
expect(menuButton).toBeInTheDocument();
|
|
50
|
+
|
|
51
|
+
const openMenu = async () => {
|
|
52
|
+
await wait(500); // Wait for debounce
|
|
53
|
+
userEvent.click(menuButton);
|
|
54
|
+
expect(await canvas.findByRole("menuitem", { name: "New File" })).toBeInTheDocument();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Check menu closes on click outside
|
|
58
|
+
await openMenu();
|
|
59
|
+
userEvent.click(menuButton.parentElement as Element);
|
|
60
|
+
expect(canvas.queryByRole("menuitem", { name: "New File" })).not.toBeInTheDocument();
|
|
61
|
+
|
|
62
|
+
// Test arrow down/up
|
|
63
|
+
await openMenu();
|
|
64
|
+
await keyboard("{arrowdown}");
|
|
65
|
+
await keyboard("{arrowdown}");
|
|
66
|
+
await keyboard("{arrowdown}");
|
|
67
|
+
await keyboard("{arrowdown}");
|
|
68
|
+
await keyboard("{arrowdown}");
|
|
69
|
+
expect(document.activeElement?.innerHTML).toBe("Exit");
|
|
70
|
+
|
|
71
|
+
await keyboard("{arrowup}");
|
|
72
|
+
expect(document.activeElement?.innerHTML).toBe("Print...");
|
|
73
|
+
|
|
74
|
+
// Escape close
|
|
75
|
+
userEvent.type(menuButton.parentElement as Element, "{Escape}");
|
|
76
|
+
expect(canvas.queryByRole("menuitem", { name: "New File" })).not.toBeInTheDocument();
|
|
77
|
+
|
|
78
|
+
// Test enter to select
|
|
79
|
+
await openMenu();
|
|
80
|
+
await keyboard("{arrowdown}");
|
|
81
|
+
await keyboard("{enter}");
|
|
82
|
+
expect(menuItemClickAction).toHaveBeenCalled();
|
|
83
|
+
expect(newFileAction).toHaveBeenCalled();
|
|
84
|
+
|
|
85
|
+
menuItemClickAction.mockClear();
|
|
86
|
+
newFileAction.mockClear();
|
|
87
|
+
|
|
88
|
+
// Test tab to select
|
|
89
|
+
await openMenu();
|
|
90
|
+
await keyboard("{arrowdown}");
|
|
91
|
+
await keyboard("{Tab}");
|
|
92
|
+
expect(menuItemClickAction).toHaveBeenCalled();
|
|
93
|
+
expect(newFileAction).toHaveBeenCalled();
|
|
94
|
+
|
|
95
|
+
newFileAction.mockClear();
|
|
96
|
+
};
|
package/src/styles/Grid.scss
CHANGED