@onewelcome/react-lib-components 0.2.3 → 0.2.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onewelcome/react-lib-components",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "license": "Apache-2.0",
5
5
  "author": "OneWelcome B.V.",
6
6
  "main": "dist/index.js",
@@ -18,7 +18,7 @@
18
18
  "build": "dts build",
19
19
  "build-storybook": "build-storybook",
20
20
  "dev": "npm-run-all -p start test:watch storybook",
21
- "lint": "eslint --fix 'src/**/*.{ts,tsx}'",
21
+ "lint": "eslint --fix '**/*.{ts,tsx}'",
22
22
  "prepare": "husky install && dts build",
23
23
  "size": "size-limit",
24
24
  "start": "dts watch",
@@ -85,7 +85,7 @@ describe("ContextMenu should render", () => {
85
85
 
86
86
  const child = getByRole("menuitem");
87
87
 
88
- expect(child).toHaveClass("custom");
88
+ expect(child.parentElement).toHaveClass("custom");
89
89
  });
90
90
 
91
91
  it("should throw an error", () => {
@@ -46,8 +46,9 @@ export const ContextMenuItem = React.forwardRef<HTMLButtonElement, Props>(
46
46
  }, [hasFocus, innerButtonRef, contextMenuOpened]);
47
47
 
48
48
  return (
49
- <li role="menuitem" className={`${classes["context-menu-item"]} ${className ?? ""}`}>
49
+ <li role="none" className={`${classes["context-menu-item"]} ${className ?? ""}`}>
50
50
  <button
51
+ role="menuitem"
51
52
  {...rest}
52
53
  ref={innerButtonRef}
53
54
  data-focus={hasFocus}
@@ -8,7 +8,7 @@ import { ColumnName, HeaderCell, OnSortFunction, Sort } from "./datagrid.interfa
8
8
  import { Pagination, Props as PaginationProps } from "../Pagination/Pagination";
9
9
  import { Spacing, useSpacing } from "../hooks/useSpacing";
10
10
 
11
- export interface Props<T> extends ComponentPropsWithRef<"div"> {
11
+ export interface Props<T> extends Omit<ComponentPropsWithRef<"div">, "children"> {
12
12
  children: ({ item, index }: { item: T; index: number }) => ReactElement;
13
13
  data?: T[];
14
14
  initialSort?: Sort;
@@ -23,7 +23,7 @@ export const DataGridRow = React.forwardRef<HTMLTableRowElement, Props>(
23
23
  disableContextMenuColumn
24
24
  });
25
25
 
26
- const visible = headers?.length! > index ? !headers![index].hidden : true;
26
+ const visible = headers && headers.length > index ? !headers[index].hidden : true;
27
27
  return visible && cellWithSpacing;
28
28
  }
29
29
  return null;
@@ -17,11 +17,6 @@ $borderRadius: 2.5rem;
17
17
  display: block;
18
18
  pointer-events: none;
19
19
 
20
- &.disabled {
21
- opacity: 0.25;
22
- cursor: not-allowed;
23
- }
24
-
25
20
  &:before {
26
21
  content: "";
27
22
  width: 1rem;
@@ -42,6 +37,11 @@ $borderRadius: 2.5rem;
42
37
  transform: translateY(-50%) translateX(calc(100% - 0.25rem));
43
38
  }
44
39
  }
40
+
41
+ &.disabled {
42
+ background-color: var(--disabled);
43
+ cursor: not-allowed;
44
+ }
45
45
  }
46
46
 
47
47
  .toggle-helper {
@@ -11,5 +11,5 @@ export interface FormSelector extends FormElement {
11
11
  /** Default form elements */
12
12
  export interface FormElement {
13
13
  error?: boolean;
14
- [dataAttribute: DataAttributeKey]: any;
14
+ [dataAttribute: DataAttributeKey]: unknown;
15
15
  }
@@ -2,7 +2,7 @@ import * as H from "history";
2
2
 
3
3
  export interface LinkProps<S = H.LocationState>
4
4
  extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
5
- component?: React.ComponentType<any> | undefined;
5
+ component?: React.ComponentType<unknown> | undefined;
6
6
  to: H.LocationDescriptor<S> | ((location: H.Location<S>) => H.LocationDescriptor<S>);
7
7
  replace?: boolean | undefined;
8
8
  innerRef?: React.Ref<HTMLAnchorElement> | undefined;
@@ -1,4 +1,4 @@
1
- import React, { useState } from "react";
1
+ import React, { useEffect, useState } from "react";
2
2
  import {
3
3
  render,
4
4
  getByTestId,
@@ -6,20 +6,26 @@ import {
6
6
  waitFor,
7
7
  getAllByRole,
8
8
  getByText,
9
- findByText,
10
- findAllByText,
11
- queryByText
9
+ fireEvent
12
10
  } from "@testing-library/react";
13
11
  import { SnackbarProvider, Props } from "./SnackbarProvider";
14
12
  import { useSnackbar } from "../useSnackbar";
15
13
  import userEvent from "@testing-library/user-event";
16
14
 
17
15
  const successProps = {
18
- title: "success title"
16
+ title: "success title",
17
+ options: {
18
+ duration: 10,
19
+ onClose: jest.fn()
20
+ }
19
21
  };
20
22
 
21
23
  const errorProps = {
22
- title: "error title"
24
+ title: "error title",
25
+ options: {
26
+ duration: 10,
27
+ onClose: jest.fn()
28
+ }
23
29
  };
24
30
 
25
31
  const infoProps = {
@@ -43,7 +49,7 @@ const renderSnackbarProvider = (props?: Partial<Props>) => {
43
49
  <button
44
50
  data-testid="show-success"
45
51
  onClick={() => {
46
- enqueueSuccessSnackbar(successProps.title + index);
52
+ enqueueSuccessSnackbar(successProps.title + index, undefined, successProps.options);
47
53
  setIndex(index + 1);
48
54
  }}
49
55
  >
@@ -96,24 +102,24 @@ describe("SnackbarProvider", () => {
96
102
  expect(container).toHaveTextContent("content");
97
103
  });
98
104
 
99
- it("should stack 3 snackbars at one time", () => {
105
+ it("should stack 3 snackbars at one time", async () => {
100
106
  const { showSuccessSnackbarBtn } = renderSnackbarProvider();
101
107
 
102
- userEvent.click(showSuccessSnackbarBtn);
103
- userEvent.click(showSuccessSnackbarBtn);
104
- userEvent.click(showSuccessSnackbarBtn);
105
- userEvent.click(showSuccessSnackbarBtn);
108
+ await userEvent.click(showSuccessSnackbarBtn);
109
+ await userEvent.click(showSuccessSnackbarBtn);
110
+ await userEvent.click(showSuccessSnackbarBtn);
111
+ await userEvent.click(showSuccessSnackbarBtn);
106
112
 
107
113
  expect(getAllByText(document.body, new RegExp(successProps.title))).toHaveLength(3);
108
114
  });
109
115
 
110
- it("should render 3 variants of snackbars", () => {
116
+ it("should render 3 variants of snackbars", async () => {
111
117
  const { showSuccessSnackbarBtn, showErrorSnackbarBtn, showInfoSnackbarBtn } =
112
118
  renderSnackbarProvider();
113
119
 
114
- userEvent.click(showSuccessSnackbarBtn);
115
- userEvent.click(showErrorSnackbarBtn);
116
- userEvent.click(showInfoSnackbarBtn);
120
+ await userEvent.click(showSuccessSnackbarBtn);
121
+ await userEvent.click(showErrorSnackbarBtn);
122
+ await userEvent.click(showInfoSnackbarBtn);
117
123
 
118
124
  expect(getByText(document.body, new RegExp(successProps.title))).toBeDefined();
119
125
  expect(getByText(document.body, new RegExp(errorProps.title))).toBeDefined();
@@ -122,58 +128,45 @@ describe("SnackbarProvider", () => {
122
128
  const infoSnackbarActions = getAllByRole(document.body, "button", { name: /Contact/i });
123
129
  expect(infoSnackbarActions).toHaveLength(2);
124
130
 
125
- userEvent.click(infoSnackbarActions[0]);
126
- userEvent.click(infoSnackbarActions[1]);
131
+ await userEvent.click(infoSnackbarActions[0]);
132
+ await userEvent.click(infoSnackbarActions[1]);
127
133
 
128
134
  expect(infoProps.options.actions[0].onClick).toBeCalledTimes(1);
129
- waitFor(() => expect(infoProps.options.actions[1].onClick).toBeCalledTimes(1));
130
135
  });
136
+ });
131
137
 
132
- it("should stack 3 snackbars at one time and then after 3 disapear show the fourth one", () => {
133
- const { showSuccessSnackbarBtn } = renderSnackbarProvider({
134
- autoHideDuration: { long: 1, short: 1 }
135
- });
138
+ describe("handlers", () => {
139
+ it("should fire onClose", async () => {
140
+ const onCloseHandler = jest.fn();
141
+ const ExampleComponent = () => {
142
+ const { enqueueErrorSnackbar, enqueueSuccessSnackbar } = useSnackbar();
136
143
 
137
- userEvent.click(showSuccessSnackbarBtn);
138
- userEvent.click(showSuccessSnackbarBtn);
139
- userEvent.click(showSuccessSnackbarBtn);
140
- userEvent.click(showSuccessSnackbarBtn);
144
+ useEffect(() => {
145
+ enqueueErrorSnackbar("error", undefined, { onClose: onCloseHandler, duration: 1 });
146
+ enqueueSuccessSnackbar("success", undefined, { onClose: onCloseHandler, duration: 1 });
147
+ }, []);
141
148
 
142
- expect(getAllByText(document.body, new RegExp(successProps.title))).toHaveLength(3);
149
+ return <div></div>;
150
+ };
143
151
 
144
- /** Looking for fourth one to be shown */
145
- waitFor(() => expect(getAllByText(document.body, successProps.title + "3")).toHaveLength(1));
146
-
147
- /** There shouldn't be any other snackbars */
148
- waitFor(() =>
149
- expect(getAllByText(document.body, new RegExp(successProps.title))).not.toBeDefined()
152
+ const queries = render(
153
+ <SnackbarProvider closeButtonTitle="close">
154
+ <ExampleComponent />
155
+ </SnackbarProvider>
150
156
  );
151
- });
152
-
153
- it("should close snackbar after clicking X button", async () => {
154
- const { showSuccessSnackbarBtn } = renderSnackbarProvider({
155
- autoHideDuration: { long: 1_000_000, short: 1_000_000 }
156
- });
157
157
 
158
- userEvent.click(showSuccessSnackbarBtn);
159
- userEvent.click(showSuccessSnackbarBtn);
160
- userEvent.click(showSuccessSnackbarBtn);
161
- userEvent.click(showSuccessSnackbarBtn);
158
+ const errorSnackbar = await queries.findByText(/error/i);
159
+ const successSnackbar = await queries.findByText(/success/i);
162
160
 
163
- const closeButtons = getAllByRole(document.body, "button", { name: "close" });
164
-
165
- expect(closeButtons).toHaveLength(3);
166
- expect(getAllByText(document.body, new RegExp(successProps.title))).toHaveLength(3);
161
+ expect(errorSnackbar).toBeTruthy();
162
+ expect(successSnackbar).toBeTruthy();
167
163
 
168
- userEvent.click(closeButtons[0]);
169
- expect(
170
- await findAllByText(document.body, new RegExp(successProps.title + "[12]+"))
171
- ).toHaveLength(2);
164
+ const parentErrorSnackbar = errorSnackbar.closest(".snackbar")!;
165
+ const parentSuccessSnackbar = successSnackbar.closest(".snackbar")!;
172
166
 
173
- userEvent.click(closeButtons[1]);
174
- expect(await findByText(document.body, successProps.title + "2")).toBeDefined();
167
+ await fireEvent.animationEnd(parentErrorSnackbar);
168
+ await fireEvent.animationEnd(parentSuccessSnackbar);
175
169
 
176
- userEvent.click(closeButtons[2]);
177
- waitFor(() => expect(queryByText(document.body, new RegExp(successProps.title))).toBeNull());
170
+ await waitFor(() => expect(onCloseHandler).toHaveBeenCalledTimes(2));
178
171
  });
179
172
  });
@@ -29,6 +29,7 @@ interface Item {
29
29
  variant: Variant;
30
30
  content?: string;
31
31
  actions?: Actions;
32
+ onClose?: () => void;
32
33
  }
33
34
 
34
35
  export const SnackbarProvider = (
@@ -65,7 +66,8 @@ export const SnackbarProvider = (
65
66
  const {
66
67
  variant = "info",
67
68
  actions,
68
- duration = getDuration(variant, actions, content)
69
+ duration = getDuration(variant, actions, content),
70
+ onClose
69
71
  } = options;
70
72
  const item: Item = {
71
73
  title,
@@ -73,7 +75,8 @@ export const SnackbarProvider = (
73
75
  variant,
74
76
  actions,
75
77
  duration,
76
- id: generateID(15, title)
78
+ id: generateID(15, title),
79
+ onClose
77
80
  };
78
81
  addSnackbar(item);
79
82
  };
@@ -103,7 +106,10 @@ export const SnackbarProvider = (
103
106
  <SnackbarItem
104
107
  {...item}
105
108
  key={item.id}
106
- onClose={onItemClosed}
109
+ onClose={() => {
110
+ onItemClosed(item.id);
111
+ item.onClose && item.onClose();
112
+ }}
107
113
  closeButtonTitle={closeButtonTitle}
108
114
  />
109
115
  ) : null
@@ -8,4 +8,5 @@ export interface SnackbarOptionsProps {
8
8
  actions?: Actions;
9
9
  variant?: Variant;
10
10
  duration?: number;
11
+ onClose?: () => void;
11
12
  }
@@ -8,7 +8,7 @@ export interface ConfigObject {
8
8
  offset?: Offset;
9
9
  }
10
10
 
11
- export type HorizontalPlacment = "left" | "center" | "centerh" | "right";
11
+ export type HorizontalPlacement = "left" | "center" | "centerh" | "right";
12
12
  export type VerticalPlacement = "top" | "center" | "centerv" | "bottom";
13
13
 
14
14
  type Axis = "vertical" | "horizontal";
@@ -29,7 +29,7 @@ interface DomRectObject {
29
29
  }
30
30
 
31
31
  export interface Placement {
32
- horizontal: HorizontalPlacment;
32
+ horizontal: HorizontalPlacement;
33
33
  vertical: VerticalPlacement;
34
34
  }
35
35
 
@@ -73,6 +73,7 @@ const defaultConfigObject: ConfigObject = {
73
73
  }
74
74
  };
75
75
 
76
+ /* eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain*/
76
77
  export const usePosition = (providedConfigObject: ConfigObject = defaultConfigObject) => {
77
78
  const configObject = { ...defaultConfigObject, ...providedConfigObject };
78
79
 
@@ -198,7 +199,7 @@ export const usePosition = (providedConfigObject: ConfigObject = defaultConfigOb
198
199
  transformOrigin: Placement,
199
200
  requestedReturnValue: Axis,
200
201
  relEl: DomRectObject,
201
- placementOriginDefinition: HorizontalPlacment | VerticalPlacement,
202
+ placementOriginDefinition: HorizontalPlacement | VerticalPlacement,
202
203
  elDimensions: Dimensions
203
204
  ) => {
204
205
  let value = 0;
@@ -236,13 +237,13 @@ export const usePosition = (providedConfigObject: ConfigObject = defaultConfigOb
236
237
  return "centerv";
237
238
  }
238
239
  throw new Error(
239
- `the requested return value isn\'t "vertical" or "horizontal" ${requestedReturnValue} was given.`
240
+ `the requested return value isn't "vertical" or "horizontal" ${requestedReturnValue} was given.`
240
241
  );
241
242
  };
242
243
 
243
244
  const _calculatePlacementValue = (
244
245
  transformOrigin: Placement,
245
- placement: HorizontalPlacment | VerticalPlacement,
246
+ placement: HorizontalPlacement | VerticalPlacement,
246
247
  requestedReturnValue: Axis,
247
248
  relEl: DomRectObject,
248
249
  elDimensions: Dimensions
package/src/interfaces.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type DataAttributeKey = `data-${string}`;
2
2
 
3
3
  export interface KeyValuePair {
4
- [dataAttribute: DataAttributeKey]: any;
4
+ [dataAttribute: DataAttributeKey]: unknown;
5
5
  }