@etsoo/materialui 1.5.86 → 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,58 +1,70 @@
1
- import { DataTypes } from "@etsoo/shared";
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";
8
- type ItemType = DataTypes.IdLabelItem<string | number>;
8
+ type ItemType = {
9
+ id: IdType;
10
+ };
9
11
  declare const componentMap: {
10
- input: typeof InputField;
11
12
  email: typeof EmailInput;
12
13
  phone: typeof PhoneInput;
13
14
  mobile: typeof MobileInput;
14
15
  };
15
16
  type ComponentMap = typeof componentMap;
16
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
+ };
17
41
  /**
18
42
  * InputField with tips properties
19
43
  */
20
- 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> = {
21
45
  /**
22
- * Component key
46
+ * Component properties
23
47
  */
24
- component?: K;
48
+ componentProps: ComponentProps<T>;
49
+ } & (({
25
50
  /**
26
51
  * Component properties
27
52
  */
28
- componentProps: {
53
+ componentProps: ComponentProps<T>;
54
+ } & {
55
+ [K in ComponentKey]: {
29
56
  /**
30
- * Load data
31
- * @param value Duplicate test value
57
+ * Component key
32
58
  */
33
- loadData(value: string): Promise<[T[]?, string?]>;
34
- /**
35
- * Label props
36
- */
37
- labelProps?: Omit<TypographyProps, "onClick">;
38
- /**
39
- * Custom item label
40
- * @param item List item data
41
- * @returns Result
42
- */
43
- itemLabel?: (item: T) => React.ReactNode;
44
- /**
45
- * Custom render item
46
- * @param item List item data
47
- * @returns Result
48
- */
49
- renderItem?: (item: T) => React.ReactNode;
50
- };
51
- };
59
+ component: K;
60
+ } & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
61
+ }[ComponentKey]) | ({
62
+ component?: "input";
63
+ } & Omit<InputFieldProps, "component">));
52
64
  /**
53
65
  * InputField with tips
54
66
  * @param props Props
55
67
  * @returns Component
56
68
  */
57
- 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;
58
70
  export {};
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.InputTipField = InputTipField;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const shared_1 = require("@etsoo/shared");
8
9
  const Typography_1 = __importDefault(require("@mui/material/Typography"));
9
10
  const react_1 = __importDefault(require("react"));
10
11
  const InputField_1 = require("./InputField");
@@ -17,7 +18,6 @@ const EmailInput_1 = require("./EmailInput");
17
18
  const MobileInput_1 = require("./MobileInput");
18
19
  const PhoneInput_1 = require("./PhoneInput");
19
20
  const componentMap = {
20
- input: InputField_1.InputField,
21
21
  email: EmailInput_1.EmailInput,
22
22
  phone: PhoneInput_1.PhoneInput,
23
23
  mobile: MobileInput_1.MobileInput
@@ -39,9 +39,9 @@ function InputTipField(props) {
39
39
  const { labelProps = {
40
40
  title: app?.get("clickForDetails"),
41
41
  sx: { color: (theme) => theme.palette.error.main, cursor: "pointer" }
42
- }, loadData, itemLabel = (item) => item.label, renderItem = (item) => (0, jsx_runtime_1.jsx)(ListItem_1.default, { children: itemLabel(item) }, item.id) } = componentProps;
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;
43
43
  const { input, ...slotRests } = slotProps;
44
- const Component = componentMap[component];
44
+ const Component = component === "input" ? InputField_1.InputField : componentMap[component];
45
45
  const load = (value) => {
46
46
  if (value.length < 2) {
47
47
  setTitle(undefined);
@@ -1,58 +1,70 @@
1
- import { DataTypes } from "@etsoo/shared";
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";
8
- type ItemType = DataTypes.IdLabelItem<string | number>;
8
+ type ItemType = {
9
+ id: IdType;
10
+ };
9
11
  declare const componentMap: {
10
- input: typeof InputField;
11
12
  email: typeof EmailInput;
12
13
  phone: typeof PhoneInput;
13
14
  mobile: typeof MobileInput;
14
15
  };
15
16
  type ComponentMap = typeof componentMap;
16
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
+ };
17
41
  /**
18
42
  * InputField with tips properties
19
43
  */
20
- 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> = {
21
45
  /**
22
- * Component key
46
+ * Component properties
23
47
  */
24
- component?: K;
48
+ componentProps: ComponentProps<T>;
49
+ } & (({
25
50
  /**
26
51
  * Component properties
27
52
  */
28
- componentProps: {
53
+ componentProps: ComponentProps<T>;
54
+ } & {
55
+ [K in ComponentKey]: {
29
56
  /**
30
- * Load data
31
- * @param value Duplicate test value
57
+ * Component key
32
58
  */
33
- loadData(value: string): Promise<[T[]?, string?]>;
34
- /**
35
- * Label props
36
- */
37
- labelProps?: Omit<TypographyProps, "onClick">;
38
- /**
39
- * Custom item label
40
- * @param item List item data
41
- * @returns Result
42
- */
43
- itemLabel?: (item: T) => React.ReactNode;
44
- /**
45
- * Custom render item
46
- * @param item List item data
47
- * @returns Result
48
- */
49
- renderItem?: (item: T) => React.ReactNode;
50
- };
51
- };
59
+ component: K;
60
+ } & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
61
+ }[ComponentKey]) | ({
62
+ component?: "input";
63
+ } & Omit<InputFieldProps, "component">));
52
64
  /**
53
65
  * InputField with tips
54
66
  * @param props Props
55
67
  * @returns Component
56
68
  */
57
- 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;
58
70
  export {};
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DataTypes } from "@etsoo/shared";
2
3
  import Typography from "@mui/material/Typography";
3
4
  import React from "react";
4
5
  import { InputField } from "./InputField";
@@ -11,7 +12,6 @@ import { EmailInput } from "./EmailInput";
11
12
  import { MobileInput } from "./MobileInput";
12
13
  import { PhoneInput } from "./PhoneInput";
13
14
  const componentMap = {
14
- input: InputField,
15
15
  email: EmailInput,
16
16
  phone: PhoneInput,
17
17
  mobile: MobileInput
@@ -33,9 +33,9 @@ export function InputTipField(props) {
33
33
  const { labelProps = {
34
34
  title: app?.get("clickForDetails"),
35
35
  sx: { color: (theme) => theme.palette.error.main, cursor: "pointer" }
36
- }, loadData, itemLabel = (item) => item.label, renderItem = (item) => _jsx(ListItem, { children: itemLabel(item) }, item.id) } = componentProps;
36
+ }, loadData, itemLabel = (item) => DataTypes.getObjectItemLabel(item), renderItem = (item) => _jsx(ListItem, { children: itemLabel(item) }, item.id) } = componentProps;
37
37
  const { input, ...slotRests } = slotProps;
38
- const Component = componentMap[component];
38
+ const Component = component === "input" ? InputField : componentMap[component];
39
39
  const load = (value) => {
40
40
  if (value.length < 2) {
41
41
  setTitle(undefined);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.5.86",
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",
@@ -42,7 +42,7 @@
42
42
  "@emotion/styled": "^11.14.1",
43
43
  "@etsoo/appscript": "^1.6.48",
44
44
  "@etsoo/notificationbase": "^1.1.66",
45
- "@etsoo/react": "^1.8.62",
45
+ "@etsoo/react": "^1.8.63",
46
46
  "@etsoo/shared": "^1.2.79",
47
47
  "@mui/icons-material": "^7.3.5",
48
48
  "@mui/material": "^7.3.5",
@@ -1,7 +1,7 @@
1
- import { DataTypes } from "@etsoo/shared";
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";
@@ -11,10 +11,11 @@ import { EmailInput } from "./EmailInput";
11
11
  import { MobileInput } from "./MobileInput";
12
12
  import { PhoneInput } from "./PhoneInput";
13
13
 
14
- type ItemType = DataTypes.IdLabelItem<string | number>;
14
+ type ItemType = {
15
+ id: IdType;
16
+ };
15
17
 
16
18
  const componentMap = {
17
- input: InputField,
18
19
  email: EmailInput,
19
20
  phone: PhoneInput,
20
21
  mobile: MobileInput
@@ -23,58 +24,66 @@ const componentMap = {
23
24
  type ComponentMap = typeof componentMap;
24
25
  type ComponentKey = keyof ComponentMap;
25
26
 
26
- /**
27
- * InputField with tips properties
28
- */
29
- export type InputTipFieldProps<
30
- T extends ItemType = ItemType,
31
- K extends ComponentKey = "input"
32
- > = Omit<React.ComponentProps<ComponentMap[K]>, "component"> & {
27
+ type ComponentProps<T extends ItemType> = {
33
28
  /**
34
- * Component key
29
+ * Load data
30
+ * @param value Duplicate test value
35
31
  */
36
- component?: K;
32
+ loadData(value: string): Promise<[T[]?, string?]>;
37
33
 
38
34
  /**
39
- * Component properties
35
+ * Label props
40
36
  */
41
- componentProps: {
42
- /**
43
- * Load data
44
- * @param value Duplicate test value
45
- */
46
- loadData(value: string): Promise<[T[]?, string?]>;
47
-
48
- /**
49
- * Label props
50
- */
51
- labelProps?: Omit<TypographyProps, "onClick">;
52
-
53
- /**
54
- * Custom item label
55
- * @param item List item data
56
- * @returns Result
57
- */
58
- itemLabel?: (item: T) => React.ReactNode;
59
-
60
- /**
61
- * Custom render item
62
- * @param item List item data
63
- * @returns Result
64
- */
65
- renderItem?: (item: T) => React.ReactNode;
66
- };
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;
67
52
  };
68
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
+
69
79
  /**
70
80
  * InputField with tips
71
81
  * @param props Props
72
82
  * @returns Component
73
83
  */
74
- export function InputTipField<
75
- T extends ItemType = ItemType,
76
- K extends ComponentKey = "input"
77
- >(props: InputTipFieldProps<T, K>) {
84
+ export function InputTipField<T extends ItemType = ItemType>(
85
+ props: InputTipFieldProps<T>
86
+ ) {
78
87
  // Global app
79
88
  const app = useAppContext();
80
89
 
@@ -100,13 +109,14 @@ export function InputTipField<
100
109
  sx: { color: (theme) => theme.palette.error.main, cursor: "pointer" }
101
110
  },
102
111
  loadData,
103
- itemLabel = (item) => item.label,
112
+ itemLabel = (item) => DataTypes.getObjectItemLabel(item),
104
113
  renderItem = (item) => <ListItem key={item.id}>{itemLabel(item)}</ListItem>
105
114
  } = componentProps;
106
115
 
107
116
  const { input, ...slotRests } = slotProps;
108
117
 
109
- const Component = componentMap[component];
118
+ const Component =
119
+ component === "input" ? InputField : componentMap[component];
110
120
 
111
121
  const load = (value: string) => {
112
122
  if (value.length < 2) {
@@ -158,7 +168,7 @@ export function InputTipField<
158
168
  },
159
169
  ...slotRests
160
170
  }}
161
- {...(rest as any)}
171
+ {...rest}
162
172
  />
163
173
  </React.Fragment>
164
174
  );