@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.
Files changed (113) hide show
  1. package/components/alert/alert.js +1 -1
  2. package/components/breadcrumbs/breadcrumbs.js +1 -1
  3. package/components/card/card.d.ts +2 -2
  4. package/components/card/card.js +4 -15
  5. package/components/data-pagination/data-pagination.d.ts +6 -6
  6. package/components/data-pagination/data-pagination.js +1 -1
  7. package/components/dialog/dialog-base.js +1 -1
  8. package/components/dialog/dialog.js +12 -13
  9. package/components/dropdown/dropdown-base.js +2 -2
  10. package/components/dropdown/dropdown.js +1 -0
  11. package/components/footer-1177-pro/footer-1177-pro.d.ts +2 -1
  12. package/components/footer-1177-pro/footer-1177-pro.js +2 -2
  13. package/components/form/checkbox/checkbox-group-base.d.ts +2 -1
  14. package/components/form/checkbox/checkbox-group-base.js +4 -2
  15. package/components/form/checkbox/checkbox-group.d.ts +1 -0
  16. package/components/form/checkbox/checkbox-group.js +4 -3
  17. package/components/form/datepicker/datepicker.d.ts +2 -1
  18. package/components/form/datepicker/datepicker.js +60 -37
  19. package/components/form/input/input-base.d.ts +2 -1
  20. package/components/form/input/input-base.js +10 -10
  21. package/components/form/input/input.d.ts +1 -0
  22. package/components/form/radio/radio-group-base.d.ts +2 -1
  23. package/components/form/radio/radio-group-base.js +4 -2
  24. package/components/form/radio/radio-group.d.ts +1 -0
  25. package/components/form/radio/radio-group.js +4 -3
  26. package/components/form/radio/radio.js +1 -3
  27. package/components/form/radio-button/radio-button-group-base.js +1 -1
  28. package/components/form/select/select.d.ts +1 -1
  29. package/components/form/select/select.js +2 -2
  30. package/components/form/select-multiple/select-multiple-base.d.ts +3 -3
  31. package/components/form/select-multiple/select-multiple-base.js +5 -6
  32. package/components/form/select-multiple/select-multiple.d.ts +1 -1
  33. package/components/form/select-multiple/select-multiple.js +10 -23
  34. package/components/form/textarea/textarea.d.ts +1 -1
  35. package/components/form/textarea/textarea.js +2 -2
  36. package/components/form/time/time.d.ts +1 -1
  37. package/components/form/time/time.js +2 -2
  38. package/components/{alert → global-alert}/global-alert.d.ts +1 -1
  39. package/components/{alert → global-alert}/global-alert.js +2 -2
  40. package/components/header-1177/header-1177-avatar-base.d.ts +2 -1
  41. package/components/header-1177/header-1177-avatar-base.js +2 -2
  42. package/components/header-1177/header-1177-avatar.js +11 -24
  43. package/components/header-1177/header-1177-menu-mobile-base.d.ts +2 -1
  44. package/components/header-1177/header-1177-menu-mobile-base.js +2 -2
  45. package/components/header-1177/header-1177-menu-mobile.js +9 -14
  46. package/components/header-1177/header-1177-nav-item-base.d.ts +2 -1
  47. package/components/header-1177/header-1177-nav-item-base.js +2 -2
  48. package/components/header-1177/header-1177-nav-item.js +8 -14
  49. package/components/header-1177-admin/header-1177-admin-avatar-base.d.ts +2 -1
  50. package/components/header-1177-admin/header-1177-admin-avatar-base.js +2 -2
  51. package/components/header-1177-admin/header-1177-admin-avatar-mobile-base.d.ts +2 -1
  52. package/components/header-1177-admin/header-1177-admin-avatar-mobile-base.js +2 -2
  53. package/components/header-1177-admin/header-1177-admin-avatar-mobile.js +12 -24
  54. package/components/header-1177-admin/header-1177-admin-avatar.js +11 -14
  55. package/components/header-1177-admin/header-1177-admin-menu-mobile-base.d.ts +2 -1
  56. package/components/header-1177-admin/header-1177-admin-menu-mobile-base.js +2 -2
  57. package/components/header-1177-admin/header-1177-admin-menu-mobile.js +9 -14
  58. package/components/header-1177-admin/header-1177-admin-nav-item-base.d.ts +2 -1
  59. package/components/header-1177-admin/header-1177-admin-nav-item-base.js +2 -2
  60. package/components/header-1177-admin/header-1177-admin-nav-item.js +8 -14
  61. package/components/header-1177-pro/header-1177-pro-avatar-base.d.ts +2 -1
  62. package/components/header-1177-pro/header-1177-pro-avatar-base.js +2 -2
  63. package/components/header-1177-pro/header-1177-pro-avatar-mobile-base.d.ts +2 -1
  64. package/components/header-1177-pro/header-1177-pro-avatar-mobile-base.js +2 -2
  65. package/components/header-1177-pro/header-1177-pro-avatar-mobile.js +12 -24
  66. package/components/header-1177-pro/header-1177-pro-avatar.js +11 -14
  67. package/components/header-1177-pro/header-1177-pro-menu-mobile-base.d.ts +2 -1
  68. package/components/header-1177-pro/header-1177-pro-menu-mobile-base.js +2 -2
  69. package/components/header-1177-pro/header-1177-pro-menu-mobile.js +9 -14
  70. package/components/header-1177-pro/header-1177-pro-nav-item-base.d.ts +2 -1
  71. package/components/header-1177-pro/header-1177-pro-nav-item-base.js +2 -2
  72. package/components/header-1177-pro/header-1177-pro-nav-item.js +8 -14
  73. package/components/header-inera/header-inera-menu-mobile-base.d.ts +2 -1
  74. package/components/header-inera/header-inera-menu-mobile-base.js +2 -2
  75. package/components/header-inera/header-inera-menu-mobile.js +9 -14
  76. package/components/header-inera/header-inera-nav-item-base.d.ts +2 -1
  77. package/components/header-inera/header-inera-nav-item-base.js +2 -2
  78. package/components/header-inera/header-inera-nav-item.js +8 -14
  79. package/components/header-inera-admin/header-inera-admin-avatar-base.d.ts +2 -1
  80. package/components/header-inera-admin/header-inera-admin-avatar-base.js +2 -2
  81. package/components/header-inera-admin/header-inera-admin-avatar-mobile-base.d.ts +2 -1
  82. package/components/header-inera-admin/header-inera-admin-avatar-mobile-base.js +2 -2
  83. package/components/header-inera-admin/header-inera-admin-avatar-mobile.js +12 -24
  84. package/components/header-inera-admin/header-inera-admin-avatar.js +12 -16
  85. package/components/header-inera-admin/header-inera-admin-menu-mobile-base.d.ts +2 -1
  86. package/components/header-inera-admin/header-inera-admin-menu-mobile-base.js +2 -2
  87. package/components/header-inera-admin/header-inera-admin-menu-mobile.js +9 -14
  88. package/components/header-inera-admin/header-inera-admin-nav-item-base.d.ts +2 -1
  89. package/components/header-inera-admin/header-inera-admin-nav-item-base.js +2 -2
  90. package/components/header-inera-admin/header-inera-admin-nav-item.js +8 -14
  91. package/components/popover/popover-content.js +1 -1
  92. package/components/popover/popover.js +1 -1
  93. package/components/puff-list/puff-list-item-header.js +1 -1
  94. package/components/puff-list/puff-list-item.js +1 -1
  95. package/components/side-panel/side-panel-base.js +6 -2
  96. package/components/side-panel/side-panel.js +50 -41
  97. package/components/stepper/step-base.js +1 -1
  98. package/components/stepper/step.js +12 -10
  99. package/components/tabs/tab-panel.js +1 -1
  100. package/components/tabs/tab.js +1 -1
  101. package/components/tabs/tabs.d.ts +1 -1
  102. package/components/tabs/tabs.js +8 -4
  103. package/components/utils/hooks/useClickOutside.d.ts +10 -0
  104. package/components/utils/hooks/useClickOutside.js +31 -0
  105. package/components/utils/hooks/useEsc.d.ts +10 -0
  106. package/components/utils/hooks/useEsc.js +27 -0
  107. package/components/utils/hooks/useHasFocusableChildren.d.ts +2 -0
  108. package/components/utils/hooks/useHasFocusableChildren.js +25 -0
  109. package/index.d.ts +2 -2
  110. package/index.js +2 -2
  111. package/package.json +2 -2
  112. /package/components/{alert → global-alert}/global-alert-base.d.ts +0 -0
  113. /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
- // Escape should also close
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, useEffect } from 'react';
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 toggleAvatar = () => setIsExpanded(prev => !prev);
14
- const handleClickOutside = (event) => {
15
- if (!persistent && componentRef.current && !componentRef.current.contains(event.target)) {
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
- useEffect(() => {
20
- document.addEventListener("click", handleClickOutside);
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 { useId, useState, useRef, useEffect } from 'react';
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
- // Escape should also close
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
- // Escape should also close
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
- // Escape should also close
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 = false, menu = false, noScrollAreaFocus = false, srLabel = "Sidopanel", onVisibilityChange, srClose = "Stäng", srOpen = "Öppna", onOpen, onClose, className, children, ...props }) {
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 [internalShow, setInternalShow] = useState(show);
10
- useEffect(() => {
11
- if (show !== internalShow) {
12
- setInternalShow(show);
13
- onVisibilityChange?.(show);
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
- }, [show]);
16
- // Escape key
17
- useEffect(() => {
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 (internalShow) {
22
+ if (visible) {
29
23
  onOpen?.();
30
24
  const heading = internalRef.current?.querySelector("h1, h2, h3, h4, h5, h6");
31
- heading?.setAttribute("tabindex", "-1");
32
- heading?.focus();
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
- }, [internalShow]);
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
- if (window.innerWidth <= 1024) {
47
- panel.setAttribute("role", "dialog");
48
- panel.setAttribute("aria-modal", "true");
49
- panel.setAttribute("aria-label", srLabel);
50
- }
51
- else {
52
- panel.removeAttribute("role");
53
- panel.removeAttribute("aria-modal");
54
- panel.removeAttribute("aria-label");
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
- setInternalShow(false);
64
- onVisibilityChange?.(false);
65
- };
66
- const onTogglePanel = () => {
67
- setInternalShow(prev => !prev);
68
- };
69
- return (jsx(IDSSidePanelBase, { ...props, ref: internalRef, client: true, menu: menu, className: className, srClose: srClose, srOpen: srOpen, noScrollAreaFocus: noScrollAreaFocus, visible: internalShow, onClosePanel: onClosePanel, onTogglePanel: onTogglePanel, hamburgerRef: hamburgerRef, children: children }));
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: [label && jsx("div", { className: "ids-step__label", children: label }), headline && jsx("div", { className: "ids-step__headline", children: headline })] }), jsx("div", { className: clsx("ids-step__chevron", {
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