@inera/ids-react 9.0.3 → 9.1.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/components/alert/alert.js +1 -1
- package/components/breadcrumbs/breadcrumbs.js +1 -1
- package/components/card/card.d.ts +2 -2
- package/components/card/card.js +4 -15
- package/components/data-pagination/data-pagination.d.ts +6 -6
- package/components/data-pagination/data-pagination.js +1 -1
- package/components/dialog/dialog-base.js +1 -1
- package/components/dialog/dialog.js +12 -13
- package/components/dropdown/dropdown-base.js +2 -2
- package/components/dropdown/dropdown.js +1 -0
- package/components/footer-1177-pro/footer-1177-pro.d.ts +2 -1
- package/components/footer-1177-pro/footer-1177-pro.js +2 -2
- package/components/form/checkbox/checkbox-group-base.d.ts +2 -1
- package/components/form/checkbox/checkbox-group-base.js +4 -2
- package/components/form/checkbox/checkbox-group.d.ts +1 -0
- package/components/form/checkbox/checkbox-group.js +4 -3
- package/components/form/datepicker/datepicker.d.ts +2 -1
- package/components/form/datepicker/datepicker.js +60 -37
- package/components/form/input/input-base.d.ts +2 -1
- package/components/form/input/input-base.js +10 -10
- package/components/form/input/input.d.ts +1 -0
- package/components/form/radio/radio-group-base.d.ts +2 -1
- package/components/form/radio/radio-group-base.js +4 -2
- package/components/form/radio/radio-group.d.ts +1 -0
- package/components/form/radio/radio-group.js +4 -3
- package/components/form/radio/radio.js +1 -3
- package/components/form/radio-button/radio-button-group-base.js +1 -1
- package/components/form/select/select.d.ts +1 -1
- package/components/form/select/select.js +2 -2
- package/components/form/select-multiple/select-multiple-base.d.ts +3 -3
- package/components/form/select-multiple/select-multiple-base.js +5 -6
- package/components/form/select-multiple/select-multiple.d.ts +1 -1
- package/components/form/select-multiple/select-multiple.js +10 -23
- package/components/form/textarea/textarea.d.ts +1 -1
- package/components/form/textarea/textarea.js +2 -2
- package/components/form/time/time.d.ts +1 -1
- package/components/form/time/time.js +2 -2
- package/components/{alert → global-alert}/global-alert.d.ts +1 -1
- package/components/{alert → global-alert}/global-alert.js +2 -2
- package/components/header-1177/header-1177-avatar-base.d.ts +2 -1
- package/components/header-1177/header-1177-avatar-base.js +2 -2
- package/components/header-1177/header-1177-avatar.js +11 -24
- package/components/header-1177/header-1177-menu-mobile-base.d.ts +2 -1
- package/components/header-1177/header-1177-menu-mobile-base.js +2 -2
- package/components/header-1177/header-1177-menu-mobile.js +9 -14
- package/components/header-1177/header-1177-nav-item-base.d.ts +2 -1
- package/components/header-1177/header-1177-nav-item-base.js +2 -2
- package/components/header-1177/header-1177-nav-item.js +8 -14
- package/components/header-1177-admin/header-1177-admin-avatar-base.d.ts +2 -1
- package/components/header-1177-admin/header-1177-admin-avatar-base.js +2 -2
- package/components/header-1177-admin/header-1177-admin-avatar-mobile-base.d.ts +2 -1
- package/components/header-1177-admin/header-1177-admin-avatar-mobile-base.js +2 -2
- package/components/header-1177-admin/header-1177-admin-avatar-mobile.js +12 -24
- package/components/header-1177-admin/header-1177-admin-avatar.js +11 -14
- package/components/header-1177-admin/header-1177-admin-menu-mobile-base.d.ts +2 -1
- package/components/header-1177-admin/header-1177-admin-menu-mobile-base.js +2 -2
- package/components/header-1177-admin/header-1177-admin-menu-mobile.js +9 -14
- package/components/header-1177-admin/header-1177-admin-nav-item-base.d.ts +2 -1
- package/components/header-1177-admin/header-1177-admin-nav-item-base.js +2 -2
- package/components/header-1177-admin/header-1177-admin-nav-item.js +8 -14
- package/components/header-1177-pro/header-1177-pro-avatar-base.d.ts +2 -1
- package/components/header-1177-pro/header-1177-pro-avatar-base.js +2 -2
- package/components/header-1177-pro/header-1177-pro-avatar-mobile-base.d.ts +2 -1
- package/components/header-1177-pro/header-1177-pro-avatar-mobile-base.js +2 -2
- package/components/header-1177-pro/header-1177-pro-avatar-mobile.js +12 -24
- package/components/header-1177-pro/header-1177-pro-avatar.js +11 -14
- package/components/header-1177-pro/header-1177-pro-menu-mobile-base.d.ts +2 -1
- package/components/header-1177-pro/header-1177-pro-menu-mobile-base.js +2 -2
- package/components/header-1177-pro/header-1177-pro-menu-mobile.js +9 -14
- package/components/header-1177-pro/header-1177-pro-nav-item-base.d.ts +2 -1
- package/components/header-1177-pro/header-1177-pro-nav-item-base.js +2 -2
- package/components/header-1177-pro/header-1177-pro-nav-item.js +8 -14
- package/components/header-inera/header-inera-menu-mobile-base.d.ts +2 -1
- package/components/header-inera/header-inera-menu-mobile-base.js +2 -2
- package/components/header-inera/header-inera-menu-mobile.js +9 -14
- package/components/header-inera/header-inera-nav-item-base.d.ts +2 -1
- package/components/header-inera/header-inera-nav-item-base.js +2 -2
- package/components/header-inera/header-inera-nav-item.js +8 -14
- package/components/header-inera-admin/header-inera-admin-avatar-base.d.ts +2 -1
- package/components/header-inera-admin/header-inera-admin-avatar-base.js +2 -2
- package/components/header-inera-admin/header-inera-admin-avatar-mobile-base.d.ts +2 -1
- package/components/header-inera-admin/header-inera-admin-avatar-mobile-base.js +2 -2
- package/components/header-inera-admin/header-inera-admin-avatar-mobile.js +12 -24
- package/components/header-inera-admin/header-inera-admin-avatar.js +12 -16
- package/components/header-inera-admin/header-inera-admin-menu-mobile-base.d.ts +2 -1
- package/components/header-inera-admin/header-inera-admin-menu-mobile-base.js +2 -2
- package/components/header-inera-admin/header-inera-admin-menu-mobile.js +9 -14
- package/components/header-inera-admin/header-inera-admin-nav-item-base.d.ts +2 -1
- package/components/header-inera-admin/header-inera-admin-nav-item-base.js +2 -2
- package/components/header-inera-admin/header-inera-admin-nav-item.js +8 -14
- package/components/popover/popover-content.js +1 -1
- package/components/popover/popover.js +1 -1
- package/components/puff-list/puff-list-item-header.js +1 -1
- package/components/puff-list/puff-list-item.js +1 -1
- package/components/side-panel/side-panel-base.js +6 -2
- package/components/side-panel/side-panel.js +50 -41
- package/components/stepper/step-base.js +1 -1
- package/components/stepper/step.js +12 -10
- package/components/tabs/tab-panel.js +1 -1
- package/components/tabs/tab.js +1 -1
- package/components/tabs/tabs.d.ts +1 -1
- package/components/tabs/tabs.js +8 -4
- package/components/utils/hooks/useClickOutside.d.ts +10 -0
- package/components/utils/hooks/useClickOutside.js +31 -0
- package/components/utils/hooks/useEsc.d.ts +10 -0
- package/components/utils/hooks/useEsc.js +27 -0
- package/components/utils/hooks/useHasFocusableChildren.d.ts +2 -0
- package/components/utils/hooks/useHasFocusableChildren.js +25 -0
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/package.json +2 -2
- /package/components/{alert → global-alert}/global-alert-base.d.ts +0 -0
- /package/components/{alert → global-alert}/global-alert-base.js +0 -0
|
@@ -11,7 +11,8 @@ export interface IDSHeaderIneraNavItemBaseProps extends HTMLAttributes<HTMLEleme
|
|
|
11
11
|
col4?: React.ReactNode;
|
|
12
12
|
componentRef?: React.Ref<HTMLDivElement>;
|
|
13
13
|
menuRef?: React.Ref<HTMLDivElement>;
|
|
14
|
+
buttonRef?: React.Ref<HTMLButtonElement>;
|
|
14
15
|
onToggleItem?: () => void;
|
|
15
16
|
unresponsive?: boolean;
|
|
16
17
|
}
|
|
17
|
-
export declare function IDSHeaderIneraNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, onToggleItem, unresponsive, ...props }: IDSHeaderIneraNavItemBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function IDSHeaderIneraNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, buttonRef, onToggleItem, unresponsive, ...props }: IDSHeaderIneraNavItemBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,13 +2,13 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import React, { useId } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
|
|
5
|
-
function IDSHeaderIneraNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, onToggleItem, unresponsive, ...props }) {
|
|
5
|
+
function IDSHeaderIneraNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, buttonRef, onToggleItem, unresponsive, ...props }) {
|
|
6
6
|
const itemId = `header-inera-item-${useId()}`;
|
|
7
7
|
return (jsxs("div", { ...props, ref: componentRef, className: clsx("ids-header-inera-nav-item", {
|
|
8
8
|
"ids-header-inera-nav-item--unresponsive": unresponsive,
|
|
9
9
|
"ids-header-inera-nav-item--expanded": expanded,
|
|
10
10
|
"ids-header-inera-nav-item--active": active
|
|
11
|
-
}), children: [!!label && (jsx("button", { "aria-controls": itemId, "aria-expanded": expanded, className: "ids-header-inera-nav-item__button", onClick: onToggleItem, children: label })), !label && (jsx("span", { className: "ids-header-inera-nav-item__link", children: React.Children.map(children, child => {
|
|
11
|
+
}), children: [!!label && (jsx("button", { ref: buttonRef, "aria-controls": itemId, "aria-expanded": expanded, className: "ids-header-inera-nav-item__button", onClick: onToggleItem, children: label })), !label && (jsx("span", { className: "ids-header-inera-nav-item__link", children: React.Children.map(children, child => {
|
|
12
12
|
if (!React.isValidElement(child))
|
|
13
13
|
return child;
|
|
14
14
|
const element = child;
|
|
@@ -3,12 +3,19 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
3
3
|
import { useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { IDSHeaderIneraNavItemBase } from './header-inera-nav-item-base.js';
|
|
5
5
|
import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
|
|
6
|
+
import { useClickOutside } from '../utils/hooks/useClickOutside.js';
|
|
7
|
+
import { useEsc } from '../utils/hooks/useEsc.js';
|
|
6
8
|
|
|
7
9
|
function IDSHeaderIneraNavItem({ expanded = false, ...props }) {
|
|
8
10
|
const headerContext = useHeaderContext();
|
|
9
11
|
const [isExpanded, setIsExpanded] = useState(expanded);
|
|
10
12
|
const componentRef = useRef(null);
|
|
11
13
|
const menuRef = useRef(null);
|
|
14
|
+
const buttonRef = useRef(null);
|
|
15
|
+
useClickOutside([componentRef, buttonRef], () => {
|
|
16
|
+
setIsExpanded(false);
|
|
17
|
+
});
|
|
18
|
+
useEsc(() => setIsExpanded(false), buttonRef);
|
|
12
19
|
useEffect(() => {
|
|
13
20
|
setIsExpanded(expanded);
|
|
14
21
|
}, [expanded]);
|
|
@@ -37,20 +44,7 @@ function IDSHeaderIneraNavItem({ expanded = false, ...props }) {
|
|
|
37
44
|
menuEl.addEventListener("click", onMenuClick);
|
|
38
45
|
return () => menuEl.removeEventListener("click", onMenuClick);
|
|
39
46
|
}, [menuRef]);
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (!isExpanded)
|
|
43
|
-
return;
|
|
44
|
-
const handleKeyDown = (event) => {
|
|
45
|
-
if (event.key === "Escape") {
|
|
46
|
-
event.preventDefault();
|
|
47
|
-
setIsExpanded(false);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
51
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
52
|
-
}, [isExpanded]);
|
|
53
|
-
return (jsx(IDSHeaderIneraNavItemBase, { ...props, expanded: isExpanded, unresponsive: headerContext?.unresponsive, componentRef: componentRef, menuRef: menuRef, onToggleItem: () => setIsExpanded((prev) => !prev) }));
|
|
47
|
+
return (jsx(IDSHeaderIneraNavItemBase, { ...props, expanded: isExpanded, unresponsive: headerContext?.unresponsive, componentRef: componentRef, menuRef: menuRef, buttonRef: buttonRef, onToggleItem: () => setIsExpanded((prev) => !prev) }));
|
|
54
48
|
}
|
|
55
49
|
|
|
56
50
|
export { IDSHeaderIneraNavItem };
|
|
@@ -8,7 +8,8 @@ export interface IDSHeaderIneraAdminAvatarBaseProps extends HTMLAttributes<HTMLE
|
|
|
8
8
|
onToggleAvatar?: () => void;
|
|
9
9
|
componentRef?: React.RefObject<HTMLDivElement>;
|
|
10
10
|
menuRef?: React.RefObject<HTMLDivElement>;
|
|
11
|
+
buttonRef?: React.RefObject<HTMLButtonElement>;
|
|
11
12
|
unresponsive?: boolean;
|
|
12
13
|
client?: boolean;
|
|
13
14
|
}
|
|
14
|
-
export declare function IDSHeaderIneraAdminAvatarBase({ username, unit, children, expanded, hide, onToggleAvatar, componentRef, menuRef, unresponsive, client }: IDSHeaderIneraAdminAvatarBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function IDSHeaderIneraAdminAvatarBase({ username, unit, children, expanded, hide, onToggleAvatar, componentRef, menuRef, buttonRef, unresponsive, client }: IDSHeaderIneraAdminAvatarBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,7 +2,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { useId } from 'react';
|
|
4
4
|
|
|
5
|
-
function IDSHeaderIneraAdminAvatarBase({ username, unit, children, expanded = false, hide = false, onToggleAvatar, componentRef, menuRef, unresponsive, client = false }) {
|
|
5
|
+
function IDSHeaderIneraAdminAvatarBase({ username, unit, children, expanded = false, hide = false, onToggleAvatar, componentRef, menuRef, buttonRef, unresponsive, client = false }) {
|
|
6
6
|
if (hide)
|
|
7
7
|
return null;
|
|
8
8
|
const menuId = `header-inera-admin-menu-${useId()}`;
|
|
@@ -13,7 +13,7 @@ function IDSHeaderIneraAdminAvatarBase({ username, unit, children, expanded = fa
|
|
|
13
13
|
: {};
|
|
14
14
|
return (jsx("div", { ref: componentRef || undefined, className: clsx("ids-header-inera-admin-avatar", {
|
|
15
15
|
"ids-header-inera-admin-avatar--unresponsive": unresponsive
|
|
16
|
-
}), children: jsxs("div", { className: "ids-header-inera-admin-avatar__menu-wrapper", children: [jsxs("button", { className: clsx("ids-header-inera-admin-avatar__button", {
|
|
16
|
+
}), children: jsxs("div", { className: "ids-header-inera-admin-avatar__menu-wrapper", children: [jsxs("button", { ref: buttonRef, className: clsx("ids-header-inera-admin-avatar__button", {
|
|
17
17
|
"ids-header-inera-admin-avatar__button--expanded": expanded
|
|
18
18
|
}), ...toggleHandler, "aria-controls": menuId, "aria-expanded": expanded, children: [jsx("div", { className: "ids-header-inera-admin-avatar__name", title: username, children: username }), unit && (jsx("div", { className: "ids-header-inera-admin-avatar__unit", title: unit, children: unit }))] }), jsx("div", { ref: menuRef || undefined, id: menuId, className: clsx("ids-header-inera-admin-avatar__menu", {
|
|
19
19
|
"ids-header-inera-admin-avatar__menu--expanded": expanded
|
|
@@ -7,7 +7,8 @@ interface IDSHeaderIneraAdminAvatarMobileBaseProps extends HTMLAttributes<HTMLDi
|
|
|
7
7
|
unresponsive?: boolean;
|
|
8
8
|
onToggleMenu?: () => void;
|
|
9
9
|
componentRef?: React.RefObject<HTMLDivElement>;
|
|
10
|
+
buttonRef?: React.RefObject<HTMLButtonElement>;
|
|
10
11
|
client?: boolean;
|
|
11
12
|
}
|
|
12
|
-
export declare function IDSHeaderIneraAdminAvatarMobileBase({ username, unit, expanded, hide, unresponsive, componentRef, children, onToggleMenu, client, ...props }: IDSHeaderIneraAdminAvatarMobileBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function IDSHeaderIneraAdminAvatarMobileBase({ username, unit, expanded, hide, unresponsive, componentRef, buttonRef, children, onToggleMenu, client, ...props }: IDSHeaderIneraAdminAvatarMobileBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
13
14
|
export {};
|
|
@@ -2,7 +2,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import { useId } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
|
|
5
|
-
function IDSHeaderIneraAdminAvatarMobileBase({ username = "", unit = "", expanded, hide, unresponsive, componentRef, children, onToggleMenu, client = false, ...props }) {
|
|
5
|
+
function IDSHeaderIneraAdminAvatarMobileBase({ username = "", unit = "", expanded, hide, unresponsive, componentRef, buttonRef, children, onToggleMenu, client = false, ...props }) {
|
|
6
6
|
if (hide)
|
|
7
7
|
return null;
|
|
8
8
|
const menuId = `header-inera-admin-menu-${useId()}`;
|
|
@@ -13,7 +13,7 @@ function IDSHeaderIneraAdminAvatarMobileBase({ username = "", unit = "", expande
|
|
|
13
13
|
: {};
|
|
14
14
|
return (jsx("div", { ...props, ref: componentRef, className: clsx("ids-header-inera-admin-avatar-mobile", {
|
|
15
15
|
"ids-header-inera-admin-avatar-mobile--unresponsive": unresponsive
|
|
16
|
-
}), children: jsxs("div", { className: "ids-header-inera-admin-avatar-mobile__menu-wrapper", children: [jsx("button", { ...toggleHandler, className: clsx("ids-header-inera-admin-avatar-mobile__button", {
|
|
16
|
+
}), children: jsxs("div", { className: "ids-header-inera-admin-avatar-mobile__menu-wrapper", children: [jsx("button", { ...toggleHandler, ref: buttonRef, className: clsx("ids-header-inera-admin-avatar-mobile__button", {
|
|
17
17
|
"ids-header-inera-admin-avatar-mobile__button--expanded": expanded
|
|
18
18
|
}), "aria-controls": menuId, "aria-expanded": expanded, children: jsx("div", { className: "ids-header-inera-admin-avatar-mobile-content__name", title: username, children: username }) }), jsxs("div", { id: menuId, className: clsx("ids-header-inera-admin-avatar-mobile__menu", {
|
|
19
19
|
"ids-header-inera-admin-avatar-mobile__menu--expanded": expanded
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { useState, useRef
|
|
3
|
+
import { useState, useRef } from 'react';
|
|
4
4
|
import { IDSHeaderIneraAdminAvatarMobileBase } from './header-inera-admin-avatar-mobile-base.js';
|
|
5
5
|
import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
|
|
6
|
+
import { useFocusTrap } from '../utils/hooks/useFocusTrap.js';
|
|
7
|
+
import { useClickOutside } from '../utils/hooks/useClickOutside.js';
|
|
8
|
+
import { useEsc } from '../utils/hooks/useEsc.js';
|
|
6
9
|
|
|
7
10
|
function IDSHeaderIneraAdminAvatarMobile({ username = "", unit = "", expanded = false, persistent = false, children, ...props }) {
|
|
8
11
|
const headerContext = useHeaderContext();
|
|
@@ -10,30 +13,15 @@ function IDSHeaderIneraAdminAvatarMobile({ username = "", unit = "", expanded =
|
|
|
10
13
|
return null;
|
|
11
14
|
const [isExpanded, setIsExpanded] = useState(expanded);
|
|
12
15
|
const componentRef = useRef(null);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const buttonRef = useRef(null);
|
|
17
|
+
useFocusTrap(componentRef.current, isExpanded && !persistent);
|
|
18
|
+
useClickOutside([componentRef, buttonRef], () => {
|
|
19
|
+
if (!persistent)
|
|
16
20
|
setIsExpanded(false);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return () => document.removeEventListener("click", handleClickOutside);
|
|
22
|
-
}, [persistent]);
|
|
23
|
-
// Escape should also close
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (!isExpanded || persistent)
|
|
26
|
-
return;
|
|
27
|
-
const handleKeyDown = (event) => {
|
|
28
|
-
if (event.key === "Escape") {
|
|
29
|
-
event.preventDefault();
|
|
30
|
-
setIsExpanded(false);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
34
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
35
|
-
}, [isExpanded, persistent]);
|
|
36
|
-
return (jsx(IDSHeaderIneraAdminAvatarMobileBase, { ...props, client: true, username: username, unit: unit, expanded: isExpanded, componentRef: componentRef, onToggleMenu: username ? toggleAvatar : undefined, unresponsive: headerContext?.unresponsive ?? false, children: children }));
|
|
21
|
+
});
|
|
22
|
+
useEsc(() => setIsExpanded(false), buttonRef, isExpanded && !persistent);
|
|
23
|
+
const toggleAvatar = () => setIsExpanded(prev => !prev);
|
|
24
|
+
return (jsx(IDSHeaderIneraAdminAvatarMobileBase, { ...props, client: true, username: username, unit: unit, expanded: isExpanded, componentRef: componentRef, buttonRef: buttonRef, onToggleMenu: username ? toggleAvatar : undefined, unresponsive: headerContext?.unresponsive ?? false, children: children }));
|
|
37
25
|
}
|
|
38
26
|
|
|
39
27
|
export { IDSHeaderIneraAdminAvatarMobile };
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
import {
|
|
3
|
+
import { useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { IDSHeaderIneraAdminAvatarBase } from './header-inera-admin-avatar-base.js';
|
|
5
5
|
import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
|
|
6
|
+
import { useFocusTrap } from '../utils/hooks/useFocusTrap.js';
|
|
7
|
+
import { useClickOutside } from '../utils/hooks/useClickOutside.js';
|
|
8
|
+
import { useEsc } from '../utils/hooks/useEsc.js';
|
|
6
9
|
|
|
7
10
|
function IDSHeaderIneraAdminAvatar({ username, unit, expanded = false, children, persistent = false, ...props }) {
|
|
8
11
|
const headerContext = useHeaderContext();
|
|
9
12
|
if (headerContext?.hideAvatar)
|
|
10
13
|
return null;
|
|
11
|
-
useId();
|
|
12
14
|
const [isExpanded, setIsExpanded] = useState(expanded);
|
|
13
15
|
const componentRef = useRef(null);
|
|
14
16
|
const menuRef = useRef(null);
|
|
17
|
+
const buttonRef = useRef(null);
|
|
18
|
+
useFocusTrap(componentRef.current, isExpanded && !persistent);
|
|
19
|
+
useClickOutside([componentRef, buttonRef], () => {
|
|
20
|
+
if (!persistent)
|
|
21
|
+
setIsExpanded(false);
|
|
22
|
+
});
|
|
23
|
+
useEsc(() => setIsExpanded(false), buttonRef, isExpanded && !persistent);
|
|
15
24
|
const toggleAvatar = () => setIsExpanded(prev => !prev);
|
|
16
25
|
useEffect(() => {
|
|
17
26
|
const clickOutsideHandler = (e) => {
|
|
@@ -32,20 +41,7 @@ function IDSHeaderIneraAdminAvatar({ username, unit, expanded = false, children,
|
|
|
32
41
|
};
|
|
33
42
|
}
|
|
34
43
|
}, [isExpanded, persistent]);
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
if (!isExpanded || persistent)
|
|
38
|
-
return;
|
|
39
|
-
const handleKeyDown = (event) => {
|
|
40
|
-
if (event.key === "Escape") {
|
|
41
|
-
event.preventDefault();
|
|
42
|
-
setIsExpanded(false);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
46
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
47
|
-
}, [isExpanded, persistent]);
|
|
48
|
-
return (jsx(IDSHeaderIneraAdminAvatarBase, { ...props, client: true, username: username, unit: unit, children: children, componentRef: componentRef, menuRef: menuRef, expanded: isExpanded, onToggleAvatar: toggleAvatar, unresponsive: headerContext?.unresponsive ?? false }));
|
|
44
|
+
return (jsx(IDSHeaderIneraAdminAvatarBase, { ...props, client: true, username: username, unit: unit, children: children, componentRef: componentRef, menuRef: menuRef, buttonRef: buttonRef, expanded: isExpanded, onToggleAvatar: toggleAvatar, unresponsive: headerContext?.unresponsive ?? false }));
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
export { IDSHeaderIneraAdminAvatar };
|
|
@@ -5,7 +5,8 @@ interface IDSHeaderIneraAdminMenuMobileBaseProps extends HTMLAttributes<HTMLElem
|
|
|
5
5
|
unresponsive?: boolean;
|
|
6
6
|
onToggleMenu?: () => void;
|
|
7
7
|
componentRef?: React.RefObject<HTMLDivElement>;
|
|
8
|
+
buttonRef?: React.RefObject<HTMLButtonElement>;
|
|
8
9
|
client?: boolean;
|
|
9
10
|
}
|
|
10
|
-
export declare function IDSHeaderIneraAdminMenuMobileBase({ srLabel, expanded, unresponsive, children, componentRef, onToggleMenu, client, ...props }: IDSHeaderIneraAdminMenuMobileBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function IDSHeaderIneraAdminMenuMobileBase({ srLabel, expanded, unresponsive, children, componentRef, buttonRef, onToggleMenu, client, ...props }: IDSHeaderIneraAdminMenuMobileBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
export {};
|
|
@@ -2,7 +2,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { useId } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
|
|
5
|
-
function IDSHeaderIneraAdminMenuMobileBase({ srLabel = "Meny", expanded = false, unresponsive = false, children, componentRef, onToggleMenu, client = false, ...props }) {
|
|
5
|
+
function IDSHeaderIneraAdminMenuMobileBase({ srLabel = "Meny", expanded = false, unresponsive = false, children, componentRef, buttonRef, onToggleMenu, client = false, ...props }) {
|
|
6
6
|
const menuId = `header-inera-admin-menu-${useId()}`;
|
|
7
7
|
const toggleHandler = client && onToggleMenu
|
|
8
8
|
? {
|
|
@@ -12,7 +12,7 @@ function IDSHeaderIneraAdminMenuMobileBase({ srLabel = "Meny", expanded = false,
|
|
|
12
12
|
return (jsxs("div", { ref: componentRef, className: clsx("ids-header-inera-admin-menu-mobile", {
|
|
13
13
|
"ids-header-inera-admin-menu-mobile--expanded": expanded,
|
|
14
14
|
"ids-header-inera-admin-menu-mobile--unresponsive": unresponsive
|
|
15
|
-
}), ...props, children: [jsx("button", { "aria-label": srLabel, "aria-expanded": expanded, "aria-controls": menuId, ...toggleHandler, className: "ids-header-inera-admin-menu-mobile__button", children: jsx("div", { className: "ids-hamburger", children: jsx("div", { className: "ids-hamburger__lines" }) }) }), jsx("div", { id: menuId, className: "ids-header-inera-admin-menu-mobile__items", children: children })] }));
|
|
15
|
+
}), ...props, children: [jsx("button", { ref: buttonRef, "aria-label": srLabel, "aria-expanded": expanded, "aria-controls": menuId, ...toggleHandler, className: "ids-header-inera-admin-menu-mobile__button", children: jsx("div", { className: "ids-hamburger", children: jsx("div", { className: "ids-hamburger__lines" }) }) }), jsx("div", { id: menuId, className: "ids-header-inera-admin-menu-mobile__items", children: children })] }));
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export { IDSHeaderIneraAdminMenuMobileBase };
|
|
@@ -3,11 +3,19 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
3
3
|
import { useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { IDSHeaderIneraAdminMenuMobileBase } from './header-inera-admin-menu-mobile-base.js';
|
|
5
5
|
import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
|
|
6
|
+
import { useClickOutside } from '../utils/hooks/useClickOutside.js';
|
|
7
|
+
import { useEsc } from '../utils/hooks/useEsc.js';
|
|
6
8
|
|
|
7
9
|
function IDSHeaderIneraAdminMenuMobile({ srLabel = "Meny", expanded = false, persistent = false, children, onExpanded, onClosed, ...props }) {
|
|
8
10
|
const headerContext = useHeaderContext();
|
|
9
11
|
const [isExpanded, setIsExpanded] = useState(expanded);
|
|
10
12
|
const componentRef = useRef(null);
|
|
13
|
+
const buttonRef = useRef(null);
|
|
14
|
+
useClickOutside([componentRef, buttonRef], () => {
|
|
15
|
+
if (!persistent)
|
|
16
|
+
setIsExpanded(false);
|
|
17
|
+
});
|
|
18
|
+
useEsc(() => setIsExpanded(false), buttonRef, isExpanded && !persistent);
|
|
11
19
|
const handleLinkClick = () => {
|
|
12
20
|
setIsExpanded(false);
|
|
13
21
|
onClosed?.();
|
|
@@ -36,20 +44,7 @@ function IDSHeaderIneraAdminMenuMobile({ srLabel = "Meny", expanded = false, per
|
|
|
36
44
|
setIsExpanded(next);
|
|
37
45
|
next ? onExpanded?.() : onClosed?.();
|
|
38
46
|
};
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (!isExpanded || persistent)
|
|
42
|
-
return;
|
|
43
|
-
const handleKeyDown = (event) => {
|
|
44
|
-
if (event.key === "Escape") {
|
|
45
|
-
event.preventDefault();
|
|
46
|
-
setIsExpanded(false);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
50
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
51
|
-
}, [isExpanded, persistent]);
|
|
52
|
-
return (jsx(IDSHeaderIneraAdminMenuMobileBase, { ...props, client: true, children: children, srLabel: srLabel, expanded: isExpanded, unresponsive: headerContext?.unresponsive, onToggleMenu: toggleMenu, componentRef: componentRef }));
|
|
47
|
+
return (jsx(IDSHeaderIneraAdminMenuMobileBase, { ...props, client: true, children: children, srLabel: srLabel, expanded: isExpanded, unresponsive: headerContext?.unresponsive, onToggleMenu: toggleMenu, componentRef: componentRef, buttonRef: buttonRef }));
|
|
53
48
|
}
|
|
54
49
|
|
|
55
50
|
export { IDSHeaderIneraAdminMenuMobile };
|
|
@@ -11,8 +11,9 @@ export interface IDSHeaderIneraAdminNavItemBaseProps extends HTMLAttributes<HTML
|
|
|
11
11
|
col4?: React.ReactNode;
|
|
12
12
|
componentRef?: React.Ref<HTMLDivElement>;
|
|
13
13
|
menuRef?: React.Ref<HTMLDivElement>;
|
|
14
|
+
buttonRef?: React.Ref<HTMLButtonElement>;
|
|
14
15
|
onToggleItem?: () => void;
|
|
15
16
|
unresponsive?: boolean;
|
|
16
17
|
client?: boolean;
|
|
17
18
|
}
|
|
18
|
-
export declare function IDSHeaderIneraAdminNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, onToggleItem, unresponsive, client, ...props }: IDSHeaderIneraAdminNavItemBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare function IDSHeaderIneraAdminNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, buttonRef, onToggleItem, unresponsive, client, ...props }: IDSHeaderIneraAdminNavItemBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,7 +2,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import React, { useId } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
|
|
5
|
-
function IDSHeaderIneraAdminNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, onToggleItem, unresponsive, client = false, ...props }) {
|
|
5
|
+
function IDSHeaderIneraAdminNavItemBase({ label, active, expanded, children, col1, col2, col3, col4, componentRef, menuRef, buttonRef, onToggleItem, unresponsive, client = false, ...props }) {
|
|
6
6
|
const itemId = `header-inera-admin-item-${useId()}`;
|
|
7
7
|
const toggleHandler = client && onToggleItem
|
|
8
8
|
? {
|
|
@@ -13,7 +13,7 @@ function IDSHeaderIneraAdminNavItemBase({ label, active, expanded, children, col
|
|
|
13
13
|
"ids-header-inera-admin-nav-item--unresponsive": unresponsive,
|
|
14
14
|
"ids-header-inera-admin-nav-item--expanded": expanded,
|
|
15
15
|
"ids-header-inera-admin-nav-item--active": active
|
|
16
|
-
}), ...props, children: [!!label && (jsx("button", { "aria-controls": itemId, "aria-expanded": expanded, className: "ids-header-inera-admin-nav-item__button", ...toggleHandler, children: label })), !label && (jsx("span", { className: "ids-header-inera-admin-nav-item__link", children: React.Children.map(children, child => {
|
|
16
|
+
}), ...props, children: [!!label && (jsx("button", { ref: buttonRef, "aria-controls": itemId, "aria-expanded": expanded, className: "ids-header-inera-admin-nav-item__button", ...toggleHandler, children: label })), !label && (jsx("span", { className: "ids-header-inera-admin-nav-item__link", children: React.Children.map(children, child => {
|
|
17
17
|
if (!React.isValidElement(child))
|
|
18
18
|
return child;
|
|
19
19
|
const element = child;
|
|
@@ -3,12 +3,19 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
3
3
|
import { useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { IDSHeaderIneraAdminNavItemBase } from './header-inera-admin-nav-item-base.js';
|
|
5
5
|
import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
|
|
6
|
+
import { useClickOutside } from '../utils/hooks/useClickOutside.js';
|
|
7
|
+
import { useEsc } from '../utils/hooks/useEsc.js';
|
|
6
8
|
|
|
7
9
|
function IDSHeaderIneraAdminNavItem({ expanded = false, ...props }) {
|
|
8
10
|
const headerContext = useHeaderContext();
|
|
9
11
|
const [isExpanded, setIsExpanded] = useState(expanded);
|
|
10
12
|
const componentRef = useRef(null);
|
|
11
13
|
const menuRef = useRef(null);
|
|
14
|
+
const buttonRef = useRef(null);
|
|
15
|
+
useClickOutside([componentRef, buttonRef], () => {
|
|
16
|
+
setIsExpanded(false);
|
|
17
|
+
});
|
|
18
|
+
useEsc(() => setIsExpanded(false), buttonRef);
|
|
12
19
|
useEffect(() => {
|
|
13
20
|
setIsExpanded(expanded);
|
|
14
21
|
}, [expanded]);
|
|
@@ -37,20 +44,7 @@ function IDSHeaderIneraAdminNavItem({ expanded = false, ...props }) {
|
|
|
37
44
|
menuEl.addEventListener("click", onMenuClick);
|
|
38
45
|
return () => menuEl.removeEventListener("click", onMenuClick);
|
|
39
46
|
}, [menuRef]);
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (!isExpanded)
|
|
43
|
-
return;
|
|
44
|
-
const handleKeyDown = (event) => {
|
|
45
|
-
if (event.key === "Escape") {
|
|
46
|
-
event.preventDefault();
|
|
47
|
-
setIsExpanded(false);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
51
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
52
|
-
}, [isExpanded]);
|
|
53
|
-
return (jsx(IDSHeaderIneraAdminNavItemBase, { ...props, client: true, expanded: isExpanded, unresponsive: headerContext?.unresponsive, componentRef: componentRef, menuRef: menuRef, onToggleItem: () => setIsExpanded((prev) => !prev) }));
|
|
47
|
+
return (jsx(IDSHeaderIneraAdminNavItemBase, { ...props, client: true, expanded: isExpanded, unresponsive: headerContext?.unresponsive, componentRef: componentRef, menuRef: menuRef, buttonRef: buttonRef, onToggleItem: () => setIsExpanded((prev) => !prev) }));
|
|
54
48
|
}
|
|
55
49
|
|
|
56
50
|
export { IDSHeaderIneraAdminNavItem };
|
|
@@ -13,7 +13,7 @@ const IDSPopoverContent = forwardRef(({ position = "bottom", srCloseText = "Stä
|
|
|
13
13
|
const renderCaret = (pos) => (jsxs("div", { className: `ids-popover-content__caret ids-popover-content__caret--${pos}`, children: [jsx("span", { className: `ids-popover-content__caret-body ids-popover-content__caret--${pos}` }), jsx("span", { className: `ids-popover-content__caret-border ids-popover-content__caret--${pos}` }), jsx("span", { className: `ids-popover-content__caret-shadow ids-popover-content__caret--${pos}` })] }));
|
|
14
14
|
return (jsxs("div", { ref: contentRef, className: clsx("ids-popover-content", `ids-popover-content--${position}`, {
|
|
15
15
|
"ids-focus-trap": !noFocusTrap
|
|
16
|
-
}), role: "tooltip", id: contentId, "data-position": position, children: [renderCaret(position), jsx("div", { className: "ids-popover-content__close-btn-wrapper", children: jsx("button", { "aria-label": srCloseText, className: "ids-popover-content__close-btn", ...closeHandler }) }), jsx("div", { ref: scrollAreaRef, className: "ids-popover-content__content-wrapper", tabIndex: noScrollAreaFocus ? -1 : 0, style: contentScrollAreaStyle, children: jsxs("div", { className: "ids-popover-content__content-wrapper-inner", children: [headline && jsx("div", { className: "ids-popover-content__headline", children: headline }), children] }) })] }));
|
|
16
|
+
}), role: "tooltip", id: contentId, "data-position": position, children: [renderCaret(position), jsx("div", { className: "ids-popover-content__close-btn-wrapper", children: jsx("button", { "aria-label": srCloseText, className: "ids-popover-content__close-btn", ...closeHandler }) }), jsx("div", { ref: scrollAreaRef, className: "ids-popover-content__content-wrapper", tabIndex: noScrollAreaFocus ? -1 : 0, style: contentScrollAreaStyle, children: jsxs("div", { className: "ids-popover-content__content-wrapper-inner", children: [!!headline && jsx("div", { className: "ids-popover-content__headline", children: headline }), children] }) })] }));
|
|
17
17
|
});
|
|
18
18
|
IDSPopoverContent.displayName = "IDSPopoverContent";
|
|
19
19
|
|
|
@@ -94,7 +94,7 @@ function IDSPopover({ position = "bottom", category = "", trigger, maxWidth = 26
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
}, [isExpanded, autoFocus]);
|
|
97
|
-
return (jsx("span", { "data-popover-category": category, ref: popoverRef, children: jsx(IDSPopoverBase, { ...props, client: true, expanded: isExpanded, triggerRef: triggerRef, togglePopover: togglePopover, handleKeyPress: handleKeyPress, trigger: trigger, className: className, children: jsx(IDSPopoverContent, { client: true, contentRef: contentRef, scrollAreaRef: scrollAreaRef, noScrollAreaFocus: noScrollAreaFocus, position: position, srCloseText: srCloseText, closePopover: closePopover, contentScrollAreaStyle: contentScrollAreaStyle, noFocusTrap: noFocusTrap, children: children }) }) }));
|
|
97
|
+
return (jsx("span", { "data-popover-category": category, ref: popoverRef, children: jsx(IDSPopoverBase, { ...props, client: true, expanded: isExpanded, triggerRef: triggerRef, togglePopover: togglePopover, handleKeyPress: handleKeyPress, trigger: trigger, className: className, children: jsx(IDSPopoverContent, { client: true, headline: headline, contentRef: contentRef, scrollAreaRef: scrollAreaRef, noScrollAreaFocus: noScrollAreaFocus, position: position, srCloseText: srCloseText, closePopover: closePopover, contentScrollAreaStyle: contentScrollAreaStyle, noFocusTrap: noFocusTrap, children: children }) }) }));
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export { IDSPopover };
|
|
@@ -5,7 +5,7 @@ function IDSPuffListItemHeader({ headlineLevel = 2, headlineExtra, noMargin = fa
|
|
|
5
5
|
const Tag = `h${headlineLevel}`;
|
|
6
6
|
return (jsxs(Tag, { ...props, className: clsx("ids-puff-list-item-header__headline", {
|
|
7
7
|
"ids-puff-list-item-header__headline--no-margin": noMargin
|
|
8
|
-
}), children: [children, headlineExtra && jsx("span", { className: "ids-puff-list-item-header__extra-content", children: headlineExtra })] }));
|
|
8
|
+
}), children: [jsx("span", { className: "ids-puff-list-item-header__headline-content", children: children }), headlineExtra && jsx("span", { className: "ids-puff-list-item-header__extra-content", children: headlineExtra })] }));
|
|
9
9
|
}
|
|
10
10
|
IDSPuffListItemHeader.displayName = "IDSPuffListItemHeader";
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ function IDSPuffListItem({ header, itemLink, date, dateTo, noContent = false, le
|
|
|
18
18
|
return (jsxs("div", { ...props, className: clsx("ids-puff-list-item", {
|
|
19
19
|
"ids-puff-list-item--interactive": !!itemLink,
|
|
20
20
|
"ids-puff-list-item--lean": !!lean
|
|
21
|
-
}, className), children: [jsxs("div", { className: "ids-puff-list-item__inner", children: [dateLabel && jsx("div", { className: "ids-puff-list-item__date-label", children: dateLabel }), jsxs("div", { className: "ids-puff-list-item__content", children: [!!date && date, !!date && !!dateTo && (jsxs(Fragment, { children: [jsx("span", { className: "ids-puff-list-item__date-spacer", children: "\u2015" }), dateTo] })), renderBody()] }), extra && jsx("div", { className: "ids-puff-list-item__extra-content", children: extra })] }), jsx("div", { className: "ids-puff-list-item-separator" })] }));
|
|
21
|
+
}, className), children: [jsxs("div", { className: "ids-puff-list-item__inner", children: [dateLabel && jsx("div", { className: "ids-puff-list-item__date-label", children: dateLabel }), jsxs("div", { className: "ids-puff-list-item__content-wrapper", children: [jsxs("div", { className: "ids-puff-list-item__content", children: [!!date && date, !!date && !!dateTo && (jsxs(Fragment, { children: [jsx("span", { className: "ids-puff-list-item__date-spacer", children: "\u2015" }), dateTo] })), renderBody()] }), extra && jsx("div", { className: "ids-puff-list-item__extra-content", children: extra })] })] }), jsx("div", { className: "ids-puff-list-item-separator" })] }));
|
|
22
22
|
}
|
|
23
23
|
IDSPuffListItem.displayName = "IDSPuffListItem";
|
|
24
24
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { forwardRef } from 'react';
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
import '@inera/ids-design/components/side-panel/side-panel.css';
|
|
5
5
|
|
|
6
6
|
const IDSSidePanelBase = forwardRef(({ visible = false, left = false, elevated = false, menu = false, footer = false, noScrollAreaFocus = false, footerDarkmodeToggle, size = "m", srLabel = "Sidopanel", onTogglePanel, onClosePanel, srClose, srOpen, client, headline, footerLinks, footerText, hamburgerRef, className, children, ...props }, ref) => {
|
|
7
|
+
const [ready, setReady] = React.useState(false);
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
setReady(true);
|
|
10
|
+
}, []);
|
|
7
11
|
const classNames = clsx("ids-side-panel", "ids-focus-trap--tablet", size && !menu && `ids-side-panel--${size}`, menu ? "ids-side-panel--menu" : "ids-side-panel--regular", {
|
|
8
|
-
"ids-side-panel--show": visible,
|
|
12
|
+
"ids-side-panel--show": visible && ready,
|
|
9
13
|
"ids-side-panel--elevated": elevated,
|
|
10
14
|
"ids-side-panel--left": !menu && left
|
|
11
15
|
}, className);
|
|
@@ -2,34 +2,32 @@
|
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { useRef, useState, useEffect } from 'react';
|
|
4
4
|
import { IDSSidePanelBase } from './side-panel-base.js';
|
|
5
|
+
import { useEsc } from '../utils/hooks/useEsc.js';
|
|
5
6
|
|
|
6
|
-
function IDSSidePanel({ show
|
|
7
|
+
function IDSSidePanel({ show, menu = false, noScrollAreaFocus = false, srLabel = "Sidopanel", onVisibilityChange, srClose = "Stäng", srOpen = "Öppna", onOpen, onClose, className, children, ...props }) {
|
|
7
8
|
const internalRef = useRef(null);
|
|
8
9
|
const hamburgerRef = useRef(null);
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const isControlled = show !== undefined;
|
|
11
|
+
const [internalShow, setInternalShow] = useState(false);
|
|
12
|
+
const visible = isControlled ? show : internalShow;
|
|
13
|
+
useEsc(() => setVisible(false), hamburgerRef, internalShow);
|
|
14
|
+
const setVisible = (value) => {
|
|
15
|
+
if (!isControlled) {
|
|
16
|
+
setInternalShow(value);
|
|
14
17
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const handleKeyDown = (e) => {
|
|
19
|
-
if (e.key === "Escape" && internalShow) {
|
|
20
|
-
setInternalShow(false);
|
|
21
|
-
onVisibilityChange?.(false);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
25
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
26
|
-
}, [internalShow]);
|
|
18
|
+
onVisibilityChange?.(value);
|
|
19
|
+
};
|
|
20
|
+
// Open / close side effects
|
|
27
21
|
useEffect(() => {
|
|
28
|
-
if (
|
|
22
|
+
if (visible) {
|
|
29
23
|
onOpen?.();
|
|
30
24
|
const heading = internalRef.current?.querySelector("h1, h2, h3, h4, h5, h6");
|
|
31
|
-
heading
|
|
32
|
-
|
|
25
|
+
if (heading) {
|
|
26
|
+
heading.setAttribute("tabindex", "-1");
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
heading.focus();
|
|
29
|
+
}, 50);
|
|
30
|
+
}
|
|
33
31
|
}
|
|
34
32
|
else {
|
|
35
33
|
if (menu && hamburgerRef.current) {
|
|
@@ -37,36 +35,47 @@ function IDSSidePanel({ show = false, menu = false, noScrollAreaFocus = false, s
|
|
|
37
35
|
}
|
|
38
36
|
onClose?.();
|
|
39
37
|
}
|
|
40
|
-
}, [
|
|
38
|
+
}, [visible, menu, onOpen, onClose]);
|
|
41
39
|
// Window resize ARIA attributes
|
|
42
40
|
useEffect(() => {
|
|
43
41
|
const handleResize = () => {
|
|
44
42
|
const panel = internalRef.current;
|
|
45
|
-
if (panel)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
if (!panel)
|
|
44
|
+
return;
|
|
45
|
+
if (window.innerWidth <= 1024) {
|
|
46
|
+
panel.setAttribute("role", "dialog");
|
|
47
|
+
panel.setAttribute("aria-modal", "true");
|
|
48
|
+
panel.setAttribute("aria-label", srLabel);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
panel.removeAttribute("role");
|
|
52
|
+
panel.removeAttribute("aria-modal");
|
|
53
|
+
panel.removeAttribute("aria-label");
|
|
56
54
|
}
|
|
57
55
|
};
|
|
58
56
|
handleResize();
|
|
59
57
|
window.addEventListener("resize", handleResize);
|
|
60
58
|
return () => window.removeEventListener("resize", handleResize);
|
|
61
59
|
}, [srLabel]);
|
|
62
|
-
const onClosePanel = () =>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
const onClosePanel = () => setVisible(false);
|
|
61
|
+
const onTogglePanel = () => setVisible(!visible);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const handleBodyScroll = () => {
|
|
64
|
+
if (visible && window.innerWidth <= 1024) {
|
|
65
|
+
document.body.style.overflow = "hidden";
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
document.body.style.overflow = "";
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
handleBodyScroll();
|
|
72
|
+
window.addEventListener("resize", handleBodyScroll);
|
|
73
|
+
return () => {
|
|
74
|
+
window.removeEventListener("resize", handleBodyScroll);
|
|
75
|
+
document.body.style.overflow = ""; // cleanup on unmount
|
|
76
|
+
};
|
|
77
|
+
}, [visible]);
|
|
78
|
+
return (jsx(IDSSidePanelBase, { ...props, ref: internalRef, client: true, menu: menu, className: className, srClose: srClose, srOpen: srOpen, noScrollAreaFocus: noScrollAreaFocus, visible: visible, onClosePanel: onClosePanel, onTogglePanel: onTogglePanel, hamburgerRef: hamburgerRef, children: children }));
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
export { IDSSidePanel };
|
|
@@ -25,7 +25,7 @@ const IDSStepBase = forwardRef(({ state = "", headline, label = "", stepNumber =
|
|
|
25
25
|
: {};
|
|
26
26
|
return (jsxs("div", { className: clsx("ids-step", className), ...props, children: [jsx("div", { ref: ref, role: "button", tabIndex: disabled ? -1 : 0, className: clsx("ids-step__button", {
|
|
27
27
|
"ids-step__button--disabled": disabled
|
|
28
|
-
}), "aria-expanded": expanded, ...toggleHandlers, children: jsxs("div", { className: "ids-step__button-inner", children: [jsx("div", { className: "ids-step__indicator-wrapper", children: jsx("div", { "aria-label": srIndicatorText || stepNumber, role: "img", className: `ids-step__indicator ids-step__indicator--${state}`, children: renderStepIndicator() }) }), jsxs("div", { className: "ids-step__button-text", children: [jsxs("div", { className: "ids-step__headline-label", children: [
|
|
28
|
+
}), "aria-expanded": expanded, ...toggleHandlers, children: jsxs("div", { className: "ids-step__button-inner", children: [jsx("div", { className: "ids-step__indicator-wrapper", children: jsx("div", { "aria-label": srIndicatorText || stepNumber, role: "img", className: `ids-step__indicator ids-step__indicator--${state}`, children: renderStepIndicator() }) }), jsxs("div", { className: "ids-step__button-text", children: [jsxs("div", { className: "ids-step__headline-label", children: [headline && jsx("div", { className: "ids-step__headline", children: headline }), label && jsx("div", { className: "ids-step__label", children: label })] }), jsx("div", { className: clsx("ids-step__chevron", {
|
|
29
29
|
"ids-step__chevron--expanded": expanded
|
|
30
30
|
}) })] })] }) }), jsx("div", { className: clsx("ids-step__content", {
|
|
31
31
|
"ids-step__content--expanded": expanded
|