@helsenorge/designsystem-react 13.3.0 → 13.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## [13.4.0](https://github.com/helsenorge/designsystem/branchCompare?baseVersion=GTv13.3.0&targetVersion=GTv13.4.0) (2025-12-18)
2
+
3
+
4
+ ### Features
5
+
6
+ * input og textarea får resources til maxcharacters tekst ([5057563](https://github.com/helsenorge/designsystem/commit/5057563de68c04df119ff8f16063041c05282562)), closes [#365224](https://github.com/helsenorge/designsystem/issues/365224)
7
+ * **formgroup:** fjerner ariadescribedby prop ([9aa55d4](https://github.com/helsenorge/designsystem/commit/9aa55d463caaeff7d715d3d604237a687c25dc1f)), closes [#367262](https://github.com/helsenorge/designsystem/issues/367262)
8
+ * **formgroup:** ny prop ariadescribedby og formfieldtag er koblet med ariadescribedby automatisk ([71569ef](https://github.com/helsenorge/designsystem/commit/71569ef9db0f955b6a06a363b137635703c2f123)), closes [#367262](https://github.com/helsenorge/designsystem/issues/367262)
9
+ * **linklist:** linkref prop kan være null ([b3bd5c1](https://github.com/helsenorge/designsystem/commit/b3bd5c1e5e786908269752cd4ccc672dd81ba88d)), closes [#367039](https://github.com/helsenorge/designsystem/issues/367039)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **datepicker:** popup vises delvis utenfor skjerm på smal desktop ([1a06d2a](https://github.com/helsenorge/designsystem/commit/1a06d2a27b3902d4fbf89a231ed13085aa1959f6)), closes [#367051](https://github.com/helsenorge/designsystem/issues/367051)
15
+ * **slider:** onclick oppfører seg rart med validering aktivert ([fe2c93a](https://github.com/helsenorge/designsystem/commit/fe2c93a917ce0b54b5f92283fd2340918529e42d)), closes [#357082](https://github.com/helsenorge/designsystem/issues/357082)
16
+
1
17
  ## [13.3.0](https://github.com/helsenorge/designsystem/branchCompare?baseVersion=GTv13.2.0&targetVersion=GTv13.3.0) (2025-12-11)
2
18
 
3
19
 
package/lib/Input.js CHANGED
@@ -1,7 +1,8 @@
1
- import { a as IconSize, i as FormSize, n as AnalyticsId, r as FormOnColor, t as AVERAGE_CHARACTER_WIDTH_PX } from "./constants2.js";
1
+ import { a as IconSize, i as FormSize, n as AnalyticsId, r as FormOnColor, s as LanguageLocales, t as AVERAGE_CHARACTER_WIDTH_PX } from "./constants2.js";
2
2
  import { t as getColor } from "./color.js";
3
3
  import { n as mergeRefs } from "./refs.js";
4
4
  import { t as Icon_default } from "./Icon.js";
5
+ import { r as useLanguage } from "./language.js";
5
6
  import { t as LazyIcon_default } from "./LazyIcon.js";
6
7
  import { n as useBreakpoint, t as Breakpoint } from "./useBreakpoint.js";
7
8
  import { t as useIdWithFallback } from "./useIdWithFallback.js";
@@ -13,6 +14,17 @@ import React, { useEffect, useRef, useState } from "react";
13
14
  import classNames from "classnames";
14
15
  import { jsx, jsxs } from "react/jsx-runtime";
15
16
  import styles from "./components/Input/styles.module.scss";
17
+ var HN_Designsystem_Input_en_GB_default = { characters: "characters" };
18
+ var HN_Designsystem_Input_nb_NO_default = { characters: "tegn" };
19
+ var HN_Designsystem_Input_nn_NO_default = { characters: "teikn" };
20
+ const getResources = (language) => {
21
+ switch (language) {
22
+ case LanguageLocales.ENGLISH: return HN_Designsystem_Input_en_GB_default;
23
+ case LanguageLocales.NORWEGIAN_NYNORSK: return HN_Designsystem_Input_nn_NO_default;
24
+ case LanguageLocales.NORWEGIAN:
25
+ default: return HN_Designsystem_Input_nb_NO_default;
26
+ }
27
+ };
16
28
  let InputTypes = /* @__PURE__ */ function(InputTypes$1) {
17
29
  InputTypes$1["text"] = "text";
18
30
  InputTypes$1["number"] = "number";
@@ -25,13 +37,20 @@ let InputTypes = /* @__PURE__ */ function(InputTypes$1) {
25
37
  InputTypes$1["time"] = "time";
26
38
  return InputTypes$1;
27
39
  }({});
28
- var getInputMaxWidth = (characters, hasIcon, iconSize) => {
40
+ var getInputMaxWidth = (characters$3, hasIcon, iconSize) => {
29
41
  const paddingWidth = hasIcon ? "1.5rem" : "2rem";
30
42
  const iconWidth = hasIcon ? `${iconSize}px` : "0px";
31
- return `calc(${characters * 12}px + ${paddingWidth} + ${iconWidth} + 4px)`;
43
+ return `calc(${characters$3 * 12}px + ${paddingWidth} + ${iconWidth} + 4px)`;
32
44
  };
33
45
  var Input = React.forwardRef((props, ref) => {
34
- const { className, defaultValue, placeholder, type = InputTypes.text, name, transparent = false, icon, iconRight, inputWrapperRef, onColor = FormOnColor.onwhite, size, baseIncrementValue, label, error, errorText, errorTextId: errorTextIdProp, inputId: inputIdProp, errorWrapperClassName, testId, disabled, readOnly, autoComplete = "off", afterInputChildren, rightOfInput, width, required, onChange, onKeyDown, autoFocus, maxCharacters, maxText, inputContainerRef, ...rest } = props;
46
+ const { className, defaultValue, placeholder, type = InputTypes.text, name, transparent = false, icon, iconRight, inputWrapperRef, onColor = FormOnColor.onwhite, size, baseIncrementValue, label, error, errorText, errorTextId: errorTextIdProp, inputId: inputIdProp, errorWrapperClassName, testId, disabled, readOnly, autoComplete = "off", afterInputChildren, rightOfInput, width, required, onChange, onKeyDown, autoFocus, maxCharacters, maxText, inputContainerRef, resources, ...rest } = props;
47
+ const { language } = useLanguage(LanguageLocales.NORWEGIAN);
48
+ const defaultResources = getResources(language);
49
+ const mergedResources = {
50
+ ...defaultResources,
51
+ ...resources,
52
+ characters: maxText || resources?.characters || defaultResources.characters
53
+ };
35
54
  const breakpoint = useBreakpoint();
36
55
  const inputContainerRefLocal = useRef(null);
37
56
  const inputId = useIdWithFallback(inputIdProp);
@@ -157,7 +176,7 @@ var Input = React.forwardRef((props, ref) => {
157
176
  maxCharacters && /* @__PURE__ */ jsx(MaxCharacters_default, {
158
177
  maxCharacters,
159
178
  length: input.toString().length,
160
- maxText,
179
+ maxText: mergedResources.characters,
161
180
  onColor,
162
181
  maxWidth
163
182
  }),
package/lib/Input.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Input.js","names":[],"sources":["../src/components/Input/Input.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\n\nimport cn from 'classnames';\n\nimport { FormOnColor, FormSize, AnalyticsId, AVERAGE_CHARACTER_WIDTH_PX } from '../../constants';\nimport { Breakpoint, useBreakpoint } from '../../hooks/useBreakpoint';\nimport { useIdWithFallback } from '../../hooks/useIdWithFallback';\nimport { getColor } from '../../theme/currys';\nimport { getAriaDescribedBy } from '../../utils/accessibility';\nimport { mergeRefs } from '../../utils/refs';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport Icon, { IconSize, SvgIcon } from '../Icon';\nimport { IconName } from '../Icons/IconNames';\nimport { renderLabel } from '../Label';\nimport LazyIcon from '../LazyIcon';\nimport MaxCharacters from '../MaxCharacters/MaxCharacters';\n\nimport styles from './styles.module.scss';\n\nexport interface InputProps\n extends ErrorWrapperClassNameProps,\n Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n | 'disabled'\n | 'readOnly'\n | 'autoComplete'\n | 'name'\n | 'placeholder'\n | 'defaultValue'\n | 'required'\n | 'value'\n | 'min'\n | 'max'\n | 'aria-describedby'\n | 'aria-labelledby'\n | 'onBlur'\n | 'onClick'\n | 'onChange'\n | 'onFocus'\n | 'onKeyDown'\n | 'autoFocus'\n | 'inputMode'\n > {\n /** The number at which the input field starts when you increment or decrement it */\n baseIncrementValue?: number;\n /** Adds custom classes to the element. */\n className?: string;\n /** HMTL Input type */\n type?: keyof typeof InputTypes;\n /** input id */\n inputId?: string;\n /** Width of input field in characters (approximate) */\n width?: number;\n /** If true, the component will be transparent. */\n transparent?: boolean;\n /** Icon to be displayed next to the input field */\n icon?: SvgIcon | IconName;\n /** Places the icon to the right */\n iconRight?: boolean;\n /** Ref that is placed on the inputContainerRef */\n inputContainerRef?: React.RefObject<HTMLDivElement>;\n /** Ref that is placed on the inputWrapper */\n inputWrapperRef?: React.RefObject<HTMLDivElement>;\n /** Changes the color profile of the input */\n onColor?: keyof typeof FormOnColor;\n /** Changes the visuals of the input */\n size?: keyof typeof FormSize;\n /** Label of the input */\n label?: React.ReactNode;\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Component shown after input */\n afterInputChildren?: React.ReactNode;\n /** Component shown to the right of input */\n rightOfInput?: React.ReactNode;\n /** max character limit in input */\n maxCharacters?: number;\n /** The text is displayed in the end of the text-counter */\n maxText?: string;\n}\n\nexport enum InputTypes {\n text = 'text',\n number = 'number',\n email = 'email',\n password = 'password',\n search = 'search',\n tel = 'tel',\n url = 'url',\n date = 'date',\n time = 'time',\n}\n\nconst getInputMaxWidth = (characters: number, hasIcon: boolean, iconSize: number): string => {\n const paddingWidth = hasIcon ? '1.5rem' : '2rem';\n const iconWidth = hasIcon ? `${iconSize}px` : '0px';\n const borderWidth = '4px';\n\n return `calc(${characters * AVERAGE_CHARACTER_WIDTH_PX}px + ${paddingWidth} + ${iconWidth} + ${borderWidth})`;\n};\n\nconst Input = React.forwardRef((props: InputProps, ref: React.Ref<HTMLInputElement>) => {\n const {\n className,\n defaultValue,\n placeholder,\n type = InputTypes.text,\n name,\n transparent = false,\n icon,\n iconRight,\n inputWrapperRef,\n onColor = FormOnColor.onwhite,\n size,\n baseIncrementValue,\n label,\n error,\n errorText,\n errorTextId: errorTextIdProp,\n inputId: inputIdProp,\n errorWrapperClassName,\n testId,\n disabled,\n readOnly,\n autoComplete = 'off',\n afterInputChildren,\n rightOfInput,\n width,\n required,\n onChange,\n onKeyDown,\n autoFocus,\n maxCharacters,\n maxText,\n inputContainerRef,\n ...rest\n } = props;\n const breakpoint = useBreakpoint();\n const inputContainerRefLocal = useRef<HTMLDivElement>(null);\n const inputId = useIdWithFallback(inputIdProp);\n const [input, setInput] = useState(defaultValue || '');\n const [prevValue, setPrevValue] = useState<string | number | undefined>(undefined);\n const numKeyPressed = useRef<boolean>(false);\n const errorTextId = useIdWithFallback(errorTextIdProp);\n const numRegex = /^[0-9]$/;\n\n useEffect(() => {\n setInput(defaultValue || '');\n }, [defaultValue]);\n\n const onDark = onColor === FormOnColor.ondark;\n const onBlueberry = onColor === FormOnColor.onblueberry;\n const maxCharactersExceeded = !!maxCharacters && input.toString().length > maxCharacters;\n const onError = onColor === FormOnColor.oninvalid || !!errorText || !!error || maxCharactersExceeded;\n const isLarge = size === FormSize.large;\n const isTransparent = transparent && onColor !== FormOnColor.ondark && !onError;\n\n const inputWrapperClass = cn(styles['input-wrapper'], className);\n\n const inputContainer = cn(styles['input-container'], {\n [styles['input-container--transparent']]: isTransparent,\n [styles['input-container--on-blueberry']]: onBlueberry,\n [styles['input-container--on-dark']]: onDark,\n [styles['input-container--invalid']]: onError,\n [styles['input-container--disabled']]: disabled,\n [styles['input-container--with-icon']]: icon,\n [styles['input-container--with-icon--right']]: icon && iconRight,\n });\n\n const inputClass = cn(styles['input-container__input'], {\n [styles['input-container__input--large']]: isLarge,\n [styles['input-container__input--disabled']]: disabled,\n });\n\n const iconColor = disabled ? getColor('neutral', 700) : getColor('black');\n const iconSize = breakpoint === Breakpoint.xs || !isLarge ? IconSize.XSmall : IconSize.Small;\n\n const renderIcon = (): React.ReactNode => {\n if (!icon) {\n return;\n }\n\n if (typeof icon === 'string') {\n return <LazyIcon className={styles['input-container__input__icon']} color={iconColor} size={iconSize} iconName={icon} />;\n }\n\n return <Icon className={styles['input-container__input__icon']} color={iconColor} size={iconSize} svgIcon={icon} />;\n };\n\n // eslint-disable-next-line\n const handleClick = (e: React.MouseEvent<any>): void => {\n if (inputContainerRefLocal && inputContainerRefLocal.current && icon) {\n const selectedChild = iconRight ? 0 : 1;\n const input = inputContainerRefLocal.current.children[selectedChild] as HTMLInputElement;\n input.focus();\n\n if (props.onClick) props.onClick(e);\n }\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {\n const newValue = getIncrementValue(e);\n\n if (onChange) {\n onChange(e);\n }\n\n setInput(newValue);\n setPrevValue(newValue);\n };\n\n // Hvis bruker endrer number value med 1 og det skal startes på en annen verdi enn 0\n const getIncrementValue = (e: React.ChangeEvent<HTMLInputElement>): string => {\n if (typeof baseIncrementValue === 'undefined' || type !== 'number') return e.target.value;\n\n const valueAsNumber = Number(e.target.value);\n\n if (!prevValue && !numKeyPressed.current && (valueAsNumber === 1 || valueAsNumber === -1)) {\n e.target.value = baseIncrementValue + '';\n }\n\n return e.target.value;\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {\n if (numRegex.test(e.key)) {\n numKeyPressed.current = true;\n }\n if (onKeyDown) onKeyDown(e);\n };\n\n const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>): void => {\n if (numRegex.test(e.key)) {\n numKeyPressed.current = false;\n }\n };\n\n const maxWidth = width ? getInputMaxWidth(width, !!icon, iconSize) : undefined;\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextId}>\n <div data-testid={testId} data-analyticsid={AnalyticsId.Input} className={inputWrapperClass} ref={inputWrapperRef}>\n {renderLabel(label, inputId, onColor as FormOnColor)}\n {/* input-elementet tillater keyboard-interaksjon */}\n <div className={styles['content-wrapper']}>\n {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */}\n <div\n onClick={handleClick}\n ref={mergeRefs([inputContainerRefLocal, inputContainerRef])}\n className={inputContainer}\n style={{ maxWidth }}\n >\n {!iconRight && renderIcon()}\n <input\n {...rest}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n name={name}\n type={type}\n defaultValue={defaultValue}\n id={inputId}\n className={inputClass}\n ref={ref}\n aria-describedby={getAriaDescribedBy(props, errorTextId)}\n aria-invalid={!!onError}\n disabled={disabled}\n placeholder={placeholder}\n readOnly={readOnly}\n autoComplete={autoComplete || 'off'}\n required={required}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n />\n {iconRight && renderIcon()}\n </div>\n <div className={styles['content-wrapper__right-of-input']}>{rightOfInput}</div>\n </div>\n {maxCharacters && (\n <MaxCharacters\n maxCharacters={maxCharacters}\n length={input.toString().length}\n maxText={maxText}\n onColor={onColor}\n maxWidth={maxWidth}\n />\n )}\n {afterInputChildren}\n </div>\n </ErrorWrapper>\n );\n});\n\nInput.displayName = 'Input';\n\nexport default Input;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Input.js","names":["mergedResources: HNDesignsystemInput"],"sources":["../src/resources/HN.Designsystem.Input.en-GB.json","../src/resources/HN.Designsystem.Input.nb-NO.json","../src/resources/HN.Designsystem.Input.nn-NO.json","../src/components/Input/resourceHelper.ts","../src/components/Input/Input.tsx"],"sourcesContent":["{\n \"characters\": \"characters\"\n}\n","{\n \"characters\": \"tegn\"\n}\n","{\n \"characters\": \"teikn\"\n}\n","import { LanguageLocales } from '../../constants';\nimport enGB from '../../resources/HN.Designsystem.Input.en-GB.json';\nimport nbNO from '../../resources/HN.Designsystem.Input.nb-NO.json';\nimport nnNO from '../../resources/HN.Designsystem.Input.nn-NO.json';\nimport { HNDesignsystemInput } from '../../resources/Resources';\n\nexport const getResources = (language: LanguageLocales): HNDesignsystemInput => {\n switch (language) {\n case LanguageLocales.ENGLISH:\n return enGB;\n case LanguageLocales.NORWEGIAN_NYNORSK:\n return nnNO;\n case LanguageLocales.NORWEGIAN:\n default:\n return nbNO;\n }\n};\n","import React, { useEffect, useRef, useState } from 'react';\n\nimport cn from 'classnames';\n\nimport { getResources } from './resourceHelper';\nimport { FormOnColor, FormSize, AnalyticsId, AVERAGE_CHARACTER_WIDTH_PX, LanguageLocales } from '../../constants';\nimport { Breakpoint, useBreakpoint } from '../../hooks/useBreakpoint';\nimport { useIdWithFallback } from '../../hooks/useIdWithFallback';\nimport { HNDesignsystemInput } from '../../resources/Resources';\nimport { getColor } from '../../theme/currys';\nimport { getAriaDescribedBy } from '../../utils/accessibility';\nimport { useLanguage } from '../../utils/language';\nimport { mergeRefs } from '../../utils/refs';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport Icon, { IconSize, SvgIcon } from '../Icon';\nimport { IconName } from '../Icons/IconNames';\nimport { renderLabel } from '../Label';\nimport LazyIcon from '../LazyIcon';\nimport MaxCharacters from '../MaxCharacters/MaxCharacters';\n\nimport styles from './styles.module.scss';\n\nexport interface InputProps\n extends ErrorWrapperClassNameProps,\n Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n | 'disabled'\n | 'readOnly'\n | 'autoComplete'\n | 'name'\n | 'placeholder'\n | 'defaultValue'\n | 'required'\n | 'value'\n | 'min'\n | 'max'\n | 'aria-describedby'\n | 'aria-labelledby'\n | 'onBlur'\n | 'onClick'\n | 'onChange'\n | 'onFocus'\n | 'onKeyDown'\n | 'autoFocus'\n | 'inputMode'\n > {\n /** The number at which the input field starts when you increment or decrement it */\n baseIncrementValue?: number;\n /** Adds custom classes to the element. */\n className?: string;\n /** HMTL Input type */\n type?: keyof typeof InputTypes;\n /** input id */\n inputId?: string;\n /** Width of input field in characters (approximate) */\n width?: number;\n /** If true, the component will be transparent. */\n transparent?: boolean;\n /** Icon to be displayed next to the input field */\n icon?: SvgIcon | IconName;\n /** Places the icon to the right */\n iconRight?: boolean;\n /** Ref that is placed on the inputContainerRef */\n inputContainerRef?: React.RefObject<HTMLDivElement>;\n /** Ref that is placed on the inputWrapper */\n inputWrapperRef?: React.RefObject<HTMLDivElement>;\n /** Changes the color profile of the input */\n onColor?: keyof typeof FormOnColor;\n /** Changes the visuals of the input */\n size?: keyof typeof FormSize;\n /** Label of the input */\n label?: React.ReactNode;\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Component shown after input */\n afterInputChildren?: React.ReactNode;\n /** Component shown to the right of input */\n rightOfInput?: React.ReactNode;\n /** max character limit in input */\n maxCharacters?: number;\n /** @deprecated use resources instead. The text is displayed in the end of the text-counter */\n maxText?: string;\n /** Resources for component */\n resources?: Partial<HNDesignsystemInput>;\n}\n\nexport enum InputTypes {\n text = 'text',\n number = 'number',\n email = 'email',\n password = 'password',\n search = 'search',\n tel = 'tel',\n url = 'url',\n date = 'date',\n time = 'time',\n}\n\nconst getInputMaxWidth = (characters: number, hasIcon: boolean, iconSize: number): string => {\n const paddingWidth = hasIcon ? '1.5rem' : '2rem';\n const iconWidth = hasIcon ? `${iconSize}px` : '0px';\n const borderWidth = '4px';\n\n return `calc(${characters * AVERAGE_CHARACTER_WIDTH_PX}px + ${paddingWidth} + ${iconWidth} + ${borderWidth})`;\n};\n\nconst Input = React.forwardRef((props: InputProps, ref: React.Ref<HTMLInputElement>) => {\n const {\n className,\n defaultValue,\n placeholder,\n type = InputTypes.text,\n name,\n transparent = false,\n icon,\n iconRight,\n inputWrapperRef,\n onColor = FormOnColor.onwhite,\n size,\n baseIncrementValue,\n label,\n error,\n errorText,\n errorTextId: errorTextIdProp,\n inputId: inputIdProp,\n errorWrapperClassName,\n testId,\n disabled,\n readOnly,\n autoComplete = 'off',\n afterInputChildren,\n rightOfInput,\n width,\n required,\n onChange,\n onKeyDown,\n autoFocus,\n maxCharacters,\n maxText,\n inputContainerRef,\n resources,\n ...rest\n } = props;\n const { language } = useLanguage<LanguageLocales>(LanguageLocales.NORWEGIAN);\n const defaultResources = getResources(language);\n\n const mergedResources: HNDesignsystemInput = {\n ...defaultResources,\n ...resources,\n characters: maxText || resources?.characters || defaultResources.characters,\n };\n\n const breakpoint = useBreakpoint();\n const inputContainerRefLocal = useRef<HTMLDivElement>(null);\n const inputId = useIdWithFallback(inputIdProp);\n const [input, setInput] = useState(defaultValue || '');\n const [prevValue, setPrevValue] = useState<string | number | undefined>(undefined);\n const numKeyPressed = useRef<boolean>(false);\n const errorTextId = useIdWithFallback(errorTextIdProp);\n const numRegex = /^[0-9]$/;\n\n useEffect(() => {\n setInput(defaultValue || '');\n }, [defaultValue]);\n\n const onDark = onColor === FormOnColor.ondark;\n const onBlueberry = onColor === FormOnColor.onblueberry;\n const maxCharactersExceeded = !!maxCharacters && input.toString().length > maxCharacters;\n const onError = onColor === FormOnColor.oninvalid || !!errorText || !!error || maxCharactersExceeded;\n const isLarge = size === FormSize.large;\n const isTransparent = transparent && onColor !== FormOnColor.ondark && !onError;\n\n const inputWrapperClass = cn(styles['input-wrapper'], className);\n\n const inputContainer = cn(styles['input-container'], {\n [styles['input-container--transparent']]: isTransparent,\n [styles['input-container--on-blueberry']]: onBlueberry,\n [styles['input-container--on-dark']]: onDark,\n [styles['input-container--invalid']]: onError,\n [styles['input-container--disabled']]: disabled,\n [styles['input-container--with-icon']]: icon,\n [styles['input-container--with-icon--right']]: icon && iconRight,\n });\n\n const inputClass = cn(styles['input-container__input'], {\n [styles['input-container__input--large']]: isLarge,\n [styles['input-container__input--disabled']]: disabled,\n });\n\n const iconColor = disabled ? getColor('neutral', 700) : getColor('black');\n const iconSize = breakpoint === Breakpoint.xs || !isLarge ? IconSize.XSmall : IconSize.Small;\n\n const renderIcon = (): React.ReactNode => {\n if (!icon) {\n return;\n }\n\n if (typeof icon === 'string') {\n return <LazyIcon className={styles['input-container__input__icon']} color={iconColor} size={iconSize} iconName={icon} />;\n }\n\n return <Icon className={styles['input-container__input__icon']} color={iconColor} size={iconSize} svgIcon={icon} />;\n };\n\n // eslint-disable-next-line\n const handleClick = (e: React.MouseEvent<any>): void => {\n if (inputContainerRefLocal && inputContainerRefLocal.current && icon) {\n const selectedChild = iconRight ? 0 : 1;\n const input = inputContainerRefLocal.current.children[selectedChild] as HTMLInputElement;\n input.focus();\n\n if (props.onClick) props.onClick(e);\n }\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {\n const newValue = getIncrementValue(e);\n\n if (onChange) {\n onChange(e);\n }\n\n setInput(newValue);\n setPrevValue(newValue);\n };\n\n // Hvis bruker endrer number value med 1 og det skal startes på en annen verdi enn 0\n const getIncrementValue = (e: React.ChangeEvent<HTMLInputElement>): string => {\n if (typeof baseIncrementValue === 'undefined' || type !== 'number') return e.target.value;\n\n const valueAsNumber = Number(e.target.value);\n\n if (!prevValue && !numKeyPressed.current && (valueAsNumber === 1 || valueAsNumber === -1)) {\n e.target.value = baseIncrementValue + '';\n }\n\n return e.target.value;\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {\n if (numRegex.test(e.key)) {\n numKeyPressed.current = true;\n }\n if (onKeyDown) onKeyDown(e);\n };\n\n const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>): void => {\n if (numRegex.test(e.key)) {\n numKeyPressed.current = false;\n }\n };\n\n const maxWidth = width ? getInputMaxWidth(width, !!icon, iconSize) : undefined;\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextId}>\n <div data-testid={testId} data-analyticsid={AnalyticsId.Input} className={inputWrapperClass} ref={inputWrapperRef}>\n {renderLabel(label, inputId, onColor as FormOnColor)}\n {/* input-elementet tillater keyboard-interaksjon */}\n <div className={styles['content-wrapper']}>\n {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */}\n <div\n onClick={handleClick}\n ref={mergeRefs([inputContainerRefLocal, inputContainerRef])}\n className={inputContainer}\n style={{ maxWidth }}\n >\n {!iconRight && renderIcon()}\n <input\n {...rest}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n name={name}\n type={type}\n defaultValue={defaultValue}\n id={inputId}\n className={inputClass}\n ref={ref}\n aria-describedby={getAriaDescribedBy(props, errorTextId)}\n aria-invalid={!!onError}\n disabled={disabled}\n placeholder={placeholder}\n readOnly={readOnly}\n autoComplete={autoComplete || 'off'}\n required={required}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n />\n {iconRight && renderIcon()}\n </div>\n <div className={styles['content-wrapper__right-of-input']}>{rightOfInput}</div>\n </div>\n {maxCharacters && (\n <MaxCharacters\n maxCharacters={maxCharacters}\n length={input.toString().length}\n maxText={mergedResources.characters}\n onColor={onColor}\n maxWidth={maxWidth}\n />\n )}\n {afterInputChildren}\n </div>\n </ErrorWrapper>\n );\n});\n\nInput.displayName = 'Input';\n\nexport default Input;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AGMA,MAAa,gBAAgB,aAAmD;AAC9E,SAAQ,UAAR;EACE,KAAK,gBAAgB,QACnB,QAAO;EACT,KAAK,gBAAgB,kBACnB,QAAO;EACT,KAAK,gBAAgB;EACrB,QACE,QAAO;;;AC8Eb,IAAY,aAAA,yBAAA,cAAL;AACL,cAAA,UAAA;AACA,cAAA,YAAA;AACA,cAAA,WAAA;AACA,cAAA,cAAA;AACA,cAAA,YAAA;AACA,cAAA,SAAA;AACA,cAAA,SAAA;AACA,cAAA,UAAA;AACA,cAAA,UAAA;;;AAGF,IAAM,oBAAoB,cAAoB,SAAkB,aAA6B;CAC3F,MAAM,eAAe,UAAU,WAAW;CAC1C,MAAM,YAAY,UAAU,GAAG,SAAS,MAAM;AAG9C,QAAO,QAAQ,eAAA,GAAwC,OAAO,aAAa,KAAK,UAAU;;AAG5F,IAAM,QAAQ,MAAM,YAAY,OAAmB,QAAqC;CACtF,MAAM,EACJ,WACA,cACA,aACA,OAAO,WAAW,MAClB,MACA,cAAc,OACd,MACA,WACA,iBACA,UAAU,YAAY,SACtB,MACA,oBACA,OACA,OACA,WACA,aAAa,iBACb,SAAS,aACT,uBACA,QACA,UACA,UACA,eAAe,OACf,oBACA,cACA,OACA,UACA,UACA,WACA,WACA,eACA,SACA,mBACA,WACA,GAAG,SACD;CACJ,MAAM,EAAE,aAAa,YAA6B,gBAAgB,UAAU;CAC5E,MAAM,mBAAmB,aAAa,SAAS;CAE/C,MAAMA,kBAAuC;EAC3C,GAAG;EACH,GAAG;EACH,YAAY,WAAW,WAAW,cAAc,iBAAiB;EAClE;CAED,MAAM,aAAa,eAAe;CAClC,MAAM,yBAAyB,OAAuB,KAAK;CAC3D,MAAM,UAAU,kBAAkB,YAAY;CAC9C,MAAM,CAAC,OAAO,YAAY,SAAS,gBAAgB,GAAG;CACtD,MAAM,CAAC,WAAW,gBAAgB,SAAsC,KAAA,EAAU;CAClF,MAAM,gBAAgB,OAAgB,MAAM;CAC5C,MAAM,cAAc,kBAAkB,gBAAgB;CACtD,MAAM,WAAW;AAEjB,iBAAgB;AACd,WAAS,gBAAgB,GAAG;IAC3B,CAAC,aAAa,CAAC;CAElB,MAAM,SAAS,YAAY,YAAY;CACvC,MAAM,cAAc,YAAY,YAAY;CAC5C,MAAM,wBAAwB,CAAC,CAAC,iBAAiB,MAAM,UAAU,CAAC,SAAS;CAC3E,MAAM,UAAU,YAAY,YAAY,aAAa,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS;CAC/E,MAAM,UAAU,SAAS,SAAS;CAClC,MAAM,gBAAgB,eAAe,YAAY,YAAY,UAAU,CAAC;CAExE,MAAM,oBAAoB,WAAG,OAAO,kBAAkB,UAAU;CAEhE,MAAM,iBAAiB,WAAG,OAAO,oBAAoB;GAClD,OAAO,kCAAkC;GACzC,OAAO,mCAAmC;GAC1C,OAAO,8BAA8B;GACrC,OAAO,8BAA8B;GACrC,OAAO,+BAA+B;GACtC,OAAO,gCAAgC;GACvC,OAAO,uCAAuC,QAAQ;EACxD,CAAC;CAEF,MAAM,aAAa,WAAG,OAAO,2BAA2B;GACrD,OAAO,mCAAmC;GAC1C,OAAO,sCAAsC;EAC/C,CAAC;CAEF,MAAM,YAAY,WAAW,SAAS,WAAW,IAAI,GAAG,SAAS,QAAQ;CACzE,MAAM,WAAW,eAAe,WAAW,MAAM,CAAC,UAAU,SAAS,SAAS,SAAS;CAEvF,MAAM,mBAAoC;AACxC,MAAI,CAAC,KACH;AAGF,MAAI,OAAO,SAAS,SAClB,QAAO,oBAAC,kBAAA;GAAS,WAAW,OAAO;GAAiC,OAAO;GAAW,MAAM;GAAU,UAAU;IAAQ;AAG1H,SAAO,oBAAC,cAAA;GAAK,WAAW,OAAO;GAAiC,OAAO;GAAW,MAAM;GAAU,SAAS;IAAQ;;CAIrH,MAAM,eAAe,MAAmC;AACtD,MAAI,0BAA0B,uBAAuB,WAAW,MAAM;GACpE,MAAM,gBAAgB,YAAY,IAAI;AACxB,0BAAuB,QAAQ,SAAS,eAChD,OAAO;AAEb,OAAI,MAAM,QAAS,OAAM,QAAQ,EAAE;;;CAIvC,MAAM,gBAAgB,MAAiD;EACrE,MAAM,WAAW,kBAAkB,EAAE;AAErC,MAAI,SACF,UAAS,EAAE;AAGb,WAAS,SAAS;AAClB,eAAa,SAAS;;CAIxB,MAAM,qBAAqB,MAAmD;AAC5E,MAAI,OAAO,uBAAuB,eAAe,SAAS,SAAU,QAAO,EAAE,OAAO;EAEpF,MAAM,gBAAgB,OAAO,EAAE,OAAO,MAAM;AAE5C,MAAI,CAAC,aAAa,CAAC,cAAc,YAAY,kBAAkB,KAAK,kBAAkB,IACpF,GAAE,OAAO,QAAQ,qBAAqB;AAGxC,SAAO,EAAE,OAAO;;CAGlB,MAAM,iBAAiB,MAAmD;AACxE,MAAI,SAAS,KAAK,EAAE,IAAI,CACtB,eAAc,UAAU;AAE1B,MAAI,UAAW,WAAU,EAAE;;CAG7B,MAAM,eAAe,MAAmD;AACtE,MAAI,SAAS,KAAK,EAAE,IAAI,CACtB,eAAc,UAAU;;CAI5B,MAAM,WAAW,QAAQ,iBAAiB,OAAO,CAAC,CAAC,MAAM,SAAS,GAAG,KAAA;AAErE,QACE,oBAAC,sBAAA;EAAa,WAAW;EAAkC;EAAwB;YACjF,qBAAC,OAAA;GAAI,eAAa;GAAQ,oBAAkB,YAAY;GAAO,WAAW;GAAmB,KAAK;;IAC/F,YAAY,OAAO,SAAS,QAAuB;IAEpD,qBAAC,OAAA;KAAI,WAAW,OAAO;gBAErB,qBAAC,OAAA;MACC,SAAS;MACT,KAAK,UAAU,CAAC,wBAAwB,kBAAkB,CAAC;MAC3D,WAAW;MACX,OAAO,EAAE,UAAU;;OAElB,CAAC,aAAa,YAAY;OAC3B,oBAAC,SAAA;QACC,GAAI;QACJ,UAAU;QACV,WAAW;QACX,SAAS;QACH;QACA;QACQ;QACd,IAAI;QACJ,WAAW;QACN;QACL,oBAAkB,mBAAmB,OAAO,YAAY;QACxD,gBAAc,CAAC,CAAC;QACN;QACG;QACH;QACV,cAAc,gBAAgB;QACpB;QAEC;SACX;OACD,aAAa,YAAY;;OACtB,EACN,oBAAC,OAAA;MAAI,WAAW,OAAO;gBAAqC;OAAmB,CAAA;MAC3E;IACL,iBACC,oBAAC,uBAAA;KACgB;KACf,QAAQ,MAAM,UAAU,CAAC;KACzB,SAAS,gBAAgB;KAChB;KACC;MACV;IAEH;;IACG;GACO;EAEjB;AAEF,MAAM,cAAc;AAEpB,IAAA,gBAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"LinkList.js","names":["Link: LinkType","mergedResources: HNDesignsystemLinkList"],"sources":["../src/resources/HN.Designsystem.LinkList.en-GB.json","../src/resources/HN.Designsystem.LinkList.nb-NO.json","../src/components/LinkList/resourceHelper.ts","../src/components/LinkList/LinkList.tsx","../src/components/LinkList/index.ts"],"sourcesContent":["{\n \"editMode_deleteButtonAriaLabel\": \"Delete\"\n}\n","{\n \"editMode_deleteButtonAriaLabel\": \"Slett\"\n}\n","import { LanguageLocales } from '../../constants';\nimport enGB from '../../resources/HN.Designsystem.LinkList.en-GB.json';\nimport nbNO from '../../resources/HN.Designsystem.LinkList.nb-NO.json';\nimport { HNDesignsystemLinkList } from '../../resources/Resources';\n\nexport const getResources = (language: LanguageLocales): HNDesignsystemLinkList => {\n switch (language) {\n case LanguageLocales.ENGLISH:\n return enGB;\n case LanguageLocales.NORWEGIAN:\n default:\n return nbNO;\n }\n};\n","import React from 'react';\n\nimport cn from 'classnames';\n\nimport { AnalyticsId, LanguageLocales } from '../../constants';\nimport { usePseudoClasses } from '../../hooks/usePseudoClasses';\nimport { HNDesignsystemLinkList } from '../../resources/Resources';\nimport { PaletteNames } from '../../theme/palette';\nimport { useLanguage } from '../../utils/language';\nimport { ElementHeaderType, renderElementHeader } from '../ElementHeader/ElementHeader';\nimport ChevronRight from '../Icons/ChevronRight';\nimport ListEditModeItem, { ListEditModeItemProps, listEditModeWrapperClassnames } from '../ListEditMode';\nimport { getResources } from './resourceHelper';\n\nimport LinkListStyles from './styles.module.scss';\n\nexport type LinkListSize = 'small' | 'medium' | 'large';\n\nexport type LinkListStatus = 'none' | 'new';\n\nexport type LinkAnchorTargets = '_self' | '_blank' | '_parent';\n\nexport type LinkListColors = Extract<PaletteNames, 'white' | 'blueberry' | 'cherry' | 'neutral'>;\nexport type LinkListVariant = 'line' | 'outline' | 'fill' | 'fill-negative';\n\nexport interface LinkType extends React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLLIElement>> {\n ElementHeader?: ElementHeaderType;\n}\n\nexport type LinkTags = 'button' | 'a';\nexport interface CompoundComponent extends React.ForwardRefExoticComponent<LinkListProps & React.RefAttributes<HTMLUListElement>> {\n Link: LinkType;\n}\n\nexport interface LinkListProps {\n /** Items in the LinkList */\n children: React.ReactNode;\n /** Adds custom classes to the element. */\n className?: string;\n /** Changes the colors of the list. */\n color?: LinkListColors;\n /** Toggles chevron icon on or off. */\n chevron?: boolean;\n /** Changes size of the LinkList. */\n size?: LinkListSize;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Sets visual priority */\n variant?: LinkListVariant;\n /** Highlights text. Used for search results */\n highlightText?: string;\n /**\n * @experimental This prop is experimental and may change in the future.\n * Enables ListEditMode\n */\n editMode?: boolean;\n /** Resources for component */\n resources?: Partial<HNDesignsystemLinkList>;\n}\n\ntype Modify<T, R> = Omit<T, keyof R> & R;\n\nexport type LinkProps = Modify<\n React.HTMLAttributes<HTMLAnchorElement | HTMLButtonElement>,\n {\n children: React.ReactNode;\n chevron?: boolean;\n className?: string;\n icon?: React.ReactElement;\n /** Renders the image in the LinkList header */\n image?: React.ReactElement;\n /** Displays a status on the left side: default none */\n status?: LinkListStatus;\n href?: string;\n target?: LinkAnchorTargets;\n /** HTML markup for link. Default: a */\n htmlMarkup?: LinkTags;\n /**\n * Ref for lenke/knapp\n */\n linkRef?: React.RefObject<HTMLButtonElement | HTMLAnchorElement>;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Highlights text. Override if different from list */\n highlightText?: string;\n /** Resources for component */\n resources?: Partial<HNDesignsystemLinkList>;\n /** @experimental id for content (only used in edit mode for aria-describedby) */\n contentId?: string;\n }\n> &\n Pick<LinkListProps, 'color' | 'size' | 'variant'> &\n ListEditModeItemProps;\n\nexport const Link: LinkType = React.forwardRef((props: LinkProps, ref: React.Ref<HTMLLIElement>) => {\n const {\n children,\n className = '',\n color = 'white',\n icon,\n image,\n size = 'medium',\n chevron = false,\n linkRef,\n status = 'none',\n testId,\n target,\n variant,\n htmlMarkup = 'a',\n highlightText,\n editMode = false,\n contentId,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n resources, // used by ListEditModeItem in LinkList\n ...restProps\n } = props;\n const { refObject, isHovered } = usePseudoClasses<HTMLButtonElement | HTMLAnchorElement>(linkRef);\n\n const isFill = variant === 'fill';\n const isFillNegative = variant === 'fill-negative';\n const isOutline = variant === 'outline';\n const isLine = variant === 'line';\n\n const liClasses = cn(LinkListStyles['link-list'], {\n [LinkListStyles['link-list__list-item--line']]: isLine,\n [LinkListStyles['link-list__list-item--outline']]: isOutline,\n [LinkListStyles[`link-list__list-item--outline--${color}`]]: isOutline,\n });\n const linkClasses = cn(\n LinkListStyles['link-list__anchor'],\n LinkListStyles[`link-list__anchor--${color}`],\n {\n [LinkListStyles[`link-list__anchor--line--${color}`]]: isLine,\n [LinkListStyles['link-list__anchor--fill']]: isFill,\n [LinkListStyles[`link-list__anchor--fill--${color}`]]: isFill,\n [LinkListStyles['link-list__anchor--outline']]: isOutline,\n [LinkListStyles[`link-list__anchor--outline--${color}`]]: isOutline,\n [LinkListStyles['link-list__anchor--fill-negative']]: isFillNegative,\n [LinkListStyles[`link-list__anchor--fill-negative--${color}`]]: isFillNegative,\n [LinkListStyles[`link-list__anchor--${size}`]]: size,\n [LinkListStyles['link-list__anchor--button']]: htmlMarkup === 'button',\n [LinkListStyles['link-list__anchor--new']]: status === 'new',\n },\n className\n );\n\n const statusMarkerClasses = cn(LinkListStyles['link-list__status-marker'], {\n [LinkListStyles['link-list__status-marker--new']]: status === 'new',\n });\n\n const imageContainer = <span className={LinkListStyles['link-list__image-container']}>{image}</span>;\n\n return editMode ? (\n <div id={contentId} className={liClasses} data-testid={testId} data-analyticsid={AnalyticsId.Link}>\n <div className={linkClasses}>\n <div className={statusMarkerClasses}></div>\n {renderElementHeader(children, {\n titleHtmlMarkup: 'span',\n size,\n parentType: 'linklist',\n chevronIcon: chevron ? ChevronRight : undefined,\n icon: icon ?? imageContainer,\n highlightText,\n })}\n </div>\n </div>\n ) : (\n <li className={liClasses} ref={ref} data-testid={testId} data-analyticsid={AnalyticsId.Link}>\n {htmlMarkup === 'a' ? (\n <a\n className={linkClasses}\n ref={refObject as React.RefObject<HTMLAnchorElement>}\n rel={target === '_blank' ? 'noopener noreferrer' : undefined}\n target={target}\n {...restProps}\n >\n <div className={statusMarkerClasses}></div>\n {renderElementHeader(children, {\n titleHtmlMarkup: 'span',\n isHovered,\n size,\n parentType: 'linklist',\n chevronIcon: chevron ? ChevronRight : undefined,\n icon: icon ?? imageContainer,\n highlightText,\n })}\n </a>\n ) : (\n htmlMarkup === 'button' && (\n <button className={linkClasses} ref={refObject as React.RefObject<HTMLButtonElement>} type=\"button\" {...restProps}>\n <div className={statusMarkerClasses}></div>\n {renderElementHeader(children, {\n titleHtmlMarkup: 'span',\n isHovered,\n size,\n parentType: 'linklist',\n chevronIcon: chevron ? ChevronRight : undefined,\n icon: icon ?? imageContainer,\n highlightText,\n })}\n </button>\n )\n )}\n </li>\n );\n});\n\nexport const LinkList = React.forwardRef(function LinkListForwardedRef(props: LinkListProps, ref: React.Ref<HTMLUListElement>) {\n const {\n children,\n className = '',\n chevron = false,\n size = 'medium',\n color = 'white',\n testId,\n variant = 'line',\n highlightText,\n editMode = false,\n resources,\n } = props;\n\n const { language } = useLanguage<LanguageLocales>(LanguageLocales.NORWEGIAN);\n const defaultResources = getResources(language);\n\n const mergedResources: HNDesignsystemLinkList = {\n ...defaultResources,\n ...resources,\n };\n\n const listClassNames = cn(LinkListStyles['link-list'], className, {\n [LinkListStyles[`link-list--outline--${color}`]]: variant === 'outline',\n [listEditModeWrapperClassnames]: editMode,\n });\n\n return (\n <ul ref={ref} className={listClassNames} data-testid={testId} data-analyticsid={AnalyticsId.LinkList}>\n {React.Children.map(children, (child: React.ReactNode, index) => {\n if (React.isValidElement<LinkProps>(child) && child.type === Link) {\n if (editMode) {\n const childResources = child.props.resources;\n const deleteAriaLabel = childResources?.editMode_deleteButtonAriaLabel ?? mergedResources.editMode_deleteButtonAriaLabel;\n const itemId = `linklist-item-${index}`;\n\n return (\n <ListEditModeItem\n color={color}\n variant={variant}\n onDelete={child.props.onDelete}\n contentId={itemId}\n deleteButtonAriaLabel={deleteAriaLabel}\n >\n {React.cloneElement(child, {\n color,\n size,\n chevron: false,\n variant,\n highlightText: highlightText,\n editMode: true,\n contentId: itemId,\n })}\n </ListEditModeItem>\n );\n } else {\n return React.cloneElement(child, {\n color,\n size,\n chevron,\n variant,\n highlightText: highlightText,\n editMode: false,\n });\n }\n }\n return null;\n })}\n </ul>\n );\n}) as CompoundComponent;\n\nLinkList.displayName = 'LinkList';\nLinkList.Link = Link;\nLink.displayName = 'LinkList.Link';\n\nexport default LinkList;\n","import LinkList from './LinkList';\nexport * from './LinkList';\nexport default LinkList;\n"],"mappings":"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"}
1
+ {"version":3,"file":"LinkList.js","names":["Link: LinkType","mergedResources: HNDesignsystemLinkList"],"sources":["../src/resources/HN.Designsystem.LinkList.en-GB.json","../src/resources/HN.Designsystem.LinkList.nb-NO.json","../src/components/LinkList/resourceHelper.ts","../src/components/LinkList/LinkList.tsx","../src/components/LinkList/index.ts"],"sourcesContent":["{\n \"editMode_deleteButtonAriaLabel\": \"Delete\"\n}\n","{\n \"editMode_deleteButtonAriaLabel\": \"Slett\"\n}\n","import { LanguageLocales } from '../../constants';\nimport enGB from '../../resources/HN.Designsystem.LinkList.en-GB.json';\nimport nbNO from '../../resources/HN.Designsystem.LinkList.nb-NO.json';\nimport { HNDesignsystemLinkList } from '../../resources/Resources';\n\nexport const getResources = (language: LanguageLocales): HNDesignsystemLinkList => {\n switch (language) {\n case LanguageLocales.ENGLISH:\n return enGB;\n case LanguageLocales.NORWEGIAN:\n default:\n return nbNO;\n }\n};\n","import React from 'react';\n\nimport cn from 'classnames';\n\nimport { AnalyticsId, LanguageLocales } from '../../constants';\nimport { usePseudoClasses } from '../../hooks/usePseudoClasses';\nimport { HNDesignsystemLinkList } from '../../resources/Resources';\nimport { PaletteNames } from '../../theme/palette';\nimport { useLanguage } from '../../utils/language';\nimport { ElementHeaderType, renderElementHeader } from '../ElementHeader/ElementHeader';\nimport ChevronRight from '../Icons/ChevronRight';\nimport ListEditModeItem, { ListEditModeItemProps, listEditModeWrapperClassnames } from '../ListEditMode';\nimport { getResources } from './resourceHelper';\n\nimport LinkListStyles from './styles.module.scss';\n\nexport type LinkListSize = 'small' | 'medium' | 'large';\n\nexport type LinkListStatus = 'none' | 'new';\n\nexport type LinkAnchorTargets = '_self' | '_blank' | '_parent';\n\nexport type LinkListColors = Extract<PaletteNames, 'white' | 'blueberry' | 'cherry' | 'neutral'>;\nexport type LinkListVariant = 'line' | 'outline' | 'fill' | 'fill-negative';\n\nexport interface LinkType extends React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLLIElement>> {\n ElementHeader?: ElementHeaderType;\n}\n\nexport type LinkTags = 'button' | 'a';\nexport interface CompoundComponent extends React.ForwardRefExoticComponent<LinkListProps & React.RefAttributes<HTMLUListElement>> {\n Link: LinkType;\n}\n\nexport interface LinkListProps {\n /** Items in the LinkList */\n children: React.ReactNode;\n /** Adds custom classes to the element. */\n className?: string;\n /** Changes the colors of the list. */\n color?: LinkListColors;\n /** Toggles chevron icon on or off. */\n chevron?: boolean;\n /** Changes size of the LinkList. */\n size?: LinkListSize;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Sets visual priority */\n variant?: LinkListVariant;\n /** Highlights text. Used for search results */\n highlightText?: string;\n /**\n * @experimental This prop is experimental and may change in the future.\n * Enables ListEditMode\n */\n editMode?: boolean;\n /** Resources for component */\n resources?: Partial<HNDesignsystemLinkList>;\n}\n\ntype Modify<T, R> = Omit<T, keyof R> & R;\n\nexport type LinkProps = Modify<\n React.HTMLAttributes<HTMLAnchorElement | HTMLButtonElement>,\n {\n children: React.ReactNode;\n chevron?: boolean;\n className?: string;\n icon?: React.ReactElement;\n /** Renders the image in the LinkList header */\n image?: React.ReactElement;\n /** Displays a status on the left side: default none */\n status?: LinkListStatus;\n href?: string;\n target?: LinkAnchorTargets;\n /** HTML markup for link. Default: a */\n htmlMarkup?: LinkTags;\n /**\n * Ref for lenke/knapp\n */\n linkRef?: React.RefObject<HTMLButtonElement | HTMLAnchorElement> | null;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Highlights text. Override if different from list */\n highlightText?: string;\n /** Resources for component */\n resources?: Partial<HNDesignsystemLinkList>;\n /** @experimental id for content (only used in edit mode for aria-describedby) */\n contentId?: string;\n }\n> &\n Pick<LinkListProps, 'color' | 'size' | 'variant'> &\n ListEditModeItemProps;\n\nexport const Link: LinkType = React.forwardRef((props: LinkProps, ref: React.Ref<HTMLLIElement>) => {\n const {\n children,\n className = '',\n color = 'white',\n icon,\n image,\n size = 'medium',\n chevron = false,\n linkRef,\n status = 'none',\n testId,\n target,\n variant,\n htmlMarkup = 'a',\n highlightText,\n editMode = false,\n contentId,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n resources, // used by ListEditModeItem in LinkList\n ...restProps\n } = props;\n const { refObject, isHovered } = usePseudoClasses<HTMLButtonElement | HTMLAnchorElement>(linkRef);\n\n const isFill = variant === 'fill';\n const isFillNegative = variant === 'fill-negative';\n const isOutline = variant === 'outline';\n const isLine = variant === 'line';\n\n const liClasses = cn(LinkListStyles['link-list'], {\n [LinkListStyles['link-list__list-item--line']]: isLine,\n [LinkListStyles['link-list__list-item--outline']]: isOutline,\n [LinkListStyles[`link-list__list-item--outline--${color}`]]: isOutline,\n });\n const linkClasses = cn(\n LinkListStyles['link-list__anchor'],\n LinkListStyles[`link-list__anchor--${color}`],\n {\n [LinkListStyles[`link-list__anchor--line--${color}`]]: isLine,\n [LinkListStyles['link-list__anchor--fill']]: isFill,\n [LinkListStyles[`link-list__anchor--fill--${color}`]]: isFill,\n [LinkListStyles['link-list__anchor--outline']]: isOutline,\n [LinkListStyles[`link-list__anchor--outline--${color}`]]: isOutline,\n [LinkListStyles['link-list__anchor--fill-negative']]: isFillNegative,\n [LinkListStyles[`link-list__anchor--fill-negative--${color}`]]: isFillNegative,\n [LinkListStyles[`link-list__anchor--${size}`]]: size,\n [LinkListStyles['link-list__anchor--button']]: htmlMarkup === 'button',\n [LinkListStyles['link-list__anchor--new']]: status === 'new',\n },\n className\n );\n\n const statusMarkerClasses = cn(LinkListStyles['link-list__status-marker'], {\n [LinkListStyles['link-list__status-marker--new']]: status === 'new',\n });\n\n const imageContainer = <span className={LinkListStyles['link-list__image-container']}>{image}</span>;\n\n return editMode ? (\n <div id={contentId} className={liClasses} data-testid={testId} data-analyticsid={AnalyticsId.Link}>\n <div className={linkClasses}>\n <div className={statusMarkerClasses}></div>\n {renderElementHeader(children, {\n titleHtmlMarkup: 'span',\n size,\n parentType: 'linklist',\n chevronIcon: chevron ? ChevronRight : undefined,\n icon: icon ?? imageContainer,\n highlightText,\n })}\n </div>\n </div>\n ) : (\n <li className={liClasses} ref={ref} data-testid={testId} data-analyticsid={AnalyticsId.Link}>\n {htmlMarkup === 'a' ? (\n <a\n className={linkClasses}\n ref={refObject as React.RefObject<HTMLAnchorElement>}\n rel={target === '_blank' ? 'noopener noreferrer' : undefined}\n target={target}\n {...restProps}\n >\n <div className={statusMarkerClasses}></div>\n {renderElementHeader(children, {\n titleHtmlMarkup: 'span',\n isHovered,\n size,\n parentType: 'linklist',\n chevronIcon: chevron ? ChevronRight : undefined,\n icon: icon ?? imageContainer,\n highlightText,\n })}\n </a>\n ) : (\n htmlMarkup === 'button' && (\n <button className={linkClasses} ref={refObject as React.RefObject<HTMLButtonElement>} type=\"button\" {...restProps}>\n <div className={statusMarkerClasses}></div>\n {renderElementHeader(children, {\n titleHtmlMarkup: 'span',\n isHovered,\n size,\n parentType: 'linklist',\n chevronIcon: chevron ? ChevronRight : undefined,\n icon: icon ?? imageContainer,\n highlightText,\n })}\n </button>\n )\n )}\n </li>\n );\n});\n\nexport const LinkList = React.forwardRef(function LinkListForwardedRef(props: LinkListProps, ref: React.Ref<HTMLUListElement>) {\n const {\n children,\n className = '',\n chevron = false,\n size = 'medium',\n color = 'white',\n testId,\n variant = 'line',\n highlightText,\n editMode = false,\n resources,\n } = props;\n\n const { language } = useLanguage<LanguageLocales>(LanguageLocales.NORWEGIAN);\n const defaultResources = getResources(language);\n\n const mergedResources: HNDesignsystemLinkList = {\n ...defaultResources,\n ...resources,\n };\n\n const listClassNames = cn(LinkListStyles['link-list'], className, {\n [LinkListStyles[`link-list--outline--${color}`]]: variant === 'outline',\n [listEditModeWrapperClassnames]: editMode,\n });\n\n return (\n <ul ref={ref} className={listClassNames} data-testid={testId} data-analyticsid={AnalyticsId.LinkList}>\n {React.Children.map(children, (child: React.ReactNode, index) => {\n if (React.isValidElement<LinkProps>(child) && child.type === Link) {\n if (editMode) {\n const childResources = child.props.resources;\n const deleteAriaLabel = childResources?.editMode_deleteButtonAriaLabel ?? mergedResources.editMode_deleteButtonAriaLabel;\n const itemId = `linklist-item-${index}`;\n\n return (\n <ListEditModeItem\n color={color}\n variant={variant}\n onDelete={child.props.onDelete}\n contentId={itemId}\n deleteButtonAriaLabel={deleteAriaLabel}\n >\n {React.cloneElement(child, {\n color,\n size,\n chevron: false,\n variant,\n highlightText: highlightText,\n editMode: true,\n contentId: itemId,\n })}\n </ListEditModeItem>\n );\n } else {\n return React.cloneElement(child, {\n color,\n size,\n chevron,\n variant,\n highlightText: highlightText,\n editMode: false,\n });\n }\n }\n return null;\n })}\n </ul>\n );\n}) as CompoundComponent;\n\nLinkList.displayName = 'LinkList';\nLinkList.Link = Link;\nLink.displayName = 'LinkList.Link';\n\nexport default LinkList;\n","import LinkList from './LinkList';\nexport * from './LinkList';\nexport default LinkList;\n"],"mappings":"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"}
@@ -15,7 +15,7 @@ var MaxCharacters = ({ maxCharacters, maxText, length, onColor, maxWidth }) => {
15
15
  "aria-atomic": "true",
16
16
  className: counterTextClass,
17
17
  style: { maxWidth },
18
- children: `${length}/${maxCharacters} ${maxText ? maxText : "tegn"}`
18
+ children: `${length}/${maxCharacters} ${maxText}`
19
19
  });
20
20
  };
21
21
  var MaxCharacters_default = MaxCharacters;
@@ -1 +1 @@
1
- {"version":3,"file":"MaxCharacters.js","names":["MaxCharacters: React.FC<MaxCharactersProps>"],"sources":["../src/components/MaxCharacters/MaxCharacters.tsx"],"sourcesContent":["import React from 'react';\n\nimport classNames from 'classnames';\n\nimport { FormOnColor } from '../../constants';\n\nimport styles from './styles.module.scss';\n\ninterface MaxCharactersProps {\n /** Current input length */\n length: number;\n /** max character limit in textarea */\n maxCharacters: number;\n /** The text is displayed in the end of the text-counter */\n maxText?: string;\n /** Changes the visuals of the textarea */\n onColor?: keyof typeof FormOnColor;\n /** Max width of the component */\n maxWidth?: string;\n}\n\nconst MaxCharacters: React.FC<MaxCharactersProps> = ({ maxCharacters, maxText, length, onColor, maxWidth }) => {\n const progress = length / maxCharacters;\n\n const counterTextClass = classNames(styles['max-characters'], {\n [styles[`max-characters--on-dark`]]: onColor === FormOnColor.ondark,\n [styles[`max-characters--invalid`]]: progress > 1,\n });\n\n const ariaLevel = progress > 0.95 ? 'polite' : 'off';\n\n return (\n <div aria-live={ariaLevel} aria-atomic={'true'} className={counterTextClass} style={{ maxWidth }}>\n {`${length}/${maxCharacters} ${maxText ? maxText : 'tegn'}`}\n </div>\n );\n};\n\nexport default MaxCharacters;\n"],"mappings":";;;;;AAqBA,IAAMA,iBAA+C,EAAE,eAAe,SAAS,QAAQ,SAAS,eAAe;CAC7G,MAAM,WAAW,SAAS;CAE1B,MAAM,mBAAmB,WAAW,OAAO,mBAAmB;GAC3D,OAAO,6BAA6B,YAAY,YAAY;GAC5D,OAAO,6BAA6B,WAAW;EACjD,CAAC;CAEF,MAAM,YAAY,WAAW,MAAO,WAAW;AAE/C,QACE,oBAAC,OAAA;EAAI,aAAW;EAAW,eAAa;EAAQ,WAAW;EAAkB,OAAO,EAAE,UAAU;YAC7F,GAAG,OAAO,GAAG,cAAc,GAAG,UAAU,UAAU;GAC/C;;AAIV,IAAA,wBAAe"}
1
+ {"version":3,"file":"MaxCharacters.js","names":["MaxCharacters: React.FC<MaxCharactersProps>"],"sources":["../src/components/MaxCharacters/MaxCharacters.tsx"],"sourcesContent":["import React from 'react';\n\nimport classNames from 'classnames';\n\nimport { FormOnColor } from '../../constants';\n\nimport styles from './styles.module.scss';\n\ninterface MaxCharactersProps {\n /** Current input length */\n length: number;\n /** max character limit in textarea */\n maxCharacters: number;\n /** The text is displayed in the end of the text-counter */\n maxText: string;\n /** Changes the visuals of the textarea */\n onColor?: keyof typeof FormOnColor;\n /** Max width of the component */\n maxWidth?: string;\n}\n\nconst MaxCharacters: React.FC<MaxCharactersProps> = ({ maxCharacters, maxText, length, onColor, maxWidth }) => {\n const progress = length / maxCharacters;\n\n const counterTextClass = classNames(styles['max-characters'], {\n [styles[`max-characters--on-dark`]]: onColor === FormOnColor.ondark,\n [styles[`max-characters--invalid`]]: progress > 1,\n });\n\n const ariaLevel = progress > 0.95 ? 'polite' : 'off';\n\n return (\n <div aria-live={ariaLevel} aria-atomic={'true'} className={counterTextClass} style={{ maxWidth }}>\n {`${length}/${maxCharacters} ${maxText}`}\n </div>\n );\n};\n\nexport default MaxCharacters;\n"],"mappings":";;;;;AAqBA,IAAMA,iBAA+C,EAAE,eAAe,SAAS,QAAQ,SAAS,eAAe;CAC7G,MAAM,WAAW,SAAS;CAE1B,MAAM,mBAAmB,WAAW,OAAO,mBAAmB;GAC3D,OAAO,6BAA6B,YAAY,YAAY;GAC5D,OAAO,6BAA6B,WAAW;EACjD,CAAC;CAEF,MAAM,YAAY,WAAW,MAAO,WAAW;AAE/C,QACE,oBAAC,OAAA;EAAI,aAAW;EAAW,eAAa;EAAQ,WAAW;EAAkB,OAAO,EAAE,UAAU;YAC7F,GAAG,OAAO,GAAG,cAAc,GAAG;GAC3B;;AAIV,IAAA,wBAAe"}
package/lib/Slider.js CHANGED
@@ -119,6 +119,7 @@ const Slider = React.forwardRef((props, ref) => {
119
119
  };
120
120
  const handlePointerDown = (e) => {
121
121
  if (disabled) return;
122
+ handleTrackClick(e);
122
123
  setIsMoving(true);
123
124
  handleSelected();
124
125
  e.preventDefault();
@@ -230,7 +231,6 @@ const Slider = React.forwardRef((props, ref) => {
230
231
  /* @__PURE__ */ jsxs("div", {
231
232
  ref: trackRef,
232
233
  className: classNames(styles["slider__track-wrapper"], disabled && styles["slider__track-wrapper--disabled"]),
233
- onClick: handleTrackClick,
234
234
  onPointerDown: handlePointerDown,
235
235
  children: [/* @__PURE__ */ jsx("div", {
236
236
  className: classNames(styles.slider__track, disabled && styles["slider__track--disabled"]),
package/lib/Slider.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Slider.js","names":["handleKeyDown: React.KeyboardEventHandler<HTMLDivElement>","handleTrackClick: React.MouseEventHandler<HTMLDivElement>","handlePointerDown: React.PointerEventHandler<HTMLDivElement>"],"sources":["../src/components/Slider/Slider.tsx","../src/components/Slider/index.ts"],"sourcesContent":["import React, { useEffect, useState, useRef, useId } from 'react';\n\nimport classNames from 'classnames';\n\nimport { AnalyticsId } from '../../constants';\nimport { useIdWithFallback } from '../../hooks/useIdWithFallback';\nimport { usePseudoClasses } from '../../hooks/usePseudoClasses';\nimport { useSize } from '../../hooks/useSize';\nimport { getAriaLabelAttributes } from '../../utils/accessibility';\nimport { isMutableRefObject, mergeRefs } from '../../utils/refs';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport Title from '../Title';\n\nimport styles from './styles.module.scss';\n\nconst useSafeNumberValue = (initial: number, min: number, max: number): [number, (value: number) => void] => {\n const [value, setValue] = useState(initial);\n\n const setSafeValue = (newValue: number): void => {\n if (newValue > max) {\n setValue(max);\n } else if (newValue < min) {\n setValue(min);\n } else {\n setValue(newValue);\n }\n };\n\n useEffect(() => {\n setSafeValue(initial);\n }, [min, max]);\n\n return [value, setSafeValue];\n};\n\nexport type SliderStep = {\n label?: number | string;\n emojiUniCode?: string;\n};\n\nexport interface SliderProps\n extends ErrorWrapperClassNameProps,\n Pick<React.InputHTMLAttributes<HTMLInputElement>, 'id' | 'name' | 'onChange' | 'onBlur'> {\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n /**\tSets the title of the slider. */\n title?: string;\n /** Adds the left hand label to the element. */\n labelLeft?: string;\n /** Adds the right hand label to the element. */\n labelRight?: string;\n /**\tSets aria-label of the slider. */\n ariaLabel?: string;\n /** Disables the slider element. */\n disabled?: boolean;\n /** Sets the minimum allowed value on the slider - this overrides the use of steps prop for minValue/maxValue. */\n minValue?: number;\n /** Sets the maximum allowed value on the slider - this overrides the use of steps prop for minValue/maxValue. */\n maxValue?: number;\n /** If set to false will only trigger onChange once a user interaction has been made, updates to this prop will be taken into account - true by default */\n selected?: boolean;\n /** Sets the steps data for the slider */\n steps?: SliderStep[];\n /** Sets the step to move per point in the slider */\n step?: number;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Sets the value of the slider */\n value?: number;\n}\n\nexport const Slider = React.forwardRef((props: SliderProps, ref: React.Ref<HTMLInputElement>) => {\n const {\n title,\n ariaLabel,\n error,\n errorText,\n errorTextId: errorTextIdProp,\n errorWrapperClassName,\n labelLeft,\n labelRight,\n disabled = false,\n onChange,\n steps,\n step = 1,\n minValue = 0,\n maxValue = steps ? steps.length - 1 : 100,\n selected = true,\n testId,\n value,\n ...rest\n } = props;\n\n const [isMoving, setIsMoving] = useState(false);\n const [selectedState, setSelectedState] = useState(typeof value === 'undefined' ? selected : true);\n const [valueState, setValueState] = useSafeNumberValue(\n typeof value === 'undefined' ? (maxValue - minValue) / 2 + minValue : value,\n minValue,\n maxValue\n );\n\n const errorTextId = useIdWithFallback(errorTextIdProp);\n const baseId = useId();\n const titleId = 'title-' + baseId;\n const labelLeftId = 'label-' + baseId;\n const labelRightId = 'label-right-' + baseId;\n const trackRef = useRef<HTMLDivElement>(null);\n const { refObject, isFocused } = usePseudoClasses<HTMLInputElement>(isMutableRefObject(ref) ? ref : null);\n const mergedRefs = mergeRefs([ref, refObject]);\n\n const { width: trackWidth } = useSize(trackRef) || { width: 0 };\n const largeStep = maxValue / 10;\n const invalid = !!errorText || !!error;\n\n useEffect(() => {\n const handlePointerUp = (): void => {\n setIsMoving(false);\n };\n\n document.addEventListener('pointerup', handlePointerUp);\n\n return (): void => {\n document.removeEventListener('pointerup', handlePointerUp);\n };\n }, []);\n\n const getValueBasedOnMarkerPosition = (markerPosition: number): number => {\n const trackPosition = trackRef.current?.getBoundingClientRect().x ?? 0;\n\n // Calculate the normalized position (0 to 1) of the marker along the track\n const normalizedPosition = (markerPosition - trackPosition) / trackWidth;\n const valueRange = maxValue - minValue;\n // Calculate the value without considering the step\n let value = normalizedPosition * valueRange + minValue;\n // Adjust the value to account for the step increment\n const stepCount = Math.round(value / step);\n value = stepCount * step;\n value = Math.max(minValue, Math.min(maxValue, value));\n\n return value;\n };\n\n useEffect(() => {\n const handlePointerMove = (e: PointerEvent): void => {\n if (!disabled && isMoving) {\n const newValue = getValueBasedOnMarkerPosition(e.clientX);\n setValueState(newValue);\n }\n };\n\n document.addEventListener('pointermove', handlePointerMove);\n\n return (): void => {\n document.removeEventListener('pointermove', handlePointerMove);\n };\n }, [isMoving]);\n\n useEffect(() => {\n if (value !== valueState && typeof value !== 'undefined') {\n handleSelected();\n setValueState(value);\n }\n }, [value]);\n\n useEffect(() => {\n if (typeof value === 'undefined' && selected !== selectedState) {\n setSelectedState(selected);\n }\n }, [selected]);\n\n const handleSelected = (): void => {\n if (selectedState === false) {\n setSelectedState(true);\n }\n };\n\n const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = e => {\n if (disabled) return;\n\n let flag = false;\n\n switch (e.key) {\n case 'ArrowLeft':\n case 'ArrowDown':\n setValueState(valueState - step);\n flag = true;\n break;\n case 'PageDown':\n setValueState(valueState - largeStep);\n flag = true;\n break;\n case 'ArrowRight':\n case 'ArrowUp':\n setValueState(valueState + step);\n flag = true;\n break;\n case 'PageUp':\n setValueState(valueState + largeStep);\n flag = true;\n break;\n case 'Home':\n setValueState(minValue);\n flag = true;\n break;\n case 'End':\n setValueState(maxValue);\n flag = true;\n break;\n default:\n break;\n }\n\n if (flag) {\n handleSelected();\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n const handleTrackClick: React.MouseEventHandler<HTMLDivElement> = e => {\n if (disabled) return;\n\n const newValue = getValueBasedOnMarkerPosition(e.clientX);\n setValueState(newValue);\n refObject.current?.focus();\n };\n\n const handlePointerDown: React.PointerEventHandler<HTMLDivElement> = e => {\n if (disabled) return;\n\n setIsMoving(true);\n handleSelected();\n\n e.preventDefault();\n e.stopPropagation();\n\n refObject.current?.focus();\n };\n\n const markerXPos = maxValue !== minValue ? (trackWidth / (maxValue - minValue)) * (valueState - minValue) : 0;\n\n const getAriaValueText = (): string | undefined => {\n const stepIndex = steps ? Math.round((valueState - minValue) / step) : null;\n\n if (steps && stepIndex !== null && stepIndex >= 0 && stepIndex < steps.length) {\n const step = steps[stepIndex];\n const emojiCode = step.emojiUniCode;\n const label = typeof step.label !== 'undefined' ? step.label.toString() : undefined;\n\n return emojiCode && label ? `${emojiCode} ${label}` : emojiCode || label;\n }\n\n return undefined;\n };\n\n const getAriaLabeledById = (): string | undefined => {\n if (title && labelLeft && labelRight) {\n return [titleId, labelLeftId, labelRightId].join(' ');\n }\n if (title && labelLeft) {\n return [titleId, labelLeftId].join(' ');\n }\n if (title && labelRight) {\n return [titleId, labelRightId].join(' ');\n }\n if (title) {\n return titleId;\n }\n };\n\n const ariaLabelAttributes = getAriaLabelAttributes({\n label: ariaLabel,\n id: getAriaLabeledById(),\n prefer: 'label',\n });\n\n const getXPositionStyling = (index: number, stepsLength: number): { left: string } => {\n return { left: `${(index / (stepsLength - 1)) * 100}%` };\n };\n\n useEffect(() => {\n if (selectedState && onChange) {\n onChange({\n target: {\n name: props.name,\n value: valueState,\n },\n } as unknown as React.ChangeEvent<HTMLInputElement>);\n }\n }, [valueState, selectedState]);\n\n const renderEmojies = (): React.ReactNode => {\n return (\n <div className={styles['slider__emoji-container']}>\n {steps?.map((step, index) => {\n return (\n step.emojiUniCode && (\n <div\n aria-hidden={true}\n key={'emoji' + index}\n className={styles['slider__emoji']}\n style={getXPositionStyling(index, steps.length)}\n >\n {step.emojiUniCode}\n </div>\n )\n );\n })}\n </div>\n );\n };\n\n const renderSteps = (): React.ReactNode => {\n return steps?.map((_step, index) => {\n return <div key={'step' + index} className={styles['slider__track__step']} style={getXPositionStyling(index, steps.length)} />;\n });\n };\n\n const renderStepLabels = (): React.ReactNode => {\n return (\n <div className={styles['slider__value-container']}>\n {steps?.map((step, index) => {\n return (\n typeof step.label !== 'undefined' && (\n <div\n aria-hidden={true}\n key={'label' + index}\n className={styles['slider__value']}\n style={getXPositionStyling(index, steps.length)}\n >\n {step.label}\n </div>\n )\n );\n })}\n </div>\n );\n };\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextId}>\n <input\n aria-valuetext={getAriaValueText()}\n className={styles['sr-only-slider']}\n disabled={disabled}\n min={minValue}\n max={maxValue}\n onChange={onChange}\n onKeyDown={handleKeyDown}\n value={valueState}\n ref={mergedRefs}\n type=\"range\"\n {...rest}\n {...ariaLabelAttributes}\n />\n <div className={styles.slider} data-testid={testId} data-analyticsid={AnalyticsId.Slider}>\n {title && (\n <Title className={styles['slider__title']} htmlMarkup={'h3'} margin={0} appearance={'title3'} id={titleId}>\n {title}\n </Title>\n )}\n <div className={styles['slider__content-container']}>\n {renderEmojies()}\n {/* Slider streken er klikkbar med mus/touch */}\n {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */}\n <div\n ref={trackRef}\n className={classNames(styles['slider__track-wrapper'], disabled && styles['slider__track-wrapper--disabled'])}\n onClick={handleTrackClick}\n onPointerDown={handlePointerDown}\n >\n <div className={classNames(styles.slider__track, disabled && styles['slider__track--disabled'])}>{renderSteps()}</div>\n <div\n className={classNames(styles.slider__marker, {\n [styles['slider__marker--disabled']]: disabled,\n [styles['slider__marker--selected']]: selectedState,\n [styles['slider__marker--invalid']]: invalid,\n [styles['slider__marker--focused']]: !disabled && isFocused,\n })}\n style={{\n left: `${markerXPos}px`,\n }}\n />\n </div>\n {renderStepLabels()}\n </div>\n {(labelLeft || labelRight) && (\n <span className={styles.slider__options}>\n <span id={labelLeftId}>{labelLeft}</span>\n <span id={labelRightId}>{labelRight}</span>\n </span>\n )}\n </div>\n </ErrorWrapper>\n );\n});\n\nSlider.displayName = 'Slider';\n\nexport default Slider;\n","import Slider from './Slider';\nexport * from './Slider';\nexport default Slider;\n"],"mappings":";;;;;;;;;;;;AAeA,IAAM,sBAAsB,SAAiB,KAAa,QAAmD;CAC3G,MAAM,CAAC,OAAO,YAAY,SAAS,QAAQ;CAE3C,MAAM,gBAAgB,aAA2B;AAC/C,MAAI,WAAW,IACb,UAAS,IAAI;WACJ,WAAW,IACpB,UAAS,IAAI;MAEb,UAAS,SAAS;;AAItB,iBAAgB;AACd,eAAa,QAAQ;IACpB,CAAC,KAAK,IAAI,CAAC;AAEd,QAAO,CAAC,OAAO,aAAa;;AA2C9B,MAAa,SAAS,MAAM,YAAY,OAAoB,QAAqC;CAC/F,MAAM,EACJ,OACA,WACA,OACA,WACA,aAAa,iBACb,uBACA,WACA,YACA,WAAW,OACX,UACA,OACA,OAAO,GACP,WAAW,GACX,WAAW,QAAQ,MAAM,SAAS,IAAI,KACtC,WAAW,MACX,QACA,OACA,GAAG,SACD;CAEJ,MAAM,CAAC,UAAU,eAAe,SAAS,MAAM;CAC/C,MAAM,CAAC,eAAe,oBAAoB,SAAS,OAAO,UAAU,cAAc,WAAW,KAAK;CAClG,MAAM,CAAC,YAAY,iBAAiB,mBAClC,OAAO,UAAU,eAAe,WAAW,YAAY,IAAI,WAAW,OACtE,UACA,SACD;CAED,MAAM,cAAc,kBAAkB,gBAAgB;CACtD,MAAM,SAAS,OAAO;CACtB,MAAM,UAAU,WAAW;CAC3B,MAAM,cAAc,WAAW;CAC/B,MAAM,eAAe,iBAAiB;CACtC,MAAM,WAAW,OAAuB,KAAK;CAC7C,MAAM,EAAE,WAAW,cAAc,iBAAmC,mBAAmB,IAAI,GAAG,MAAM,KAAK;CACzG,MAAM,aAAa,UAAU,CAAC,KAAK,UAAU,CAAC;CAE9C,MAAM,EAAE,OAAO,eAAe,QAAQ,SAAS,IAAI,EAAE,OAAO,GAAG;CAC/D,MAAM,YAAY,WAAW;CAC7B,MAAM,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC;AAEjC,iBAAgB;EACd,MAAM,wBAA8B;AAClC,eAAY,MAAM;;AAGpB,WAAS,iBAAiB,aAAa,gBAAgB;AAEvD,eAAmB;AACjB,YAAS,oBAAoB,aAAa,gBAAgB;;IAE3D,EAAE,CAAC;CAEN,MAAM,iCAAiC,mBAAmC;EAOxE,IAAI,WAHwB,kBAHN,SAAS,SAAS,uBAAuB,CAAC,KAAK,MAGP,cAC3C,WAAW,YAEgB;AAG9C,YADkB,KAAK,MAAM,UAAQ,KAAK,GACtB;AACpB,YAAQ,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,QAAM,CAAC;AAErD,SAAO;;AAGT,iBAAgB;EACd,MAAM,qBAAqB,MAA0B;AACnD,OAAI,CAAC,YAAY,SAEf,eADiB,8BAA8B,EAAE,QAAQ,CAClC;;AAI3B,WAAS,iBAAiB,eAAe,kBAAkB;AAE3D,eAAmB;AACjB,YAAS,oBAAoB,eAAe,kBAAkB;;IAE/D,CAAC,SAAS,CAAC;AAEd,iBAAgB;AACd,MAAI,UAAU,cAAc,OAAO,UAAU,aAAa;AACxD,mBAAgB;AAChB,iBAAc,MAAM;;IAErB,CAAC,MAAM,CAAC;AAEX,iBAAgB;AACd,MAAI,OAAO,UAAU,eAAe,aAAa,cAC/C,kBAAiB,SAAS;IAE3B,CAAC,SAAS,CAAC;CAEd,MAAM,uBAA6B;AACjC,MAAI,kBAAkB,MACpB,kBAAiB,KAAK;;CAI1B,MAAMA,iBAA4D,MAAK;AACrE,MAAI,SAAU;EAEd,IAAI,OAAO;AAEX,UAAQ,EAAE,KAAV;GACE,KAAK;GACL,KAAK;AACH,kBAAc,aAAa,KAAK;AAChC,WAAO;AACP;GACF,KAAK;AACH,kBAAc,aAAa,UAAU;AACrC,WAAO;AACP;GACF,KAAK;GACL,KAAK;AACH,kBAAc,aAAa,KAAK;AAChC,WAAO;AACP;GACF,KAAK;AACH,kBAAc,aAAa,UAAU;AACrC,WAAO;AACP;GACF,KAAK;AACH,kBAAc,SAAS;AACvB,WAAO;AACP;GACF,KAAK;AACH,kBAAc,SAAS;AACvB,WAAO;AACP;GACF,QACE;;AAGJ,MAAI,MAAM;AACR,mBAAgB;AAChB,KAAE,gBAAgB;AAClB,KAAE,iBAAiB;;;CAIvB,MAAMC,oBAA4D,MAAK;AACrE,MAAI,SAAU;AAGd,gBADiB,8BAA8B,EAAE,QAAQ,CAClC;AACvB,YAAU,SAAS,OAAO;;CAG5B,MAAMC,qBAA+D,MAAK;AACxE,MAAI,SAAU;AAEd,cAAY,KAAK;AACjB,kBAAgB;AAEhB,IAAE,gBAAgB;AAClB,IAAE,iBAAiB;AAEnB,YAAU,SAAS,OAAO;;CAG5B,MAAM,aAAa,aAAa,WAAY,cAAc,WAAW,aAAc,aAAa,YAAY;CAE5G,MAAM,yBAA6C;EACjD,MAAM,YAAY,QAAQ,KAAK,OAAO,aAAa,YAAY,KAAK,GAAG;AAEvE,MAAI,SAAS,cAAc,QAAQ,aAAa,KAAK,YAAY,MAAM,QAAQ;GAC7E,MAAM,SAAO,MAAM;GACnB,MAAM,YAAY,OAAK;GACvB,MAAM,QAAQ,OAAO,OAAK,UAAU,cAAc,OAAK,MAAM,UAAU,GAAG,KAAA;AAE1E,UAAO,aAAa,QAAQ,GAAG,UAAU,GAAG,UAAU,aAAa;;;CAMvE,MAAM,2BAA+C;AACnD,MAAI,SAAS,aAAa,WACxB,QAAO;GAAC;GAAS;GAAa;GAAa,CAAC,KAAK,IAAI;AAEvD,MAAI,SAAS,UACX,QAAO,CAAC,SAAS,YAAY,CAAC,KAAK,IAAI;AAEzC,MAAI,SAAS,WACX,QAAO,CAAC,SAAS,aAAa,CAAC,KAAK,IAAI;AAE1C,MAAI,MACF,QAAO;;CAIX,MAAM,sBAAsB,uBAAuB;EACjD,OAAO;EACP,IAAI,oBAAoB;EACxB,QAAQ;EACT,CAAC;CAEF,MAAM,uBAAuB,OAAe,gBAA0C;AACpF,SAAO,EAAE,MAAM,GAAI,SAAS,cAAc,KAAM,IAAI,IAAI;;AAG1D,iBAAgB;AACd,MAAI,iBAAiB,SACnB,UAAS,EACP,QAAQ;GACN,MAAM,MAAM;GACZ,OAAO;GACR,EACF,CAAmD;IAErD,CAAC,YAAY,cAAc,CAAC;CAE/B,MAAM,sBAAuC;AAC3C,SACE,oBAAC,OAAA;GAAI,WAAW,OAAO;aACpB,OAAO,KAAK,QAAM,UAAU;AAC3B,WACE,OAAK,gBACH,oBAAC,OAAA;KACC,eAAa;KAEb,WAAW,OAAO;KAClB,OAAO,oBAAoB,OAAO,MAAM,OAAO;eAE9C,OAAK;OAJD,UAAU,MAKX;KAGV;IACE;;CAIV,MAAM,oBAAqC;AACzC,SAAO,OAAO,KAAK,OAAO,UAAU;AAClC,UAAO,oBAAC,OAAA;IAAyB,WAAW,OAAO;IAAwB,OAAO,oBAAoB,OAAO,MAAM,OAAO;MAAzG,SAAS,MAAoG;IAC9H;;CAGJ,MAAM,yBAA0C;AAC9C,SACE,oBAAC,OAAA;GAAI,WAAW,OAAO;aACpB,OAAO,KAAK,QAAM,UAAU;AAC3B,WACE,OAAO,OAAK,UAAU,eACpB,oBAAC,OAAA;KACC,eAAa;KAEb,WAAW,OAAO;KAClB,OAAO,oBAAoB,OAAO,MAAM,OAAO;eAE9C,OAAK;OAJD,UAAU,MAKX;KAGV;IACE;;AAIV,QACE,qBAAC,sBAAA;EAAa,WAAW;EAAkC;EAAwB;aACjF,oBAAC,SAAA;GACC,kBAAgB,kBAAkB;GAClC,WAAW,OAAO;GACR;GACV,KAAK;GACL,KAAK;GACK;GACV,WAAW;GACX,OAAO;GACP,KAAK;GACL,MAAK;GACL,GAAI;GACJ,GAAI;IACJ,EACF,qBAAC,OAAA;GAAI,WAAW,OAAO;GAAQ,eAAa;GAAQ,oBAAkB,YAAY;;IAC/E,SACC,oBAAC,eAAA;KAAM,WAAW,OAAO;KAAkB,YAAY;KAAM,QAAQ;KAAG,YAAY;KAAU,IAAI;eAC/F;MACK;IAEV,qBAAC,OAAA;KAAI,WAAW,OAAO;;MACpB,eAAe;MAGhB,qBAAC,OAAA;OACC,KAAK;OACL,WAAW,WAAW,OAAO,0BAA0B,YAAY,OAAO,mCAAmC;OAC7G,SAAS;OACT,eAAe;kBAEf,oBAAC,OAAA;QAAI,WAAW,WAAW,OAAO,eAAe,YAAY,OAAO,2BAA2B;kBAAG,aAAa;SAAO,EACtH,oBAAC,OAAA;QACC,WAAW,WAAW,OAAO,gBAAgB;UAC1C,OAAO,8BAA8B;UACrC,OAAO,8BAA8B;UACrC,OAAO,6BAA6B;UACpC,OAAO,6BAA6B,CAAC,YAAY;SACnD,CAAC;QACF,OAAO,EACL,MAAM,GAAG,WAAW,KACrB;SACD,CAAA;QACE;MACL,kBAAkB;;MACf;KACJ,aAAa,eACb,qBAAC,QAAA;KAAK,WAAW,OAAO;gBACtB,oBAAC,QAAA;MAAK,IAAI;gBAAc;OAAiB,EACzC,oBAAC,QAAA;MAAK,IAAI;gBAAe;OAAkB,CAAA;MACtC;;IAEL,CAAA;GACO;EAEjB;AAEF,OAAO,cAAc;AC/YrB,IAAA,mBDiZe"}
1
+ {"version":3,"file":"Slider.js","names":["handleKeyDown: React.KeyboardEventHandler<HTMLDivElement>","handleTrackClick: React.MouseEventHandler<HTMLDivElement>","handlePointerDown: React.PointerEventHandler<HTMLDivElement>"],"sources":["../src/components/Slider/Slider.tsx","../src/components/Slider/index.ts"],"sourcesContent":["import React, { useEffect, useState, useRef, useId } from 'react';\n\nimport classNames from 'classnames';\n\nimport { AnalyticsId } from '../../constants';\nimport { useIdWithFallback } from '../../hooks/useIdWithFallback';\nimport { usePseudoClasses } from '../../hooks/usePseudoClasses';\nimport { useSize } from '../../hooks/useSize';\nimport { getAriaLabelAttributes } from '../../utils/accessibility';\nimport { isMutableRefObject, mergeRefs } from '../../utils/refs';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport Title from '../Title';\n\nimport styles from './styles.module.scss';\n\nconst useSafeNumberValue = (initial: number, min: number, max: number): [number, (value: number) => void] => {\n const [value, setValue] = useState(initial);\n\n const setSafeValue = (newValue: number): void => {\n if (newValue > max) {\n setValue(max);\n } else if (newValue < min) {\n setValue(min);\n } else {\n setValue(newValue);\n }\n };\n\n useEffect(() => {\n setSafeValue(initial);\n }, [min, max]);\n\n return [value, setSafeValue];\n};\n\nexport type SliderStep = {\n label?: number | string;\n emojiUniCode?: string;\n};\n\nexport interface SliderProps\n extends ErrorWrapperClassNameProps,\n Pick<React.InputHTMLAttributes<HTMLInputElement>, 'id' | 'name' | 'onChange' | 'onBlur'> {\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n /**\tSets the title of the slider. */\n title?: string;\n /** Adds the left hand label to the element. */\n labelLeft?: string;\n /** Adds the right hand label to the element. */\n labelRight?: string;\n /**\tSets aria-label of the slider. */\n ariaLabel?: string;\n /** Disables the slider element. */\n disabled?: boolean;\n /** Sets the minimum allowed value on the slider - this overrides the use of steps prop for minValue/maxValue. */\n minValue?: number;\n /** Sets the maximum allowed value on the slider - this overrides the use of steps prop for minValue/maxValue. */\n maxValue?: number;\n /** If set to false will only trigger onChange once a user interaction has been made, updates to this prop will be taken into account - true by default */\n selected?: boolean;\n /** Sets the steps data for the slider */\n steps?: SliderStep[];\n /** Sets the step to move per point in the slider */\n step?: number;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** Sets the value of the slider */\n value?: number;\n}\n\nexport const Slider = React.forwardRef((props: SliderProps, ref: React.Ref<HTMLInputElement>) => {\n const {\n title,\n ariaLabel,\n error,\n errorText,\n errorTextId: errorTextIdProp,\n errorWrapperClassName,\n labelLeft,\n labelRight,\n disabled = false,\n onChange,\n steps,\n step = 1,\n minValue = 0,\n maxValue = steps ? steps.length - 1 : 100,\n selected = true,\n testId,\n value,\n ...rest\n } = props;\n\n const [isMoving, setIsMoving] = useState(false);\n const [selectedState, setSelectedState] = useState(typeof value === 'undefined' ? selected : true);\n const [valueState, setValueState] = useSafeNumberValue(\n typeof value === 'undefined' ? (maxValue - minValue) / 2 + minValue : value,\n minValue,\n maxValue\n );\n\n const errorTextId = useIdWithFallback(errorTextIdProp);\n const baseId = useId();\n const titleId = 'title-' + baseId;\n const labelLeftId = 'label-' + baseId;\n const labelRightId = 'label-right-' + baseId;\n const trackRef = useRef<HTMLDivElement>(null);\n const { refObject, isFocused } = usePseudoClasses<HTMLInputElement>(isMutableRefObject(ref) ? ref : null);\n const mergedRefs = mergeRefs([ref, refObject]);\n\n const { width: trackWidth } = useSize(trackRef) || { width: 0 };\n const largeStep = maxValue / 10;\n const invalid = !!errorText || !!error;\n\n useEffect(() => {\n const handlePointerUp = (): void => {\n setIsMoving(false);\n };\n\n document.addEventListener('pointerup', handlePointerUp);\n\n return (): void => {\n document.removeEventListener('pointerup', handlePointerUp);\n };\n }, []);\n\n const getValueBasedOnMarkerPosition = (markerPosition: number): number => {\n const trackPosition = trackRef.current?.getBoundingClientRect().x ?? 0;\n\n // Calculate the normalized position (0 to 1) of the marker along the track\n const normalizedPosition = (markerPosition - trackPosition) / trackWidth;\n const valueRange = maxValue - minValue;\n // Calculate the value without considering the step\n let value = normalizedPosition * valueRange + minValue;\n // Adjust the value to account for the step increment\n const stepCount = Math.round(value / step);\n value = stepCount * step;\n value = Math.max(minValue, Math.min(maxValue, value));\n\n return value;\n };\n\n useEffect(() => {\n const handlePointerMove = (e: PointerEvent): void => {\n if (!disabled && isMoving) {\n const newValue = getValueBasedOnMarkerPosition(e.clientX);\n setValueState(newValue);\n }\n };\n\n document.addEventListener('pointermove', handlePointerMove);\n\n return (): void => {\n document.removeEventListener('pointermove', handlePointerMove);\n };\n }, [isMoving]);\n\n useEffect(() => {\n if (value !== valueState && typeof value !== 'undefined') {\n handleSelected();\n setValueState(value);\n }\n }, [value]);\n\n useEffect(() => {\n if (typeof value === 'undefined' && selected !== selectedState) {\n setSelectedState(selected);\n }\n }, [selected]);\n\n const handleSelected = (): void => {\n if (selectedState === false) {\n setSelectedState(true);\n }\n };\n\n const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = e => {\n if (disabled) return;\n\n let flag = false;\n\n switch (e.key) {\n case 'ArrowLeft':\n case 'ArrowDown':\n setValueState(valueState - step);\n flag = true;\n break;\n case 'PageDown':\n setValueState(valueState - largeStep);\n flag = true;\n break;\n case 'ArrowRight':\n case 'ArrowUp':\n setValueState(valueState + step);\n flag = true;\n break;\n case 'PageUp':\n setValueState(valueState + largeStep);\n flag = true;\n break;\n case 'Home':\n setValueState(minValue);\n flag = true;\n break;\n case 'End':\n setValueState(maxValue);\n flag = true;\n break;\n default:\n break;\n }\n\n if (flag) {\n handleSelected();\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n const handleTrackClick: React.MouseEventHandler<HTMLDivElement> = e => {\n if (disabled) return;\n\n const newValue = getValueBasedOnMarkerPosition(e.clientX);\n setValueState(newValue);\n refObject.current?.focus();\n };\n\n const handlePointerDown: React.PointerEventHandler<HTMLDivElement> = e => {\n if (disabled) return;\n\n handleTrackClick(e);\n setIsMoving(true);\n handleSelected();\n\n e.preventDefault();\n e.stopPropagation();\n\n refObject.current?.focus();\n };\n\n const markerXPos = maxValue !== minValue ? (trackWidth / (maxValue - minValue)) * (valueState - minValue) : 0;\n\n const getAriaValueText = (): string | undefined => {\n const stepIndex = steps ? Math.round((valueState - minValue) / step) : null;\n\n if (steps && stepIndex !== null && stepIndex >= 0 && stepIndex < steps.length) {\n const step = steps[stepIndex];\n const emojiCode = step.emojiUniCode;\n const label = typeof step.label !== 'undefined' ? step.label.toString() : undefined;\n\n return emojiCode && label ? `${emojiCode} ${label}` : emojiCode || label;\n }\n\n return undefined;\n };\n\n const getAriaLabeledById = (): string | undefined => {\n if (title && labelLeft && labelRight) {\n return [titleId, labelLeftId, labelRightId].join(' ');\n }\n if (title && labelLeft) {\n return [titleId, labelLeftId].join(' ');\n }\n if (title && labelRight) {\n return [titleId, labelRightId].join(' ');\n }\n if (title) {\n return titleId;\n }\n };\n\n const ariaLabelAttributes = getAriaLabelAttributes({\n label: ariaLabel,\n id: getAriaLabeledById(),\n prefer: 'label',\n });\n\n const getXPositionStyling = (index: number, stepsLength: number): { left: string } => {\n return { left: `${(index / (stepsLength - 1)) * 100}%` };\n };\n\n useEffect(() => {\n if (selectedState && onChange) {\n onChange({\n target: {\n name: props.name,\n value: valueState,\n },\n } as unknown as React.ChangeEvent<HTMLInputElement>);\n }\n }, [valueState, selectedState]);\n\n const renderEmojies = (): React.ReactNode => {\n return (\n <div className={styles['slider__emoji-container']}>\n {steps?.map((step, index) => {\n return (\n step.emojiUniCode && (\n <div\n aria-hidden={true}\n key={'emoji' + index}\n className={styles['slider__emoji']}\n style={getXPositionStyling(index, steps.length)}\n >\n {step.emojiUniCode}\n </div>\n )\n );\n })}\n </div>\n );\n };\n\n const renderSteps = (): React.ReactNode => {\n return steps?.map((_step, index) => {\n return <div key={'step' + index} className={styles['slider__track__step']} style={getXPositionStyling(index, steps.length)} />;\n });\n };\n\n const renderStepLabels = (): React.ReactNode => {\n return (\n <div className={styles['slider__value-container']}>\n {steps?.map((step, index) => {\n return (\n typeof step.label !== 'undefined' && (\n <div\n aria-hidden={true}\n key={'label' + index}\n className={styles['slider__value']}\n style={getXPositionStyling(index, steps.length)}\n >\n {step.label}\n </div>\n )\n );\n })}\n </div>\n );\n };\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextId}>\n <input\n aria-valuetext={getAriaValueText()}\n className={styles['sr-only-slider']}\n disabled={disabled}\n min={minValue}\n max={maxValue}\n onChange={onChange}\n onKeyDown={handleKeyDown}\n value={valueState}\n ref={mergedRefs}\n type=\"range\"\n {...rest}\n {...ariaLabelAttributes}\n />\n <div className={styles.slider} data-testid={testId} data-analyticsid={AnalyticsId.Slider}>\n {title && (\n <Title className={styles['slider__title']} htmlMarkup={'h3'} margin={0} appearance={'title3'} id={titleId}>\n {title}\n </Title>\n )}\n <div className={styles['slider__content-container']}>\n {renderEmojies()}\n {/* Slider streken er klikkbar med mus/touch */}\n <div\n ref={trackRef}\n className={classNames(styles['slider__track-wrapper'], disabled && styles['slider__track-wrapper--disabled'])}\n onPointerDown={handlePointerDown}\n >\n <div className={classNames(styles.slider__track, disabled && styles['slider__track--disabled'])}>{renderSteps()}</div>\n <div\n className={classNames(styles.slider__marker, {\n [styles['slider__marker--disabled']]: disabled,\n [styles['slider__marker--selected']]: selectedState,\n [styles['slider__marker--invalid']]: invalid,\n [styles['slider__marker--focused']]: !disabled && isFocused,\n })}\n style={{\n left: `${markerXPos}px`,\n }}\n />\n </div>\n {renderStepLabels()}\n </div>\n {(labelLeft || labelRight) && (\n <span className={styles.slider__options}>\n <span id={labelLeftId}>{labelLeft}</span>\n <span id={labelRightId}>{labelRight}</span>\n </span>\n )}\n </div>\n </ErrorWrapper>\n );\n});\n\nSlider.displayName = 'Slider';\n\nexport default Slider;\n","import Slider from './Slider';\nexport * from './Slider';\nexport default Slider;\n"],"mappings":"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"}
package/lib/Textarea.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { t as uuid } from "./uuid.js";
2
- import { n as AnalyticsId, r as FormOnColor, t as AVERAGE_CHARACTER_WIDTH_PX } from "./constants2.js";
2
+ import { n as AnalyticsId, r as FormOnColor, s as LanguageLocales, t as AVERAGE_CHARACTER_WIDTH_PX } from "./constants2.js";
3
+ import { r as useLanguage } from "./language.js";
3
4
  import { t as useIdWithFallback } from "./useIdWithFallback.js";
4
5
  import { t as getAriaDescribedBy } from "./accessibility.js";
5
6
  import { t as ErrorWrapper_default } from "./ErrorWrapper.js";
@@ -9,15 +10,33 @@ import React, { useEffect, useRef, useState } from "react";
9
10
  import classNames from "classnames";
10
11
  import { jsx, jsxs } from "react/jsx-runtime";
11
12
  import styles from "./components/Textarea/styles.module.scss";
12
- var getTextareaMaxWidth = (characters) => {
13
- return `calc(${characters * 12}px + 2rem + 16px + 4px)`;
13
+ var HN_Designsystem_TextArea_en_GB_default = { characters: "characters" };
14
+ var HN_Designsystem_TextArea_nb_NO_default = { characters: "tegn" };
15
+ var HN_Designsystem_TextArea_nn_NO_default = { characters: "teikn" };
16
+ const getResources = (language) => {
17
+ switch (language) {
18
+ case LanguageLocales.ENGLISH: return HN_Designsystem_TextArea_en_GB_default;
19
+ case LanguageLocales.NORWEGIAN_NYNORSK: return HN_Designsystem_TextArea_nn_NO_default;
20
+ case LanguageLocales.NORWEGIAN:
21
+ default: return HN_Designsystem_TextArea_nb_NO_default;
22
+ }
23
+ };
24
+ var getTextareaMaxWidth = (characters$3) => {
25
+ return `calc(${characters$3 * 12}px + 2rem + 16px + 4px)`;
14
26
  };
15
27
  var Textarea = React.forwardRef((props, ref) => {
16
- const { maxCharacters, maxText, width, testId, defaultValue, marginBottom: gutterBottom, transparent, onColor = FormOnColor.onwhite, label, textareaId = uuid(), minRows = 3, maxRows = 10, grow, error, errorText, errorTextId: errorTextIdProp, errorWrapperClassName, autoFocus, disabled, name, autoComplete = "off", placeholder, readOnly, required, onChange, value, ...rest } = props;
28
+ const { maxCharacters, maxText, width, testId, defaultValue, marginBottom: gutterBottom, transparent, onColor = FormOnColor.onwhite, label, textareaId = uuid(), minRows = 3, maxRows = 10, grow, error, errorText, errorTextId: errorTextIdProp, errorWrapperClassName, autoFocus, disabled, name, autoComplete = "off", placeholder, readOnly, required, onChange, value, resources, ...rest } = props;
17
29
  const [rows, setRows] = useState(minRows);
18
30
  const [textareaInput, setTextareaInput] = useState(value || defaultValue || "");
19
31
  const referanse = useRef(null);
20
32
  const errorTextUuid = useIdWithFallback(errorTextIdProp);
33
+ const { language } = useLanguage(LanguageLocales.NORWEGIAN);
34
+ const defaultResources = getResources(language);
35
+ const mergedResources = {
36
+ ...defaultResources,
37
+ ...resources,
38
+ characters: maxText || resources?.characters || defaultResources.characters
39
+ };
21
40
  useEffect(() => {
22
41
  setTextareaInput(defaultValue || "");
23
42
  }, [defaultValue]);
@@ -97,7 +116,7 @@ var Textarea = React.forwardRef((props, ref) => {
97
116
  maxCharacters && /* @__PURE__ */ jsx(MaxCharacters_default, {
98
117
  maxCharacters,
99
118
  length: textareaInput.toString().length,
100
- maxText,
119
+ maxText: mergedResources.characters,
101
120
  onColor,
102
121
  maxWidth
103
122
  })
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.js","names":[],"sources":["../src/components/Textarea/Textarea.tsx","../src/components/Textarea/index.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\n\nimport cn from 'classnames';\n\nimport { AnalyticsId, AVERAGE_CHARACTER_WIDTH_PX, FormOnColor } from '../../constants';\nimport { useIdWithFallback } from '../../hooks/useIdWithFallback';\nimport { getAriaDescribedBy } from '../../utils/accessibility';\nimport { uuid } from '../../utils/uuid';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport { renderLabel } from '../Label';\nimport MaxCharacters from '../MaxCharacters/MaxCharacters';\n\nimport styles from './styles.module.scss';\n\nexport interface TextareaProps\n extends ErrorWrapperClassNameProps,\n Pick<\n React.InputHTMLAttributes<HTMLTextAreaElement>,\n | 'aria-describedby'\n | 'autoFocus'\n | 'disabled'\n | 'name'\n | 'autoComplete'\n | 'placeholder'\n | 'readOnly'\n | 'required'\n | 'defaultValue'\n | 'onChange'\n | 'value'\n > {\n /** max character limit in textarea */\n maxCharacters?: number;\n /** The text is displayed in the end of the text-counter */\n maxText?: string;\n /** Width of textarea in characters (approximate) */\n width?: number;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** If true, the component will have a bottom margin. */\n marginBottom?: boolean;\n /** If true, the component will be transparent. */\n transparent?: boolean;\n /** Changes the visuals of the textarea */\n onColor?: keyof typeof FormOnColor;\n /** Label of the input */\n label?: React.ReactNode;\n /** id of the textarea */\n textareaId?: string;\n /** max rows */\n maxRows?: number;\n /** min rows */\n minRows?: number;\n /** auto-grows until maxRows */\n grow?: boolean;\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n}\n\nconst getTextareaMaxWidth = (characters: number): string => {\n const paddingWidth = '2rem';\n const scrollbarWidth = '16px';\n const borderWidth = '4px';\n\n return `calc(${characters * AVERAGE_CHARACTER_WIDTH_PX}px + ${paddingWidth} + ${scrollbarWidth} + ${borderWidth})`;\n};\n\nconst Textarea = React.forwardRef((props: TextareaProps, ref: React.Ref<HTMLTextAreaElement>) => {\n const {\n maxCharacters,\n maxText,\n width,\n testId,\n defaultValue,\n marginBottom: gutterBottom,\n transparent,\n onColor = FormOnColor.onwhite,\n label,\n textareaId = uuid(),\n minRows = 3,\n maxRows = 10,\n grow,\n error,\n errorText,\n errorTextId: errorTextIdProp,\n errorWrapperClassName,\n autoFocus,\n disabled,\n name,\n autoComplete = 'off',\n placeholder,\n readOnly,\n required,\n onChange,\n value,\n ...rest\n } = props;\n\n const [rows, setRows] = useState(minRows);\n const [textareaInput, setTextareaInput] = useState(value || defaultValue || '');\n const referanse = useRef<HTMLDivElement>(null);\n const errorTextUuid = useIdWithFallback(errorTextIdProp);\n\n useEffect(() => {\n setTextareaInput(defaultValue || '');\n }, [defaultValue]);\n\n const resizeHeight = (target: HTMLTextAreaElement): void => {\n const textareaLineHeight = 28;\n\n const previousRows = target.rows;\n target.rows = minRows; // reset number of rows in textarea\n\n const currentRows = Math.floor((target.scrollHeight - 16) / textareaLineHeight); // scrollHeight - 16px of padding to calculate the rows\n\n if (currentRows === previousRows) {\n target.rows = currentRows;\n }\n\n if (currentRows >= maxRows) {\n target.rows = maxRows;\n target.scrollTop = target.scrollHeight;\n }\n\n if (currentRows < maxRows) {\n setRows(currentRows);\n } else {\n setRows(maxRows);\n }\n };\n\n const onDark = onColor === FormOnColor.ondark;\n const onBlueberry = onColor === FormOnColor.onblueberry;\n const maxCharactersExceeded = !!maxCharacters && textareaInput.toString().length > maxCharacters;\n const onError = onColor === FormOnColor.oninvalid || !!errorText || !!error || maxCharactersExceeded;\n\n const textareaWrapperClass = cn(styles.textarea, {\n [styles['textarea--gutterBottom']]: gutterBottom,\n });\n\n const contentWrapperClass = cn(styles['input-container'], {\n [styles['input-container--transparent']]: transparent,\n [styles['input-container--on-blueberry']]: onBlueberry,\n [styles['input-container--on-dark']]: onDark,\n [styles['input-container--invalid']]: onError,\n [styles['input-container--disabled']]: props.disabled,\n });\n\n const textareaClass = cn(styles['input-container__input'], {\n [styles[`input-container__input--disabled`]]: props.disabled,\n });\n\n useEffect(() => {\n if (value) setTextareaInput(value);\n\n if (grow && referanse.current?.children && referanse.current?.children[0]) {\n const textarea = referanse.current?.children[0] as HTMLTextAreaElement;\n resizeHeight(textarea);\n }\n }, [value]);\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {\n setTextareaInput(e.target.value);\n\n if (onChange) {\n onChange(e);\n }\n\n if (grow) {\n resizeHeight(e.target);\n }\n };\n\n const maxWidth = width ? getTextareaMaxWidth(width) : undefined;\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextUuid}>\n <div data-testid={testId} data-analyticsid={AnalyticsId.Textarea} className={textareaWrapperClass}>\n {renderLabel(label, textareaId, onColor as FormOnColor)}\n <div className={contentWrapperClass} ref={referanse} style={{ maxWidth }}>\n <textarea\n {...rest}\n rows={rows}\n defaultValue={defaultValue}\n id={textareaId}\n className={textareaClass}\n ref={ref}\n aria-describedby={getAriaDescribedBy(props, errorTextUuid)}\n aria-invalid={!!onError}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n disabled={disabled}\n name={name}\n autoComplete={autoComplete ? autoComplete : undefined}\n placeholder={placeholder}\n readOnly={readOnly}\n required={required}\n onChange={onChangeHandler}\n value={value}\n />\n </div>\n {maxCharacters && (\n <MaxCharacters\n maxCharacters={maxCharacters}\n length={textareaInput.toString().length}\n maxText={maxText}\n onColor={onColor}\n maxWidth={maxWidth}\n />\n )}\n </div>\n </ErrorWrapper>\n );\n});\n\nTextarea.displayName = 'Textarea';\n\nexport default Textarea;\n","import Textarea from './Textarea';\nexport * from './Textarea';\nexport default Textarea;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Textarea.js","names":["mergedResources: HNDesignsystemTextArea"],"sources":["../src/resources/HN.Designsystem.TextArea.en-GB.json","../src/resources/HN.Designsystem.TextArea.nb-NO.json","../src/resources/HN.Designsystem.TextArea.nn-NO.json","../src/components/Textarea/resourceHelper.ts","../src/components/Textarea/Textarea.tsx","../src/components/Textarea/index.tsx"],"sourcesContent":["{\n \"characters\": \"characters\"\n}\n","{\n \"characters\": \"tegn\"\n}\n","{\n \"characters\": \"teikn\"\n}\n","import { LanguageLocales } from '../../constants';\nimport enGB from '../../resources/HN.Designsystem.TextArea.en-GB.json';\nimport nbNO from '../../resources/HN.Designsystem.TextArea.nb-NO.json';\nimport nnNO from '../../resources/HN.Designsystem.TextArea.nn-NO.json';\nimport { HNDesignsystemTextArea } from '../../resources/Resources';\n\nexport const getResources = (language: LanguageLocales): HNDesignsystemTextArea => {\n switch (language) {\n case LanguageLocales.ENGLISH:\n return enGB;\n case LanguageLocales.NORWEGIAN_NYNORSK:\n return nnNO;\n case LanguageLocales.NORWEGIAN:\n default:\n return nbNO;\n }\n};\n","import React, { useState, useRef, useEffect } from 'react';\n\nimport cn from 'classnames';\n\nimport { getResources } from './resourceHelper';\nimport { AnalyticsId, AVERAGE_CHARACTER_WIDTH_PX, FormOnColor, LanguageLocales } from '../../constants';\nimport { useIdWithFallback } from '../../hooks/useIdWithFallback';\nimport { HNDesignsystemTextArea } from '../../resources/Resources';\nimport { getAriaDescribedBy } from '../../utils/accessibility';\nimport { useLanguage } from '../../utils/language';\nimport { uuid } from '../../utils/uuid';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport { renderLabel } from '../Label';\nimport MaxCharacters from '../MaxCharacters/MaxCharacters';\n\nimport styles from './styles.module.scss';\n\nexport interface TextareaProps\n extends ErrorWrapperClassNameProps,\n Pick<\n React.InputHTMLAttributes<HTMLTextAreaElement>,\n | 'aria-describedby'\n | 'autoFocus'\n | 'disabled'\n | 'name'\n | 'autoComplete'\n | 'placeholder'\n | 'readOnly'\n | 'required'\n | 'defaultValue'\n | 'onChange'\n | 'value'\n > {\n /** max character limit in textarea */\n maxCharacters?: number;\n /** @deprecated use resources instead. The text is displayed in the end of the text-counter */\n maxText?: string;\n /** Width of textarea in characters (approximate) */\n width?: number;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** If true, the component will have a bottom margin. */\n marginBottom?: boolean;\n /** If true, the component will be transparent. */\n transparent?: boolean;\n /** Changes the visuals of the textarea */\n onColor?: keyof typeof FormOnColor;\n /** Label of the input */\n label?: React.ReactNode;\n /** id of the textarea */\n textareaId?: string;\n /** max rows */\n maxRows?: number;\n /** min rows */\n minRows?: number;\n /** auto-grows until maxRows */\n grow?: boolean;\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n /** Resources for component */\n resources?: Partial<HNDesignsystemTextArea>;\n}\n\nconst getTextareaMaxWidth = (characters: number): string => {\n const paddingWidth = '2rem';\n const scrollbarWidth = '16px';\n const borderWidth = '4px';\n\n return `calc(${characters * AVERAGE_CHARACTER_WIDTH_PX}px + ${paddingWidth} + ${scrollbarWidth} + ${borderWidth})`;\n};\n\nconst Textarea = React.forwardRef((props: TextareaProps, ref: React.Ref<HTMLTextAreaElement>) => {\n const {\n maxCharacters,\n maxText,\n width,\n testId,\n defaultValue,\n marginBottom: gutterBottom,\n transparent,\n onColor = FormOnColor.onwhite,\n label,\n textareaId = uuid(),\n minRows = 3,\n maxRows = 10,\n grow,\n error,\n errorText,\n errorTextId: errorTextIdProp,\n errorWrapperClassName,\n autoFocus,\n disabled,\n name,\n autoComplete = 'off',\n placeholder,\n readOnly,\n required,\n onChange,\n value,\n resources,\n ...rest\n } = props;\n\n const [rows, setRows] = useState(minRows);\n const [textareaInput, setTextareaInput] = useState(value || defaultValue || '');\n const referanse = useRef<HTMLDivElement>(null);\n const errorTextUuid = useIdWithFallback(errorTextIdProp);\n\n const { language } = useLanguage<LanguageLocales>(LanguageLocales.NORWEGIAN);\n const defaultResources = getResources(language);\n\n const mergedResources: HNDesignsystemTextArea = {\n ...defaultResources,\n ...resources,\n characters: maxText || resources?.characters || defaultResources.characters,\n };\n\n useEffect(() => {\n setTextareaInput(defaultValue || '');\n }, [defaultValue]);\n\n const resizeHeight = (target: HTMLTextAreaElement): void => {\n const textareaLineHeight = 28;\n\n const previousRows = target.rows;\n target.rows = minRows; // reset number of rows in textarea\n\n const currentRows = Math.floor((target.scrollHeight - 16) / textareaLineHeight); // scrollHeight - 16px of padding to calculate the rows\n\n if (currentRows === previousRows) {\n target.rows = currentRows;\n }\n\n if (currentRows >= maxRows) {\n target.rows = maxRows;\n target.scrollTop = target.scrollHeight;\n }\n\n if (currentRows < maxRows) {\n setRows(currentRows);\n } else {\n setRows(maxRows);\n }\n };\n\n const onDark = onColor === FormOnColor.ondark;\n const onBlueberry = onColor === FormOnColor.onblueberry;\n const maxCharactersExceeded = !!maxCharacters && textareaInput.toString().length > maxCharacters;\n const onError = onColor === FormOnColor.oninvalid || !!errorText || !!error || maxCharactersExceeded;\n\n const textareaWrapperClass = cn(styles.textarea, {\n [styles['textarea--gutterBottom']]: gutterBottom,\n });\n\n const contentWrapperClass = cn(styles['input-container'], {\n [styles['input-container--transparent']]: transparent,\n [styles['input-container--on-blueberry']]: onBlueberry,\n [styles['input-container--on-dark']]: onDark,\n [styles['input-container--invalid']]: onError,\n [styles['input-container--disabled']]: props.disabled,\n });\n\n const textareaClass = cn(styles['input-container__input'], {\n [styles[`input-container__input--disabled`]]: props.disabled,\n });\n\n useEffect(() => {\n if (value) setTextareaInput(value);\n\n if (grow && referanse.current?.children && referanse.current?.children[0]) {\n const textarea = referanse.current?.children[0] as HTMLTextAreaElement;\n resizeHeight(textarea);\n }\n }, [value]);\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {\n setTextareaInput(e.target.value);\n\n if (onChange) {\n onChange(e);\n }\n\n if (grow) {\n resizeHeight(e.target);\n }\n };\n\n const maxWidth = width ? getTextareaMaxWidth(width) : undefined;\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextUuid}>\n <div data-testid={testId} data-analyticsid={AnalyticsId.Textarea} className={textareaWrapperClass}>\n {renderLabel(label, textareaId, onColor as FormOnColor)}\n <div className={contentWrapperClass} ref={referanse} style={{ maxWidth }}>\n <textarea\n {...rest}\n rows={rows}\n defaultValue={defaultValue}\n id={textareaId}\n className={textareaClass}\n ref={ref}\n aria-describedby={getAriaDescribedBy(props, errorTextUuid)}\n aria-invalid={!!onError}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n disabled={disabled}\n name={name}\n autoComplete={autoComplete ? autoComplete : undefined}\n placeholder={placeholder}\n readOnly={readOnly}\n required={required}\n onChange={onChangeHandler}\n value={value}\n />\n </div>\n {maxCharacters && (\n <MaxCharacters\n maxCharacters={maxCharacters}\n length={textareaInput.toString().length}\n maxText={mergedResources.characters}\n onColor={onColor}\n maxWidth={maxWidth}\n />\n )}\n </div>\n </ErrorWrapper>\n );\n});\n\nTextarea.displayName = 'Textarea';\n\nexport default Textarea;\n","import Textarea from './Textarea';\nexport * from './Textarea';\nexport default Textarea;\n"],"mappings":";;;;;;;;;;;;;;;AGMA,MAAa,gBAAgB,aAAsD;AACjF,SAAQ,UAAR;EACE,KAAK,gBAAgB,QACnB,QAAO;EACT,KAAK,gBAAgB,kBACnB,QAAO;EACT,KAAK,gBAAgB;EACrB,QACE,QAAO;;;ACqDb,IAAM,uBAAuB,iBAA+B;AAK1D,QAAO,QAAQ,eAAA,GAAwC;;AAGzD,IAAM,WAAW,MAAM,YAAY,OAAsB,QAAwC;CAC/F,MAAM,EACJ,eACA,SACA,OACA,QACA,cACA,cAAc,cACd,aACA,UAAU,YAAY,SACtB,OACA,aAAa,MAAM,EACnB,UAAU,GACV,UAAU,IACV,MACA,OACA,WACA,aAAa,iBACb,uBACA,WACA,UACA,MACA,eAAe,OACf,aACA,UACA,UACA,UACA,OACA,WACA,GAAG,SACD;CAEJ,MAAM,CAAC,MAAM,WAAW,SAAS,QAAQ;CACzC,MAAM,CAAC,eAAe,oBAAoB,SAAS,SAAS,gBAAgB,GAAG;CAC/E,MAAM,YAAY,OAAuB,KAAK;CAC9C,MAAM,gBAAgB,kBAAkB,gBAAgB;CAExD,MAAM,EAAE,aAAa,YAA6B,gBAAgB,UAAU;CAC5E,MAAM,mBAAmB,aAAa,SAAS;CAE/C,MAAMA,kBAA0C;EAC9C,GAAG;EACH,GAAG;EACH,YAAY,WAAW,WAAW,cAAc,iBAAiB;EAClE;AAED,iBAAgB;AACd,mBAAiB,gBAAgB,GAAG;IACnC,CAAC,aAAa,CAAC;CAElB,MAAM,gBAAgB,WAAsC;EAC1D,MAAM,qBAAqB;EAE3B,MAAM,eAAe,OAAO;AAC5B,SAAO,OAAO;EAEd,MAAM,cAAc,KAAK,OAAO,OAAO,eAAe,MAAM,mBAAmB;AAE/E,MAAI,gBAAgB,aAClB,QAAO,OAAO;AAGhB,MAAI,eAAe,SAAS;AAC1B,UAAO,OAAO;AACd,UAAO,YAAY,OAAO;;AAG5B,MAAI,cAAc,QAChB,SAAQ,YAAY;MAEpB,SAAQ,QAAQ;;CAIpB,MAAM,SAAS,YAAY,YAAY;CACvC,MAAM,cAAc,YAAY,YAAY;CAC5C,MAAM,wBAAwB,CAAC,CAAC,iBAAiB,cAAc,UAAU,CAAC,SAAS;CACnF,MAAM,UAAU,YAAY,YAAY,aAAa,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS;CAE/E,MAAM,uBAAuB,WAAG,OAAO,UAAU,GAC9C,OAAO,4BAA4B,cACrC,CAAC;CAEF,MAAM,sBAAsB,WAAG,OAAO,oBAAoB;GACvD,OAAO,kCAAkC;GACzC,OAAO,mCAAmC;GAC1C,OAAO,8BAA8B;GACrC,OAAO,8BAA8B;GACrC,OAAO,+BAA+B,MAAM;EAC9C,CAAC;CAEF,MAAM,gBAAgB,WAAG,OAAO,2BAA2B,GACxD,OAAO,sCAAsC,MAAM,UACrD,CAAC;AAEF,iBAAgB;AACd,MAAI,MAAO,kBAAiB,MAAM;AAElC,MAAI,QAAQ,UAAU,SAAS,YAAY,UAAU,SAAS,SAAS,IAAI;GACzE,MAAM,WAAW,UAAU,SAAS,SAAS;AAC7C,gBAAa,SAAS;;IAEvB,CAAC,MAAM,CAAC;CAEX,MAAM,mBAAmB,MAAoD;AAC3E,mBAAiB,EAAE,OAAO,MAAM;AAEhC,MAAI,SACF,UAAS,EAAE;AAGb,MAAI,KACF,cAAa,EAAE,OAAO;;CAI1B,MAAM,WAAW,QAAQ,oBAAoB,MAAM,GAAG,KAAA;AAEtD,QACE,oBAAC,sBAAA;EAAa,WAAW;EAAkC;EAAW,aAAa;YACjF,qBAAC,OAAA;GAAI,eAAa;GAAQ,oBAAkB,YAAY;GAAU,WAAW;;IAC1E,YAAY,OAAO,YAAY,QAAuB;IACvD,oBAAC,OAAA;KAAI,WAAW;KAAqB,KAAK;KAAW,OAAO,EAAE,UAAU;eACtE,oBAAC,YAAA;MACC,GAAI;MACE;MACQ;MACd,IAAI;MACJ,WAAW;MACN;MACL,oBAAkB,mBAAmB,OAAO,cAAc;MAC1D,gBAAc,CAAC,CAAC;MAEL;MACD;MACJ;MACN,cAAc,eAAe,eAAe,KAAA;MAC/B;MACH;MACA;MACV,UAAU;MACH;OACP;MACE;IACL,iBACC,oBAAC,uBAAA;KACgB;KACf,QAAQ,cAAc,UAAU,CAAC;KACjC,SAAS,gBAAgB;KAChB;KACC;MACV;;IAEA;GACO;EAEjB;AAEF,SAAS,cAAc;ACvOvB,IAAA,qBDyOe"}
@@ -47,8 +47,8 @@ import "../../Title.js";
47
47
  import "../../Title2.js";
48
48
  import "../../ChevronDown.js";
49
49
  import "../../FormLayout.js";
50
- import "../../MaxCharacters.js";
51
50
  import "../../Input.js";
51
+ import "../../MaxCharacters.js";
52
52
  import "../../RadioButton.js";
53
53
  import "../../Select.js";
54
54
  import "../../Slider.js";
@@ -1,5 +1,6 @@
1
1
  import { default as React } from 'react';
2
2
  import { FormOnColor, FormSize } from '../../constants';
3
+ import { HNDesignsystemInput } from '../../resources/Resources';
3
4
  import { ErrorWrapperClassNameProps } from '../ErrorWrapper';
4
5
  import { SvgIcon } from '../Icon';
5
6
  import { IconName } from '../Icons/IconNames';
@@ -44,8 +45,10 @@ export interface InputProps extends ErrorWrapperClassNameProps, Pick<React.Input
44
45
  rightOfInput?: React.ReactNode;
45
46
  /** max character limit in input */
46
47
  maxCharacters?: number;
47
- /** The text is displayed in the end of the text-counter */
48
+ /** @deprecated use resources instead. The text is displayed in the end of the text-counter */
48
49
  maxText?: string;
50
+ /** Resources for component */
51
+ resources?: Partial<HNDesignsystemInput>;
49
52
  }
50
53
  export declare enum InputTypes {
51
54
  text = "text",
@@ -41,7 +41,7 @@ import "../../useOutsideEvent.js";
41
41
  import "../../mobile.js";
42
42
  import "../../src.js";
43
43
  import "../../StatusDot.js";
44
- import "../../MaxCharacters.js";
45
44
  import { t as InputTypes } from "../../Input.js";
45
+ import "../../MaxCharacters.js";
46
46
  import { t as Input_default } from "../../Input2.js";
47
47
  export { InputTypes, Input_default as default };
@@ -0,0 +1,3 @@
1
+ import { LanguageLocales } from '../../constants';
2
+ import { HNDesignsystemInput } from '../../resources/Resources';
3
+ export declare const getResources: (language: LanguageLocales) => HNDesignsystemInput;
@@ -57,7 +57,7 @@ export type LinkProps = Modify<React.HTMLAttributes<HTMLAnchorElement | HTMLButt
57
57
  /**
58
58
  * Ref for lenke/knapp
59
59
  */
60
- linkRef?: React.RefObject<HTMLButtonElement | HTMLAnchorElement>;
60
+ linkRef?: React.RefObject<HTMLButtonElement | HTMLAnchorElement> | null;
61
61
  /** Sets the data-testid attribute. */
62
62
  testId?: string;
63
63
  /** Highlights text. Override if different from list */
@@ -6,7 +6,7 @@ interface MaxCharactersProps {
6
6
  /** max character limit in textarea */
7
7
  maxCharacters: number;
8
8
  /** The text is displayed in the end of the text-counter */
9
- maxText?: string;
9
+ maxText: string;
10
10
  /** Changes the visuals of the textarea */
11
11
  onColor?: keyof typeof FormOnColor;
12
12
  /** Max width of the component */
@@ -1,10 +1,11 @@
1
1
  import { default as React } from 'react';
2
2
  import { FormOnColor } from '../../constants';
3
+ import { HNDesignsystemTextArea } from '../../resources/Resources';
3
4
  import { ErrorWrapperClassNameProps } from '../ErrorWrapper';
4
5
  export interface TextareaProps extends ErrorWrapperClassNameProps, Pick<React.InputHTMLAttributes<HTMLTextAreaElement>, 'aria-describedby' | 'autoFocus' | 'disabled' | 'name' | 'autoComplete' | 'placeholder' | 'readOnly' | 'required' | 'defaultValue' | 'onChange' | 'value'> {
5
6
  /** max character limit in textarea */
6
7
  maxCharacters?: number;
7
- /** The text is displayed in the end of the text-counter */
8
+ /** @deprecated use resources instead. The text is displayed in the end of the text-counter */
8
9
  maxText?: string;
9
10
  /** Width of textarea in characters (approximate) */
10
11
  width?: number;
@@ -32,6 +33,8 @@ export interface TextareaProps extends ErrorWrapperClassNameProps, Pick<React.In
32
33
  errorText?: string;
33
34
  /** Error text id */
34
35
  errorTextId?: string;
36
+ /** Resources for component */
37
+ resources?: Partial<HNDesignsystemTextArea>;
35
38
  }
36
39
  declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
37
40
  export default Textarea;
@@ -0,0 +1,3 @@
1
+ import { LanguageLocales } from '../../constants';
2
+ import { HNDesignsystemTextArea } from '../../resources/Resources';
3
+ export declare const getResources: (language: LanguageLocales) => HNDesignsystemTextArea;
@@ -51,8 +51,8 @@ import "../../Title.js";
51
51
  import { t as Title_default } from "../../Title2.js";
52
52
  import "../../ChevronDown.js";
53
53
  import "../../FormLayout.js";
54
- import "../../MaxCharacters.js";
55
54
  import "../../Input.js";
55
+ import "../../MaxCharacters.js";
56
56
  import "../../RadioButton.js";
57
57
  import { t as Select_default } from "../../Select.js";
58
58
  import { t as Slider_default } from "../../Slider.js";
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ "characters": "characters"
3
+ }
4
+ ;
5
+
6
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ "characters": "tegn"
3
+ }
4
+ ;
5
+
6
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ "characters": "teikn"
3
+ }
4
+ ;
5
+
6
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ "characters": "characters"
3
+ }
4
+ ;
5
+
6
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ "characters": "tegn"
3
+ }
4
+ ;
5
+
6
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ "characters": "teikn"
3
+ }
4
+ ;
5
+
6
+ export default _default;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@helsenorge/designsystem-react",
3
3
  "sideEffects": false,
4
4
  "private": false,
5
- "version": "13.3.0",
5
+ "version": "13.4.0",
6
6
  "description": "The official design system for Helsenorge built with React.",
7
7
  "repository": {
8
8
  "type": "git",