@inera/ids-react 7.0.0 → 7.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 (37) hide show
  1. package/components/accordion/accordion.d.ts +1 -0
  2. package/components/accordion/accordion.js +2 -1
  3. package/components/button/button.js +1 -0
  4. package/components/dialog/dialog.js +1 -0
  5. package/components/dropdown/dropdown.js +2 -2
  6. package/components/form/check-button/check-button.d.ts +3 -2
  7. package/components/form/check-button/check-button.js +9 -3
  8. package/components/form/checkbox/checkbox.d.ts +2 -1
  9. package/components/form/checkbox/checkbox.js +12 -8
  10. package/components/form/input/input.d.ts +2 -1
  11. package/components/form/input/input.js +15 -8
  12. package/components/form/radio/radio.d.ts +2 -1
  13. package/components/form/radio/radio.js +8 -5
  14. package/components/form/radio-button/radio-button.d.ts +3 -2
  15. package/components/form/radio-button/radio-button.js +9 -5
  16. package/components/form/range/range.d.ts +2 -1
  17. package/components/form/range/range.js +8 -4
  18. package/components/form/select/select.d.ts +2 -1
  19. package/components/form/select/select.js +7 -4
  20. package/components/form/select-multiple/select-multiple.d.ts +1 -0
  21. package/components/form/select-multiple/select-multiple.js +3 -2
  22. package/components/form/textarea/textarea.d.ts +3 -2
  23. package/components/form/textarea/textarea.js +7 -4
  24. package/components/form/time/time.d.ts +3 -2
  25. package/components/form/time/time.js +11 -8
  26. package/components/form/toggle/toggle.d.ts +3 -2
  27. package/components/form/toggle/toggle.js +8 -4
  28. package/components/header-1177/header-1177-avatar.js +24 -11
  29. package/components/header-1177/header-1177-nav-item.js +22 -5
  30. package/components/header-1177-admin/header-1177-admin-nav-item.js +21 -6
  31. package/components/header-1177-pro/header-1177-pro-nav-item.js +21 -6
  32. package/components/header-inera/header-inera-nav-item.js +6 -1
  33. package/components/header-inera-admin/header-inera-admin-nav-item.js +6 -1
  34. package/components/link/link.d.ts +3 -3
  35. package/components/puff-list/puff-list-item/puff-list-item.d.ts +2 -0
  36. package/components/puff-list/puff-list-item/puff-list-item.js +12 -12
  37. package/package.json +2 -2
@@ -6,6 +6,7 @@ interface IDSAccordionProps extends React.HTMLAttributes<HTMLDivElement> {
6
6
  level?: 1 | 2;
7
7
  expanded?: boolean;
8
8
  lean?: boolean;
9
+ noBorder?: boolean;
9
10
  onCollapsed?: () => void;
10
11
  onExpanded?: () => void;
11
12
  children?: ReactNode;
@@ -5,7 +5,7 @@ import clsx from 'clsx';
5
5
  import '@inera/ids-design/components/accordion/accordion.css';
6
6
  import { useElementId } from '../utils/hooks/useElementId.js';
7
7
 
8
- const IDSAccordion = ({ headline = "", level = 1, headlineSize = level === 2 ? "s" : "m", expanded = false, lean = false, onCollapsed, onExpanded, children, className, ...props }) => {
8
+ const IDSAccordion = ({ headline = "", level = 1, headlineSize = level === 2 ? "s" : "m", expanded = false, lean = false, noBorder = false, onCollapsed, onExpanded, children, className, ...props }) => {
9
9
  const [isExpanded, setIsExpanded] = useState(expanded);
10
10
  const [isLean, setIsLean] = useState(lean);
11
11
  const [insideIDSCard, setInsideIDSCard] = useState(false);
@@ -63,6 +63,7 @@ const IDSAccordion = ({ headline = "", level = 1, headlineSize = level === 2 ? "
63
63
  };
64
64
  return (jsxs("div", { ref: accordionRef, className: clsx("ids-accordion", {
65
65
  "ids-accordion--expanded": isExpanded,
66
+ "ids-accordion--no-border": noBorder,
66
67
  "ids-accordion--lean": lean || isLean,
67
68
  "ids-accordion--has-children": hasChildren,
68
69
  "ids-accordion--is-child": level === 2
@@ -94,5 +94,6 @@ const IDSButton = forwardRef(({ active = false, block = false, disabled = false,
94
94
  : oldIcon;
95
95
  return (jsxs("button", { ref: ref, className: classNames, "aria-disabled": disabled || loading, "aria-pressed": toggle, tabIndex: !disabled && !loading ? 0 : -1, disabled: disabled, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, ...props, children: [icon && jsx("span", { className: `ids-icon-${icon}` }), oldIcon && renderOldIcon, children] }));
96
96
  });
97
+ IDSButton.displayName = "IDSButton";
97
98
 
98
99
  export { IDSButton };
@@ -51,6 +51,7 @@ const IDSDialog = ({ show = false, srClose = "Stäng", dismissible = false, auto
51
51
  const focusable = bodyRef.current?.querySelector(".ids-focus-anchor") ||
52
52
  bodyRef.current?.querySelector("h1, h2, h3, [tabindex]:not([tabindex='-1']), button:not([disabled]), a, input:not([disabled]), textarea:not([disabled])") ||
53
53
  dialogRef.current?.querySelector("button.ids-dialog__header__button");
54
+ console.log("focusable", focusable);
54
55
  focusable?.focus();
55
56
  });
56
57
  }
@@ -60,12 +60,12 @@ const IDSDropdown = ({ expanded = false, persistent = false, position = "right",
60
60
  key: `dropdown-content-link-${i}`
61
61
  });
62
62
  });
63
- return (jsx("div", { id: contentId, ref: contentRef, "aria-labelledby": buttonId, className: clsx("ids-dropdown__content", {
63
+ return (jsx("div", { id: contentId, ref: contentRef, "aria-labelledby": buttonId, className: clsx(`ids-dropdown__content ids-dropdown__content--position-${position}`, {
64
64
  "ids-dropdown__content--mblock": mBlock,
65
65
  "ids-dropdown__content--sblock": sBlock
66
66
  }), ...props, children: enhancedChildren }));
67
67
  };
68
- return (jsxs("span", { className: clsx(`ids-dropdown ids-dropdown--position-${position}`, className, {
68
+ return (jsxs("span", { className: clsx(`ids-dropdown`, className, {
69
69
  "ids-dropdown--mblock": mBlock,
70
70
  "ids-dropdown--sblock": sBlock
71
71
  }), children: [renderTrigger(), isExpanded && renderDropdownContent()] }));
@@ -1,7 +1,8 @@
1
- import React, { ReactNode, InputHTMLAttributes } from "react";
1
+ import { ReactNode, InputHTMLAttributes } from "react";
2
2
  interface IDSCheckButtonProps extends InputHTMLAttributes<HTMLInputElement> {
3
3
  disabled?: boolean;
4
+ focusAnchor?: boolean;
4
5
  children?: ReactNode;
5
6
  }
6
- export declare const IDSCheckButton: React.FC<IDSCheckButtonProps>;
7
+ export declare const IDSCheckButton: import("react").ForwardRefExoticComponent<IDSCheckButtonProps & import("react").RefAttributes<HTMLInputElement>>;
7
8
  export {};
@@ -1,11 +1,17 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
3
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
4
5
  import clsx from 'clsx';
5
6
 
6
- const IDSCheckButton = ({ disabled = false, id, children, className, ...props }) => {
7
+ const IDSCheckButton = forwardRef(({ disabled = false, focusAnchor = false, id, children, className, ...props }, ref) => {
7
8
  const fieldId = useElementId(id);
8
- return (jsxs("div", { className: clsx("ids-check-button", { "ids-check-button--disabled": disabled }, className), children: [jsx("input", { id: fieldId, className: "ids-check-button__input", type: "checkbox", disabled: disabled, ...props }), jsx("label", { htmlFor: fieldId, className: "ids-check-button__label", children: children })] }));
9
- };
9
+ const checkButtonRef = useRef(null);
10
+ useImperativeHandle(ref, () => checkButtonRef.current);
11
+ return (jsxs("div", { className: clsx("ids-check-button", { "ids-check-button--disabled": disabled }, className), children: [jsx("input", { id: fieldId, ref: checkButtonRef, className: clsx("ids-check-button__input", {
12
+ "ids-focus-anchor": focusAnchor
13
+ }), type: "checkbox", disabled: disabled, ...props }), jsx("label", { htmlFor: fieldId, className: "ids-check-button__label", children: children })] }));
14
+ });
15
+ IDSCheckButton.displayName = "IDSCheckButton";
10
16
 
11
17
  export { IDSCheckButton };
@@ -9,9 +9,10 @@ export interface IDSCheckboxProps extends InputHTMLAttributes<HTMLInputElement>
9
9
  light?: boolean;
10
10
  block?: boolean;
11
11
  compact?: boolean;
12
+ focusAnchor?: boolean;
12
13
  errorMsg?: string | ReactNode;
13
14
  groupErrorMsgId?: string;
14
15
  tooltip?: ReactNode;
15
16
  children?: ReactNode;
16
17
  }
17
- export declare const IDSCheckbox: React.FC<IDSCheckboxProps>;
18
+ export declare const IDSCheckbox: React.ForwardRefExoticComponent<IDSCheckboxProps & React.RefAttributes<HTMLInputElement>>;
@@ -1,16 +1,17 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useRef, useEffect } from 'react';
3
+ import { forwardRef, useRef, useEffect } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import { IDSErrorMessage } from '../error-message/error-message.js';
6
6
  import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
7
7
  import { useInputValidity } from '../form-hooks/useInputValidity.js';
8
8
  import clsx from 'clsx';
9
9
 
10
- const IDSCheckbox = ({ invalid = false, disabled = false, required = false, indeterminate = false, noValidation = false, noLabel = false, light = false, block = false, compact = false, errorMsg = "", groupErrorMsgId = "", tooltip, id, children, className, ...props }) => {
10
+ const IDSCheckbox = forwardRef(({ invalid = false, disabled = false, required = false, indeterminate = false, noValidation = false, noLabel = false, light = false, block = false, compact = false, focusAnchor = false, errorMsg = "", groupErrorMsgId = "", tooltip, id, children, className, ...props }, ref) => {
11
+ const internalRef = useRef(null);
12
+ const checkboxRef = ref ?? internalRef;
11
13
  const fieldId = useElementId(id);
12
14
  const errorMsgId = useElementId();
13
- const checkboxRef = useRef(null);
14
15
  const hasValidValue = useInputValidity(checkboxRef);
15
16
  const isInvalid = (invalid || !hasValidValue) && !noValidation;
16
17
  if (groupErrorMsgId) {
@@ -20,13 +21,13 @@ const IDSCheckbox = ({ invalid = false, disabled = false, required = false, inde
20
21
  useAriaDescribedBy(checkboxRef, errorMsgId, isInvalid, !!errorMsg);
21
22
  }
22
23
  useEffect(() => {
23
- if (indeterminate) {
24
+ if (checkboxRef.current) {
24
25
  checkboxRef.current.indeterminate = indeterminate;
25
26
  }
26
27
  }, [checkboxRef, indeterminate]);
27
28
  useEffect(() => {
28
- if (checkboxRef.current) {
29
- const checkboxEl = checkboxRef.current;
29
+ const checkboxEl = checkboxRef.current;
30
+ if (checkboxEl) {
30
31
  const updateAriaChecked = () => {
31
32
  checkboxEl.setAttribute("aria-checked", checkboxEl.indeterminate ? "mixed" : `${checkboxEl.checked}`);
32
33
  };
@@ -41,13 +42,16 @@ const IDSCheckbox = ({ invalid = false, disabled = false, required = false, inde
41
42
  "ids-checkbox--light": light,
42
43
  "ids-checkbox--block": block,
43
44
  "ids-checkbox--compact": compact
44
- }), children: [jsx("input", { id: fieldId, ref: checkboxRef, type: "checkbox", className: "ids-checkbox__input", "aria-invalid": isInvalid, disabled: disabled, "aria-disabled": disabled, required: required, "aria-required": required, ...props }), jsxs("div", { className: clsx("ids-label-tooltip-wrapper", {
45
+ }), children: [jsx("input", { id: fieldId, ref: checkboxRef, type: "checkbox", className: clsx("ids-checkbox__input", {
46
+ "ids-focus-anchor": focusAnchor
47
+ }), "aria-invalid": isInvalid, disabled: disabled, "aria-disabled": disabled, required: required, "aria-required": required, ...props }), jsxs("div", { className: clsx("ids-label-tooltip-wrapper", {
45
48
  "ids-label-tooltip-wrapper--block": block,
46
49
  "ids-label-tooltip-wrapper--inline": tooltip
47
50
  }), children: [jsx("label", { htmlFor: fieldId, className: clsx("ds-checkbox__label", {
48
51
  "ids-label--clickable": disabled,
49
52
  "ids-label--no-label": noLabel
50
53
  }), children: !noLabel && children }), tooltip] })] }), isInvalid && errorMsg && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, compact: true, children: errorMsg }))] }));
51
- };
54
+ });
55
+ IDSCheckbox.displayName = "IDSCheckbox";
52
56
 
53
57
  export { IDSCheckbox };
@@ -9,6 +9,7 @@ interface IDSInputProps extends InputHTMLAttributes<HTMLInputElement> {
9
9
  disabled?: boolean;
10
10
  invalid?: boolean;
11
11
  required?: boolean;
12
+ focusAnchor?: boolean;
12
13
  noValidation?: boolean;
13
14
  autoSize?: boolean;
14
15
  block?: boolean;
@@ -18,5 +19,5 @@ interface IDSInputProps extends InputHTMLAttributes<HTMLInputElement> {
18
19
  submitButton?: ReactNode;
19
20
  oldIcon?: ReactNode;
20
21
  }
21
- export declare const IDSInput: React.FC<IDSInputProps>;
22
+ export declare const IDSInput: React.ForwardRefExoticComponent<IDSInputProps & React.RefAttributes<HTMLInputElement>>;
22
23
  export {};
@@ -1,18 +1,25 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import React__default, { useRef, useEffect } from 'react';
3
+ import React__default, { forwardRef, useRef, useEffect } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import { IDSErrorMessage } from '../error-message/error-message.js';
6
6
  import { useInputValidity } from '../form-hooks/useInputValidity.js';
7
7
  import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
8
8
  import clsx from 'clsx';
9
9
 
10
- const IDSInput = ({ label = "", type = "text", icon = "", hint = "", showSearchLabel = false, errorMsg = "", disabled = false, invalid = false, required = false, noValidation = false, autoSize = false, block = false, light = false, readOnly = false, id, tooltip, submitButton, oldIcon, className, ...props }) => {
10
+ const IDSInput = forwardRef(({ label = "", type = "text", icon = "", hint = "", showSearchLabel = false, errorMsg = "", disabled = false, invalid = false, required = false, noValidation = false, autoSize = false, block = false, light = false, readOnly = false, focusAnchor = false, id, tooltip, submitButton, oldIcon, className, ...props }, ref) => {
11
11
  const fieldId = useElementId(id);
12
12
  const errorMsgId = useElementId();
13
13
  const hintId = useElementId();
14
14
  const oldIconRef = useRef(null);
15
15
  const inputRef = useRef(null);
16
+ const combinedRef = (node) => {
17
+ inputRef.current = node;
18
+ if (typeof ref === "function")
19
+ ref(node);
20
+ else if (ref)
21
+ ref.current = node;
22
+ };
16
23
  const hasValidValue = useInputValidity(inputRef);
17
24
  const isInvalid = (invalid || !hasValidValue) && !noValidation;
18
25
  useAriaDescribedBy(inputRef, errorMsgId, isInvalid, !!errorMsg && !noValidation, !!hint, hintId);
@@ -36,19 +43,19 @@ const IDSInput = ({ label = "", type = "text", icon = "", hint = "", showSearchL
36
43
  iconComponent.setAttribute("color", color);
37
44
  iconComponent.setAttribute("color2", color2);
38
45
  };
39
- const renderOldIcon = oldIcon && React__default.isValidElement(oldIcon)
40
- ? React__default.cloneElement(oldIcon, { ref: oldIconRef })
41
- : oldIcon;
46
+ const renderOldIcon = oldIcon && React__default.isValidElement(oldIcon) ? React__default.cloneElement(oldIcon, { ref: oldIconRef }) : oldIcon;
42
47
  return (jsxs("div", { className: clsx("ids-input-component", className), children: [jsxs("div", { className: "ids-label-tooltip-wrapper", children: [jsx("label", { className: clsx("ids-label", {
43
48
  "ids-label--disabled": disabled || readOnly,
44
49
  "ids-hidden": type === "search" && !showSearchLabel
45
50
  }), "aria-hidden": "false", htmlFor: fieldId, children: label }), tooltip] }), jsxs("div", { className: "ids-input__wrapper", children: [jsxs("div", { className: clsx("ids-input__inner-wrapper", {
46
51
  "ids-input--icon": icon,
47
52
  "ids-input__inner-wrapper--search": type === "search"
48
- }), children: [jsx("input", { ref: inputRef, id: fieldId, type: type, readOnly: readOnly, className: clsx("ids-input", {
53
+ }), children: [jsx("input", { ref: combinedRef, id: fieldId, type: type, readOnly: readOnly, className: clsx("ids-input", {
49
54
  "ids-input--light": light,
50
- "ids-input--invalid": invalid
55
+ "ids-input--invalid": invalid,
56
+ "ids-focus-anchor": focusAnchor
51
57
  }), "aria-invalid": isInvalid, required: required, "aria-required": required, disabled: disabled, "aria-disabled": disabled, ...props }), type === "search" && jsx("span", { className: "ids-input__search-icon" }), icon && jsx("span", { className: `ids-input__icon ids-icon-${icon}` }), oldIcon && jsx("span", { className: "ids-input__icon", children: renderOldIcon })] }), submitButton] }), hint && (jsx("div", { id: hintId, className: "ids-input__hint", children: hint })), isInvalid && errorMsg && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, children: errorMsg }))] }));
52
- };
58
+ });
59
+ IDSInput.displayName = "IDSInput"; // Needed when using forwardRef
53
60
 
54
61
  export { IDSInput };
@@ -10,8 +10,9 @@ export interface IDSRadioProps extends InputHTMLAttributes<HTMLInputElement> {
10
10
  noValidation?: boolean;
11
11
  light?: boolean;
12
12
  compact?: boolean;
13
+ focusAnchor?: boolean;
13
14
  tooltip?: ReactNode;
14
15
  children?: ReactNode;
15
16
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
16
17
  }
17
- export declare const IDSRadio: React.FC<IDSRadioProps>;
18
+ export declare const IDSRadio: React.ForwardRefExoticComponent<IDSRadioProps & React.RefAttributes<HTMLInputElement>>;
@@ -1,26 +1,29 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useRef } from 'react';
3
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import { useInputValidity } from '../form-hooks/useInputValidity.js';
6
6
  import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
7
7
  import clsx from 'clsx';
8
8
 
9
- const IDSRadio = ({ name = "", groupErrorMsgId = "", invalid = false, groupInvalid = false, disabled = false, noValidation = false, light = false, compact = false, tooltip, id, children, className, onChange, ...props }) => {
9
+ const IDSRadio = forwardRef(({ name = "", groupErrorMsgId = "", invalid = false, groupInvalid = false, disabled = false, noValidation = false, light = false, compact = false, focusAnchor = false, tooltip, id, children, className, onChange, ...props }, ref) => {
10
10
  const fieldId = useElementId(id);
11
11
  const radioRef = useRef(null);
12
+ useImperativeHandle(ref, () => radioRef.current);
12
13
  const hasValidValue = useInputValidity(radioRef);
13
14
  const isInvalid = (invalid || groupInvalid || !hasValidValue) && !noValidation;
14
15
  useAriaDescribedBy(radioRef, groupErrorMsgId, isInvalid, !!groupErrorMsgId);
15
16
  return (jsxs("div", { className: clsx("ids-radio", {
16
17
  "ids-radio--compact": compact
17
- }, className), children: [jsx("input", { id: fieldId, ref: radioRef, type: "radio", className: clsx({
18
- "ids-input--light": light
18
+ }, className), children: [jsx("input", { id: fieldId, ref: radioRef, type: "radio", className: clsx("ids-radio__input", {
19
+ "ids-input--light": light,
20
+ "ids-focus-anchor": focusAnchor
19
21
  }), disabled: disabled, "aria-disabled": disabled, "aria-invalid": isInvalid, name: name, onChange: onChange, ...props }), jsxs("div", { className: clsx("ids-label-tooltip-wrapper", {
20
22
  "ids-label-tooltip-wrapper--inline": tooltip
21
23
  }), children: [jsx("label", { htmlFor: fieldId, className: clsx("ids-radio__label ids-label", {
22
24
  "ids-input--clickable": !disabled
23
25
  }), children: children }), tooltip] })] }));
24
- };
26
+ });
27
+ IDSRadio.displayName = "IDSRadio";
25
28
 
26
29
  export { IDSRadio };
@@ -2,8 +2,9 @@ import React, { ReactNode, InputHTMLAttributes } from "react";
2
2
  export interface IDSRadioButtonProps extends InputHTMLAttributes<HTMLInputElement> {
3
3
  name?: string;
4
4
  id?: string;
5
+ focusAnchor?: boolean;
5
6
  icon: string;
6
7
  children?: ReactNode;
7
- onChange?: (e: React.ChangeEvent<HTMLInputElement>) => {};
8
+ onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
8
9
  }
9
- export declare const IDSRadioButton: React.FC<IDSRadioButtonProps>;
10
+ export declare const IDSRadioButton: React.ForwardRefExoticComponent<IDSRadioButtonProps & React.RefAttributes<HTMLInputElement>>;
@@ -1,13 +1,17 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useRef } from 'react';
3
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import clsx from 'clsx';
6
6
 
7
- const IDSRadioButton = ({ name = "", icon = "user", id, children, onChange, className, ...props }) => {
7
+ const IDSRadioButton = forwardRef(({ name = "", icon = "user", focusAnchor = false, id, children, onChange, className, ...props }, ref) => {
8
8
  const fieldId = useElementId(id);
9
- const radioRef = useRef(null);
10
- return (jsxs("div", { className: clsx("ids-radio-button", className), children: [jsx("input", { id: fieldId, ref: radioRef, type: "radio", className: "ids-radio-button__input", name: name, onChange: onChange, ...props }), jsx("label", { htmlFor: fieldId, className: `ids-radio-button__label ids-icon-${icon}`, children: children })] }));
11
- };
9
+ const radioButtonRef = useRef(null);
10
+ useImperativeHandle(ref, () => radioButtonRef.current);
11
+ return (jsxs("div", { className: clsx("ids-radio-button", className), children: [jsx("input", { id: fieldId, ref: radioButtonRef, type: "radio", className: clsx("ids-radio-button__input", {
12
+ "ids-focus-anchor": focusAnchor
13
+ }), name: name, onChange: onChange, ...props }), jsx("label", { htmlFor: fieldId, className: `ids-radio-button__label ids-icon-${icon}`, children: children })] }));
14
+ });
15
+ IDSRadioButton.displayName = "IDSRadioButton";
12
16
 
13
17
  export { IDSRadioButton };
@@ -9,8 +9,9 @@ interface IDSRangeProps extends InputHTMLAttributes<HTMLInputElement> {
9
9
  max?: number;
10
10
  step?: number;
11
11
  disabled?: boolean;
12
+ focusAnchor?: boolean;
12
13
  tooltip?: ReactNode;
13
14
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
14
15
  }
15
- export declare const IDSRange: React.FC<IDSRangeProps>;
16
+ export declare const IDSRange: React.ForwardRefExoticComponent<IDSRangeProps & React.RefAttributes<HTMLInputElement>>;
16
17
  export {};
@@ -1,15 +1,16 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useState, useRef, useEffect } from 'react';
3
+ import { forwardRef, useState, useRef, useImperativeHandle, useEffect } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import '@inera/ids-design/components/form/range/range.css';
6
6
  import clsx from 'clsx';
7
7
 
8
- const IDSRange = ({ label = "", value = 0, showTicks = false, interval = 0, min = 0, max = 0, step = 0, disabled = false, tooltip, id, onChange, className, ...props }) => {
8
+ const IDSRange = forwardRef(({ label = "", value = 0, showTicks = false, interval = 0, min = 0, max = 0, step = 0, disabled = false, focusAnchor = false, tooltip, id, onChange, className, ...props }, ref) => {
9
9
  const [internalValue, setInternalValue] = useState(value);
10
10
  const [ticks, setTicks] = useState([]);
11
11
  const fieldId = useElementId(id);
12
12
  const rangeRef = useRef(null);
13
+ useImperativeHandle(ref, () => rangeRef.current);
13
14
  useEffect(() => {
14
15
  if (step > 0) {
15
16
  const steps = [];
@@ -26,7 +27,10 @@ const IDSRange = ({ label = "", value = 0, showTicks = false, interval = 0, min
26
27
  onChange(ev);
27
28
  }
28
29
  };
29
- return (jsxs("div", { className: clsx("ids-range", className), children: [jsxs("div", { className: "ids-label-tooltip-wrapper", children: [jsx("label", { htmlFor: fieldId, className: `ids-label ${disabled ? "ids-label--disabled" : ""}`, children: label }), tooltip] }), jsx("input", { id: fieldId, ref: rangeRef, type: "range", className: "ids-range__input", min: min, "aria-valuemin": min, max: max, "aria-valuemax": max, step: step, value: internalValue, "aria-valuenow": internalValue, disabled: disabled, style: { backgroundSize: ((internalValue - min) * 100) / (max - min) + "% 100%" }, onChange: handleOnChange, ...props }), showTicks && (jsx("div", { className: `ids-range-ticks ${disabled ? "ids-range-ticks--disabled" : ""}`, children: ticks.map(tick => (jsx("div", { className: "ids-range-tick", children: tick }, tick))) }))] }));
30
- };
30
+ return (jsxs("div", { className: clsx("ids-range", className), children: [jsxs("div", { className: "ids-label-tooltip-wrapper", children: [jsx("label", { htmlFor: fieldId, className: clsx("ids-label", { "ids-label--disabled": disabled }), children: label }), tooltip] }), jsx("input", { id: fieldId, ref: rangeRef, type: "range", className: clsx("ids-range__input", {
31
+ "ids-focus-anchor": focusAnchor
32
+ }), min: min, "aria-valuemin": min, max: max, "aria-valuemax": max, step: step, value: internalValue, "aria-valuenow": internalValue, disabled: disabled, style: { backgroundSize: ((internalValue - min) * 100) / (max - min) + "% 100%" }, onChange: handleOnChange, ...props }), showTicks && (jsx("div", { className: clsx("ids-range-ticks", { "ids-range-ticks--disabled": disabled }), children: ticks.map(tick => (jsx("div", { className: "ids-range-tick", children: tick }, tick))) }))] }));
33
+ });
34
+ IDSRange.displayName = "IDSRange";
31
35
 
32
36
  export { IDSRange };
@@ -7,9 +7,10 @@ interface IDSSelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {
7
7
  required?: boolean;
8
8
  invalid?: boolean;
9
9
  light?: boolean;
10
+ focusAnchor?: boolean;
10
11
  noValidation?: boolean;
11
12
  tooltip?: ReactNode;
12
13
  children?: ReactNode;
13
14
  }
14
- export declare const IDSSelect: React.FC<IDSSelectProps>;
15
+ export declare const IDSSelect: React.ForwardRefExoticComponent<IDSSelectProps & React.RefAttributes<HTMLSelectElement>>;
15
16
  export {};
@@ -1,22 +1,25 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useRef } from 'react';
3
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import { IDSErrorMessage } from '../error-message/error-message.js';
6
6
  import { useInputValidity } from '../form-hooks/useInputValidity.js';
7
7
  import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
8
8
  import clsx from 'clsx';
9
9
 
10
- const IDSSelect = ({ label = "", srOf = "av", errorMsg = "", disabled = false, required = false, invalid = false, light = false, noValidation = false, tooltip, id, children, className, ...props }) => {
10
+ const IDSSelect = forwardRef(({ label = "", srOf = "av", errorMsg = "", disabled = false, required = false, invalid = false, light = false, noValidation = false, focusAnchor = false, tooltip, id, children, className, ...props }, ref) => {
11
11
  const fieldId = useElementId(id);
12
12
  const errorMsgId = useElementId();
13
13
  const selectRef = useRef(null);
14
+ useImperativeHandle(ref, () => selectRef.current);
14
15
  const hasValidValue = useInputValidity(selectRef);
15
16
  const isInvalid = (invalid || !hasValidValue) && !noValidation;
16
17
  useAriaDescribedBy(selectRef, errorMsgId, isInvalid, !!errorMsg);
17
18
  return (jsxs("div", { className: clsx("ids-select-component", className), children: [jsxs("div", { className: "ids-label-tooltip-wrapper", children: [jsx("label", { htmlFor: fieldId, className: "ids-label", children: label }), tooltip] }), jsx("div", { className: "ids-select-wrapper", children: jsx("select", { id: fieldId, ref: selectRef, className: clsx("ids-select", {
18
- "ids-input--light": light
19
+ "ids-input--light": light,
20
+ "ids-focus-anchor": focusAnchor
19
21
  }), "aria-invalid": isInvalid, required: required, disabled: disabled, ...props, children: children }) }), isInvalid && errorMsg && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, children: errorMsg }))] }));
20
- };
22
+ });
23
+ IDSSelect.displayName = "IDSSelect";
21
24
 
22
25
  export { IDSSelect };
@@ -10,6 +10,7 @@ interface IDSSelectMultipleProps extends React.InputHTMLAttributes<HTMLInputElem
10
10
  errorMsg?: string;
11
11
  invalid?: boolean;
12
12
  light?: boolean;
13
+ focusAnchor?: boolean;
13
14
  noValidation?: boolean;
14
15
  tooltip?: ReactNode;
15
16
  children?: ReactNode;
@@ -7,7 +7,7 @@ import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
7
7
  import '@inera/ids-design/components/form/select-multiple/select-multiple.css';
8
8
  import clsx from 'clsx';
9
9
 
10
- const IDSSelectMultiple = ({ label = "", selectedLabel = "vald", selectedLabelPlural = "valda", placeholder = "", maxHeight = "", expanded = false, errorMsg = "", invalid = false, light = false, noValidation = false, tooltip, id, children, className, ...props }) => {
10
+ const IDSSelectMultiple = ({ label = "", selectedLabel = "vald", selectedLabelPlural = "valda", placeholder = "", maxHeight = "", expanded = false, errorMsg = "", invalid = false, light = false, noValidation = false, focusAnchor = false, tooltip, id, children, className, ...props }) => {
11
11
  const [checkboxListInvalid, setCheckboxListInvalid] = useState(false);
12
12
  const [checkedBoxesCount, setCheckedBoxesCount] = useState(0);
13
13
  const [value, setValue] = useState(placeholder);
@@ -52,7 +52,8 @@ const IDSSelectMultiple = ({ label = "", selectedLabel = "vald", selectedLabelPl
52
52
  };
53
53
  }, [isExpanded]);
54
54
  return (jsxs("div", { className: clsx("ids-select-multiple-component", className), children: [jsxs("div", { className: "ids-label-tooltip-wrapper", children: [jsx("label", { id: labelId, htmlFor: inputId, className: "ids-label", children: label }), tooltip] }), jsx("div", { className: "ids-select-multiple-wrapper", children: jsx("input", { id: inputId, "aria-labelledby": labelId, ref: selectMultipleRef, type: "button", className: clsx("ids-select-multiple__select", {
55
- "ids-input--light": light
55
+ "ids-input--light": light,
56
+ "ids-focus-anchor": focusAnchor
56
57
  }), "aria-expanded": isExpanded, "aria-invalid": invalid || checkboxListInvalid, placeholder: placeholder, value: value, onClick: () => setIsExpanded(!isExpanded), ...props }) }), jsx("div", { className: "ids-select-multiple__dropdown__wrapper", children: jsx("div", { className: clsx("ids-select-multiple__dropdown", {
57
58
  "ids-select-multiple__dropdown--show": isExpanded
58
59
  }), children: jsx("div", { className: "ids-select-multiple__dropdown__inner", style: { maxHeight: maxHeight }, children: jsx(IDSCheckboxGroup, { block: true, errorMsg: errorMsg, setCheckedBoxesCount: setCheckedBoxesCount, onValidityChange: (isValid) => {
@@ -1,4 +1,4 @@
1
- import React, { ReactNode, TextareaHTMLAttributes } from "react";
1
+ import { ReactNode, TextareaHTMLAttributes } from "react";
2
2
  interface IDSTextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
3
3
  label?: string;
4
4
  hint?: string | ReactNode;
@@ -11,8 +11,9 @@ interface IDSTextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
11
11
  noResize?: boolean;
12
12
  block?: boolean;
13
13
  light?: boolean;
14
+ focusAnchor?: boolean;
14
15
  readOnly?: boolean;
15
16
  tooltip?: ReactNode;
16
17
  }
17
- export declare const IDSTextarea: React.FC<IDSTextareaProps>;
18
+ export declare const IDSTextarea: import("react").ForwardRefExoticComponent<IDSTextareaProps & import("react").RefAttributes<HTMLTextAreaElement>>;
18
19
  export {};
@@ -1,17 +1,18 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useRef } from 'react';
3
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import { IDSErrorMessage } from '../error-message/error-message.js';
6
6
  import { useInputValidity } from '../form-hooks/useInputValidity.js';
7
7
  import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
8
8
  import clsx from 'clsx';
9
9
 
10
- const IDSTextarea = ({ label = "", hint, errorMsg = "", disabled = false, invalid = false, required = false, noValidation = false, autoSize = false, noResize = false, block = false, light = false, readOnly = false, id, tooltip, className, ...props }) => {
10
+ const IDSTextarea = forwardRef(({ label = "", hint, errorMsg = "", disabled = false, invalid = false, required = false, noValidation = false, autoSize = false, noResize = false, block = false, light = false, readOnly = false, focusAnchor = false, id, tooltip, className, ...props }, ref) => {
11
11
  const fieldId = useElementId(id);
12
12
  const errorMsgId = useElementId();
13
13
  const hintId = useElementId();
14
14
  const textareaRef = useRef(null);
15
+ useImperativeHandle(ref, () => textareaRef.current);
15
16
  const hasValidValue = useInputValidity(textareaRef);
16
17
  const isInvalid = (invalid || !hasValidValue) && !noValidation;
17
18
  useAriaDescribedBy(textareaRef, errorMsgId, isInvalid, !!errorMsg, !!hint, hintId);
@@ -22,8 +23,10 @@ const IDSTextarea = ({ label = "", hint, errorMsg = "", disabled = false, invali
22
23
  }, className), children: [jsxs("div", { className: "ids-label-tooltip-wrapper", children: [jsx("label", { className: clsx("ids-label", {
23
24
  "ids-label--disabled": disabled || readOnly
24
25
  }), htmlFor: fieldId, children: label }), tooltip && tooltip] }), jsx("textarea", { ref: textareaRef, id: fieldId, className: clsx("ids-textarea__textarea", {
25
- "ids-input--light": light
26
+ "ids-input--light": light,
27
+ "ids-focus-anchor": focusAnchor
26
28
  }), "aria-invalid": isInvalid, required: required, "aria-required": required, disabled: disabled, "aria-disabled": disabled, readOnly: readOnly, ...props }), hint && (jsx("div", { id: hintId, className: "ids-input__hint", children: hint })), isInvalid && errorMsg && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, children: errorMsg }))] }));
27
- };
29
+ });
30
+ IDSTextarea.displayName = "IDSTextarea";
28
31
 
29
32
  export { IDSTextarea };
@@ -1,4 +1,4 @@
1
- import React, { ReactNode, InputHTMLAttributes } from "react";
1
+ import { ReactNode, InputHTMLAttributes } from "react";
2
2
  interface IDSTimeProps extends InputHTMLAttributes<HTMLInputElement> {
3
3
  label?: string;
4
4
  errorMsg?: string;
@@ -6,8 +6,9 @@ interface IDSTimeProps extends InputHTMLAttributes<HTMLInputElement> {
6
6
  invalid?: boolean;
7
7
  required?: boolean;
8
8
  noValidation?: boolean;
9
+ focusAnchor?: boolean;
9
10
  light?: boolean;
10
11
  tooltip?: ReactNode;
11
12
  }
12
- export declare const IDSTime: React.FC<IDSTimeProps>;
13
+ export declare const IDSTime: import("react").ForwardRefExoticComponent<IDSTimeProps & import("react").RefAttributes<HTMLInputElement>>;
13
14
  export {};
@@ -1,24 +1,27 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useRef } from 'react';
3
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import { IDSErrorMessage } from '../error-message/error-message.js';
6
6
  import { useInputValidity } from '../form-hooks/useInputValidity.js';
7
7
  import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
8
8
  import clsx from 'clsx';
9
9
 
10
- const IDSTime = ({ label = "", errorMsg = "", disabled = false, invalid = false, required = false, noValidation = false, light = false, id, tooltip, className, ...props }) => {
10
+ const IDSTime = forwardRef(({ label = "", errorMsg = "", disabled = false, invalid = false, required = false, noValidation = false, light = false, focusAnchor = false, id, tooltip, className, ...props }, ref) => {
11
11
  const fieldId = useElementId(id);
12
12
  const errorMsgId = useElementId();
13
- const timeRef = useRef(null);
14
- const hasValidValue = useInputValidity(timeRef); // can this happen? i cannot enter an invalid value when i try
13
+ const inputRef = useRef(null);
14
+ useImperativeHandle(ref, () => inputRef.current);
15
+ const hasValidValue = useInputValidity(inputRef);
15
16
  const isInvalid = (invalid || !hasValidValue) && !noValidation;
16
- useAriaDescribedBy(timeRef, errorMsgId, isInvalid, !!errorMsg);
17
+ useAriaDescribedBy(inputRef, errorMsgId, isInvalid, !!errorMsg);
17
18
  return (jsxs("div", { className: clsx("ids-time-component", className), children: [jsxs("div", { className: "ids-label-tooltip-wrapper", children: [jsx("label", { className: clsx("ids-label", {
18
19
  "ids-label--disabled": disabled
19
- }), htmlFor: fieldId, children: label }), tooltip] }), jsx("div", { className: "ids-time", children: jsx("div", { className: "ids-time__input-wrapper", children: jsx("input", { ref: timeRef, id: fieldId, type: "time", className: clsx("ids-time__input", {
20
- "ids-input--light": light
20
+ }), htmlFor: fieldId, children: label }), tooltip] }), jsx("div", { className: "ids-time", children: jsx("div", { className: "ids-time__input-wrapper", children: jsx("input", { ref: inputRef, id: fieldId, type: "time", className: clsx("ids-time__input", {
21
+ "ids-input--light": light,
22
+ "ids-focus-anchor": focusAnchor
21
23
  }), "aria-invalid": isInvalid, required: required, "aria-required": required, disabled: disabled, "aria-disabled": disabled, ...props }) }) }), isInvalid && errorMsg && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, children: errorMsg }))] }));
22
- };
24
+ });
25
+ IDSTime.displayName = "IDSTime";
23
26
 
24
27
  export { IDSTime };
@@ -1,8 +1,9 @@
1
- import React, { ReactNode, InputHTMLAttributes } from "react";
1
+ import { ReactNode, InputHTMLAttributes } from "react";
2
2
  interface IDSToggleProps extends InputHTMLAttributes<HTMLInputElement> {
3
3
  disabled?: boolean;
4
4
  tooltip?: ReactNode;
5
+ focusAnchor?: boolean;
5
6
  children?: ReactNode;
6
7
  }
7
- export declare const IDSToggle: React.FC<IDSToggleProps>;
8
+ export declare const IDSToggle: import("react").ForwardRefExoticComponent<IDSToggleProps & import("react").RefAttributes<HTMLInputElement>>;
8
9
  export {};
@@ -1,13 +1,17 @@
1
1
  "use client";
2
2
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
- import { useRef } from 'react';
3
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
4
4
  import { useElementId } from '../../utils/hooks/useElementId.js';
5
5
  import clsx from 'clsx';
6
6
 
7
- const IDSToggle = ({ disabled = false, tooltip, id, children, className, ...props }) => {
7
+ const IDSToggle = forwardRef(({ disabled = false, focusAnchor = false, tooltip, id, children, className, ...props }, ref) => {
8
8
  const fieldId = useElementId(id);
9
9
  const toggleRef = useRef(null);
10
- return (jsx(Fragment, { children: jsxs("div", { className: clsx("ids-toggle", className), children: [jsx("input", { id: fieldId, ref: toggleRef, className: "ids-toggle__input", type: "checkbox", disabled: disabled, ...props }), jsxs("div", { className: "ids-label-tooltip-wrapper ids-label-tooltip-wrapper--inline", children: [jsx("label", { htmlFor: fieldId, className: "ids-toggle__label ids-label ids-label--clickable", children: children }), tooltip] })] }) }));
11
- };
10
+ useImperativeHandle(ref, () => toggleRef.current);
11
+ return (jsx(Fragment, { children: jsxs("div", { className: clsx("ids-toggle", className), children: [jsx("input", { id: fieldId, ref: toggleRef, className: clsx("ids-toggle__input", {
12
+ "ids-focus-anchor": focusAnchor
13
+ }), type: "checkbox", disabled: disabled, ...props }), jsxs("div", { className: "ids-label-tooltip-wrapper ids-label-tooltip-wrapper--inline", children: [jsx("label", { htmlFor: fieldId, className: "ids-toggle__label ids-label ids-label--clickable", children: children }), tooltip] })] }) }));
14
+ });
15
+ IDSToggle.displayName = "IDSToggle";
12
16
 
13
17
  export { IDSToggle };
@@ -6,27 +6,40 @@ import clsx from 'clsx';
6
6
  import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
7
7
 
8
8
  const IDSHeader1177Avatar = ({ username, agent, links, persistent = false }) => {
9
- const [expanded, setExpanded] = useState(false);
9
+ const [isExpanded, setIsExpanded] = useState(false);
10
10
  const headerContext = useHeaderContext();
11
- const avatarRef = useRef(null);
12
- const toggleExpanded = () => setExpanded(prev => !prev);
11
+ const containerRef = useRef(null);
12
+ const dropdownRef = useRef(null);
13
+ const toggleExpanded = () => setIsExpanded(prev => !prev);
13
14
  const handleClickOutside = (event) => {
14
- if (!persistent && avatarRef.current && !avatarRef.current.contains(event.target)) {
15
- setExpanded(false);
15
+ if (!persistent && containerRef.current && !containerRef.current.contains(event.target)) {
16
+ setIsExpanded(false);
16
17
  }
17
18
  };
18
19
  useEffect(() => {
19
- document.addEventListener("click", handleClickOutside);
20
+ document.addEventListener("mousedown", handleClickOutside);
20
21
  return () => {
21
- document.removeEventListener("click", handleClickOutside);
22
+ document.removeEventListener("mousedown", handleClickOutside);
22
23
  };
23
24
  }, [persistent]);
24
- return (jsx("div", { ref: avatarRef, className: clsx("ids-header-1177-avatar", {
25
+ const handleLinkClick = () => {
26
+ setIsExpanded(false);
27
+ };
28
+ useEffect(() => {
29
+ if (!persistent && isExpanded) {
30
+ const links = dropdownRef.current?.querySelectorAll("a") || [];
31
+ links.forEach(link => link.addEventListener("click", handleLinkClick));
32
+ return () => {
33
+ links.forEach(link => link.removeEventListener("click", handleLinkClick));
34
+ };
35
+ }
36
+ }, [isExpanded, persistent]);
37
+ return (jsx("div", { ref: containerRef, className: clsx("ids-header-1177-avatar", {
25
38
  "ids-header-1177-avatar--unresponsive": headerContext?.unresponsive
26
39
  }), children: jsxs("div", { className: "ids-header-1177-avatar__dropdown-wrapper", children: [jsx("button", { className: clsx("ids-header-1177-avatar__button", {
27
- "ids-header-1177-avatar__button--expanded": expanded
28
- }), onClick: toggleExpanded, "aria-controls": "ids-header-1177-avatar__dropdown", "aria-expanded": expanded, children: jsx("div", { className: "ids-header-1177-avatar-content__name", title: username, children: username }) }), jsxs("div", { id: "ids-header-1177-avatar__dropdown", className: clsx("ids-header-1177-avatar__dropdown", {
29
- "ids-header-1177-avatar__dropdown--expanded": expanded
40
+ "ids-header-1177-avatar__button--expanded": isExpanded
41
+ }), onClick: toggleExpanded, "aria-controls": "ids-header-1177-avatar__dropdown", "aria-expanded": isExpanded, children: jsx("div", { className: "ids-header-1177-avatar-content__name", title: username, children: username }) }), jsxs("div", { ref: dropdownRef, id: "ids-header-1177-avatar__dropdown", className: clsx("ids-header-1177-avatar__dropdown", {
42
+ "ids-header-1177-avatar__dropdown--expanded": isExpanded
30
43
  }), children: [agent && jsx("div", { className: "ids-header-1177-avatar__agent", children: agent }), agent && links && jsx("div", { className: "ids-header-1177-avatar__menu-separator" }), links && jsx("div", { className: "ids-header-1177-avatar__menu-links", children: links })] })] }) }));
31
44
  };
32
45
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import React__default, { useState } from 'react';
3
+ import React__default, { useState, useRef, useEffect } from 'react';
4
4
  import '@inera/ids-design/components/header-1177/header-1177-nav-item.css';
5
5
  import clsx from 'clsx';
6
6
  import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
@@ -8,18 +8,35 @@ import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
8
8
  const IDSHeader1177NavItem = ({ active = false, expanded = false, label = "", col1, col2, col3, col4, children }) => {
9
9
  const [isExpanded, setIsExpanded] = useState(expanded);
10
10
  const headerContext = useHeaderContext();
11
- const toggleExpanded = () => setIsExpanded(prev => !prev);
11
+ const containerRef = useRef(null);
12
+ const handleClickOutside = (event) => {
13
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
14
+ setIsExpanded(false);
15
+ }
16
+ };
17
+ useEffect(() => {
18
+ setIsExpanded(expanded);
19
+ document.addEventListener("click", handleClickOutside);
20
+ return () => {
21
+ document.removeEventListener("click", handleClickOutside);
22
+ };
23
+ }, [expanded]);
12
24
  const renderLink = (link) => {
13
25
  return React__default.isValidElement(link)
14
- ? React__default.cloneElement(link, { activeIcon: true, block: true, colorPreset: 2 })
26
+ ? React__default.cloneElement(link, {
27
+ activeIcon: true,
28
+ block: true,
29
+ colorPreset: 2,
30
+ onClick: () => setIsExpanded(false)
31
+ })
15
32
  : link;
16
33
  };
17
34
  const renderDropdown = () => isExpanded && (jsx("div", { id: "ids-header-1177-nav-dropdown", className: "ids-header-1177__items__item-dropdown", children: jsxs("div", { className: "ids-header-1177__items__item-dropdown__content", children: [jsx("div", { className: "ids-header-1177__items__item-dropdown__content-col-1", children: col1?.map((link, idx) => (jsx("div", { className: "ids-header-1177__items-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177__items__item-dropdown__content-col-2", children: col2?.map((link, idx) => (jsx("div", { className: "ids-header-1177__items-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177__items__item-dropdown__content-col-3", children: col3?.map((link, idx) => (jsx("div", { className: "ids-header-1177__items-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177__items__item-dropdown__content-col-4", children: col4 })] }) }));
18
- return (jsxs("div", { className: clsx("ids-header-1177__nav-item", {
35
+ return (jsxs("div", { ref: containerRef, className: clsx("ids-header-1177__nav-item", {
19
36
  "ids-header-1177__nav-item--unresponsive": headerContext?.unresponsive,
20
37
  "ids-header-1177__nav-item--fluid": headerContext?.fluid,
21
38
  "ids-header-1177__nav-item--active": active || isExpanded
22
- }), children: [label ? (jsx("button", { onClick: toggleExpanded, "aria-expanded": isExpanded, "aria-controls": "ids-header-1177-nav-dropdown", children: label })) : (children), renderDropdown()] }));
39
+ }), children: [label ? (jsx("button", { onClick: () => setIsExpanded(prev => !prev), "aria-expanded": isExpanded, "aria-controls": "ids-header-1177-nav-dropdown", children: label })) : (children), renderDropdown()] }));
23
40
  };
24
41
 
25
42
  export { IDSHeader1177NavItem };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import React__default, { useState } from 'react';
3
+ import React__default, { useState, useRef, useEffect } from 'react';
4
4
  import '@inera/ids-design/components/header-1177-admin/header-1177-admin-nav-item.css';
5
5
  import clsx from 'clsx';
6
6
  import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
@@ -8,20 +8,35 @@ import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
8
8
  const IDSHeader1177AdminNavItem = ({ active = false, expanded = false, label = "", col1, col2, col3, col4, children }) => {
9
9
  const headerContext = useHeaderContext();
10
10
  const [isExpanded, setIsExpanded] = useState(expanded);
11
- const toggleExpanded = () => {
12
- setIsExpanded(prev => !prev);
11
+ const containerRef = useRef(null);
12
+ const handleClickOutside = (event) => {
13
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
14
+ setIsExpanded(false);
15
+ }
13
16
  };
17
+ useEffect(() => {
18
+ setIsExpanded(expanded);
19
+ document.addEventListener("click", handleClickOutside);
20
+ return () => {
21
+ document.removeEventListener("click", handleClickOutside);
22
+ };
23
+ }, [expanded]);
14
24
  const renderLink = (link) => {
15
25
  return React__default.isValidElement(link)
16
- ? React__default.cloneElement(link, { activeIcon: true, block: true, colorPreset: 1 })
26
+ ? React__default.cloneElement(link, {
27
+ activeIcon: true,
28
+ block: true,
29
+ colorPreset: 1,
30
+ onClick: () => setIsExpanded(false)
31
+ })
17
32
  : link;
18
33
  };
19
34
  const renderDropdown = () => isExpanded && (jsx("div", { style: { marginTop: "0.125rem" }, id: "ids-header-1177-admin-nav-dropdown", className: "ids-header-1177-admin__items__item-dropdown", children: jsxs("div", { className: "ids-header-1177-admin__items__item-dropdown__content", children: [jsx("div", { className: "ids-header-1177-admin__items__item-dropdown__content-col-1", children: col1?.map((link, idx) => (jsx("div", { className: "ids-header-1177-admin__items-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177-admin__items__item-dropdown__content-col-2", children: col2?.map((link, idx) => (jsx("div", { className: "ids-header-1177-admin__items-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177-admin__items__item-dropdown__content-col-3", children: col3?.map((link, idx) => (jsx("div", { className: "ids-header-1177-admin__items-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177-admin__items__item-dropdown__content-col-4", children: col4?.map((link, idx) => (jsx("div", { className: "ids-header-1177-admin__items-wrapper", children: renderLink(link) }, idx))) })] }) }));
20
- return (jsxs("div", { className: clsx("ids-header-1177-admin__nav-item", {
35
+ return (jsxs("div", { ref: containerRef, className: clsx("ids-header-1177-admin__nav-item", {
21
36
  "ids-header-1177-admin__nav-item--fluid": headerContext?.fluid,
22
37
  "ids-header-1177-admin__nav-item--unresponsive": headerContext?.unresponsive,
23
38
  "ids-header-1177-admin__nav-item--active": active || isExpanded
24
- }), children: [label ? (jsx("button", { onClick: toggleExpanded, "aria-expanded": isExpanded, "aria-controls": "ids-header-1177-admin-nav-dropdown", children: label })) : (children), renderDropdown()] }));
39
+ }), children: [label ? (jsx("button", { onClick: () => setIsExpanded(prev => !prev), "aria-expanded": isExpanded, "aria-controls": "ids-header-1177-admin-nav-dropdown", children: label })) : (children), renderDropdown()] }));
25
40
  };
26
41
 
27
42
  export { IDSHeader1177AdminNavItem };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import React__default, { useState } from 'react';
3
+ import React__default, { useState, useRef, useEffect } from 'react';
4
4
  import '@inera/ids-design/components/header-1177-pro/header-1177-pro-nav-item.css';
5
5
  import clsx from 'clsx';
6
6
  import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
@@ -8,18 +8,33 @@ import { useHeaderContext } from '../utils/contexts/HeaderContext.js';
8
8
  const IDSHeader1177ProNavItem = ({ active = false, expanded = false, label = "", col1, col2, col3, col4, children }) => {
9
9
  const headerContext = useHeaderContext();
10
10
  const [isExpanded, setIsExpanded] = useState(expanded);
11
- const toggleExpanded = () => {
12
- setIsExpanded(prev => !prev);
11
+ const containerRef = useRef(null);
12
+ const handleClickOutside = (event) => {
13
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
14
+ setIsExpanded(false);
15
+ }
13
16
  };
17
+ useEffect(() => {
18
+ setIsExpanded(expanded);
19
+ document.addEventListener("click", handleClickOutside);
20
+ return () => {
21
+ document.removeEventListener("click", handleClickOutside);
22
+ };
23
+ }, [expanded]);
14
24
  const renderItem = () => {
15
25
  if (label) {
16
- return (jsx("button", { onClick: toggleExpanded, "aria-expanded": isExpanded, "aria-controls": "ids-dropdown", children: label }));
26
+ return (jsx("button", { onClick: () => setIsExpanded(prev => !prev), "aria-expanded": isExpanded, "aria-controls": "ids-dropdown", children: label }));
17
27
  }
18
28
  return children;
19
29
  };
20
30
  const renderLink = (link) => {
21
31
  return React__default.isValidElement(link)
22
- ? React__default.cloneElement(link, { activeIcon: true, block: true, colorPreset: 1 })
32
+ ? React__default.cloneElement(link, {
33
+ activeIcon: true,
34
+ block: true,
35
+ colorPreset: 1,
36
+ onClick: () => setIsExpanded(false)
37
+ })
23
38
  : link;
24
39
  };
25
40
  const renderDropdown = () => {
@@ -27,7 +42,7 @@ const IDSHeader1177ProNavItem = ({ active = false, expanded = false, label = "",
27
42
  return null;
28
43
  return (jsx("div", { id: "ids-dropdown", className: "ids-header-1177-pro__items__item-dropdown", children: jsxs("div", { className: "ids-header-1177-pro__items__item-dropdown__content", children: [jsx("div", { className: "ids-header-1177-pro__items__item-dropdown__content-col-1", children: col1?.map((link, idx) => (jsx("div", { className: "ids-header-1177-pro__item-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177-pro__items__item-dropdown__content-col-2", children: col2?.map((link, idx) => (jsx("div", { className: "ids-header-1177-pro__item-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177-pro__items__item-dropdown__content-col-3", children: col3?.map((link, idx) => (jsx("div", { className: "ids-header-1177-pro__item-wrapper", children: renderLink(link) }, idx))) }), jsx("div", { className: "ids-header-1177-pro__items__item-dropdown__content-col-4", children: col4?.map((link, idx) => (jsx("div", { className: "ids-header-1177-pro__item-wrapper", children: renderLink(link) }, idx))) })] }) }));
29
44
  };
30
- return (jsxs("div", { className: clsx("ids-header-1177-pro__nav-item", {
45
+ return (jsxs("div", { ref: containerRef, className: clsx("ids-header-1177-pro__nav-item", {
31
46
  "ids-header-1177-pro__nav-item--unresponsive": headerContext?.unresponsive,
32
47
  "ids-header-1177-pro__nav-item--active": active || isExpanded
33
48
  }), children: [renderItem(), renderDropdown()] }));
@@ -38,7 +38,12 @@ const IDSHeaderIneraNavItem = ({ label = "", active = false, expanded = false, n
38
38
  };
39
39
  const renderLink = (link) => {
40
40
  return React__default.isValidElement(link)
41
- ? React__default.cloneElement(link, { activeIcon: true, block: true, colorPreset: 2 })
41
+ ? React__default.cloneElement(link, {
42
+ activeIcon: true,
43
+ block: true,
44
+ colorPreset: 2,
45
+ onClick: () => setIsExpanded(false)
46
+ })
42
47
  : link;
43
48
  };
44
49
  const renderContent = () => {
@@ -38,7 +38,12 @@ const IDSHeaderIneraAdminNavItem = ({ label = "", active = false, expanded = fal
38
38
  };
39
39
  const renderLink = (link) => {
40
40
  return React__default.isValidElement(link)
41
- ? React__default.cloneElement(link, { activeIcon: true, block: true, colorPreset: 2 })
41
+ ? React__default.cloneElement(link, {
42
+ activeIcon: true,
43
+ block: true,
44
+ colorPreset: 2,
45
+ onClick: () => setIsExpanded(false)
46
+ })
42
47
  : link;
43
48
  };
44
49
  const renderContent = () => {
@@ -1,6 +1,6 @@
1
- import React, { ReactNode, HTMLAttributes, ReactElement } from "react";
1
+ import React, { ReactNode, ReactElement, AnchorHTMLAttributes } from "react";
2
2
  export type ColorPreset = 0 | 1 | 2 | 3 | 4;
3
- export interface IDSLinkProps extends Omit<HTMLAttributes<HTMLElement>, "children"> {
3
+ export interface IDSLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "children"> {
4
4
  colorPreset?: ColorPreset;
5
5
  light?: boolean;
6
6
  active?: boolean;
@@ -12,6 +12,6 @@ export interface IDSLinkProps extends Omit<HTMLAttributes<HTMLElement>, "childre
12
12
  large?: boolean;
13
13
  focusAnchor?: boolean;
14
14
  endItem?: ReactNode;
15
- children: ReactElement;
15
+ children?: ReactElement;
16
16
  }
17
17
  export declare const IDSLink: React.FC<IDSLinkProps>;
@@ -2,6 +2,7 @@ import React, { ReactNode } from "react";
2
2
  import "@inera/ids-design/components/puff-list/puff-list.css";
3
3
  interface IDSPuffListItemProps extends React.HTMLAttributes<HTMLDivElement> {
4
4
  headline?: ReactNode;
5
+ headlineLevel?: 2 | 3 | 4 | 5;
5
6
  headlineLink?: React.ReactElement;
6
7
  itemLink?: React.ReactElement;
7
8
  date?: Date | null;
@@ -11,6 +12,7 @@ interface IDSPuffListItemProps extends React.HTMLAttributes<HTMLDivElement> {
11
12
  day?: number;
12
13
  time?: string;
13
14
  noContent?: boolean;
15
+ noMargin?: boolean;
14
16
  dateLabel?: ReactNode;
15
17
  children?: ReactNode;
16
18
  }
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import { useState, useEffect, isValidElement, cloneElement } from 'react';
3
+ import React__default, { useState, useEffect, isValidElement, cloneElement } from 'react';
4
4
  import '@inera/ids-design/components/puff-list/puff-list.css';
5
5
  import { getMonthAsSweText, getDayAsText } from '../../utils/utils.js';
6
6
  import clsx from 'clsx';
7
7
 
8
- const IDSPuffListItem = ({ headline = "", headlineLink, itemLink, date = null, year = "", month = -1, monthLabel = "", day = -1, time = "", noContent = false, dateLabel, className, children }) => {
8
+ const IDSPuffListItem = ({ headline = "", headlineLevel = 2, headlineLink, itemLink, date = null, year = "", month = -1, monthLabel = "", day = -1, time = "", noContent = false, noMargin = false, dateLabel, className, children }) => {
9
9
  const [presentedDate, setPresentedDate] = useState(date);
10
10
  useEffect(() => {
11
11
  if (date) {
@@ -27,23 +27,23 @@ const IDSPuffListItem = ({ headline = "", headlineLink, itemLink, date = null, y
27
27
  }
28
28
  return "";
29
29
  };
30
- const getHeaderClass = (noContent) => clsx("ids-puff-list-item__header", {
31
- "ids-puff-list-item--no-margin": noContent
30
+ const getHeaderClass = (noMargin) => clsx("ids-puff-list-item__header", {
31
+ "ids-puff-list-item--no-margin": noMargin
32
32
  });
33
33
  const renderHeadline = () => {
34
+ const level = [2, 3, 4, 5].includes(headlineLevel) ? headlineLevel : 2;
35
+ const Tag = `h${level}`;
34
36
  const headlineContent = jsx(Fragment, { children: headline });
35
37
  if (headlineLink && isValidElement(headlineLink)) {
36
- return (jsx("h2", { className: getHeaderClass(noContent), children: cloneElement(headlineLink, {
37
- ...headlineLink.props,
38
- children: headlineContent
39
- }) }));
38
+ return React__default.createElement(Tag, { className: getHeaderClass(noMargin) }, cloneElement(headlineLink, {
39
+ ...headlineLink.props,
40
+ children: headlineContent
41
+ }));
40
42
  }
41
- return jsx("h2", { className: getHeaderClass(noContent), children: headline });
43
+ return React__default.createElement(Tag, { className: getHeaderClass(noMargin) }, headline);
42
44
  };
43
45
  const renderBody = () => {
44
- if (noContent)
45
- return null;
46
- const content = (jsxs(Fragment, { children: [renderHeadline(), jsx("div", { className: "ids-puff-list-item__body", children: children })] }));
46
+ const content = (jsxs(Fragment, { children: [renderHeadline(), !noContent && jsx("div", { className: "ids-puff-list-item__body", children: children })] }));
47
47
  if (itemLink && isValidElement(itemLink)) {
48
48
  return cloneElement(itemLink, {
49
49
  ...itemLink.props,
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@inera/ids-react",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "type": "module",
5
5
  "peerDependencies": {
6
6
  "react": "*"
7
7
  },
8
8
  "dependencies": {
9
- "@inera/ids-core": "7.0.x",
9
+ "@inera/ids-core": "7.1.x",
10
10
  "@lit-labs/react": "^1.1.0",
11
11
  "clsx": "*"
12
12
  },