@conduction/components 2.2.17 → 2.2.18

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 CHANGED
@@ -4,6 +4,11 @@
4
4
 
5
5
  - **Version 2.2 (breaking changes from 2.1.x)**
6
6
 
7
+ - 2.2.18:
8
+ - Refactored select role attribute.
9
+ - Fixed Pagination-button border-radius.
10
+ - Added colors for Focus and Selected options in Select forms.
11
+ - Add HorizontalOverflowWrapper component and refactor Tabs Component overflow scroll.
7
12
  - 2.2.17: Refactor Pagination to include aria labels and make aria label required on texarea, input and select components.
8
13
  - 2.2.15/2.2.16: Added more NLDS options to Pagination.
9
14
  - 2.2.13/2.2.14:
@@ -150,7 +150,7 @@
150
150
  border-width: var(--conduction-pagination-navigation-button-border-width, var(--utrecht-button-border-width)) !important;
151
151
  border-style: var(--conduction-pagination-navigation-button-border-style, var(--utrecht-button-border-style)) !important;
152
152
  border-color: var(--conduction-pagination-navigation-button-border-color, var(--utrecht-button-border-color)) !important;
153
- border-radius: var(--conduction-pagination-navigation-button-border-radius, var(--utrecht-button-border-radius));
153
+ border-radius: var(--conduction-pagination-navigation-button-border-radius, var(--utrecht-button-border-radius)) !important;
154
154
  padding-inline-start: var(--conduction-pagination-navigation-button-padding-inline-start) !important;
155
155
  padding-inline-end: var(--conduction-pagination-navigation-button-padding-inline-end) !important;
156
156
  padding-block-start: var(--conduction-pagination-navigation-button-padding-block-start) !important;
@@ -8,10 +8,23 @@ import clsx from "clsx";
8
8
  import { ErrorMessage } from "../errorMessage/ErrorMessage";
9
9
  const selectStyles = {
10
10
  menuPortal: (base) => ({ ...base, zIndex: 100 }),
11
- option: (base) => ({
11
+ option: (base, state) => ({
12
12
  ...base,
13
13
  fontFamily: `var(--conduction-input-select-list-option-font-family, ${base.fontFamily})`,
14
- backgroundColor: `var(--conduction-input-select-list-option-background-color, ${base.backgroundColor}) `,
14
+ backgroundColor: [
15
+ state.isFocused
16
+ ? `var(--conduction-input-select-list-option-focus-background-color, ${base.backgroundColor})`
17
+ : state.isSelected
18
+ ? `var(--conduction-input-select-list-option-selected-background-color, ${base.backgroundColor})`
19
+ : `var(--conduction-input-select-list-option-background-color, ${base.backgroundColor})`,
20
+ ],
21
+ color: [
22
+ state.isFocused
23
+ ? `var(--conduction-input-select-list-option-focus-color, ${base.color})`
24
+ : state.isSelected
25
+ ? `var(--conduction-input-select-list-option-selected-color, ${base.color})`
26
+ : `var(--conduction-input-select-list-option-color, ${base.color})`,
27
+ ],
15
28
  "&:hover": {
16
29
  backgroundColor: `var(--conduction-input-select-list-option-hover-background-color, ${base.backgroundColor})`,
17
30
  color: `var(--conduction-input-select-list-option-hover-color, ${base.color})`,
@@ -24,41 +37,20 @@ const selectStyles = {
24
37
  color: `var(--conduction-input-select-placeholder-color, var(--utrecht-form-input-placeholder-color, ${base.color}) )`,
25
38
  }),
26
39
  };
27
- const selectMultiStyles = {
28
- menuPortal: (base) => ({ ...base, zIndex: 100 }),
29
- option: (base) => ({
30
- ...base,
31
- fontFamily: `var(--conduction-input-select-list-option-font-family, ${base.fontFamily})`,
32
- backgroundColor: `var(--conduction-input-select-list-option-background-color, ${base.backgroundColor}) `,
33
- "&:hover": {
34
- backgroundColor: `var(--conduction-input-select-list-option-hover-background-color, ${base.backgroundColor})`,
35
- color: `var(--conduction-input-select-list-option-hover-color, ${base.color})`,
36
- fontFamily: `var(--conduction-input-select-list-option-hover-font-family, var(--conduction-input-select-list-option-font-family, ${base.fontFamily}))`,
37
- },
38
- }),
39
- placeholder: (base) => ({
40
- ...base,
41
- fontFamily: `var(--conduction-input-select-placeholder-font-family, var(--utrecht-form-input-placeholder-font-family, ${base.fontFamily}))`,
42
- color: `var(--conduction-input-select-placeholder-color, var(--utrecht-form-input-placeholder-color, ${base.color}) )`,
43
- }),
40
+ const setAttributes = () => {
41
+ const setRoleToPresentation = (selector, role) => {
42
+ document.querySelectorAll(selector).forEach((element) => {
43
+ if (element.getAttribute("role") !== "presentation")
44
+ element.setAttribute("role", role);
45
+ });
46
+ };
47
+ setRoleToPresentation('[id*="live-region"]', "presentation");
48
+ setRoleToPresentation('[class*="indicatorSeparator"]', "separator");
49
+ setRoleToPresentation('[class*="a11yText"]', "presentation");
44
50
  };
45
51
  export const SelectMultiple = ({ id, name, options, errors, control, validation, defaultValue, disabled, hideErrorMessage, menuPlacement, placeholder, ariaLabel, }) => {
46
52
  React.useEffect(() => {
47
- document.querySelectorAll('[id*="live-region"]').forEach((element) => {
48
- if (element?.role !== "presentation") {
49
- element.setAttribute("role", "presentation");
50
- }
51
- });
52
- document.querySelectorAll('[class*="indicatorSeparator"]').forEach((element) => {
53
- if (element.role !== "presentation") {
54
- element.setAttribute("role", "presentation");
55
- }
56
- });
57
- document.querySelectorAll('[class*="a11yText"]').forEach((element) => {
58
- if (element.role !== "presentation") {
59
- element.setAttribute("role", "presentation");
60
- }
61
- });
53
+ setAttributes();
62
54
  }, []);
63
55
  return (_jsx(Controller, { ...{ control, name, defaultValue }, rules: validation, render: ({ field: { onChange, value } }) => {
64
56
  return (_jsxs(_Fragment, { children: [_jsx(ReactSelect, { "aria-label": ariaLabel, inputId: id, value: value ?? "", className: clsx(styles.select, errors[name] && styles.error), isMulti: true, isDisabled: disabled, ...{ options, onChange, errors }, menuPortalTarget: document.body, menuPlacement: menuPlacement, styles: selectStyles, placeholder: disabled ? "Disabled..." : placeholder ?? "Select one or more options..." }), errors[name] && !hideErrorMessage && _jsx(ErrorMessage, { message: errors[name].message })] }));
@@ -66,21 +58,7 @@ export const SelectMultiple = ({ id, name, options, errors, control, validation,
66
58
  };
67
59
  export const SelectCreate = ({ id, name, options, errors, control, validation, defaultValue, disabled, hideErrorMessage, menuPlacement, placeholder, ariaLabel, }) => {
68
60
  React.useEffect(() => {
69
- document.querySelectorAll('[id*="live-region"]').forEach((element) => {
70
- if (element.role !== "presentation") {
71
- element.setAttribute("role", "presentation");
72
- }
73
- });
74
- document.querySelectorAll('[class*="indicatorSeparator"]').forEach((element) => {
75
- if (element.role !== "presentation") {
76
- element.setAttribute("role", "presentation");
77
- }
78
- });
79
- document.querySelectorAll('[class*="a11yText"]').forEach((element) => {
80
- if (element.role !== "presentation") {
81
- element.setAttribute("role", "presentation");
82
- }
83
- });
61
+ setAttributes();
84
62
  }, []);
85
63
  return (_jsx(Controller, { ...{ control, name, defaultValue }, rules: validation, render: ({ field: { onChange, value } }) => {
86
64
  return (_jsxs(_Fragment, { children: [_jsx(CreatableSelect, { "aria-label": ariaLabel, inputId: id, value: value ?? "", placeholder: disabled ? "Disabled..." : placeholder ?? "Select one or more options...", className: clsx(styles.select, errors[name] && styles.error), isMulti: true, isDisabled: disabled, ...{ options, onChange, errors }, menuPortalTarget: document.body, menuPlacement: menuPlacement, styles: selectStyles }), errors[name] && !hideErrorMessage && _jsx(ErrorMessage, { message: errors[name].message })] }));
@@ -88,21 +66,7 @@ export const SelectCreate = ({ id, name, options, errors, control, validation, d
88
66
  };
89
67
  export const SelectSingle = ({ id, name, options, errors, control, validation, isClearable, defaultValue, disabled, hideErrorMessage, menuPlacement, placeholder, ariaLabel, }) => {
90
68
  React.useEffect(() => {
91
- document.querySelectorAll('[id*="live-region"]').forEach((element) => {
92
- if (element.role !== "presentation") {
93
- element.setAttribute("role", "presentation");
94
- }
95
- });
96
- document.querySelectorAll('[class*="indicatorSeparator"]').forEach((element) => {
97
- if (element.role !== "presentation") {
98
- element.setAttribute("role", "presentation");
99
- }
100
- });
101
- document.querySelectorAll('[class*="a11yText"]').forEach((element) => {
102
- if (element.role !== "presentation") {
103
- element.setAttribute("role", "presentation");
104
- }
105
- });
69
+ setAttributes();
106
70
  }, []);
107
71
  return (_jsx(Controller, { ...{ control, name, defaultValue }, rules: validation, render: ({ field: { onChange, value } }) => {
108
72
  return (_jsxs(_Fragment, { children: [_jsx(ReactSelect, { "aria-label": ariaLabel, inputId: id, value: value ?? "", className: clsx(styles.select, errors[name] && styles.error), isDisabled: disabled, ...{ options, onChange, errors, isClearable }, menuPortalTarget: document.body, menuPlacement: menuPlacement, styles: selectStyles, placeholder: disabled ? "Disabled..." : placeholder ?? "Select one or more options..." }), errors[name] && !hideErrorMessage && _jsx(ErrorMessage, { message: errors[name].message })] }));
@@ -12,6 +12,11 @@
12
12
 
13
13
  --conduction-input-select-list-option-font-family: "Noto Sans", Arial, sans-serif;
14
14
  /* --conduction-input-select-list-option-background-color: unset; */
15
+ /* --conduction-input-select-list-option-color: unset; */
16
+ /* --conduction-input-select-list-option-selected--background-color: unset; */
17
+ /* --conduction-input-select-list-option-selected-color: unset; */
18
+ /* --conduction-input-select-list-option-focus--background-color: unset; */
19
+ /* --conduction-input-select-list-option-focus-color: unset; */
15
20
 
16
21
  /* --conduction-input-select-list-option-hover-background-color: unset; */
17
22
  /* --conduction-input-select-list-option-hover-color: unset; */
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ interface HorizontalOverflowWrapperProps {
3
+ children: React.ReactNode;
4
+ ariaLabels: {
5
+ scrollRightButton: string;
6
+ scrollLeftButton: string;
7
+ };
8
+ }
9
+ export declare const HorizontalOverflowWrapper: React.FC<HorizontalOverflowWrapperProps>;
10
+ export {};
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import * as styles from "./HorizontalOverflowWrapper.module.css";
4
+ import clsx from "clsx";
5
+ import { Button } from "@utrecht/component-library-react/dist/css-module";
6
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
7
+ import { faChevronLeft, faChevronRight } from "@fortawesome/free-solid-svg-icons";
8
+ export const HorizontalOverflowWrapper = ({ children, ariaLabels }) => {
9
+ const [canScrollRight, setCanScrollRight] = React.useState(false);
10
+ const [canScrollLeft, setCanScrollLeft] = React.useState(false);
11
+ const wrapperRef = React.useRef(null);
12
+ const scrollRight = () => {
13
+ wrapperRef.current?.scrollTo({
14
+ left: wrapperRef.current.scrollLeft + wrapperRef.current.clientWidth * 0.9,
15
+ behavior: "smooth",
16
+ });
17
+ };
18
+ const scrollLeft = () => {
19
+ wrapperRef.current?.scrollTo({
20
+ left: wrapperRef.current.scrollLeft - wrapperRef.current.clientWidth * 0.9,
21
+ behavior: "smooth",
22
+ });
23
+ };
24
+ React.useEffect(() => {
25
+ checkScrollDirections(); // initiate available scroll directions
26
+ window.addEventListener("resize", checkScrollDirections);
27
+ return () => window.removeEventListener("resize", checkScrollDirections);
28
+ }, []);
29
+ const checkScrollDirections = () => {
30
+ if (!wrapperRef.current)
31
+ return;
32
+ setCanScrollRight(wrapperRef.current.scrollLeft + wrapperRef.current.clientWidth < wrapperRef.current.scrollWidth);
33
+ setCanScrollLeft(wrapperRef.current.scrollLeft > 0);
34
+ };
35
+ return (_jsxs("div", { className: styles.container, children: [canScrollLeft && (_jsx(Button, { className: clsx(styles.scrollButton, styles.left), onClick: scrollLeft, appearance: "secondary-action-button", "aria-label": ariaLabels.scrollLeftButton, children: _jsx(FontAwesomeIcon, { icon: faChevronLeft }) })), canScrollRight && (_jsx(Button, { className: clsx(styles.scrollButton, styles.right), onClick: scrollRight, appearance: "secondary-action-button", "aria-label": ariaLabels.scrollRightButton, children: _jsx(FontAwesomeIcon, { icon: faChevronRight }) })), _jsx("div", { ref: wrapperRef, className: styles.wrapper, onScroll: checkScrollDirections, children: children })] }));
36
+ };
@@ -0,0 +1,41 @@
1
+ :root {
2
+ --conduction-horizontal-overflow-wrapper-background-color: unset;
3
+ --conduction-horizontal-overflow-wrapper-buttons-top: 12px;
4
+
5
+ --conduction-horizontal-overflow-wrapper-margin-inline-start: 8px;
6
+ --conduction-horizontal-overflow-wrapper-margin-inline-end: 8px;
7
+ --conduction-horizontal-overflow-wrapper-margin-block-start: 8px;
8
+ --conduction-horizontal-overflow-wrapper-margin-block-end: 8px;
9
+ }
10
+
11
+ .container {
12
+ position: relative;
13
+ background-color: var(--conduction-horizontal-overflow-wrapper-background-color);
14
+ }
15
+
16
+ .wrapper {
17
+ overflow-x: scroll;
18
+ }
19
+
20
+ .scrollButton {
21
+ position: sticky;
22
+ top: var(--conduction-horizontal-overflow-wrapper-buttons-top);
23
+
24
+ margin-inline-start: var(--conduction-horizontal-overflow-wrapper-margin-inline-start);
25
+ margin-inline-end: var(--conduction-horizontal-overflow-wrapper-margin-inline-end);
26
+ margin-block-start: var(--conduction-horizontal-overflow-wrapper-margin-block-start);
27
+ margin-block-end: var(--conduction-horizontal-overflow-wrapper-margin-block-end);
28
+ }
29
+
30
+ .scrollButton.right {
31
+ left: 100%;
32
+ }
33
+
34
+ /* Hide scrollbar */
35
+ .wrapper::-webkit-scrollbar {
36
+ display: none;
37
+ }
38
+ .wrapper {
39
+ -ms-overflow-style: none;
40
+ scrollbar-width: none;
41
+ }
@@ -21,11 +21,17 @@ export const TabList = ({ children, ...otherProps }) => {
21
21
  };
22
22
  const handleScrollRight = () => {
23
23
  if (wrapperRef.current)
24
- wrapperRef.current.scrollTo({ left: wrapperRef.current.scrollWidth, behavior: "smooth" });
24
+ wrapperRef.current.scrollTo({
25
+ left: wrapperRef.current.scrollLeft + wrapperRef.current.clientWidth * 0.9,
26
+ behavior: "smooth",
27
+ });
25
28
  };
26
29
  const handleScrollLeft = () => {
27
30
  if (wrapperRef.current)
28
- wrapperRef.current.scrollTo({ left: 0, behavior: "smooth" });
31
+ wrapperRef.current.scrollTo({
32
+ left: wrapperRef.current.scrollLeft - wrapperRef.current.clientWidth * 0.9,
33
+ behavior: "smooth",
34
+ });
29
35
  };
30
36
  React.useEffect(() => {
31
37
  if (wrapperRef.current) {
package/lib/index.d.ts CHANGED
@@ -23,5 +23,5 @@ import { CodeBlock } from "./components/codeBlock/CodeBlock";
23
23
  import { ToolTip } from "./components/toolTip/ToolTip";
24
24
  import { Pagination } from "./components/Pagination/Pagination";
25
25
  import { Tabs, TabList, Tab, TabPanel } from "./components/tabs/Tabs";
26
- import { TableWrapper } from "./components/tableWrapper/TableWrapper";
27
- export { DownloadCard, HorizontalImageCard, ImageAndDetailsCard, DetailsCard, InfoCard, Container, Breadcrumbs, InputText, InputPassword, InputEmail, InputDate, InputNumber, InputFile, Textarea, InputCheckbox, SelectMultiple, SelectSingle, ImageDivider, AuthenticatedLogo, UnauthenticatedLogo, MetaIcon, PrivateRoute, PrimaryTopNav, SecondaryTopNav, Tag, NotificationPopUp, QuoteWrapper, Pagination, BadgeCounter, CodeBlock, ToolTip, CardWrapper, CardHeader, CardHeaderTitle, CardHeaderDate, Tabs, TabList, Tab, TabPanel, TableWrapper, };
26
+ import { HorizontalOverflowWrapper } from "./components/horizontalOverflowWrapper/HorizontalOverflowWrapper";
27
+ export { DownloadCard, HorizontalImageCard, ImageAndDetailsCard, DetailsCard, InfoCard, Container, Breadcrumbs, InputText, InputPassword, InputEmail, InputDate, InputNumber, InputFile, Textarea, InputCheckbox, SelectMultiple, SelectSingle, ImageDivider, AuthenticatedLogo, UnauthenticatedLogo, MetaIcon, PrivateRoute, PrimaryTopNav, SecondaryTopNav, Tag, NotificationPopUp, QuoteWrapper, Pagination, BadgeCounter, CodeBlock, ToolTip, CardWrapper, CardHeader, CardHeaderTitle, CardHeaderDate, Tabs, TabList, Tab, TabPanel, HorizontalOverflowWrapper, };
package/lib/index.js CHANGED
@@ -16,5 +16,5 @@ import { CodeBlock } from "./components/codeBlock/CodeBlock";
16
16
  import { ToolTip } from "./components/toolTip/ToolTip";
17
17
  import { Pagination } from "./components/Pagination/Pagination";
18
18
  import { Tabs, TabList, Tab, TabPanel } from "./components/tabs/Tabs";
19
- import { TableWrapper } from "./components/tableWrapper/TableWrapper";
20
- export { DownloadCard, HorizontalImageCard, ImageAndDetailsCard, DetailsCard, InfoCard, Container, Breadcrumbs, InputText, InputPassword, InputEmail, InputDate, InputNumber, InputFile, Textarea, InputCheckbox, SelectMultiple, SelectSingle, ImageDivider, AuthenticatedLogo, UnauthenticatedLogo, MetaIcon, PrivateRoute, PrimaryTopNav, SecondaryTopNav, Tag, NotificationPopUp, QuoteWrapper, Pagination, BadgeCounter, CodeBlock, ToolTip, CardWrapper, CardHeader, CardHeaderTitle, CardHeaderDate, Tabs, TabList, Tab, TabPanel, TableWrapper, };
19
+ import { HorizontalOverflowWrapper } from "./components/horizontalOverflowWrapper/HorizontalOverflowWrapper";
20
+ export { DownloadCard, HorizontalImageCard, ImageAndDetailsCard, DetailsCard, InfoCard, Container, Breadcrumbs, InputText, InputPassword, InputEmail, InputDate, InputNumber, InputFile, Textarea, InputCheckbox, SelectMultiple, SelectSingle, ImageDivider, AuthenticatedLogo, UnauthenticatedLogo, MetaIcon, PrivateRoute, PrimaryTopNav, SecondaryTopNav, Tag, NotificationPopUp, QuoteWrapper, Pagination, BadgeCounter, CodeBlock, ToolTip, CardWrapper, CardHeader, CardHeaderTitle, CardHeaderDate, Tabs, TabList, Tab, TabPanel, HorizontalOverflowWrapper, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduction/components",
3
- "version": "2.2.17",
3
+ "version": "2.2.18",
4
4
  "description": "React (Gatsby) components used within the Conduction Skeleton Application (and its implementations)",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -150,7 +150,7 @@
150
150
  border-width: var(--conduction-pagination-navigation-button-border-width, var(--utrecht-button-border-width)) !important;
151
151
  border-style: var(--conduction-pagination-navigation-button-border-style, var(--utrecht-button-border-style)) !important;
152
152
  border-color: var(--conduction-pagination-navigation-button-border-color, var(--utrecht-button-border-color)) !important;
153
- border-radius: var(--conduction-pagination-navigation-button-border-radius, var(--utrecht-button-border-radius));
153
+ border-radius: var(--conduction-pagination-navigation-button-border-radius, var(--utrecht-button-border-radius)) !important;
154
154
  padding-inline-start: var(--conduction-pagination-navigation-button-padding-inline-start) !important;
155
155
  padding-inline-end: var(--conduction-pagination-navigation-button-padding-inline-end) !important;
156
156
  padding-block-start: var(--conduction-pagination-navigation-button-padding-block-start) !important;
@@ -12,6 +12,11 @@
12
12
 
13
13
  --conduction-input-select-list-option-font-family: "Noto Sans", Arial, sans-serif;
14
14
  /* --conduction-input-select-list-option-background-color: unset; */
15
+ /* --conduction-input-select-list-option-color: unset; */
16
+ /* --conduction-input-select-list-option-selected--background-color: unset; */
17
+ /* --conduction-input-select-list-option-selected-color: unset; */
18
+ /* --conduction-input-select-list-option-focus--background-color: unset; */
19
+ /* --conduction-input-select-list-option-focus-color: unset; */
15
20
 
16
21
  /* --conduction-input-select-list-option-hover-background-color: unset; */
17
22
  /* --conduction-input-select-list-option-hover-color: unset; */
@@ -23,10 +23,24 @@ interface ISelectProps {
23
23
 
24
24
  const selectStyles: StylesConfig = {
25
25
  menuPortal: (base) => ({ ...base, zIndex: 100 }),
26
- option: (base) => ({
26
+ option: (base, state) => ({
27
27
  ...base,
28
28
  fontFamily: `var(--conduction-input-select-list-option-font-family, ${base.fontFamily})`,
29
- backgroundColor: `var(--conduction-input-select-list-option-background-color, ${base.backgroundColor}) `,
29
+ backgroundColor: [
30
+ state.isFocused
31
+ ? `var(--conduction-input-select-list-option-focus-background-color, ${base.backgroundColor})`
32
+ : state.isSelected
33
+ ? `var(--conduction-input-select-list-option-selected-background-color, ${base.backgroundColor})`
34
+ : `var(--conduction-input-select-list-option-background-color, ${base.backgroundColor})`,
35
+ ],
36
+
37
+ color: [
38
+ state.isFocused
39
+ ? `var(--conduction-input-select-list-option-focus-color, ${base.color})`
40
+ : state.isSelected
41
+ ? `var(--conduction-input-select-list-option-selected-color, ${base.color})`
42
+ : `var(--conduction-input-select-list-option-color, ${base.color})`,
43
+ ],
30
44
 
31
45
  "&:hover": {
32
46
  backgroundColor: `var(--conduction-input-select-list-option-hover-background-color, ${base.backgroundColor})`,
@@ -41,24 +55,16 @@ const selectStyles: StylesConfig = {
41
55
  }),
42
56
  };
43
57
 
44
- const selectMultiStyles: StylesConfig = {
45
- menuPortal: (base) => ({ ...base, zIndex: 100 }),
46
- option: (base) => ({
47
- ...base,
48
- fontFamily: `var(--conduction-input-select-list-option-font-family, ${base.fontFamily})`,
49
- backgroundColor: `var(--conduction-input-select-list-option-background-color, ${base.backgroundColor}) `,
58
+ const setAttributes = (): void => {
59
+ const setRoleToPresentation = (selector: string, role: string) => {
60
+ document.querySelectorAll(selector).forEach((element) => {
61
+ if (element.getAttribute("role") !== "presentation") element.setAttribute("role", role);
62
+ });
63
+ };
50
64
 
51
- "&:hover": {
52
- backgroundColor: `var(--conduction-input-select-list-option-hover-background-color, ${base.backgroundColor})`,
53
- color: `var(--conduction-input-select-list-option-hover-color, ${base.color})`,
54
- fontFamily: `var(--conduction-input-select-list-option-hover-font-family, var(--conduction-input-select-list-option-font-family, ${base.fontFamily}))`,
55
- },
56
- }),
57
- placeholder: (base) => ({
58
- ...base,
59
- fontFamily: `var(--conduction-input-select-placeholder-font-family, var(--utrecht-form-input-placeholder-font-family, ${base.fontFamily}))`,
60
- color: `var(--conduction-input-select-placeholder-color, var(--utrecht-form-input-placeholder-color, ${base.color}) )`,
61
- }),
65
+ setRoleToPresentation('[id*="live-region"]', "presentation");
66
+ setRoleToPresentation('[class*="indicatorSeparator"]', "separator");
67
+ setRoleToPresentation('[class*="a11yText"]', "presentation");
62
68
  };
63
69
 
64
70
  export const SelectMultiple = ({
@@ -76,21 +82,7 @@ export const SelectMultiple = ({
76
82
  ariaLabel,
77
83
  }: ISelectProps & IReactHookFormProps): JSX.Element => {
78
84
  React.useEffect(() => {
79
- document.querySelectorAll('[id*="live-region"]').forEach((element: any) => {
80
- if (element?.role !== "presentation") {
81
- element.setAttribute("role", "presentation");
82
- }
83
- });
84
- document.querySelectorAll('[class*="indicatorSeparator"]').forEach((element: any) => {
85
- if (element.role !== "presentation") {
86
- element.setAttribute("role", "presentation");
87
- }
88
- });
89
- document.querySelectorAll('[class*="a11yText"]').forEach((element: any) => {
90
- if (element.role !== "presentation") {
91
- element.setAttribute("role", "presentation");
92
- }
93
- });
85
+ setAttributes();
94
86
  }, []);
95
87
  return (
96
88
  <Controller
@@ -135,21 +127,7 @@ export const SelectCreate = ({
135
127
  ariaLabel,
136
128
  }: ISelectProps & IReactHookFormProps): JSX.Element => {
137
129
  React.useEffect(() => {
138
- document.querySelectorAll('[id*="live-region"]').forEach((element: any) => {
139
- if (element.role !== "presentation") {
140
- element.setAttribute("role", "presentation");
141
- }
142
- });
143
- document.querySelectorAll('[class*="indicatorSeparator"]').forEach((element: any) => {
144
- if (element.role !== "presentation") {
145
- element.setAttribute("role", "presentation");
146
- }
147
- });
148
- document.querySelectorAll('[class*="a11yText"]').forEach((element: any) => {
149
- if (element.role !== "presentation") {
150
- element.setAttribute("role", "presentation");
151
- }
152
- });
130
+ setAttributes();
153
131
  }, []);
154
132
  return (
155
133
  <Controller
@@ -195,21 +173,7 @@ export const SelectSingle = ({
195
173
  ariaLabel,
196
174
  }: ISelectProps & IReactHookFormProps): JSX.Element => {
197
175
  React.useEffect(() => {
198
- document.querySelectorAll('[id*="live-region"]').forEach((element: any) => {
199
- if (element.role !== "presentation") {
200
- element.setAttribute("role", "presentation");
201
- }
202
- });
203
- document.querySelectorAll('[class*="indicatorSeparator"]').forEach((element: any) => {
204
- if (element.role !== "presentation") {
205
- element.setAttribute("role", "presentation");
206
- }
207
- });
208
- document.querySelectorAll('[class*="a11yText"]').forEach((element: any) => {
209
- if (element.role !== "presentation") {
210
- element.setAttribute("role", "presentation");
211
- }
212
- });
176
+ setAttributes();
213
177
  }, []);
214
178
  return (
215
179
  <Controller
@@ -0,0 +1,41 @@
1
+ :root {
2
+ --conduction-horizontal-overflow-wrapper-background-color: unset;
3
+ --conduction-horizontal-overflow-wrapper-buttons-top: 12px;
4
+
5
+ --conduction-horizontal-overflow-wrapper-margin-inline-start: 8px;
6
+ --conduction-horizontal-overflow-wrapper-margin-inline-end: 8px;
7
+ --conduction-horizontal-overflow-wrapper-margin-block-start: 8px;
8
+ --conduction-horizontal-overflow-wrapper-margin-block-end: 8px;
9
+ }
10
+
11
+ .container {
12
+ position: relative;
13
+ background-color: var(--conduction-horizontal-overflow-wrapper-background-color);
14
+ }
15
+
16
+ .wrapper {
17
+ overflow-x: scroll;
18
+ }
19
+
20
+ .scrollButton {
21
+ position: sticky;
22
+ top: var(--conduction-horizontal-overflow-wrapper-buttons-top);
23
+
24
+ margin-inline-start: var(--conduction-horizontal-overflow-wrapper-margin-inline-start);
25
+ margin-inline-end: var(--conduction-horizontal-overflow-wrapper-margin-inline-end);
26
+ margin-block-start: var(--conduction-horizontal-overflow-wrapper-margin-block-start);
27
+ margin-block-end: var(--conduction-horizontal-overflow-wrapper-margin-block-end);
28
+ }
29
+
30
+ .scrollButton.right {
31
+ left: 100%;
32
+ }
33
+
34
+ /* Hide scrollbar */
35
+ .wrapper::-webkit-scrollbar {
36
+ display: none;
37
+ }
38
+ .wrapper {
39
+ -ms-overflow-style: none;
40
+ scrollbar-width: none;
41
+ }
@@ -0,0 +1,80 @@
1
+ import * as React from "react";
2
+ import * as styles from "./HorizontalOverflowWrapper.module.css";
3
+ import clsx from "clsx";
4
+ import { Button } from "@utrecht/component-library-react/dist/css-module";
5
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
6
+ import { faChevronLeft, faChevronRight } from "@fortawesome/free-solid-svg-icons";
7
+
8
+ interface HorizontalOverflowWrapperProps {
9
+ children: React.ReactNode;
10
+ ariaLabels: {
11
+ scrollRightButton: string;
12
+ scrollLeftButton: string;
13
+ };
14
+ }
15
+
16
+ export const HorizontalOverflowWrapper: React.FC<HorizontalOverflowWrapperProps> = ({ children, ariaLabels }) => {
17
+ const [canScrollRight, setCanScrollRight] = React.useState<boolean>(false);
18
+ const [canScrollLeft, setCanScrollLeft] = React.useState<boolean>(false);
19
+
20
+ const wrapperRef = React.useRef<HTMLDivElement | null>(null);
21
+
22
+ const scrollRight = (): void => {
23
+ wrapperRef.current?.scrollTo({
24
+ left: wrapperRef.current.scrollLeft + wrapperRef.current.clientWidth * 0.9,
25
+ behavior: "smooth",
26
+ });
27
+ };
28
+
29
+ const scrollLeft = (): void => {
30
+ wrapperRef.current?.scrollTo({
31
+ left: wrapperRef.current.scrollLeft - wrapperRef.current.clientWidth * 0.9,
32
+ behavior: "smooth",
33
+ });
34
+ };
35
+
36
+ React.useEffect(() => {
37
+ checkScrollDirections(); // initiate available scroll directions
38
+
39
+ window.addEventListener("resize", checkScrollDirections);
40
+
41
+ return () => window.removeEventListener("resize", checkScrollDirections);
42
+ }, []);
43
+
44
+ const checkScrollDirections = (): void => {
45
+ if (!wrapperRef.current) return;
46
+
47
+ setCanScrollRight(wrapperRef.current.scrollLeft + wrapperRef.current.clientWidth < wrapperRef.current.scrollWidth);
48
+ setCanScrollLeft(wrapperRef.current.scrollLeft > 0);
49
+ };
50
+
51
+ return (
52
+ <div className={styles.container}>
53
+ {canScrollLeft && (
54
+ <Button
55
+ className={clsx(styles.scrollButton, styles.left)}
56
+ onClick={scrollLeft}
57
+ appearance="secondary-action-button"
58
+ aria-label={ariaLabels.scrollLeftButton}
59
+ >
60
+ <FontAwesomeIcon icon={faChevronLeft} />
61
+ </Button>
62
+ )}
63
+
64
+ {canScrollRight && (
65
+ <Button
66
+ className={clsx(styles.scrollButton, styles.right)}
67
+ onClick={scrollRight}
68
+ appearance="secondary-action-button"
69
+ aria-label={ariaLabels.scrollRightButton}
70
+ >
71
+ <FontAwesomeIcon icon={faChevronRight} />
72
+ </Button>
73
+ )}
74
+
75
+ <div ref={wrapperRef} className={styles.wrapper} onScroll={checkScrollDirections}>
76
+ {children}
77
+ </div>
78
+ </div>
79
+ );
80
+ };
@@ -41,11 +41,19 @@ export const TabList: ReactTabsFunctionComponent<TabListProps> = ({ children, ..
41
41
  };
42
42
 
43
43
  const handleScrollRight = () => {
44
- if (wrapperRef.current) wrapperRef.current.scrollTo({ left: wrapperRef.current.scrollWidth, behavior: "smooth" });
44
+ if (wrapperRef.current)
45
+ wrapperRef.current.scrollTo({
46
+ left: wrapperRef.current.scrollLeft + wrapperRef.current.clientWidth * 0.9,
47
+ behavior: "smooth",
48
+ });
45
49
  };
46
50
 
47
51
  const handleScrollLeft = () => {
48
- if (wrapperRef.current) wrapperRef.current.scrollTo({ left: 0, behavior: "smooth" });
52
+ if (wrapperRef.current)
53
+ wrapperRef.current.scrollTo({
54
+ left: wrapperRef.current.scrollLeft - wrapperRef.current.clientWidth * 0.9,
55
+ behavior: "smooth",
56
+ });
49
57
  };
50
58
 
51
59
  React.useEffect(() => {
package/src/index.ts CHANGED
@@ -40,7 +40,7 @@ import { CodeBlock } from "./components/codeBlock/CodeBlock";
40
40
  import { ToolTip } from "./components/toolTip/ToolTip";
41
41
  import { Pagination } from "./components/Pagination/Pagination";
42
42
  import { Tabs, TabList, Tab, TabPanel } from "./components/tabs/Tabs";
43
- import { TableWrapper } from "./components/tableWrapper/TableWrapper";
43
+ import { HorizontalOverflowWrapper } from "./components/horizontalOverflowWrapper/HorizontalOverflowWrapper";
44
44
 
45
45
  export {
46
46
  DownloadCard,
@@ -82,5 +82,5 @@ export {
82
82
  TabList,
83
83
  Tab,
84
84
  TabPanel,
85
- TableWrapper,
85
+ HorizontalOverflowWrapper,
86
86
  };
package/tsconfig.json CHANGED
@@ -3,10 +3,7 @@
3
3
  "declaration": true,
4
4
  "outDir": "./lib",
5
5
  "target": "esnext",
6
- "lib": [
7
- "dom",
8
- "esnext"
9
- ],
6
+ "lib": ["dom", "esnext"],
10
7
  "jsx": "react-jsx",
11
8
  "module": "esnext",
12
9
  "moduleResolution": "node",
@@ -15,15 +12,7 @@
15
12
  "strict": true,
16
13
  "skipLibCheck": true
17
14
  },
18
- "hooks": [
19
- "copy-files"
20
- ],
21
- "include": [
22
- "src",
23
- "src/**/*.css"
24
- ],
25
- "exclude": [
26
- "node_modules",
27
- "**/__tests__/*"
28
- ]
29
- }
15
+ "hooks": ["copy-files"],
16
+ "include": ["src", "src/**/*.css"],
17
+ "exclude": ["node_modules", "**/__tests__/*"]
18
+ }
@@ -1,67 +0,0 @@
1
- :root {
2
- --conduction-table-wrapper-scroll-button-background-color: #ffffff;
3
- --conduction-table-wrapper-scroll-button-color: #000000;
4
- --conduction-table-wrapper-scroll-button-padding-inline-start: 14px;
5
- --conduction-table-wrapper-scroll-button-padding-inline-end: 14px;
6
- /* --conduction-table-wrapper-scroll-button-padding-block-start: 10px; */
7
- /* --conduction-table-wrapper-scroll-button-padding-block-end: 10px; */
8
- /* --conduction-table-wrapper-scroll-button-border-color: 1px; */
9
- /* --conduction-table-wrapper-scroll-button-border-color: solid; */
10
- /* --conduction-table-wrapper-scroll-button-border-color: #000000; */
11
-
12
- --conduction-table-wrapper-scroll-button-hover-background-color: #ffffff;
13
- --conduction-table-wrapper-scroll-button-hover-color: #4376fc;
14
- }
15
- .container {
16
- position: relative;
17
- }
18
-
19
- .wrapper,
20
- .wrapperTouchscreen {
21
- overflow-x: scroll;
22
- }
23
-
24
- .scrollRightButton,
25
- .scrollLeftButton {
26
- top: 0%;
27
- position: absolute;
28
- display: flex;
29
- height: 100%;
30
- background-color: var(--conduction-table-wrapper-scroll-button-background-color);
31
- color: var(--conduction-table-wrapper-scroll-button-color);
32
- padding-inline-start: var(--conduction-table-wrapper-scroll-button-padding-inline-start);
33
- padding-inline-end: var(--conduction-table-wrapper-scroll-button-padding-inline-end);
34
- padding-block-start: var(--conduction-table-wrapper-scroll-button-padding-block-start);
35
- padding-block-end: var(--conduction-table-wrapper-scroll-button-padding-block-end);
36
- border-width: var(--conduction-table-wrapper-scroll-button-border-width);
37
- border-style: var(--conduction-table-wrapper-scroll-button-border-style);
38
- border-color: var(--conduction-table-wrapper-scroll-button-border-color);
39
- }
40
-
41
- .scrollLeftButton:hover,
42
- .scrollRightButton:hover {
43
- background-color: var(--conduction-table-wrapper-scroll-button-hover-background-color);
44
- color: var(--conduction-table-wrapper-scroll-button-hover-color);
45
- cursor: pointer;
46
- }
47
-
48
- .scrollRightButton {
49
- right: 0;
50
- }
51
-
52
- .scrollLeftButton {
53
- left: 0;
54
- }
55
-
56
- .scrollButton {
57
- align-self: center;
58
- }
59
-
60
- /* Hide scrollbar */
61
- .wrapper::-webkit-scrollbar {
62
- display: none;
63
- }
64
- .wrapper {
65
- -ms-overflow-style: none;
66
- scrollbar-width: none;
67
- }
@@ -1,56 +0,0 @@
1
- import React, { useState, useEffect } from "react";
2
- import * as styles from "./TableWrapper.module.css";
3
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
- import { faChevronLeft, faChevronRight } from "@fortawesome/free-solid-svg-icons";
5
-
6
- export const TableWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
7
- const [canScrollRight, setCanScrollRight] = useState(false);
8
- const [canScrollLeft, setCanScrollLeft] = useState(false);
9
-
10
- const wrapperRef = React.useRef<HTMLDivElement | null>(null);
11
-
12
- const handleScroll = () => {
13
- if (wrapperRef.current) {
14
- setCanScrollLeft(wrapperRef.current.scrollLeft > 0);
15
- setCanScrollRight(
16
- wrapperRef.current.scrollWidth - wrapperRef.current.scrollLeft > wrapperRef.current.clientWidth,
17
- );
18
- }
19
- };
20
-
21
- const handleScrollRight = () => {
22
- if (wrapperRef.current) wrapperRef.current.scrollTo({ left: wrapperRef.current.scrollWidth, behavior: "smooth" });
23
- };
24
-
25
- const handleScrollLeft = () => {
26
- if (wrapperRef.current) wrapperRef.current.scrollTo({ left: 0, behavior: "smooth" });
27
- };
28
-
29
- useEffect(() => {
30
- if (wrapperRef.current) {
31
- setCanScrollRight(wrapperRef.current.scrollWidth > wrapperRef.current.clientWidth); // initiate scroll
32
- }
33
- }, []);
34
-
35
- return (
36
- <div className={styles.container}>
37
- <div onScroll={handleScroll} ref={wrapperRef} className={styles.wrapper}>
38
- {canScrollLeft && (
39
- <div onClick={handleScrollLeft} className={styles.scrollLeftButton}>
40
- <div className={styles.scrollButton}>
41
- <FontAwesomeIcon icon={faChevronLeft} />
42
- </div>
43
- </div>
44
- )}
45
- {children}
46
- {canScrollRight && (
47
- <div onClick={handleScrollRight} className={styles.scrollRightButton}>
48
- <div className={styles.scrollButton}>
49
- <FontAwesomeIcon icon={faChevronRight} />
50
- </div>
51
- </div>
52
- )}
53
- </div>
54
- </div>
55
- );
56
- };