@etsoo/materialui 1.5.87 → 1.5.88

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.
@@ -1,6 +1,11 @@
1
- import React from "react";
2
1
  import { ComboBox } from "../src";
3
- import { act, fireEvent, render, screen } from "@testing-library/react";
2
+ import {
3
+ act,
4
+ fireEvent,
5
+ render,
6
+ screen,
7
+ waitFor
8
+ } from "@testing-library/react";
4
9
 
5
10
  it("Render ComboBox", async () => {
6
11
  // Arrange
@@ -21,21 +26,15 @@ it("Render ComboBox", async () => {
21
26
  );
22
27
  });
23
28
 
24
- await vi.waitFor(
25
- async () => {
26
- await screen.findByRole("button");
27
- },
28
- {
29
- timeout: 500, // default is 1000
30
- interval: 20 // default is 50
31
- }
32
- );
29
+ await waitFor(async () => {
30
+ const button = await screen.findByRole("button");
33
31
 
34
- // Act, click the list
35
- const clicked = fireEvent.click(screen.getByRole("button"));
36
- expect(clicked).toBeTruthy();
32
+ // Act, click the list
33
+ const clicked = fireEvent.click(button);
34
+ expect(clicked).toBeTruthy();
37
35
 
38
- // Get list item
39
- const item = screen.getByText("Name 1");
40
- expect(item.nodeName).toBe("LI");
36
+ // Get list item
37
+ const item = await screen.findByText("Name 1");
38
+ expect(item.nodeName).toBe("LI");
39
+ });
41
40
  });
@@ -137,13 +137,13 @@ it("Render FieldSelect", async () => {
137
137
  );
138
138
  });
139
139
 
140
- const button = screen.getByRole("combobox");
140
+ const button = await screen.findByRole("combobox");
141
141
 
142
142
  act(() => {
143
143
  // Act, click to open the dropdown list
144
144
  vi.useFakeTimers();
145
145
  fireEvent.mouseDown(button);
146
- vi.advanceTimersByTime(100);
146
+ vi.runAllTimers();
147
147
  });
148
148
 
149
149
  const input = document.querySelector<HTMLInputElement>("input");
@@ -0,0 +1,76 @@
1
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
2
+ import { act } from "react";
3
+ import { InputTipField } from "../src";
4
+
5
+ it("Render default InputTipField", async () => {
6
+ // Render component
7
+ act(() => {
8
+ render(
9
+ <InputTipField
10
+ name="amount"
11
+ type="number"
12
+ componentProps={{
13
+ loadData: (_value) => Promise.resolve([])
14
+ }}
15
+ slotProps={{ htmlInput: { role: "input" } }}
16
+ />
17
+ );
18
+ });
19
+
20
+ const input = screen.getByRole<HTMLInputElement>("input");
21
+ expect(input.type).toBe("number");
22
+ });
23
+
24
+ it("Render email InputTipField", async () => {
25
+ // Arrange
26
+ type T = { id: number; name: string };
27
+ const options: T[] = [
28
+ { id: 1, name: "Name 1" },
29
+ { id: 2, name: "Name 2" }
30
+ ];
31
+
32
+ const changeHandler = vi.fn();
33
+
34
+ const flag = "2 items";
35
+
36
+ // Render component
37
+ act(() => {
38
+ render(
39
+ <InputTipField<T>
40
+ component="email"
41
+ componentProps={{
42
+ loadData: (_value) => Promise.resolve([options, flag]),
43
+ itemLabel: (item) => item.name + ` (${item.id})`
44
+ }}
45
+ onChangeDelay={changeHandler}
46
+ slotProps={{ htmlInput: { role: "input" } }}
47
+ />
48
+ );
49
+ });
50
+
51
+ const input = screen.getByRole<HTMLInputElement>("input");
52
+ expect(input.type).toBe("email");
53
+
54
+ act(() => {
55
+ vi.useFakeTimers();
56
+
57
+ fireEvent.change(input, { target: { value: "info@etsoo.com" } });
58
+ expect(input.value).toBe("info@etsoo.com");
59
+
60
+ vi.runAllTimers();
61
+ expect(changeHandler).toHaveBeenCalled();
62
+
63
+ // Restore timers, otherwise 'waitFor' will fail
64
+ vi.useRealTimers();
65
+ });
66
+
67
+ await waitFor(() => {
68
+ const button = screen.getByText(flag);
69
+ expect(button.nodeName).toBe("P");
70
+
71
+ fireEvent.click(button);
72
+
73
+ const item = screen.getByText("Name 2 (2)");
74
+ expect(item.nodeName).toBe("LI");
75
+ });
76
+ });
@@ -1,7 +1,7 @@
1
1
  import { IdType } from "@etsoo/shared";
2
2
  import { TypographyProps } from "@mui/material/Typography";
3
3
  import React from "react";
4
- import { InputField } from "./InputField";
4
+ import { InputFieldProps } from "./InputField";
5
5
  import { EmailInput } from "./EmailInput";
6
6
  import { MobileInput } from "./MobileInput";
7
7
  import { PhoneInput } from "./PhoneInput";
@@ -9,52 +9,62 @@ type ItemType = {
9
9
  id: IdType;
10
10
  };
11
11
  declare const componentMap: {
12
- input: typeof InputField;
13
12
  email: typeof EmailInput;
14
13
  phone: typeof PhoneInput;
15
14
  mobile: typeof MobileInput;
16
15
  };
17
16
  type ComponentMap = typeof componentMap;
18
17
  type ComponentKey = keyof ComponentMap;
18
+ type ComponentProps<T extends ItemType> = {
19
+ /**
20
+ * Load data
21
+ * @param value Duplicate test value
22
+ */
23
+ loadData(value: string): Promise<[T[]?, string?]>;
24
+ /**
25
+ * Label props
26
+ */
27
+ labelProps?: Omit<TypographyProps, "onClick">;
28
+ /**
29
+ * Custom item label
30
+ * @param item List item data
31
+ * @returns Result
32
+ */
33
+ itemLabel?: (item: T) => React.ReactNode;
34
+ /**
35
+ * Custom render item
36
+ * @param item List item data
37
+ * @returns Result
38
+ */
39
+ renderItem?: (item: T) => React.ReactNode;
40
+ };
19
41
  /**
20
42
  * InputField with tips properties
21
43
  */
22
- export type InputTipFieldProps<T extends ItemType = ItemType, K extends ComponentKey = "input"> = Omit<React.ComponentProps<ComponentMap[K]>, "component"> & {
44
+ export type InputTipFieldProps<T extends ItemType = ItemType> = {
23
45
  /**
24
- * Component key
46
+ * Component properties
25
47
  */
26
- component?: K;
48
+ componentProps: ComponentProps<T>;
49
+ } & (({
27
50
  /**
28
51
  * Component properties
29
52
  */
30
- componentProps: {
31
- /**
32
- * Load data
33
- * @param value Duplicate test value
34
- */
35
- loadData(value: string): Promise<[T[]?, string?]>;
36
- /**
37
- * Label props
38
- */
39
- labelProps?: Omit<TypographyProps, "onClick">;
40
- /**
41
- * Custom item label
42
- * @param item List item data
43
- * @returns Result
44
- */
45
- itemLabel?: (item: T) => React.ReactNode;
53
+ componentProps: ComponentProps<T>;
54
+ } & {
55
+ [K in ComponentKey]: {
46
56
  /**
47
- * Custom render item
48
- * @param item List item data
49
- * @returns Result
57
+ * Component key
50
58
  */
51
- renderItem?: (item: T) => React.ReactNode;
52
- };
53
- };
59
+ component: K;
60
+ } & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
61
+ }[ComponentKey]) | ({
62
+ component?: "input";
63
+ } & Omit<InputFieldProps, "component">));
54
64
  /**
55
65
  * InputField with tips
56
66
  * @param props Props
57
67
  * @returns Component
58
68
  */
59
- export declare function InputTipField<T extends ItemType = ItemType, K extends ComponentKey = "input">(props: InputTipFieldProps<T, K>): import("react/jsx-runtime").JSX.Element;
69
+ export declare function InputTipField<T extends ItemType = ItemType>(props: InputTipFieldProps<T>): import("react/jsx-runtime").JSX.Element;
60
70
  export {};
@@ -18,7 +18,6 @@ const EmailInput_1 = require("./EmailInput");
18
18
  const MobileInput_1 = require("./MobileInput");
19
19
  const PhoneInput_1 = require("./PhoneInput");
20
20
  const componentMap = {
21
- input: InputField_1.InputField,
22
21
  email: EmailInput_1.EmailInput,
23
22
  phone: PhoneInput_1.PhoneInput,
24
23
  mobile: MobileInput_1.MobileInput
@@ -42,7 +41,7 @@ function InputTipField(props) {
42
41
  sx: { color: (theme) => theme.palette.error.main, cursor: "pointer" }
43
42
  }, loadData, itemLabel = (item) => shared_1.DataTypes.getObjectItemLabel(item), renderItem = (item) => (0, jsx_runtime_1.jsx)(ListItem_1.default, { children: itemLabel(item) }, item.id) } = componentProps;
44
43
  const { input, ...slotRests } = slotProps;
45
- const Component = componentMap[component];
44
+ const Component = component === "input" ? InputField_1.InputField : componentMap[component];
46
45
  const load = (value) => {
47
46
  if (value.length < 2) {
48
47
  setTitle(undefined);
@@ -1,7 +1,7 @@
1
1
  import { IdType } from "@etsoo/shared";
2
2
  import { TypographyProps } from "@mui/material/Typography";
3
3
  import React from "react";
4
- import { InputField } from "./InputField";
4
+ import { InputFieldProps } from "./InputField";
5
5
  import { EmailInput } from "./EmailInput";
6
6
  import { MobileInput } from "./MobileInput";
7
7
  import { PhoneInput } from "./PhoneInput";
@@ -9,52 +9,62 @@ type ItemType = {
9
9
  id: IdType;
10
10
  };
11
11
  declare const componentMap: {
12
- input: typeof InputField;
13
12
  email: typeof EmailInput;
14
13
  phone: typeof PhoneInput;
15
14
  mobile: typeof MobileInput;
16
15
  };
17
16
  type ComponentMap = typeof componentMap;
18
17
  type ComponentKey = keyof ComponentMap;
18
+ type ComponentProps<T extends ItemType> = {
19
+ /**
20
+ * Load data
21
+ * @param value Duplicate test value
22
+ */
23
+ loadData(value: string): Promise<[T[]?, string?]>;
24
+ /**
25
+ * Label props
26
+ */
27
+ labelProps?: Omit<TypographyProps, "onClick">;
28
+ /**
29
+ * Custom item label
30
+ * @param item List item data
31
+ * @returns Result
32
+ */
33
+ itemLabel?: (item: T) => React.ReactNode;
34
+ /**
35
+ * Custom render item
36
+ * @param item List item data
37
+ * @returns Result
38
+ */
39
+ renderItem?: (item: T) => React.ReactNode;
40
+ };
19
41
  /**
20
42
  * InputField with tips properties
21
43
  */
22
- export type InputTipFieldProps<T extends ItemType = ItemType, K extends ComponentKey = "input"> = Omit<React.ComponentProps<ComponentMap[K]>, "component"> & {
44
+ export type InputTipFieldProps<T extends ItemType = ItemType> = {
23
45
  /**
24
- * Component key
46
+ * Component properties
25
47
  */
26
- component?: K;
48
+ componentProps: ComponentProps<T>;
49
+ } & (({
27
50
  /**
28
51
  * Component properties
29
52
  */
30
- componentProps: {
31
- /**
32
- * Load data
33
- * @param value Duplicate test value
34
- */
35
- loadData(value: string): Promise<[T[]?, string?]>;
36
- /**
37
- * Label props
38
- */
39
- labelProps?: Omit<TypographyProps, "onClick">;
40
- /**
41
- * Custom item label
42
- * @param item List item data
43
- * @returns Result
44
- */
45
- itemLabel?: (item: T) => React.ReactNode;
53
+ componentProps: ComponentProps<T>;
54
+ } & {
55
+ [K in ComponentKey]: {
46
56
  /**
47
- * Custom render item
48
- * @param item List item data
49
- * @returns Result
57
+ * Component key
50
58
  */
51
- renderItem?: (item: T) => React.ReactNode;
52
- };
53
- };
59
+ component: K;
60
+ } & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
61
+ }[ComponentKey]) | ({
62
+ component?: "input";
63
+ } & Omit<InputFieldProps, "component">));
54
64
  /**
55
65
  * InputField with tips
56
66
  * @param props Props
57
67
  * @returns Component
58
68
  */
59
- export declare function InputTipField<T extends ItemType = ItemType, K extends ComponentKey = "input">(props: InputTipFieldProps<T, K>): import("react/jsx-runtime").JSX.Element;
69
+ export declare function InputTipField<T extends ItemType = ItemType>(props: InputTipFieldProps<T>): import("react/jsx-runtime").JSX.Element;
60
70
  export {};
@@ -12,7 +12,6 @@ import { EmailInput } from "./EmailInput";
12
12
  import { MobileInput } from "./MobileInput";
13
13
  import { PhoneInput } from "./PhoneInput";
14
14
  const componentMap = {
15
- input: InputField,
16
15
  email: EmailInput,
17
16
  phone: PhoneInput,
18
17
  mobile: MobileInput
@@ -36,7 +35,7 @@ export function InputTipField(props) {
36
35
  sx: { color: (theme) => theme.palette.error.main, cursor: "pointer" }
37
36
  }, loadData, itemLabel = (item) => DataTypes.getObjectItemLabel(item), renderItem = (item) => _jsx(ListItem, { children: itemLabel(item) }, item.id) } = componentProps;
38
37
  const { input, ...slotRests } = slotProps;
39
- const Component = componentMap[component];
38
+ const Component = component === "input" ? InputField : componentMap[component];
40
39
  const load = (value) => {
41
40
  if (value.length < 2) {
42
41
  setTitle(undefined);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.5.87",
3
+ "version": "1.5.88",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -1,7 +1,7 @@
1
1
  import { DataTypes, IdType } from "@etsoo/shared";
2
2
  import Typography, { TypographyProps } from "@mui/material/Typography";
3
3
  import React from "react";
4
- import { InputField } from "./InputField";
4
+ import { InputField, InputFieldProps } from "./InputField";
5
5
  import { useAppContext } from "./app/ReactApp";
6
6
  import ListItem from "@mui/material/ListItem";
7
7
  import Popover from "@mui/material/Popover";
@@ -16,7 +16,6 @@ type ItemType = {
16
16
  };
17
17
 
18
18
  const componentMap = {
19
- input: InputField,
20
19
  email: EmailInput,
21
20
  phone: PhoneInput,
22
21
  mobile: MobileInput
@@ -25,58 +24,66 @@ const componentMap = {
25
24
  type ComponentMap = typeof componentMap;
26
25
  type ComponentKey = keyof ComponentMap;
27
26
 
28
- /**
29
- * InputField with tips properties
30
- */
31
- export type InputTipFieldProps<
32
- T extends ItemType = ItemType,
33
- K extends ComponentKey = "input"
34
- > = Omit<React.ComponentProps<ComponentMap[K]>, "component"> & {
27
+ type ComponentProps<T extends ItemType> = {
35
28
  /**
36
- * Component key
29
+ * Load data
30
+ * @param value Duplicate test value
37
31
  */
38
- component?: K;
32
+ loadData(value: string): Promise<[T[]?, string?]>;
39
33
 
40
34
  /**
41
- * Component properties
35
+ * Label props
42
36
  */
43
- componentProps: {
44
- /**
45
- * Load data
46
- * @param value Duplicate test value
47
- */
48
- loadData(value: string): Promise<[T[]?, string?]>;
49
-
50
- /**
51
- * Label props
52
- */
53
- labelProps?: Omit<TypographyProps, "onClick">;
54
-
55
- /**
56
- * Custom item label
57
- * @param item List item data
58
- * @returns Result
59
- */
60
- itemLabel?: (item: T) => React.ReactNode;
61
-
62
- /**
63
- * Custom render item
64
- * @param item List item data
65
- * @returns Result
66
- */
67
- renderItem?: (item: T) => React.ReactNode;
68
- };
37
+ labelProps?: Omit<TypographyProps, "onClick">;
38
+
39
+ /**
40
+ * Custom item label
41
+ * @param item List item data
42
+ * @returns Result
43
+ */
44
+ itemLabel?: (item: T) => React.ReactNode;
45
+
46
+ /**
47
+ * Custom render item
48
+ * @param item List item data
49
+ * @returns Result
50
+ */
51
+ renderItem?: (item: T) => React.ReactNode;
69
52
  };
70
53
 
54
+ /**
55
+ * InputField with tips properties
56
+ */
57
+ export type InputTipFieldProps<T extends ItemType = ItemType> = {
58
+ /**
59
+ * Component properties
60
+ */
61
+ componentProps: ComponentProps<T>;
62
+ } & (
63
+ | ({
64
+ /**
65
+ * Component properties
66
+ */
67
+ componentProps: ComponentProps<T>;
68
+ } & {
69
+ [K in ComponentKey]: {
70
+ /**
71
+ * Component key
72
+ */
73
+ component: K;
74
+ } & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
75
+ }[ComponentKey])
76
+ | ({ component?: "input" } & Omit<InputFieldProps, "component">)
77
+ );
78
+
71
79
  /**
72
80
  * InputField with tips
73
81
  * @param props Props
74
82
  * @returns Component
75
83
  */
76
- export function InputTipField<
77
- T extends ItemType = ItemType,
78
- K extends ComponentKey = "input"
79
- >(props: InputTipFieldProps<T, K>) {
84
+ export function InputTipField<T extends ItemType = ItemType>(
85
+ props: InputTipFieldProps<T>
86
+ ) {
80
87
  // Global app
81
88
  const app = useAppContext();
82
89
 
@@ -108,7 +115,8 @@ export function InputTipField<
108
115
 
109
116
  const { input, ...slotRests } = slotProps;
110
117
 
111
- const Component = componentMap[component];
118
+ const Component =
119
+ component === "input" ? InputField : componentMap[component];
112
120
 
113
121
  const load = (value: string) => {
114
122
  if (value.length < 2) {
@@ -160,7 +168,7 @@ export function InputTipField<
160
168
  },
161
169
  ...slotRests
162
170
  }}
163
- {...(rest as any)}
171
+ {...rest}
164
172
  />
165
173
  </React.Fragment>
166
174
  );