@helsenorge/designsystem-react 12.1.0 → 12.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/HighlightPanel.js +23 -3
  3. package/HighlightPanel.js.map +1 -1
  4. package/LazyIcon.js +1 -1
  5. package/LazyIcon.js.map +1 -1
  6. package/components/ExpanderHierarchy/Expander.d.ts +2 -0
  7. package/components/ExpanderHierarchy/index.js +3 -2
  8. package/components/ExpanderHierarchy/index.js.map +1 -1
  9. package/components/HelpPanel/HelpPanel.d.ts +3 -0
  10. package/components/HelpPanel/index.js +12 -2
  11. package/components/HelpPanel/index.js.map +1 -1
  12. package/components/HighlightPanel/HighlightPanel.d.ts +3 -0
  13. package/components/HighlightPanel/styles.module.scss +26 -4
  14. package/components/HighlightPanel/styles.module.scss.d.ts +4 -0
  15. package/components/Icons/AdditionalIconInformation.d.ts +8 -0
  16. package/components/Icons/AdditionalIconInformation.js +3 -1
  17. package/components/Icons/AdditionalIconInformation.js.map +1 -1
  18. package/components/Icons/Drag.d.ts +4 -0
  19. package/components/Icons/Drag.js +11 -0
  20. package/components/Icons/Drag.js.map +1 -0
  21. package/components/Icons/Edit.d.ts +4 -0
  22. package/components/Icons/Edit.js +31 -0
  23. package/components/Icons/Edit.js.map +1 -0
  24. package/components/Icons/IconNames.d.ts +1 -1
  25. package/components/Icons/IconNames.js +2 -0
  26. package/components/Icons/IconNames.js.map +1 -1
  27. package/components/Toggle/Toggle.d.ts +6 -0
  28. package/components/Toggle/index.js +52 -59
  29. package/components/Toggle/index.js.map +1 -1
  30. package/components/Toggle/styles.module.scss +47 -28
  31. package/components/Toggle/styles.module.scss.d.ts +6 -2
  32. package/components/Validation/Validation.d.ts +2 -0
  33. package/components/Validation/ValidationSummary.d.ts +2 -0
  34. package/components/Validation/index.js +6 -2
  35. package/components/Validation/index.js.map +1 -1
  36. package/components/Validation/styles.module.scss +5 -0
  37. package/components/Validation/styles.module.scss.d.ts +1 -0
  38. package/docs/FormExample/FormExample.d.ts +1 -0
  39. package/hooks/useReturnFocusOnUnmount.js +2 -1
  40. package/hooks/useReturnFocusOnUnmount.js.map +1 -1
  41. package/package.json +1 -1
  42. package/utils/deepContains.d.ts +9 -0
  43. package/utils/deepContains.js +19 -0
  44. package/utils/deepContains.js.map +1 -0
  45. package/utils/tests/deepContains.test.d.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/Toggle/Toggle.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\n\nimport classNames from 'classnames';\nimport { useAnimate } from 'motion/react';\n\nimport { AnalyticsId } from '../../constants';\nimport { usePseudoClasses } from '../../hooks/usePseudoClasses';\nimport { useUuid } from '../../hooks/useUuid';\n\nimport styles from './styles.module.scss';\nimport '../../scss/supernova/styles/colors.css';\n\nexport type LabelText = {\n text: string;\n type?: 'subdued' | 'normal';\n};\n\nexport enum TogglePosition {\n left = 'left',\n right = 'right',\n}\n\nexport enum ToggleOnColor {\n onwhite = 'onwhite',\n onneutral = 'onneutral',\n onblueberry = 'onblueberry',\n}\n\nexport interface ToggleProps extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {\n /** Determines if the Toggle is checked */\n checked?: boolean;\n /** Sets the label of the Toggle */\n label: LabelText[];\n /** Defines the color of the toggle */\n onColor?: keyof typeof ToggleOnColor;\n /** Sets the sublabel of the Toggle */\n subLabel?: string;\n /** Sets the position of the toggle relative to the label */\n togglePosition?: keyof typeof TogglePosition;\n /** Sets the data-testid attribute. */\n testId?: string;\n}\n\nconst Toggle: React.FC<ToggleProps> = ({\n checked = false,\n label,\n onChange,\n onColor = ToggleOnColor.onwhite,\n subLabel,\n togglePosition = TogglePosition.left,\n testId,\n}: ToggleProps) => {\n const [checkedState, setCheckedState] = useState(checked);\n const [showToggleAnimation, setShowToggleAnimation] = useState(false);\n const [scope, animate] = useAnimate();\n const inputId = useUuid();\n const toggleId = useUuid();\n const toggleDotId = useUuid();\n const labelId = useUuid();\n const subLabelId = useUuid();\n const { refObject, isHovered, isActive } = usePseudoClasses<HTMLLabelElement>(scope);\n const showHoveredStyling = isHovered && !showToggleAnimation;\n const isOnWhite = onColor === ToggleOnColor.onwhite;\n\n useEffect(() => {\n if (showToggleAnimation) {\n const timer = setTimeout(() => setShowToggleAnimation(false), 300);\n return (): void => clearTimeout(timer);\n }\n }, [showToggleAnimation]);\n\n useEffect(() => {\n setCheckedState(checked);\n }, [checked]);\n\n useEffect(() => {\n animate('#' + toggleId, { background: getBackgroundColor() }, { duration: 0.2, ease: 'easeInOut' });\n animate(\n '#' + toggleDotId,\n { background: checkedState ? 'var(--color-action-graphics-ondark)' : 'var(--core-color-neutral-700)' },\n { duration: 0.2, ease: 'easeInOut' }\n );\n animate('#' + toggleDotId, { x: showHoveredStyling ? 9 : checkedState ? 18 : 0 }, { duration: 0.2, ease: 'easeInOut' });\n animate('svg', { opacity: checkedState ? 1 : 0 }, { duration: 0.2, ease: 'easeInOut' });\n }, [checkedState, showHoveredStyling, isActive]);\n\n const getBackgroundColor = (): string => {\n if (checkedState && isActive) {\n return 'var(--core-color-blueberry-800)';\n } else if (checkedState) {\n return showHoveredStyling ? 'var(--color-action-graphics-onlight-hover)' : 'var(--color-action-graphics-onlight)';\n } else if (isOnWhite && isActive) {\n return 'var(--core-color-neutral-400)';\n } else if (isOnWhite) {\n return showHoveredStyling ? 'var(--core-color-neutral-200)' : 'var(--core-color-neutral-50)';\n } else if (isActive) {\n return 'var(--core-color-neutral-200)';\n } else {\n return showHoveredStyling ? 'var(--core-color-neutral-50)' : 'var(--core-color-white)';\n }\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n setCheckedState(event.target.checked);\n setShowToggleAnimation(true);\n onChange?.(event);\n };\n\n const toggleContainerClassNames = classNames(styles['toggle-container']);\n\n const toggleRowClassNames = classNames(styles['toggle-container__row'], {\n [styles['toggle-container__row--right']]: togglePosition === TogglePosition.right,\n });\n\n const subLabelClassNames = classNames(styles['toggle-container__sublabel'], {\n [styles['toggle-container__sublabel--toggle-right']]: togglePosition === TogglePosition.right,\n });\n\n const toggleClassNames = classNames(styles['toggle-container__toggle'], {\n [styles['toggle-container__toggle--ignore-hover']]: showToggleAnimation,\n [styles['toggle-container__toggle--on-white']]: onColor === ToggleOnColor.onwhite,\n });\n\n const toggleDotClassNames = classNames(styles['toggle-container__toggle__dot'], {\n [styles['toggle-container__toggle__dot--ignore-hover']]: showToggleAnimation,\n });\n\n const renderToggle = (): React.ReactElement => (\n <label ref={refObject} className={styles['toggle-container__toggle-group']}>\n <input\n id={inputId}\n type=\"checkbox\"\n checked={checkedState}\n onChange={handleChange}\n className={styles['toggle-container__input']}\n aria-label={label.map(l => l.text).join(' ')}\n aria-describedby={subLabel ? subLabelId : undefined}\n role=\"switch\"\n />\n <span id={toggleId} className={toggleClassNames} aria-hidden=\"true\">\n <span id={toggleDotId} className={toggleDotClassNames} aria-hidden=\"true\">\n <svg\n width=\"17\"\n height=\"13\"\n viewBox=\"0 0 17 13\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={styles['toggle-container__toggle__dot__icon']}\n >\n <path d=\"M15 2L6.80839 10.548L2 5.53145\" fill=\"none\" strokeWidth=\"3\" />\n </svg>\n </span>\n </span>\n </label>\n );\n\n const renderLabelText = (): React.ReactElement => {\n return (\n <span\n id={labelId}\n className={classNames(styles['toggle-container__label'], {\n [styles['toggle-container__label--toggle-right']]: togglePosition === TogglePosition.right,\n })}\n >\n {label.map(labelText => {\n const labelClassNames = classNames({\n [styles['toggle-container__label__text--subdued']]: labelText.type === 'subdued',\n });\n\n return (\n <span key={labelId + labelText.text} className={labelClassNames}>\n {labelText.text}\n </span>\n );\n })}\n </span>\n );\n };\n\n return (\n <div className={toggleContainerClassNames} data-testid={testId} data-analyticsid={AnalyticsId.Toggle}>\n <div className={toggleRowClassNames}>\n {togglePosition === TogglePosition.left && (\n <>\n {renderToggle()}\n {renderLabelText()}\n </>\n )}\n {togglePosition === TogglePosition.right && (\n <>\n {renderLabelText()}\n {renderToggle()}\n </>\n )}\n </div>\n {subLabel && (\n <div id={subLabelId} className={subLabelClassNames}>\n {subLabel}\n </div>\n )}\n </div>\n );\n};\n\nexport default Toggle;\n"],"names":["TogglePosition","ToggleOnColor"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/Toggle/Toggle.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\n\nimport classNames from 'classnames';\nimport { useAnimate } from 'motion/react';\n\nimport { AnalyticsId } from '../../constants';\nimport { usePseudoClasses } from '../../hooks/usePseudoClasses';\nimport { useUuid } from '../../hooks/useUuid';\n\nimport styles from './styles.module.scss';\nimport '../../scss/supernova/styles/colors.css';\n\nexport type LabelText = {\n text: string;\n type?: 'subdued' | 'normal';\n};\n\nexport type StatusTextType = {\n checked: string;\n unchecked: string;\n};\n\nexport enum TogglePosition {\n left = 'left',\n right = 'right',\n}\n\nexport enum ToggleOnColor {\n onwhite = 'onwhite',\n onneutral = 'onneutral',\n onblueberry = 'onblueberry',\n}\n\nexport interface ToggleProps extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {\n /** Determines if the Toggle is checked */\n checked?: boolean;\n /** Sets the label of the Toggle */\n label: LabelText[];\n /** Defines the color of the toggle */\n onColor?: keyof typeof ToggleOnColor;\n /** A text that is shown under the Toggle switch */\n statusText?: StatusTextType;\n /** Sets the sublabel of the Toggle */\n subLabel?: string;\n /** Sets the position of the toggle relative to the label */\n togglePosition?: keyof typeof TogglePosition;\n /** Sets the data-testid attribute. */\n testId?: string;\n}\n\nconst Toggle: React.FC<ToggleProps> = ({\n checked = false,\n label,\n onChange,\n onColor = ToggleOnColor.onwhite,\n statusText,\n subLabel,\n togglePosition = TogglePosition.left,\n testId,\n}: ToggleProps) => {\n const [checkedState, setCheckedState] = useState(checked);\n const [showToggleAnimation, setShowToggleAnimation] = useState(false);\n const [scope, animate] = useAnimate();\n const inputId = useUuid();\n const toggleId = useUuid();\n const toggleDotId = useUuid();\n const labelId = useUuid();\n const subLabelId = useUuid();\n const { refObject, isHovered, isActive } = usePseudoClasses<HTMLLabelElement>(scope);\n const showHoveredStyling = isHovered && !showToggleAnimation;\n const isOnWhite = onColor === ToggleOnColor.onwhite;\n\n useEffect(() => {\n if (showToggleAnimation) {\n const timer = setTimeout(() => setShowToggleAnimation(false), 300);\n return (): void => clearTimeout(timer);\n }\n }, [showToggleAnimation]);\n\n useEffect(() => {\n setCheckedState(checked);\n }, [checked]);\n\n useEffect(() => {\n animate('#' + toggleId, { background: getBackgroundColor() }, { duration: 0.2, ease: 'easeInOut' });\n animate(\n '#' + toggleDotId,\n { background: checkedState ? 'var(--color-action-graphics-ondark)' : 'var(--core-color-neutral-700)' },\n { duration: 0.2, ease: 'easeInOut' }\n );\n animate('#' + toggleDotId, { x: showHoveredStyling ? 9 : checkedState ? 18 : 0 }, { duration: 0.2, ease: 'easeInOut' });\n animate('svg', { opacity: checkedState ? 1 : 0 }, { duration: 0.2, ease: 'easeInOut' });\n }, [checkedState, showHoveredStyling, isActive]);\n\n const getBackgroundColor = (): string => {\n if (checkedState && isActive) {\n return 'var(--core-color-blueberry-800)';\n } else if (checkedState) {\n return showHoveredStyling ? 'var(--color-action-graphics-onlight-hover)' : 'var(--color-action-graphics-onlight)';\n } else if (isOnWhite && isActive) {\n return 'var(--core-color-neutral-400)';\n } else if (isOnWhite) {\n return showHoveredStyling ? 'var(--core-color-neutral-200)' : 'var(--core-color-neutral-50)';\n } else if (isActive) {\n return 'var(--core-color-neutral-200)';\n } else {\n return showHoveredStyling ? 'var(--core-color-neutral-50)' : 'var(--core-color-white)';\n }\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {\n setCheckedState(event.target.checked);\n setShowToggleAnimation(true);\n onChange?.(event);\n };\n\n const toggleContainerClassNames = classNames(styles['toggle-container'], {\n [styles['toggle-container--position-right']]: togglePosition === TogglePosition.right,\n [styles['toggle-container--with-status']]: statusText !== undefined && statusText !== null,\n });\n\n const subLabelClassNames = classNames(styles['toggle-container__sublabel']);\n\n const statusTextClassNames = classNames(styles['toggle-container__status'], {\n [styles['toggle-container__status--checked']]: checkedState,\n });\n\n const toggleClassNames = classNames(styles['toggle-container__toggle'], {\n [styles['toggle-container__toggle--ignore-hover']]: showToggleAnimation,\n [styles['toggle-container__toggle--on-white']]: onColor === ToggleOnColor.onwhite,\n });\n\n const toggleDotClassNames = classNames(styles['toggle-container__toggle__dot'], {\n [styles['toggle-container__toggle__dot--ignore-hover']]: showToggleAnimation,\n });\n\n const renderToggle = (): React.ReactElement => (\n <div className={styles['toggle-container__outer-toggle']}>\n <label ref={refObject} className={classNames(styles['toggle-container__toggle-group'])}>\n <input\n id={inputId}\n type=\"checkbox\"\n checked={checkedState}\n onChange={handleChange}\n className={styles['toggle-container__input']}\n aria-label={label.map(l => l.text).join(' ')}\n aria-describedby={`${subLabel ? subLabelId + ' ' : undefined} ${statusText ? toggleId + '-status' : undefined}`}\n role=\"switch\"\n />\n <span id={toggleId} className={toggleClassNames} aria-hidden=\"true\">\n <span id={toggleDotId} className={toggleDotClassNames} aria-hidden=\"true\">\n <svg\n width=\"17\"\n height=\"13\"\n viewBox=\"0 0 17 13\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={styles['toggle-container__toggle__dot__icon']}\n >\n <path d=\"M15 2L6.80839 10.548L2 5.53145\" fill=\"none\" strokeWidth=\"3\" />\n </svg>\n </span>\n </span>\n </label>\n {statusText && (\n <span className={statusTextClassNames} id={toggleId + '-status'}>\n {checkedState ? statusText.checked : statusText.unchecked}\n </span>\n )}\n </div>\n );\n\n const renderLabelText = (): React.ReactElement => {\n return (\n <div className={styles['toggle-container__outer-label']}>\n <span id={labelId} className={classNames(styles['toggle-container__label'])}>\n {label.map(labelText => {\n const labelClassNames = classNames({\n [styles['toggle-container__label__text--subdued']]: labelText.type === 'subdued',\n });\n\n return (\n <span key={labelId + labelText.text} className={labelClassNames}>\n {labelText.text}\n </span>\n );\n })}\n </span>\n {subLabel && (\n <div id={subLabelId} className={subLabelClassNames}>\n {subLabel}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div className={toggleContainerClassNames} data-testid={testId} data-analyticsid={AnalyticsId.Toggle}>\n {togglePosition === TogglePosition.left && (\n <>\n {renderToggle()}\n {renderLabelText()}\n </>\n )}\n {togglePosition === TogglePosition.right && (\n <>\n {renderLabelText()}\n {renderToggle()}\n </>\n )}\n </div>\n );\n};\n\nexport default Toggle;\n"],"names":["TogglePosition","ToggleOnColor"],"mappings":"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"}
@@ -1,16 +1,36 @@
1
1
  @use 'sass:map';
2
2
  @use '../../scss/spacers' as spacers;
3
- @use '../../scss/palette' as palette;
4
3
  @use '../../scss/font-settings' as font-settings;
5
4
  @use '../../scss/font-mixins' as fonts;
6
5
  @use '../../scss/breakpoints' as breakpoints;
7
6
  @import '../../scss/supernova/styles/colors.css';
8
7
 
9
8
  .toggle-container {
10
- display: flex;
11
- flex-direction: column;
9
+ $toggle-container: &;
10
+
11
+ display: grid;
12
+ grid-template: 'toggle label' auto / min-content auto;
13
+ column-gap: spacers.getSpacer(xs);
12
14
  max-width: 43.5rem;
13
15
 
16
+ &--position-right {
17
+ grid-template: 'label toggle' auto / auto min-content;
18
+ }
19
+
20
+ &--with-status {
21
+ --status-column-size: 5.5rem;
22
+
23
+ grid-template: 'toggle label' auto / var(--status-column-size) auto;
24
+
25
+ &.toggle-container--position-right {
26
+ grid-template: 'label toggle' auto / auto var(--status-column-size);
27
+ }
28
+
29
+ @media (min-width: map.get(breakpoints.$grid-breakpoints, md)) {
30
+ --status-column-size: 6.25rem;
31
+ }
32
+ }
33
+
14
34
  &__row {
15
35
  display: flex;
16
36
  align-items: center;
@@ -21,61 +41,60 @@
21
41
  }
22
42
  }
23
43
 
44
+ &__outer-label {
45
+ grid-area: label;
46
+ margin-top: 0.5rem;
47
+ }
48
+
49
+ &__outer-toggle {
50
+ grid-area: toggle;
51
+ display: flex;
52
+ flex-direction: column;
53
+ align-items: center;
54
+ gap: 0.375rem;
55
+ }
56
+
24
57
  &__label {
25
58
  @include fonts.label;
26
59
 
27
60
  color: var(--core-color-neutral-900);
28
- margin-left: spacers.getSpacer(xs);
29
-
30
- @media (min-width: map.get(breakpoints.$grid-breakpoints, sm)) {
31
- margin-left: spacers.getSpacer(s);
32
- }
33
61
 
34
62
  &__text--subdued {
35
63
  @include fonts.label-subdued;
36
64
  }
37
-
38
- &--toggle-right {
39
- margin-left: 0;
40
- margin-right: spacers.getSpacer(xs);
41
-
42
- @media (min-width: map.get(breakpoints.$grid-breakpoints, sm)) {
43
- margin-right: spacers.getSpacer(s);
44
- }
45
- }
46
65
  }
47
66
 
48
67
  &__sublabel {
49
- --sublabel-mobile-margin: 3.9rem;
50
- --sublabel-desktop-margin: 4.1rem;
51
-
68
+ grid-area: sublabel;
52
69
  font-size: font-settings.$font-size-xs;
53
70
  line-height: 1.25rem;
54
71
  color: var(--core-color-neutral-800);
55
- margin-left: var(--sublabel-mobile-margin);
56
72
  text-align: left;
57
73
 
58
74
  @media (min-width: map.get(breakpoints.$grid-breakpoints, sm)) {
59
75
  font-size: font-settings.$font-size-sm;
60
76
  line-height: font-settings.$lineheight-size-xs;
61
77
  text-align: left;
62
- margin-left: var(--sublabel-desktop-margin);
63
78
  }
79
+ }
64
80
 
65
- &--toggle-right {
66
- margin-left: 0;
67
- margin-right: var(--sublabel-mobile-margin);
81
+ &__status {
82
+ @include fonts.sublabel;
68
83
 
69
- @media (min-width: map.get(breakpoints.$grid-breakpoints, sm)) {
70
- margin-right: var(--sublabel-desktop-margin);
71
- }
84
+ word-break: break-all;
85
+
86
+ &--checked {
87
+ color: var(--color-action-text-onlight);
72
88
  }
73
89
  }
74
90
 
75
91
  &__toggle-group {
92
+ grid-area: input;
93
+ place-self: center;
76
94
  display: flex;
77
95
  align-items: center;
78
96
  cursor: pointer;
97
+ min-height: 2.75rem;
79
98
  }
80
99
 
81
100
  &__toggle {
@@ -3,11 +3,13 @@ export type Styles = {
3
3
  'toggle-container__input': string;
4
4
  'toggle-container__label': string;
5
5
  'toggle-container__label__text--subdued': string;
6
- 'toggle-container__label--toggle-right': string;
6
+ 'toggle-container__outer-label': string;
7
+ 'toggle-container__outer-toggle': string;
7
8
  'toggle-container__row': string;
8
9
  'toggle-container__row--right': string;
10
+ 'toggle-container__status': string;
11
+ 'toggle-container__status--checked': string;
9
12
  'toggle-container__sublabel': string;
10
- 'toggle-container__sublabel--toggle-right': string;
11
13
  'toggle-container__toggle': string;
12
14
  'toggle-container__toggle__dot': string;
13
15
  'toggle-container__toggle__dot__icon': string;
@@ -15,6 +17,8 @@ export type Styles = {
15
17
  'toggle-container__toggle--ignore-hover': string;
16
18
  'toggle-container__toggle--on-white': string;
17
19
  'toggle-container__toggle-group': string;
20
+ 'toggle-container--position-right': string;
21
+ 'toggle-container--with-status': string;
18
22
  };
19
23
 
20
24
  export type ClassNames = keyof Styles;
@@ -14,6 +14,8 @@ interface ValidationProps {
14
14
  size?: keyof typeof FormSize;
15
15
  /** Sets the data-testid attribute. */
16
16
  testId?: string;
17
+ /** Hides the ValidationSummary list visually - summary is still announced by screen readers */
18
+ visuallyHiddenSummary?: boolean;
17
19
  }
18
20
  export declare const Validation: React.ForwardRefExoticComponent<ValidationProps & React.RefAttributes<HTMLDivElement>>;
19
21
  export default Validation;
@@ -10,6 +10,8 @@ interface ValidationSummaryProps {
10
10
  errorTitleHtmlMarkup?: TitleTags;
11
11
  /** Will be shown last */
12
12
  children?: React.ReactNode;
13
+ /** Hides the list visually - summary is still announced by screen readers */
14
+ visuallyHidden?: boolean;
13
15
  }
14
16
  declare const ValidationSummary: React.FC<ValidationSummaryProps>;
15
17
  export default ValidationSummary;
@@ -30,7 +30,11 @@ const ValidationSummary = (props) => {
30
30
  const { errorTitleHtmlMarkup = "h2" } = props;
31
31
  const titleId = useUuid();
32
32
  const hasErrors = !!props.errors && Object.entries(props.errors).length > 0;
33
- const summaryClasses = classNames(styles["validation__summary"], hasErrors && styles["validation__summary--visible"]);
33
+ const visuallyHidden = props.visuallyHidden;
34
+ const summaryClasses = classNames(styles["validation__summary"], {
35
+ [styles["validation__summary--visible"]]: hasErrors && !visuallyHidden,
36
+ [styles["validation__summary--sr-only"]]: visuallyHidden
37
+ });
34
38
  return /* @__PURE__ */ jsxs(
35
39
  "div",
36
40
  {
@@ -71,7 +75,7 @@ const Validation = React__default.forwardRef((props, ref) => {
71
75
  };
72
76
  return /* @__PURE__ */ jsxs(Fragment, { children: [
73
77
  /* @__PURE__ */ jsx("div", { "data-testid": props.testId, "data-analyticsid": AnalyticsId.Validation, className: props.className, ref, children: React__default.Children.map(props.children, (child) => renderChild(child)) }),
74
- /* @__PURE__ */ jsx(ValidationSummary, { errorTitle: props.errorTitle, errors: props.errors })
78
+ /* @__PURE__ */ jsx(ValidationSummary, { errorTitle: props.errorTitle, errors: props.errors, visuallyHidden: props.visuallyHiddenSummary })
75
79
  ] });
76
80
  });
77
81
  Validation.displayName = "Validation";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/Validation/ErrorListItem.tsx","../../../src/components/Validation/ErrorList.tsx","../../../src/components/Validation/ValidationSummary.tsx","../../../src/components/Validation/Validation.tsx"],"sourcesContent":["import React from 'react';\n\nimport { ErrorDetails, FocusableElement } from './types';\nimport AnchorLink, { AnchorLinkOnClickEvent } from '../AnchorLink';\n\ninterface ErrorElementProps {\n name: string;\n error: ErrorDetails;\n}\n\nconst ErrorListItem: React.FC<ErrorElementProps> = props => {\n const handleClick = (event?: AnchorLinkOnClickEvent, element?: FocusableElement): void => {\n event?.preventDefault();\n if (element?.focus) element?.focus();\n };\n\n if (props.error.ref) {\n return (\n <AnchorLink href={`#${props.name}`} onClick={(e): void => handleClick(e, props.error.ref)}>\n {props.error.message}\n </AnchorLink>\n );\n }\n\n return <>{props.error.message}</>;\n};\n\nexport default ErrorListItem;\n","import React from 'react';\n\nimport ErrorListItem from './ErrorListItem';\nimport { ValidationErrors } from './types';\nimport List from '../List';\n\ninterface ErrorListProps {\n errors: ValidationErrors;\n}\n\nconst ErrorList: React.FC<ErrorListProps> = props => (\n <List>\n {Object.entries(props.errors).map(([name, error]) => (\n <List.Item key={name}>\n <ErrorListItem name={name} error={error} />\n </List.Item>\n ))}\n </List>\n);\n\nexport default ErrorList;\n","import React from 'react';\n\nimport classNames from 'classnames';\n\nimport ErrorList from './ErrorList';\nimport { ValidationErrors } from './types';\nimport { useUuid } from '../../hooks/useUuid';\nimport Title, { TitleTags } from '../Title';\n\nimport styles from './styles.module.scss';\n\ninterface ValidationSummaryProps {\n /** Error summary title */\n errorTitle?: string;\n /** Error list */\n errors?: ValidationErrors;\n /** Markup props for error summary title. Default: h2 */\n errorTitleHtmlMarkup?: TitleTags;\n /** Will be shown last */\n children?: React.ReactNode;\n}\n\nconst ValidationSummary: React.FC<ValidationSummaryProps> = props => {\n const { errorTitleHtmlMarkup = 'h2' } = props;\n const titleId = useUuid();\n\n const hasErrors = !!props.errors && Object.entries(props.errors).length > 0;\n\n const summaryClasses = classNames(styles['validation__summary'], hasErrors && styles['validation__summary--visible']);\n\n return (\n <div\n role={'status'}\n aria-atomic={'true'}\n aria-live={'polite'}\n aria-relevant={'all'}\n aria-labelledby={hasErrors && props.errorTitle ? titleId : undefined}\n className={summaryClasses}\n >\n {hasErrors && (\n <>\n {props.errorTitle && (\n <Title appearance=\"title4\" id={titleId} htmlMarkup={errorTitleHtmlMarkup} margin={{ marginTop: 0, marginBottom: 1 }}>\n {props.errorTitle}\n </Title>\n )}\n <ErrorList errors={props.errors!} />\n </>\n )}\n {props.children}\n </div>\n );\n};\n\nexport default ValidationSummary;\n","import React from 'react';\n\nimport { ValidationErrors } from './types';\nimport ValidationSummary from './ValidationSummary';\nimport { AnalyticsId, FormSize } from '../../constants';\nimport { isComponent, isComponentWithDisplayName } from '../../utils/component';\nimport Checkbox, { CheckboxProps } from '../Checkbox';\nimport { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport FormGroup, { FormGroupProps } from '../FormGroup/FormGroup';\nimport Input, { InputProps } from '../Input';\nimport RadioButton, { RadioButtonProps } from '../RadioButton';\nimport Select, { SelectProps } from '../Select';\nimport Slider, { SliderProps } from '../Slider';\nimport Textarea, { TextareaProps } from '../Textarea';\n\nimport styles from './styles.module.scss';\n\ninterface ValidationProps {\n /** Error summary title */\n errorTitle?: string;\n /** Validation errors. If errors include references to HTML elements, the errors will be rendered as links with an onClick handler to focus the element. */\n errors?: ValidationErrors;\n /** Items in the Validation compontent */\n children?: React.ReactNode;\n /** Adds custom classes to the element. */\n className?: string;\n /** Changes the visuals of the formgroup */\n size?: keyof typeof FormSize;\n /** Sets the data-testid attribute. */\n testId?: string;\n}\n\nexport const Validation = React.forwardRef((props: ValidationProps, ref: React.ForwardedRef<HTMLDivElement>) => {\n const validationErrorClass = styles['validation__error-wrapper'];\n\n const cloneFormElement = <T extends ErrorWrapperClassNameProps>(child: React.ReactElement<T>): React.ReactElement<T> => {\n return React.cloneElement(child, {\n ...child.props,\n errorWrapperClassName: validationErrorClass,\n });\n };\n\n const renderChild = (child: React.ReactNode): React.ReactNode => {\n if (\n isComponent<FormGroupProps>(child, FormGroup) ||\n isComponent<CheckboxProps>(child, Checkbox) ||\n isComponent<RadioButtonProps>(child, RadioButton) ||\n isComponent<TextareaProps>(child, Textarea) ||\n isComponent<InputProps>(child, Input) ||\n isComponent<SelectProps>(child, Select) ||\n isComponent<SliderProps>(child, Slider) ||\n isComponentWithDisplayName<ErrorWrapperClassNameProps>(child, 'DateTimePickerWrapper') ||\n isComponentWithDisplayName<ErrorWrapperClassNameProps>(child, 'DatePicker') ||\n isComponentWithDisplayName<ErrorWrapperClassNameProps>(child, 'DateTime')\n ) {\n return cloneFormElement<ErrorWrapperClassNameProps>(child);\n }\n if (React.isValidElement(child) && child.type === React.Fragment) {\n return React.Children.map(child.props.children, (child: React.ReactNode) => {\n return renderChild(child);\n });\n }\n\n return child;\n };\n\n return (\n <>\n <div data-testid={props.testId} data-analyticsid={AnalyticsId.Validation} className={props.className} ref={ref}>\n {React.Children.map(props.children, (child: React.ReactNode) => renderChild(child))}\n </div>\n <ValidationSummary errorTitle={props.errorTitle} errors={props.errors} />\n </>\n );\n});\n\nValidation.displayName = 'Validation';\n\nexport default Validation;\n"],"names":["React","child"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/Validation/ErrorListItem.tsx","../../../src/components/Validation/ErrorList.tsx","../../../src/components/Validation/ValidationSummary.tsx","../../../src/components/Validation/Validation.tsx"],"sourcesContent":["import React from 'react';\n\nimport { ErrorDetails, FocusableElement } from './types';\nimport AnchorLink, { AnchorLinkOnClickEvent } from '../AnchorLink';\n\ninterface ErrorElementProps {\n name: string;\n error: ErrorDetails;\n}\n\nconst ErrorListItem: React.FC<ErrorElementProps> = props => {\n const handleClick = (event?: AnchorLinkOnClickEvent, element?: FocusableElement): void => {\n event?.preventDefault();\n if (element?.focus) element?.focus();\n };\n\n if (props.error.ref) {\n return (\n <AnchorLink href={`#${props.name}`} onClick={(e): void => handleClick(e, props.error.ref)}>\n {props.error.message}\n </AnchorLink>\n );\n }\n\n return <>{props.error.message}</>;\n};\n\nexport default ErrorListItem;\n","import React from 'react';\n\nimport ErrorListItem from './ErrorListItem';\nimport { ValidationErrors } from './types';\nimport List from '../List';\n\ninterface ErrorListProps {\n errors: ValidationErrors;\n}\n\nconst ErrorList: React.FC<ErrorListProps> = props => (\n <List>\n {Object.entries(props.errors).map(([name, error]) => (\n <List.Item key={name}>\n <ErrorListItem name={name} error={error} />\n </List.Item>\n ))}\n </List>\n);\n\nexport default ErrorList;\n","import React from 'react';\n\nimport classNames from 'classnames';\n\nimport ErrorList from './ErrorList';\nimport { ValidationErrors } from './types';\nimport { useUuid } from '../../hooks/useUuid';\nimport Title, { TitleTags } from '../Title';\n\nimport styles from './styles.module.scss';\n\ninterface ValidationSummaryProps {\n /** Error summary title */\n errorTitle?: string;\n /** Error list */\n errors?: ValidationErrors;\n /** Markup props for error summary title. Default: h2 */\n errorTitleHtmlMarkup?: TitleTags;\n /** Will be shown last */\n children?: React.ReactNode;\n /** Hides the list visually - summary is still announced by screen readers */\n visuallyHidden?: boolean;\n}\n\nconst ValidationSummary: React.FC<ValidationSummaryProps> = props => {\n const { errorTitleHtmlMarkup = 'h2' } = props;\n const titleId = useUuid();\n\n const hasErrors = !!props.errors && Object.entries(props.errors).length > 0;\n const visuallyHidden = props.visuallyHidden;\n\n const summaryClasses = classNames(styles['validation__summary'], {\n [styles['validation__summary--visible']]: hasErrors && !visuallyHidden,\n [styles['validation__summary--sr-only']]: visuallyHidden,\n });\n\n return (\n <div\n role={'status'}\n aria-atomic={'true'}\n aria-live={'polite'}\n aria-relevant={'all'}\n aria-labelledby={hasErrors && props.errorTitle ? titleId : undefined}\n className={summaryClasses}\n >\n {hasErrors && (\n <>\n {props.errorTitle && (\n <Title appearance=\"title4\" id={titleId} htmlMarkup={errorTitleHtmlMarkup} margin={{ marginTop: 0, marginBottom: 1 }}>\n {props.errorTitle}\n </Title>\n )}\n <ErrorList errors={props.errors!} />\n </>\n )}\n {props.children}\n </div>\n );\n};\n\nexport default ValidationSummary;\n","import React from 'react';\n\nimport { ValidationErrors } from './types';\nimport ValidationSummary from './ValidationSummary';\nimport { AnalyticsId, FormSize } from '../../constants';\nimport { isComponent, isComponentWithDisplayName } from '../../utils/component';\nimport Checkbox, { CheckboxProps } from '../Checkbox';\nimport { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport FormGroup, { FormGroupProps } from '../FormGroup/FormGroup';\nimport Input, { InputProps } from '../Input';\nimport RadioButton, { RadioButtonProps } from '../RadioButton';\nimport Select, { SelectProps } from '../Select';\nimport Slider, { SliderProps } from '../Slider';\nimport Textarea, { TextareaProps } from '../Textarea';\n\nimport styles from './styles.module.scss';\n\ninterface ValidationProps {\n /** Error summary title */\n errorTitle?: string;\n /** Validation errors. If errors include references to HTML elements, the errors will be rendered as links with an onClick handler to focus the element. */\n errors?: ValidationErrors;\n /** Items in the Validation compontent */\n children?: React.ReactNode;\n /** Adds custom classes to the element. */\n className?: string;\n /** Changes the visuals of the formgroup */\n size?: keyof typeof FormSize;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Hides the ValidationSummary list visually - summary is still announced by screen readers */\n visuallyHiddenSummary?: boolean;\n}\n\nexport const Validation = React.forwardRef((props: ValidationProps, ref: React.ForwardedRef<HTMLDivElement>) => {\n const validationErrorClass = styles['validation__error-wrapper'];\n\n const cloneFormElement = <T extends ErrorWrapperClassNameProps>(child: React.ReactElement<T>): React.ReactElement<T> => {\n return React.cloneElement(child, {\n ...child.props,\n errorWrapperClassName: validationErrorClass,\n });\n };\n\n const renderChild = (child: React.ReactNode): React.ReactNode => {\n if (\n isComponent<FormGroupProps>(child, FormGroup) ||\n isComponent<CheckboxProps>(child, Checkbox) ||\n isComponent<RadioButtonProps>(child, RadioButton) ||\n isComponent<TextareaProps>(child, Textarea) ||\n isComponent<InputProps>(child, Input) ||\n isComponent<SelectProps>(child, Select) ||\n isComponent<SliderProps>(child, Slider) ||\n isComponentWithDisplayName<ErrorWrapperClassNameProps>(child, 'DateTimePickerWrapper') ||\n isComponentWithDisplayName<ErrorWrapperClassNameProps>(child, 'DatePicker') ||\n isComponentWithDisplayName<ErrorWrapperClassNameProps>(child, 'DateTime')\n ) {\n return cloneFormElement<ErrorWrapperClassNameProps>(child);\n }\n if (React.isValidElement(child) && child.type === React.Fragment) {\n return React.Children.map(child.props.children, (child: React.ReactNode) => {\n return renderChild(child);\n });\n }\n\n return child;\n };\n\n return (\n <>\n <div data-testid={props.testId} data-analyticsid={AnalyticsId.Validation} className={props.className} ref={ref}>\n {React.Children.map(props.children, (child: React.ReactNode) => renderChild(child))}\n </div>\n <ValidationSummary errorTitle={props.errorTitle} errors={props.errors} visuallyHidden={props.visuallyHiddenSummary} />\n </>\n );\n});\n\nValidation.displayName = 'Validation';\n\nexport default Validation;\n"],"names":["React","child"],"mappings":"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"}
@@ -3,6 +3,7 @@
3
3
  @use '../../scss/palette' as palette;
4
4
  @use '../../scss/font-settings' as font-settings;
5
5
  @use '../../scss/breakpoints' as breakpoints;
6
+ @use '../../scss/screen-reader' as *;
6
7
 
7
8
  .validation {
8
9
  &__error-wrapper {
@@ -19,6 +20,10 @@
19
20
  &--visible {
20
21
  margin: spacers.getSpacer(l) 0 spacers.getSpacer(s);
21
22
  }
23
+
24
+ &--sr-only {
25
+ @include sr-only;
26
+ }
22
27
  }
23
28
 
24
29
  &__errors {
@@ -3,6 +3,7 @@ export type Styles = {
3
3
  validation__errors: string;
4
4
  'validation__errors--visible': string;
5
5
  validation__summary: string;
6
+ 'validation__summary--sr-only': string;
6
7
  'validation__summary--visible': string;
7
8
  };
8
9
 
@@ -2,6 +2,7 @@ import { FormSize } from '../../constants';
2
2
  export interface FormExampleProps {
3
3
  exampleType: FormExampleVariants;
4
4
  size?: keyof typeof FormSize;
5
+ visuallyHiddenSummary?: boolean;
5
6
  }
6
7
  export declare enum FormExampleVariants {
7
8
  formgroup = "formgroup",
@@ -1,4 +1,5 @@
1
1
  import { useRef, useEffect } from "react";
2
+ import { deepContains } from "../utils/deepContains.js";
2
3
  import { getDocumentActiveElement } from "../utils/focus.js";
3
4
  const useReturnFocusOnUnmount = (ref) => {
4
5
  const previouslyFocusedElementRef = useRef(null);
@@ -8,7 +9,7 @@ const useReturnFocusOnUnmount = (ref) => {
8
9
  previouslyFocusedElementRef.current = activeElement;
9
10
  }
10
11
  return () => {
11
- if (previouslyFocusedElementRef.current instanceof HTMLElement && document.contains(previouslyFocusedElementRef.current)) {
12
+ if (previouslyFocusedElementRef.current instanceof HTMLElement && deepContains(document, previouslyFocusedElementRef.current)) {
12
13
  previouslyFocusedElementRef.current.focus();
13
14
  }
14
15
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useReturnFocusOnUnmount.js","sources":["../../src/hooks/useReturnFocusOnUnmount.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport { getDocumentActiveElement } from '../utils/focus';\n\n/**\n * A hook that stores the currently focused element when the component mounts,\n * and returns focus to it when the component unmounts.\n */\nexport const useReturnFocusOnUnmount = (ref: React.RefObject<HTMLElement>): void => {\n const previouslyFocusedElementRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n // Captures which element was focused on mount\n // const activeElement = document.activeElement;\n const activeElement = ref.current ? getDocumentActiveElement(ref.current) : null;\n if (activeElement instanceof HTMLElement) {\n previouslyFocusedElementRef.current = activeElement;\n }\n\n // Restores focus to the stored element on unmount\n return (): void => {\n if (previouslyFocusedElementRef.current instanceof HTMLElement && document.contains(previouslyFocusedElementRef.current)) {\n previouslyFocusedElementRef.current.focus();\n }\n };\n }, []);\n};\n"],"names":[],"mappings":";;AAQO,MAAM,0BAA0B,CAAC,QAA4C;AAClF,QAAM,8BAA8B,OAA2B,IAAI;AAEnE,YAAU,MAAM;AAGd,UAAM,gBAAgB,IAAI,UAAU,yBAAyB,IAAI,OAAO,IAAI;AAC5E,QAAI,yBAAyB,aAAa;AACxC,kCAA4B,UAAU;AAAA,IACxC;AAGA,WAAO,MAAY;AACjB,UAAI,4BAA4B,mBAAmB,eAAe,SAAS,SAAS,4BAA4B,OAAO,GAAG;AACxH,oCAA4B,QAAQ,MAAA;AAAA,MACtC;AAAA,IACF;AAAA,EACF,GAAG,CAAA,CAAE;AACP;"}
1
+ {"version":3,"file":"useReturnFocusOnUnmount.js","sources":["../../src/hooks/useReturnFocusOnUnmount.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport { deepContains } from '../utils/deepContains';\nimport { getDocumentActiveElement } from '../utils/focus';\n\n/**\n * A hook that stores the currently focused element when the component mounts,\n * and returns focus to it when the component unmounts.\n */\nexport const useReturnFocusOnUnmount = (ref: React.RefObject<HTMLElement>): void => {\n const previouslyFocusedElementRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n // Captures which element was focused on mount\n // const activeElement = document.activeElement;\n const activeElement = ref.current ? getDocumentActiveElement(ref.current) : null;\n if (activeElement instanceof HTMLElement) {\n previouslyFocusedElementRef.current = activeElement;\n }\n\n // Restores focus to the stored element on unmount\n return (): void => {\n if (previouslyFocusedElementRef.current instanceof HTMLElement && deepContains(document, previouslyFocusedElementRef.current)) {\n previouslyFocusedElementRef.current.focus();\n }\n };\n }, []);\n};\n"],"names":[],"mappings":";;;AASO,MAAM,0BAA0B,CAAC,QAA4C;AAClF,QAAM,8BAA8B,OAA2B,IAAI;AAEnE,YAAU,MAAM;AAGd,UAAM,gBAAgB,IAAI,UAAU,yBAAyB,IAAI,OAAO,IAAI;AAC5E,QAAI,yBAAyB,aAAa;AACxC,kCAA4B,UAAU;AAAA,IACxC;AAGA,WAAO,MAAY;AACjB,UAAI,4BAA4B,mBAAmB,eAAe,aAAa,UAAU,4BAA4B,OAAO,GAAG;AAC7H,oCAA4B,QAAQ,MAAA;AAAA,MACtC;AAAA,IACF;AAAA,EACF,GAAG,CAAA,CAAE;AACP;"}
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "url": "git+https://github.com/helsenorge/designsystem.git"
8
8
  },
9
9
  "homepage": "https://helsenorge.design",
10
- "version": "12.1.0",
10
+ "version": "12.3.0",
11
11
  "author": "Helsenorge",
12
12
  "license": "MIT",
13
13
  "dependencies": {
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Determines whether a given container node contains a specific element, traversing through shadow DOM boundaries if necessary.
3
+ * This function extends the behavior of `Node.contains` to support scenarios involving shadow DOM.
4
+ *
5
+ * @param container - The container node to check, typically the document or a specific DOM element.
6
+ * @param element - The target node to verify if it is contained within the container.
7
+ * @returns `true` if the container node contains the target node, including through shadow DOM boundaries; otherwise, `false`.
8
+ */
9
+ export declare function deepContains(container: Node, element: Node | null): boolean;
@@ -0,0 +1,19 @@
1
+ function deepContains(container, element) {
2
+ let node = element;
3
+ while (node) {
4
+ if (node === container) {
5
+ return true;
6
+ }
7
+ const rootNode = node.getRootNode();
8
+ if (rootNode instanceof ShadowRoot) {
9
+ node = rootNode.host;
10
+ } else {
11
+ node = node.parentNode;
12
+ }
13
+ }
14
+ return false;
15
+ }
16
+ export {
17
+ deepContains
18
+ };
19
+ //# sourceMappingURL=deepContains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepContains.js","sources":["../../src/utils/deepContains.ts"],"sourcesContent":["/**\n * Determines whether a given container node contains a specific element, traversing through shadow DOM boundaries if necessary.\n * This function extends the behavior of `Node.contains` to support scenarios involving shadow DOM.\n *\n * @param container - The container node to check, typically the document or a specific DOM element.\n * @param element - The target node to verify if it is contained within the container.\n * @returns `true` if the container node contains the target node, including through shadow DOM boundaries; otherwise, `false`.\n */\nexport function deepContains(container: Node, element: Node | null): boolean {\n let node = element;\n while (node) {\n if (node === container) {\n return true;\n }\n // Step out of shadow roots if necessary\n const rootNode = node.getRootNode();\n if (rootNode instanceof ShadowRoot) {\n node = rootNode.host;\n } else {\n node = node.parentNode;\n }\n }\n return false;\n}\n"],"names":[],"mappings":"AAQO,SAAS,aAAa,WAAiB,SAA+B;AAC3E,MAAI,OAAO;AACX,SAAO,MAAM;AACX,QAAI,SAAS,WAAW;AACtB,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,KAAK,YAAA;AACtB,QAAI,oBAAoB,YAAY;AAClC,aAAO,SAAS;AAAA,IAClB,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;"}
@@ -0,0 +1 @@
1
+ export {};