@onewelcome/react-lib-components 0.2.5 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onewelcome/react-lib-components",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "license": "Apache-2.0",
5
5
  "author": "OneWelcome B.V.",
6
6
  "main": "dist/index.js",
@@ -11,7 +11,15 @@
11
11
  padding: 0;
12
12
  min-width: 200px;
13
13
 
14
+ &.no-margin-top {
15
+ margin: 0 0 1rem;
16
+ }
17
+
14
18
  button {
15
19
  text-align: left;
16
20
  }
17
21
  }
22
+
23
+ .decorative-element {
24
+ margin-top: 1rem;
25
+ }
@@ -88,6 +88,16 @@ describe("ContextMenu should render", () => {
88
88
  expect(child.parentElement).toHaveClass("custom");
89
89
  });
90
90
 
91
+ it("renders the decorative element", () => {
92
+ const { getByText } = createContextMenu(defaultParams => ({
93
+ ...defaultParams,
94
+ show: true,
95
+ decorativeElement: <div>test</div>
96
+ }));
97
+
98
+ expect(getByText("test")).toBeInTheDocument();
99
+ });
100
+
91
101
  it("should throw an error", () => {
92
102
  // Prevent throwing an error in the console when this test is executed. We fix this and the end of this test.
93
103
  const err = console.error;
@@ -252,4 +262,37 @@ describe("accessibility controls", () => {
252
262
 
253
263
  expect(thirdContextMenuItem).toHaveFocus();
254
264
  });
265
+
266
+ it("opens correctly with enter, navigate with arrow keys skipping the decorative element", () => {
267
+ onClick.mockImplementation(e => {
268
+ expect(e.target.getAttribute("data-testid")).toBe("contextmenuitem3");
269
+ });
270
+
271
+ const { trigger, getByTestId, getByText } = createContextMenu(defaultParams => ({
272
+ ...defaultParams,
273
+ decorativeElement: <div>test</div>
274
+ }));
275
+ const thirdContextMenuItem = getByTestId("contextmenuitem3");
276
+
277
+ userEvent.tab();
278
+ userEvent.keyboard("{enter}");
279
+
280
+ expect(getByText("test")).toBeInTheDocument();
281
+
282
+ expect(trigger).toHaveAttribute("aria-expanded", "true");
283
+
284
+ userEvent.keyboard("{arrowdown}");
285
+ userEvent.keyboard("{arrowdown}");
286
+ userEvent.keyboard("{arrowdown}");
287
+
288
+ expect(thirdContextMenuItem).toHaveFocus();
289
+
290
+ userEvent.keyboard("{space}");
291
+
292
+ expect(onClick).toHaveBeenCalled();
293
+
294
+ userEvent.keyboard("{space}");
295
+
296
+ expect(thirdContextMenuItem).toHaveFocus();
297
+ });
255
298
  });
@@ -16,6 +16,7 @@ import { createPortal } from "react-dom";
16
16
 
17
17
  export interface Props extends ComponentPropsWithRef<"div"> {
18
18
  trigger: ReactElement<ButtonProps> | ReactElement<IconButtonProps>;
19
+ decorativeElement?: ReactNode;
19
20
  children: ReactNode;
20
21
  placement?: Placement;
21
22
  transformOrigin?: Placement;
@@ -32,6 +33,7 @@ export const ContextMenu = React.forwardRef<HTMLDivElement, Props>(
32
33
  {
33
34
  trigger,
34
35
  children,
36
+ decorativeElement,
35
37
  id,
36
38
  show = false,
37
39
  onShow,
@@ -183,7 +185,15 @@ export const ContextMenu = React.forwardRef<HTMLDivElement, Props>(
183
185
  anchorEl={anchorEl}
184
186
  show={showContextMenu}
185
187
  >
186
- <ul className={classes["menu"]} id={`${id}-menu`} aria-describedby={id} role="menu">
188
+ {decorativeElement && (
189
+ <div className={classes["decorative-element"]}>{decorativeElement}</div>
190
+ )}
191
+ <ul
192
+ className={`${classes["menu"]} ${decorativeElement ? classes["no-margin-top"] : ""}`}
193
+ id={`${id}-menu`}
194
+ aria-describedby={id}
195
+ role="menu"
196
+ >
187
197
  {renderChildren()}
188
198
  </ul>
189
199
  </Popover>,
@@ -24,6 +24,7 @@
24
24
  box-sizing: border-box;
25
25
  border: 0;
26
26
  border-radius: var(--input-border-radius);
27
+ transition: all 0.2s ease-in-out;
27
28
 
28
29
  &:disabled {
29
30
  background-color: var(--disabled);
@@ -12,19 +12,26 @@ input {
12
12
  margin-top: 0.25rem;
13
13
  }
14
14
 
15
- .input-wrapper [data-icon]:before {
16
- transition: 0.2s ease-in-out;
17
- transform: translateY(0px);
18
- font-size: 1.125rem;
19
- }
15
+ .input-wrapper {
16
+ [data-icon]:before {
17
+ transition: 0.2s ease-in-out;
18
+ transform: translateY(0px);
19
+ font-size: 1.125rem;
20
+ }
20
21
 
21
- .input-wrapper .floating-label-active [data-icon]:before {
22
- transform: translateY(5px);
23
- }
22
+ .floating-label-active [data-icon]:before {
23
+ transform: translateY(5px);
24
+ }
24
25
 
25
- .input-wrapper [data-prefix],
26
- .input-wrapper [data-suffix] {
27
- transform: translateY(-0.125rem);
26
+ [data-prefix],
27
+ [data-suffix] {
28
+ transform: translateY(-0.125rem);
29
+ }
30
+
31
+ .disabled {
32
+ background-color: var(--disabled);
33
+ cursor: not-allowed;
34
+ }
28
35
  }
29
36
 
30
37
  .floating-label-active [data-prefix],
@@ -58,6 +58,26 @@ describe("InputWrapper should render", () => {
58
58
 
59
59
  expect(input).toHaveAttribute("aria-describedby", helperId);
60
60
  });
61
+
62
+ it("disabled input", () => {
63
+ const { getByLabelText } = createInputWrapper(defaultParams => ({
64
+ ...defaultParams,
65
+ disabled: true
66
+ }));
67
+
68
+ const input = getByLabelText("Example label");
69
+
70
+ expect(input).toBeDisabled();
71
+ });
72
+
73
+ it("consume wrapper props classname", () => {
74
+ const { container } = createInputWrapper(defaultParams => ({
75
+ ...defaultParams,
76
+ inputProps: { wrapperProps: { className: "testClass" } }
77
+ }));
78
+
79
+ expect(container.querySelector(".testClass")).toBeDefined();
80
+ });
61
81
  });
62
82
 
63
83
  describe("ref should work", () => {
@@ -56,6 +56,7 @@ export const InputWrapper = React.forwardRef<HTMLDivElement, Props>(
56
56
  onChange,
57
57
  onBlur,
58
58
  onFocus,
59
+ disabled,
59
60
  ...rest
60
61
  }: Props,
61
62
  ref
@@ -72,15 +73,21 @@ export const InputWrapper = React.forwardRef<HTMLDivElement, Props>(
72
73
  const { prefix, suffix } = inputProps || {};
73
74
  const input = useRef<HTMLInputElement>(null);
74
75
  const hasValueOrActiveFloatingLabel = !!value || floatingLabelActive;
75
- const labelClasses = [classes["input-label"]];
76
76
  const { labelOffset } = useLabelOffset(
77
77
  (inputProps && (inputProps.ref as React.RefObject<HTMLInputElement>)) || input,
78
78
  floatingLabelActive,
79
79
  prefix
80
80
  );
81
81
 
82
+ const labelClasses = [classes["input-label"]];
82
83
  hasFocus && labelClasses.push(classes["focus"]);
83
84
 
85
+ const inputWrapperClasses = [];
86
+ floatingLabelActive && inputWrapperClasses.push(classes["floating-label-active"]);
87
+ inputProps?.wrapperProps?.className &&
88
+ inputWrapperClasses.push(inputProps?.wrapperProps?.className);
89
+ disabled && inputWrapperClasses.push(classes["disabled"]);
90
+
84
91
  return (
85
92
  <Wrapper
86
93
  {...rest}
@@ -102,15 +109,14 @@ export const InputWrapper = React.forwardRef<HTMLDivElement, Props>(
102
109
  className: `${classes["input-wrapper-helper"]} ${helperProps?.className ?? ""} `
103
110
  }}
104
111
  helperIndent={20}
112
+ disabled={disabled}
105
113
  >
106
114
  <Input
107
115
  {...inputProps}
108
116
  prefix={hasValueOrActiveFloatingLabel ? prefix : ""}
109
117
  suffix={hasValueOrActiveFloatingLabel ? suffix : ""}
110
118
  wrapperProps={{
111
- className: `${floatingLabelActive ? classes["floating-label-active"] : ""} ${
112
- inputProps?.wrapperProps?.className ?? ""
113
- }`
119
+ className: inputWrapperClasses.join(" ")
114
120
  }}
115
121
  ref={(inputProps && inputProps.ref) || input}
116
122
  aria-labelledby={labelId}
@@ -22,6 +22,10 @@
22
22
  &.error {
23
23
  color: var(--error);
24
24
  }
25
+
26
+ &.disabled {
27
+ color: var(--greyed-out);
28
+ }
25
29
  }
26
30
 
27
31
  .wrapper + fieldset,
@@ -69,9 +69,10 @@ export const Wrapper = React.forwardRef<HTMLDivElement, Props>(
69
69
  labelProps?.className && labelClasses.push(labelProps.className);
70
70
  required && labelClasses.push(classes["required"]);
71
71
  error && labelClasses.push(classes["error"]);
72
+ disabled && labelClasses.push(classes["disabled"]);
72
73
 
73
74
  return (
74
- <div {...rest} ref={ref} className={`${classes.wrapper} ${className ? className : ""}`}>
75
+ <div {...rest} ref={ref} className={`${classes.wrapper} ${className ?? ""}`}>
75
76
  <FormGroup
76
77
  error={error}
77
78
  errorMessage={errorMessage}