@digdir/designsystemet-react 1.6.1 → 1.7.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.
@@ -85,7 +85,7 @@ const Dialog = react.forwardRef(function Dialog({ asChild, children, className,
85
85
  currentRef?.addEventListener('close', handleClose);
86
86
  return () => currentRef?.removeEventListener('close', handleClose);
87
87
  }, [onClose]);
88
- return (jsxRuntime.jsxs(Component, { className: cl('ds-dialog', className), ref: mergedRefs, "data-modal": modal, ...rest, children: [closeButton !== false && (jsxRuntime.jsx(button.Button, { "aria-label": closeButton, autoFocus: true, "data-color": 'neutral', icon: true, variant: 'tertiary', "data-command": 'close' })), children] }));
88
+ return (jsxRuntime.jsxs(Component, { className: cl('ds-dialog', className), ref: mergedRefs, "data-modal": modal, ...rest, children: [closeButton !== false && (jsxRuntime.jsx(button.Button, { "aria-label": closeButton, "data-color": 'neutral', icon: true, variant: 'tertiary', "data-command": 'close' })), children] }));
89
89
  });
90
90
 
91
91
  exports.Dialog = Dialog;
@@ -6,6 +6,7 @@ var react = require('react');
6
6
  var paragraph = require('../paragraph/paragraph.js');
7
7
  var validationMessage = require('../validation-message/validation-message.js');
8
8
  var fieldObserver = require('./field-observer.js');
9
+ var useDebounceCallback = require('../../utilities/hooks/deprecated/use-debounce-callback/use-debounce-callback.js');
9
10
 
10
11
  const label = (text, count) => text.replace('%d', Math.abs(count).toString());
11
12
  /**
@@ -17,12 +18,14 @@ const label = (text, count) => text.replace('%d', Math.abs(count).toString());
17
18
  * <Field.Counter limit={100} under='%d tegn igjen' over='%d tegn for mye' />
18
19
  * </Field>
19
20
  */
20
- const FieldCounter = react.forwardRef(function FieldCounter({ limit, under = '%d tegn igjen', over = '%d tegn for mye', ...rest }, ref) {
21
+ const FieldCounter = react.forwardRef(function FieldCounter({ limit, under = '%d tegn igjen', over = '%d tegn for mye', hint = 'Maks %d tegn tillatt.', ...rest }, ref) {
21
22
  const [count, setCount] = react.useState(0);
23
+ const [liveRegionText, setLiveRegionText] = react.useState('');
22
24
  const fieldInputRef = react.useRef(null);
23
25
  const counterRef = react.useRef(null);
24
26
  const hasExceededLimit = count > limit;
25
27
  const remainder = limit - count;
28
+ const debouncedSetLiveRegionText = useDebounceCallback.useDebounceCallback((text) => setLiveRegionText(text), 1200);
26
29
  // Listen to native input events (user typing) to update the counter in real time
27
30
  react.useEffect(() => {
28
31
  const field = counterRef.current?.closest('.ds-field');
@@ -45,7 +48,11 @@ const FieldCounter = react.forwardRef(function FieldCounter({ limit, under = '%d
45
48
  setCount((prev) => (prev === valueLength ? prev : valueLength));
46
49
  }
47
50
  });
48
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { "data-field": 'description', className: 'ds-sr-only', "aria-live": 'polite', ref: counterRef, children: hasExceededLimit && label(over, remainder) }), hasExceededLimit ? (jsxRuntime.jsx(validationMessage.ValidationMessage, { ref: ref, ...rest, children: label(over, remainder) })) : (jsxRuntime.jsx(paragraph.Paragraph, { ref: ref, ...rest, "data-field": 'validation', children: label(under, remainder) }))] }));
51
+ // Update live region text when count or limit changes
52
+ react.useEffect(() => {
53
+ debouncedSetLiveRegionText(label(hasExceededLimit ? over : under, remainder));
54
+ }, [count, limit, over, under, hasExceededLimit, remainder]);
55
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: 'ds-sr-only', "aria-live": 'polite', ref: counterRef, children: liveRegionText }), hasExceededLimit ? (jsxRuntime.jsx(validationMessage.ValidationMessage, { ref: ref, ...rest, "aria-hidden": 'true', "data-field": null, children: label(over, remainder) })) : (jsxRuntime.jsx(paragraph.Paragraph, { ref: ref, ...rest, "aria-hidden": 'true', children: label(under, remainder) })), jsxRuntime.jsx("div", { className: 'ds-sr-only', "aria-hidden": 'true', "data-field": 'description', children: label(hint, limit) })] }));
49
56
  });
50
57
 
51
58
  exports.FieldCounter = FieldCounter;
@@ -86,7 +86,7 @@ const Popover = react.forwardRef(function Popover({ id, className, onClose, onOp
86
86
  arrowPseudoElement,
87
87
  ],
88
88
  }).then(({ x, y }) => {
89
- popover.style.translate = `${x}px ${y}px`;
89
+ popover.style.translate = `${Math.round(x)}px ${Math.round(y)}px`;
90
90
  });
91
91
  });
92
92
  }, [controlledOpen, placement, id, autoPlacement]);
@@ -32,7 +32,7 @@ const SuggestionList = react.forwardRef(function SuggestionList({ singular = '%d
32
32
  strategy: 'fixed',
33
33
  middleware: [triggerWidth],
34
34
  }).then(({ x, y }) => {
35
- list.style.translate = `${x}px calc(${y}px + var(--dsc-suggestion-list-gap))`;
35
+ list.style.translate = `${Math.round(x)}px calc(${Math.round(y)}px + var(--dsc-suggestion-list-gap))`;
36
36
  });
37
37
  });
38
38
  }
@@ -60,7 +60,7 @@ const Tooltip = react.forwardRef(function Tooltip({ id, children, content, place
60
60
  safeAreaElement,
61
61
  ],
62
62
  }).then(({ x, y }) => {
63
- tooltip.style.translate = `${x}px ${y}px`;
63
+ tooltip.style.translate = `${Math.round(x)}px ${Math.round(y)}px`;
64
64
  });
65
65
  });
66
66
  }
@@ -83,7 +83,7 @@ const Dialog = forwardRef(function Dialog({ asChild, children, className, closeB
83
83
  currentRef?.addEventListener('close', handleClose);
84
84
  return () => currentRef?.removeEventListener('close', handleClose);
85
85
  }, [onClose]);
86
- return (jsxs(Component, { className: cl('ds-dialog', className), ref: mergedRefs, "data-modal": modal, ...rest, children: [closeButton !== false && (jsx(Button, { "aria-label": closeButton, autoFocus: true, "data-color": 'neutral', icon: true, variant: 'tertiary', "data-command": 'close' })), children] }));
86
+ return (jsxs(Component, { className: cl('ds-dialog', className), ref: mergedRefs, "data-modal": modal, ...rest, children: [closeButton !== false && (jsx(Button, { "aria-label": closeButton, "data-color": 'neutral', icon: true, variant: 'tertiary', "data-command": 'close' })), children] }));
87
87
  });
88
88
 
89
89
  export { Dialog };
@@ -4,6 +4,7 @@ import { forwardRef, useState, useRef, useEffect } from 'react';
4
4
  import { Paragraph } from '../paragraph/paragraph.js';
5
5
  import { ValidationMessage } from '../validation-message/validation-message.js';
6
6
  import { isInputLike } from './field-observer.js';
7
+ import { useDebounceCallback } from '../../utilities/hooks/deprecated/use-debounce-callback/use-debounce-callback.js';
7
8
 
8
9
  const label = (text, count) => text.replace('%d', Math.abs(count).toString());
9
10
  /**
@@ -15,12 +16,14 @@ const label = (text, count) => text.replace('%d', Math.abs(count).toString());
15
16
  * <Field.Counter limit={100} under='%d tegn igjen' over='%d tegn for mye' />
16
17
  * </Field>
17
18
  */
18
- const FieldCounter = forwardRef(function FieldCounter({ limit, under = '%d tegn igjen', over = '%d tegn for mye', ...rest }, ref) {
19
+ const FieldCounter = forwardRef(function FieldCounter({ limit, under = '%d tegn igjen', over = '%d tegn for mye', hint = 'Maks %d tegn tillatt.', ...rest }, ref) {
19
20
  const [count, setCount] = useState(0);
21
+ const [liveRegionText, setLiveRegionText] = useState('');
20
22
  const fieldInputRef = useRef(null);
21
23
  const counterRef = useRef(null);
22
24
  const hasExceededLimit = count > limit;
23
25
  const remainder = limit - count;
26
+ const debouncedSetLiveRegionText = useDebounceCallback((text) => setLiveRegionText(text), 1200);
24
27
  // Listen to native input events (user typing) to update the counter in real time
25
28
  useEffect(() => {
26
29
  const field = counterRef.current?.closest('.ds-field');
@@ -43,7 +46,11 @@ const FieldCounter = forwardRef(function FieldCounter({ limit, under = '%d tegn
43
46
  setCount((prev) => (prev === valueLength ? prev : valueLength));
44
47
  }
45
48
  });
46
- return (jsxs(Fragment, { children: [jsx("div", { "data-field": 'description', className: 'ds-sr-only', "aria-live": 'polite', ref: counterRef, children: hasExceededLimit && label(over, remainder) }), hasExceededLimit ? (jsx(ValidationMessage, { ref: ref, ...rest, children: label(over, remainder) })) : (jsx(Paragraph, { ref: ref, ...rest, "data-field": 'validation', children: label(under, remainder) }))] }));
49
+ // Update live region text when count or limit changes
50
+ useEffect(() => {
51
+ debouncedSetLiveRegionText(label(hasExceededLimit ? over : under, remainder));
52
+ }, [count, limit, over, under, hasExceededLimit, remainder]);
53
+ return (jsxs(Fragment, { children: [jsx("div", { className: 'ds-sr-only', "aria-live": 'polite', ref: counterRef, children: liveRegionText }), hasExceededLimit ? (jsx(ValidationMessage, { ref: ref, ...rest, "aria-hidden": 'true', "data-field": null, children: label(over, remainder) })) : (jsx(Paragraph, { ref: ref, ...rest, "aria-hidden": 'true', children: label(under, remainder) })), jsx("div", { className: 'ds-sr-only', "aria-hidden": 'true', "data-field": 'description', children: label(hint, limit) })] }));
47
54
  });
48
55
 
49
56
  export { FieldCounter };
@@ -84,7 +84,7 @@ const Popover = forwardRef(function Popover({ id, className, onClose, onOpen, op
84
84
  arrowPseudoElement,
85
85
  ],
86
86
  }).then(({ x, y }) => {
87
- popover.style.translate = `${x}px ${y}px`;
87
+ popover.style.translate = `${Math.round(x)}px ${Math.round(y)}px`;
88
88
  });
89
89
  });
90
90
  }, [controlledOpen, placement, id, autoPlacement]);
@@ -30,7 +30,7 @@ const SuggestionList = forwardRef(function SuggestionList({ singular = '%d forsl
30
30
  strategy: 'fixed',
31
31
  middleware: [triggerWidth],
32
32
  }).then(({ x, y }) => {
33
- list.style.translate = `${x}px calc(${y}px + var(--dsc-suggestion-list-gap))`;
33
+ list.style.translate = `${Math.round(x)}px calc(${Math.round(y)}px + var(--dsc-suggestion-list-gap))`;
34
34
  });
35
35
  });
36
36
  }
@@ -58,7 +58,7 @@ const Tooltip = forwardRef(function Tooltip({ id, children, content, placement =
58
58
  safeAreaElement,
59
59
  ],
60
60
  }).then(({ x, y }) => {
61
- tooltip.style.translate = `${x}px ${y}px`;
61
+ tooltip.style.translate = `${Math.round(x)}px ${Math.round(y)}px`;
62
62
  });
63
63
  });
64
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/components/dialog/dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKlD,MAAM,MAAM,WAAW,GAAG,UAAU,CAClC,YAAY,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,EACtD;IACE;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,KAAK,CAAC;IAC3C;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,MAAM;IA5Df;;;OAGG;kBACW,MAAM,GAAG,KAAK;IAC5B;;;;OAIG;eACQ,MAAM,GAAG,cAAc,GAAG,KAAK;IAC1C;;;;;;OAMG;YACK,OAAO;IACf;;OAEG;WACI,OAAO;IACd;;OAEG;cACO,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;IAChC;;;;;OAKG;cACO,OAAO;qDA2HpB,CAAC"}
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/components/dialog/dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKlD,MAAM,MAAM,WAAW,GAAG,UAAU,CAClC,YAAY,GAAG,oBAAoB,CAAC,iBAAiB,CAAC,EACtD;IACE;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,KAAK,CAAC;IAC3C;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,MAAM;IA5Df;;;OAGG;kBACW,MAAM,GAAG,KAAK;IAC5B;;;;OAIG;eACQ,MAAM,GAAG,cAAc,GAAG,KAAK;IAC1C;;;;;;OAMG;YACK,OAAO;IACf;;OAEG;WACI,OAAO;IACd;;OAEG;cACO,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;IAChC;;;;;OAKG;cACO,OAAO;qDA0HpB,CAAC"}
@@ -14,6 +14,13 @@ export type FieldCounterProps = {
14
14
  * @default '%d tegn igjen'
15
15
  */
16
16
  under?: string;
17
+ /**
18
+ * Text for screen readers of how many characters are allowed.
19
+ * Only read when entering the field.
20
+ *
21
+ * @default 'Maks %d tegn tillatt.'
22
+ */
23
+ hint?: string;
17
24
  /**
18
25
  * The maximum allowed characters.
19
26
  *
@@ -45,6 +52,13 @@ export declare const FieldCounter: import("react").ForwardRefExoticComponent<{
45
52
  * @default '%d tegn igjen'
46
53
  */
47
54
  under?: string;
55
+ /**
56
+ * Text for screen readers of how many characters are allowed.
57
+ * Only read when entering the field.
58
+ *
59
+ * @default 'Maks %d tegn tillatt.'
60
+ */
61
+ hint?: string;
48
62
  /**
49
63
  * The maximum allowed characters.
50
64
  *
@@ -1 +1 @@
1
- {"version":3,"file":"field-counter.d.ts","sourceRoot":"","sources":["../../../src/components/field/field-counter.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,0CAA0C,CAAC;AAGlD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;QAII;IACJ,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,sBAAsB,CAAC;AAK3B;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;IAlCvB;;;;;OAKG;WACI,MAAM;IACb;;;;;OAKG;YACK,MAAM;IACd;;;;QAII;WACG,MAAM;;;;wDA0Ed,CAAC"}
1
+ {"version":3,"file":"field-counter.d.ts","sourceRoot":"","sources":["../../../src/components/field/field-counter.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,0CAA0C,CAAC;AAGlD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;QAII;IACJ,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,sBAAsB,CAAC;AAK3B;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;IAzCvB;;;;;OAKG;WACI,MAAM;IACb;;;;;OAKG;YACK,MAAM;IACd;;;;;OAKG;WACI,MAAM;IACb;;;;QAII;WACG,MAAM;;;;wDAgGd,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@digdir/designsystemet-react",
3
3
  "type": "module",
4
- "version": "1.6.1",
4
+ "version": "1.7.0",
5
5
  "description": "React components for Designsystemet",
6
6
  "author": "Designsystemet team",
7
7
  "repository": {
@@ -38,7 +38,7 @@
38
38
  "dependencies": {
39
39
  "@floating-ui/dom": "^1.7.4",
40
40
  "@floating-ui/react": "0.26.23",
41
- "@navikt/aksel-icons": "^7.31.0",
41
+ "@navikt/aksel-icons": "^7.32.2",
42
42
  "@radix-ui/react-slot": "^1.2.3",
43
43
  "@tanstack/react-virtual": "^3.13.12",
44
44
  "@u-elements/u-combobox": "^1.0.2",
@@ -47,27 +47,27 @@
47
47
  "clsx": "^2.1.1"
48
48
  },
49
49
  "devDependencies": {
50
- "@rollup/plugin-commonjs": "^28.0.6",
51
- "@rollup/plugin-node-resolve": "^16.0.2",
52
- "@storybook/addon-docs": "^9.1.10",
53
- "@storybook/addon-vitest": "^9.1.10",
54
- "@storybook/react-vite": "^9.1.10",
50
+ "@rollup/plugin-commonjs": "^28.0.8",
51
+ "@rollup/plugin-node-resolve": "^16.0.3",
52
+ "@storybook/addon-docs": "^9.1.13",
53
+ "@storybook/addon-vitest": "^9.1.13",
54
+ "@storybook/react-vite": "^9.1.13",
55
55
  "@testing-library/dom": "^10.4.1",
56
56
  "@testing-library/jest-dom": "^6.9.1",
57
57
  "@testing-library/react": "^16.3.0",
58
58
  "@testing-library/user-event": "^14.6.1",
59
- "@types/react": "^19.2.0",
60
- "@types/react-dom": "^19.2.0",
59
+ "@types/react": "^19.2.2",
60
+ "@types/react-dom": "^19.2.2",
61
61
  "react": "^19.2.0",
62
62
  "react-dom": "^19.2.0",
63
63
  "rimraf": "^6.0.1",
64
- "rollup": "^4.52.4",
64
+ "rollup": "^4.52.5",
65
65
  "rollup-plugin-copy": "^3.5.0",
66
- "storybook": "^9.1.10",
66
+ "storybook": "^9.1.13",
67
67
  "tsx": "4.20.6",
68
68
  "typescript": "^5.9.3",
69
- "@digdir/designsystemet": "^1.6.1",
70
- "@digdir/designsystemet-css": "^1.6.1"
69
+ "@digdir/designsystemet": "^1.7.0",
70
+ "@digdir/designsystemet-css": "^1.7.0"
71
71
  },
72
72
  "scripts": {
73
73
  "build": "pnpm run clean && tsc -b tsconfig.lib.json --emitDeclarationOnly false && rollup -c --bundleConfigAsCjs",