@digdir/designsystemet-react 1.11.1 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/dist/cjs/components/Combobox/Combobox.js +1 -0
  2. package/dist/cjs/components/Combobox/Option/useComboboxOption.js +1 -0
  3. package/dist/cjs/components/Combobox/useComboboxKeyboard.js +1 -0
  4. package/dist/cjs/components/avatar/avatar.js +2 -2
  5. package/dist/cjs/components/breadcrumbs/breadcrumbs-link.js +2 -1
  6. package/dist/cjs/components/breadcrumbs/breadcrumbs-list.js +1 -11
  7. package/dist/cjs/components/breadcrumbs/breadcrumbs.js +2 -1
  8. package/dist/cjs/components/button/button.js +8 -3
  9. package/dist/cjs/components/card/card.js +17 -9
  10. package/dist/cjs/components/details/details-summary.js +3 -3
  11. package/dist/cjs/components/details/details.js +2 -2
  12. package/dist/cjs/components/dialog/dialog-trigger-context.js +5 -6
  13. package/dist/cjs/components/dialog/dialog-trigger.js +3 -8
  14. package/dist/cjs/components/dialog/dialog.js +25 -55
  15. package/dist/cjs/components/error-summary/error-summary-heading.js +2 -8
  16. package/dist/cjs/components/error-summary/error-summary.js +4 -9
  17. package/dist/cjs/components/field/field-counter.js +6 -41
  18. package/dist/cjs/components/field/field-description.js +2 -1
  19. package/dist/cjs/components/field/field.js +6 -4
  20. package/dist/cjs/components/label/label.js +2 -1
  21. package/dist/cjs/components/pagination/pagination-button.js +5 -3
  22. package/dist/cjs/components/pagination/pagination.js +7 -3
  23. package/dist/cjs/components/popover/popover-trigger.js +6 -10
  24. package/dist/cjs/components/popover/popover.js +15 -62
  25. package/dist/cjs/components/select/select.js +2 -12
  26. package/dist/cjs/components/skeleton/skeleton.js +1 -0
  27. package/dist/cjs/components/spinner/spinner.js +1 -0
  28. package/dist/cjs/components/suggestion/suggestion-clear.js +4 -2
  29. package/dist/cjs/components/suggestion/suggestion-empty.js +3 -1
  30. package/dist/cjs/components/suggestion/suggestion-input.js +4 -3
  31. package/dist/cjs/components/suggestion/suggestion-list.js +5 -41
  32. package/dist/cjs/components/suggestion/suggestion-option.js +3 -1
  33. package/dist/cjs/components/suggestion/suggestion.js +9 -9
  34. package/dist/cjs/components/tabs/tabs-list.js +4 -7
  35. package/dist/cjs/components/tabs/tabs-panel.js +5 -28
  36. package/dist/cjs/components/tabs/tabs-tab.js +11 -9
  37. package/dist/cjs/components/tabs/tabs.js +16 -6
  38. package/dist/cjs/components/toggle-group/index.js +1 -1
  39. package/dist/cjs/components/toggle-group/toggle-group-item.js +8 -6
  40. package/dist/cjs/components/toggle-group/toggle-group.js +6 -6
  41. package/dist/cjs/components/tooltip/tooltip.js +6 -147
  42. package/dist/cjs/components/validation-message/validation-message.js +2 -1
  43. package/dist/cjs/index.js +1 -0
  44. package/dist/cjs/utilities/hooks/use-pagination/use-pagination.js +13 -25
  45. package/dist/cjs/utilities/index.js +17 -0
  46. package/dist/cjs/utilities/roving-focus/roving-focus-item.js +2 -0
  47. package/dist/cjs/utilities/roving-focus/roving-focus-root.js +4 -0
  48. package/dist/cjs/utilities/roving-focus/use-roving-focus.js +3 -1
  49. package/dist/esm/components/Combobox/Combobox.js +1 -0
  50. package/dist/esm/components/Combobox/Option/useComboboxOption.js +1 -0
  51. package/dist/esm/components/Combobox/useComboboxKeyboard.js +1 -0
  52. package/dist/esm/components/avatar/avatar.js +2 -2
  53. package/dist/esm/components/breadcrumbs/breadcrumbs-link.js +2 -1
  54. package/dist/esm/components/breadcrumbs/breadcrumbs-list.js +2 -12
  55. package/dist/esm/components/breadcrumbs/breadcrumbs.js +2 -1
  56. package/dist/esm/components/button/button.js +9 -4
  57. package/dist/esm/components/card/card.js +18 -10
  58. package/dist/esm/components/details/details-summary.js +3 -3
  59. package/dist/esm/components/details/details.js +2 -2
  60. package/dist/esm/components/dialog/dialog-trigger-context.js +6 -7
  61. package/dist/esm/components/dialog/dialog-trigger.js +3 -8
  62. package/dist/esm/components/dialog/dialog.js +26 -56
  63. package/dist/esm/components/error-summary/error-summary-heading.js +3 -9
  64. package/dist/esm/components/error-summary/error-summary.js +6 -10
  65. package/dist/esm/components/field/field-counter.js +8 -43
  66. package/dist/esm/components/field/field-description.js +2 -1
  67. package/dist/esm/components/field/field.js +7 -5
  68. package/dist/esm/components/label/label.js +2 -1
  69. package/dist/esm/components/pagination/pagination-button.js +5 -3
  70. package/dist/esm/components/pagination/pagination.js +7 -3
  71. package/dist/esm/components/popover/popover-trigger.js +6 -10
  72. package/dist/esm/components/popover/popover.js +15 -62
  73. package/dist/esm/components/select/select.js +2 -12
  74. package/dist/esm/components/skeleton/skeleton.js +1 -0
  75. package/dist/esm/components/spinner/spinner.js +1 -0
  76. package/dist/esm/components/suggestion/suggestion-clear.js +4 -2
  77. package/dist/esm/components/suggestion/suggestion-empty.js +3 -1
  78. package/dist/esm/components/suggestion/suggestion-input.js +4 -3
  79. package/dist/esm/components/suggestion/suggestion-list.js +5 -41
  80. package/dist/esm/components/suggestion/suggestion-option.js +3 -1
  81. package/dist/esm/components/suggestion/suggestion.js +9 -9
  82. package/dist/esm/components/tabs/tabs-list.js +5 -8
  83. package/dist/esm/components/tabs/tabs-panel.js +6 -29
  84. package/dist/esm/components/tabs/tabs-tab.js +12 -10
  85. package/dist/esm/components/tabs/tabs.js +17 -7
  86. package/dist/esm/components/toggle-group/index.js +1 -1
  87. package/dist/esm/components/toggle-group/toggle-group-item.js +10 -8
  88. package/dist/esm/components/toggle-group/toggle-group.js +7 -7
  89. package/dist/esm/components/tooltip/tooltip.js +8 -149
  90. package/dist/esm/components/validation-message/validation-message.js +2 -1
  91. package/dist/esm/index.js +1 -0
  92. package/dist/esm/utilities/hooks/use-pagination/use-pagination.js +13 -25
  93. package/dist/esm/utilities/index.js +11 -0
  94. package/dist/esm/utilities/roving-focus/roving-focus-item.js +2 -0
  95. package/dist/esm/utilities/roving-focus/roving-focus-root.js +4 -0
  96. package/dist/esm/utilities/roving-focus/use-roving-focus.js +3 -1
  97. package/dist/react-types.d.ts +8 -0
  98. package/dist/types/components/avatar/avatar.d.ts +12 -7
  99. package/dist/types/components/avatar/avatar.d.ts.map +1 -1
  100. package/dist/types/components/breadcrumbs/breadcrumbs-link.d.ts.map +1 -1
  101. package/dist/types/components/breadcrumbs/breadcrumbs-list.d.ts.map +1 -1
  102. package/dist/types/components/breadcrumbs/breadcrumbs.d.ts +5 -3
  103. package/dist/types/components/breadcrumbs/breadcrumbs.d.ts.map +1 -1
  104. package/dist/types/components/button/button.d.ts +1 -1
  105. package/dist/types/components/button/button.d.ts.map +1 -1
  106. package/dist/types/components/card/card.d.ts.map +1 -1
  107. package/dist/types/components/details/details-summary.d.ts.map +1 -1
  108. package/dist/types/components/details/details.d.ts +1 -1
  109. package/dist/types/components/details/details.d.ts.map +1 -1
  110. package/dist/types/components/dialog/dialog-trigger-context.d.ts +10 -3
  111. package/dist/types/components/dialog/dialog-trigger-context.d.ts.map +1 -1
  112. package/dist/types/components/dialog/dialog-trigger.d.ts +1 -1
  113. package/dist/types/components/dialog/dialog-trigger.d.ts.map +1 -1
  114. package/dist/types/components/dialog/dialog.d.ts +3 -3
  115. package/dist/types/components/dialog/dialog.d.ts.map +1 -1
  116. package/dist/types/components/dropdown/dropdown.d.ts +1 -2
  117. package/dist/types/components/dropdown/dropdown.d.ts.map +1 -1
  118. package/dist/types/components/error-summary/error-summary-heading.d.ts.map +1 -1
  119. package/dist/types/components/error-summary/error-summary.d.ts +6 -6
  120. package/dist/types/components/error-summary/error-summary.d.ts.map +1 -1
  121. package/dist/types/components/field/field-counter.d.ts +2 -8
  122. package/dist/types/components/field/field-counter.d.ts.map +1 -1
  123. package/dist/types/components/field/field-description.d.ts.map +1 -1
  124. package/dist/types/components/field/field.d.ts +6 -2
  125. package/dist/types/components/field/field.d.ts.map +1 -1
  126. package/dist/types/components/index.d.ts +1 -0
  127. package/dist/types/components/index.d.ts.map +1 -1
  128. package/dist/types/components/input/input.d.ts +13 -1
  129. package/dist/types/components/input/input.d.ts.map +1 -1
  130. package/dist/types/components/label/label.d.ts.map +1 -1
  131. package/dist/types/components/pagination/pagination-button.d.ts +13 -4
  132. package/dist/types/components/pagination/pagination-button.d.ts.map +1 -1
  133. package/dist/types/components/pagination/pagination.d.ts +27 -5
  134. package/dist/types/components/pagination/pagination.d.ts.map +1 -1
  135. package/dist/types/components/popover/popover-trigger.d.ts.map +1 -1
  136. package/dist/types/components/popover/popover.d.ts +2 -14
  137. package/dist/types/components/popover/popover.d.ts.map +1 -1
  138. package/dist/types/components/search/search-button.d.ts +1 -1
  139. package/dist/types/components/select/select.d.ts +2 -0
  140. package/dist/types/components/select/select.d.ts.map +1 -1
  141. package/dist/types/components/suggestion/suggestion-clear.d.ts +7 -5
  142. package/dist/types/components/suggestion/suggestion-clear.d.ts.map +1 -1
  143. package/dist/types/components/suggestion/suggestion-empty.d.ts +1 -0
  144. package/dist/types/components/suggestion/suggestion-empty.d.ts.map +1 -1
  145. package/dist/types/components/suggestion/suggestion-input.d.ts +2 -1
  146. package/dist/types/components/suggestion/suggestion-input.d.ts.map +1 -1
  147. package/dist/types/components/suggestion/suggestion-list.d.ts +1 -1
  148. package/dist/types/components/suggestion/suggestion-list.d.ts.map +1 -1
  149. package/dist/types/components/suggestion/suggestion-option.d.ts +1 -0
  150. package/dist/types/components/suggestion/suggestion-option.d.ts.map +1 -1
  151. package/dist/types/components/suggestion/suggestion.d.ts +5 -6
  152. package/dist/types/components/suggestion/suggestion.d.ts.map +1 -1
  153. package/dist/types/components/tabs/tabs-list.d.ts +4 -2
  154. package/dist/types/components/tabs/tabs-list.d.ts.map +1 -1
  155. package/dist/types/components/tabs/tabs-panel.d.ts +4 -2
  156. package/dist/types/components/tabs/tabs-panel.d.ts.map +1 -1
  157. package/dist/types/components/tabs/tabs-tab.d.ts +4 -2
  158. package/dist/types/components/tabs/tabs-tab.d.ts.map +1 -1
  159. package/dist/types/components/tabs/tabs.d.ts +6 -6
  160. package/dist/types/components/tabs/tabs.d.ts.map +1 -1
  161. package/dist/types/components/textfield/textfield.d.ts.map +1 -1
  162. package/dist/types/components/toggle-group/index.d.ts +1 -1
  163. package/dist/types/components/toggle-group/toggle-group-item.d.ts +12 -3
  164. package/dist/types/components/toggle-group/toggle-group-item.d.ts.map +1 -1
  165. package/dist/types/components/toggle-group/toggle-group.d.ts +12 -4
  166. package/dist/types/components/toggle-group/toggle-group.d.ts.map +1 -1
  167. package/dist/types/components/tooltip/tooltip.d.ts +10 -3
  168. package/dist/types/components/tooltip/tooltip.d.ts.map +1 -1
  169. package/dist/types/components/validation-message/validation-message.d.ts.map +1 -1
  170. package/dist/types/types.d.ts +2 -0
  171. package/dist/types/types.d.ts.map +1 -1
  172. package/dist/types/utilities/hooks/use-pagination/use-pagination.d.ts +1 -1
  173. package/dist/types/utilities/hooks/use-pagination/use-pagination.d.ts.map +1 -1
  174. package/dist/types/utilities/index.d.ts +6 -0
  175. package/dist/types/utilities/index.d.ts.map +1 -1
  176. package/dist/types/utilities/roving-focus/roving-focus-item.d.ts +1 -0
  177. package/dist/types/utilities/roving-focus/roving-focus-item.d.ts.map +1 -1
  178. package/dist/types/utilities/roving-focus/roving-focus-root.d.ts +1 -0
  179. package/dist/types/utilities/roving-focus/roving-focus-root.d.ts.map +1 -1
  180. package/dist/types/utilities/roving-focus/use-roving-focus.d.ts +3 -1
  181. package/dist/types/utilities/roving-focus/use-roving-focus.d.ts.map +1 -1
  182. package/package.json +11 -14
  183. package/dist/cjs/components/field/field-observer.js +0 -112
  184. package/dist/cjs/components/toggle-group/use-toggle-groupitem.js +0 -34
  185. package/dist/esm/components/field/field-observer.js +0 -107
  186. package/dist/esm/components/toggle-group/use-toggle-groupitem.js +0 -32
  187. package/dist/types/components/field/field-observer.d.ts +0 -5
  188. package/dist/types/components/field/field-observer.d.ts.map +0 -1
  189. package/dist/types/components/toggle-group/use-toggle-groupitem.d.ts +0 -12
  190. package/dist/types/components/toggle-group/use-toggle-groupitem.d.ts.map +0 -1
@@ -2,11 +2,9 @@
2
2
  'use strict';
3
3
 
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
- var dom = require('@floating-ui/dom');
6
5
  var reactSlot = require('@radix-ui/react-slot');
7
- var cl = require('clsx/lite');
6
+ require('@digdir/designsystemet-web');
8
7
  var react = require('react');
9
- var useMergeRefs = require('../../utilities/hooks/use-merge-refs/use-merge-refs.js');
10
8
 
11
9
  /**
12
10
  * Tooltip component that displays a small piece of information when hovering or focusing on an element.
@@ -21,150 +19,11 @@ var useMergeRefs = require('../../utilities/hooks/use-merge-refs/use-merge-refs.
21
19
  * Hover me
22
20
  * </Tooltip>
23
21
  */
24
- const Tooltip = react.forwardRef(function Tooltip({ id, children, content, placement = 'top', autoPlacement = true, open, className, type, ...rest }, ref) {
25
- const randomTooltipId = react.useId();
26
- const [internalOpen, setInternalOpen] = react.useState(false);
27
- const triggerRef = react.useRef(null);
28
- const tooltipRef = react.useRef(null);
29
- const mergedRefs = useMergeRefs.useMergeRefs([tooltipRef, ref]);
30
- const controlledOpen = open ?? internalOpen;
31
- const tooltipId = id ?? randomTooltipId;
32
- const setOpen = () => {
33
- setInternalOpen(true);
34
- };
35
- const setClose = () => {
36
- setInternalOpen(false);
37
- };
38
- // Position with floating-ui
39
- react.useEffect(() => {
40
- const tooltip = tooltipRef.current;
41
- const trigger = triggerRef.current;
42
- tooltip?.togglePopover?.(controlledOpen);
43
- if (tooltip)
44
- tooltip.style.opacity = controlledOpen ? '1' : '0';
45
- if (tooltip && trigger && controlledOpen) {
46
- return dom.autoUpdate(trigger, tooltip, () => {
47
- dom.computePosition(trigger, tooltip, {
48
- placement,
49
- strategy: 'fixed',
50
- middleware: [
51
- dom.offset((data) => {
52
- // get pseudo element arrow size
53
- const styles = getComputedStyle(data.elements.floating, '::before');
54
- return parseFloat(styles.height);
55
- }),
56
- ...(autoPlacement
57
- ? [dom.flip({ fallbackAxisSideDirection: 'start' }), dom.shift()]
58
- : []),
59
- dom.shift(),
60
- arrowPseudoElement,
61
- safeAreaElement,
62
- ],
63
- }).then(({ x, y }) => {
64
- tooltip.style.translate = `${Math.round(x)}px ${Math.round(y)}px`;
65
- });
66
- });
67
- }
68
- }, [controlledOpen, placement]);
69
- /* Add listeners for ESC to dismiss and click outside on mobile */
70
- react.useEffect(() => {
71
- const tooltip = tooltipRef.current;
72
- const trigger = triggerRef.current;
73
- const handleKeyDown = (event) => {
74
- if (event.key === 'Escape') {
75
- setInternalOpen(false);
76
- }
77
- };
78
- const handleClick = (event) => {
79
- const el = event.target;
80
- const isTooltip = tooltip?.contains(el);
81
- const isTrigger = trigger?.contains(el);
82
- const isOutside = !isTrigger && !isTooltip;
83
- if (isOutside && controlledOpen) {
84
- setInternalOpen(false);
85
- }
86
- };
87
- if (controlledOpen) {
88
- window.addEventListener('keydown', handleKeyDown);
89
- /* Add click listener to handle mobile tap-to-close */
90
- document.addEventListener('click', handleClick);
91
- }
92
- return () => {
93
- window.removeEventListener('keydown', handleKeyDown);
94
- document.removeEventListener('click', handleClick);
95
- };
96
- }, [controlledOpen]);
97
- /* If children is only a string, make a span */
98
- const ChildContainer = typeof children === 'string' ? 'span' : reactSlot.Slot;
99
- /* Make sure it is valid */
100
- if (typeof children !== 'string' && children.type === react.Fragment) {
101
- console.error('<Tooltip> children needs to be a single ReactElement that can receive a ref and not: <Fragment/> | <></>');
102
- return null;
103
- }
104
- const popoverProps = {
105
- [react.version.startsWith('19') ? 'popoverTarget' : 'popovertarget']: tooltipId,
106
- [react.version.startsWith('19')
107
- ? 'popoverTargetAction'
108
- : 'popovertargetaction']: 'show',
109
- };
110
- const autoType = `aria-${triggerRef.current?.innerText?.trim() ? 'describedby' : 'labelledby'}`;
111
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ChildContainer, { ref: triggerRef, ...popoverProps, onMouseEnter: setOpen, onMouseLeave: setClose, onFocus: setOpen, onBlur: setClose, [type ? 'aria-' + type : autoType]: tooltipId, children: children }), jsxRuntime.jsx("span", { onMouseEnter: setOpen, onMouseLeave: setClose, ref: mergedRefs, role: 'tooltip', className: cl('ds-tooltip', className), id: tooltipId, popover: 'manual', ...rest, children: content })] }));
22
+ const Tooltip = react.forwardRef(function Tooltip({ content, placement = 'top', autoPlacement = true, ...rest }, _ref) {
23
+ /* check if children is a string */
24
+ const isString = typeof rest.children === 'string';
25
+ return (jsxRuntime.jsx(reactSlot.Slot, { "aria-label": content, "data-tooltip": content, "data-placement": placement, "data-autoplacement": autoPlacement, suppressHydrationWarning // Since data-tooltip adds aria-label/aria-description
26
+ : true, ...rest, children: isString ? jsxRuntime.jsx("span", { tabIndex: 0, children: rest.children }) : rest.children }));
112
27
  });
113
- const arrowPseudoElement = {
114
- name: 'ArrowPseudoElement',
115
- fn(data) {
116
- const { elements, rects, placement } = data;
117
- let arrowX = `${Math.round(rects.reference.width / 2 + rects.reference.x - data.x)}px`;
118
- let arrowY = `${Math.round(rects.reference.height / 2 + rects.reference.y - data.y)}px`;
119
- switch (placement) {
120
- case 'top':
121
- arrowY = '100%';
122
- break;
123
- case 'right':
124
- arrowX = '0';
125
- break;
126
- case 'bottom':
127
- arrowY = '0';
128
- break;
129
- case 'left':
130
- arrowX = '100%';
131
- break;
132
- }
133
- elements.floating.style.setProperty('--dsc-tooltip-arrow-x', arrowX);
134
- elements.floating.style.setProperty('--dsc-tooltip-arrow-y', arrowY);
135
- return data;
136
- },
137
- };
138
- const safeAreaElement = {
139
- name: 'SafeAreaElement',
140
- fn(data) {
141
- const { elements, placement } = data;
142
- let width = '100%';
143
- let height = 'var(--dsc-tooltip-arrow-size)';
144
- let translate = '0px';
145
- switch (placement) {
146
- case 'top':
147
- translate = `-50% 0%`;
148
- break;
149
- case 'right':
150
- height = '100%';
151
- width = 'var(--dsc-tooltip-arrow-size)';
152
- translate = '-100% -50%';
153
- break;
154
- case 'bottom':
155
- translate = '-50% -100%';
156
- break;
157
- case 'left':
158
- height = '100%';
159
- width = 'var(--dsc-tooltip-arrow-size)';
160
- translate = '0 -50%';
161
- break;
162
- }
163
- elements.floating.style.setProperty('--_dsc-tooltip-safearea-height', height);
164
- elements.floating.style.setProperty('--_dsc-tooltip-safearea-width', width);
165
- elements.floating.style.setProperty('--_dsc-tooltip-safearea-translate', translate);
166
- return data;
167
- },
168
- };
169
28
 
170
29
  exports.Tooltip = Tooltip;
@@ -14,7 +14,8 @@ var react = require('react');
14
14
  */
15
15
  const ValidationMessage = react.forwardRef(function ValidationMessage({ className, asChild, ...rest }, ref) {
16
16
  const Component = asChild ? reactSlot.Slot : 'p';
17
- return (jsxRuntime.jsx(Component, { className: cl('ds-validation-message', className), "data-field": 'validation', ref: ref, ...rest }));
17
+ return (jsxRuntime.jsx(Component, { className: cl('ds-validation-message', className), "data-field": 'validation', ref: ref, suppressHydrationWarning // Since <ds-field> adds attributes
18
+ : true, ...rest }));
18
19
  });
19
20
 
20
21
  exports.ValidationMessage = ValidationMessage;
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
+ require('@digdir/designsystemet-web');
4
5
  var alert = require('./components/alert/alert.js');
5
6
  var avatar = require('./components/avatar/avatar.js');
6
7
  var avatarStack = require('./components/avatar-stack/avatar-stack.js');
@@ -1,19 +1,9 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
+ var designsystemetWeb = require('@digdir/designsystemet-web');
4
5
  var react = require('react');
5
6
 
6
- const getSteps = (now, max, show) => {
7
- const offset = (show - 1) / 2;
8
- const start = Math.max(1, Math.min(Math.max(now - Math.floor(offset), 1), max - show + 1));
9
- const end = Math.min(Math.max(now + Math.ceil(offset), show), max);
10
- const pages = Array.from({ length: end + 1 - start }, (_, i) => i + start);
11
- if (show > 4 && start > 1)
12
- pages.splice(0, 2, 1, 0);
13
- if (show > 3 && end < max)
14
- pages.splice(-2, 2, 0, max);
15
- return pages;
16
- };
17
7
  /**
18
8
  * Hook to help manage pagination state
19
9
  *
@@ -43,11 +33,10 @@ const getSteps = (now, max, show) => {
43
33
  * </Pagination.Item>
44
34
  * </Pagination>
45
35
  **/
46
- const usePagination = ({ currentPage = 1, setCurrentPage, onChange, totalPages = 1, showPages = 7, }) => react.useMemo(() => {
47
- const hasNext = currentPage < totalPages;
48
- const hasPrev = currentPage !== 1;
36
+ const usePagination = ({ currentPage: current = 1, setCurrentPage, onChange, totalPages: total = 1, showPages: show = 7, }) => react.useMemo(() => {
37
+ const { next, prev, pages } = designsystemetWeb.pagination({ current, total, show });
49
38
  const handleClick = (page) => (event) => {
50
- if (page < 1 || page > totalPages)
39
+ if (page < 1 || page > total)
51
40
  return event.preventDefault(); // Prevent out of bounds navigation
52
41
  onChange?.(event, page);
53
42
  if (!event.defaultPrevented)
@@ -55,7 +44,7 @@ const usePagination = ({ currentPage = 1, setCurrentPage, onChange, totalPages =
55
44
  };
56
45
  return {
57
46
  /** Number of steps */
58
- pages: getSteps(currentPage, totalPages, showPages).map((page, index) => ({
47
+ pages: pages.map(({ page, current }, index) => ({
59
48
  /**
60
49
  * Page number or "ellipsis" for the ellipsis item
61
50
  */
@@ -69,29 +58,28 @@ const usePagination = ({ currentPage = 1, setCurrentPage, onChange, totalPages =
69
58
  */
70
59
  buttonProps: (page
71
60
  ? {
72
- 'aria-current': page === currentPage ? 'page' : undefined,
61
+ 'aria-current': current ? 'true' : undefined,
73
62
  onClick: handleClick(page),
74
- variant: page === currentPage ? 'primary' : 'tertiary',
75
63
  }
76
64
  : null),
77
65
  })),
78
66
  /** Properties to spread on Pagination.Button used for previous naviagation */
79
67
  prevButtonProps: {
80
- 'aria-hidden': !hasPrev, // Using aria-hidden to support all HTML elements because of potential asChild
81
- onClick: handleClick(currentPage - 1),
68
+ 'aria-hidden': !prev, // Using aria-hidden to support all HTML elements because of potential asChild
69
+ onClick: handleClick(prev),
82
70
  variant: 'tertiary',
83
71
  },
84
72
  /** Properties to spread on Pagination.Button used for next naviagation */
85
73
  nextButtonProps: {
86
- 'aria-hidden': !hasNext, // Using aria-hidden to support all HTML elements because of potential asChild
87
- onClick: handleClick(currentPage + 1),
74
+ 'aria-hidden': !next, // Using aria-hidden to support all HTML elements because of potential asChild
75
+ onClick: handleClick(next),
88
76
  variant: 'tertiary',
89
77
  },
90
78
  /** Indication if previous page action should be shown or not */
91
- hasPrev,
79
+ hasPrev: !!prev,
92
80
  /** Indication if next page action should be shown or not */
93
- hasNext,
81
+ hasNext: !!next,
94
82
  };
95
- }, [currentPage, totalPages, showPages]);
83
+ }, [current, total, show]);
96
84
 
97
85
  exports.usePagination = usePagination;
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ require('react');
5
+ require('@digdir/designsystemet-web');
6
+ var rovingFocusItem = require('./roving-focus/roving-focus-item.js');
7
+ var rovingFocusRoot = require('./roving-focus/roving-focus-root.js');
8
+
9
+ const warn = (message, ...args) => typeof window === 'undefined' ||
10
+ window.dsWarnings === false ||
11
+ console.warn(`Designsystemet: ${message}`, ...args);
12
+
13
+ exports.RovingFocusItem = rovingFocusItem.RovingFocusItem;
14
+ exports.getNextFocusableValue = rovingFocusItem.getNextFocusableValue;
15
+ exports.getPrevFocusableValue = rovingFocusItem.getPrevFocusableValue;
16
+ exports.RovingFocusRoot = rovingFocusRoot.RovingFocusRoot;
17
+ exports.warn = warn;
@@ -5,6 +5,7 @@ var jsxRuntime = require('react/jsx-runtime');
5
5
  var reactSlot = require('@radix-ui/react-slot');
6
6
  var react = require('react');
7
7
  var useMergeRefs = require('../hooks/use-merge-refs/use-merge-refs.js');
8
+ require('@digdir/designsystemet-web');
8
9
  var useRovingFocus = require('./use-roving-focus.js');
9
10
 
10
11
  /** Get the next focusable RovingFocusItem */
@@ -17,6 +18,7 @@ function getPrevFocusableValue(items, value) {
17
18
  const currIndex = items.findIndex((item) => item.value === value);
18
19
  return items.at(currIndex === 0 ? -1 : currIndex - 1);
19
20
  }
21
+ /** @deprecated RovingFocusItem is deprecated.*/
20
22
  const RovingFocusItem = react.forwardRef(({ value, asChild, ...rest }, ref) => {
21
23
  const Component = asChild ? reactSlot.Slot : 'div';
22
24
  const focusValue = value ?? (typeof rest.children === 'string' ? rest.children : '');
@@ -4,7 +4,9 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var reactSlot = require('@radix-ui/react-slot');
6
6
  var react = require('react');
7
+ var index = require('../index.js');
7
8
  var useMergeRefs = require('../hooks/use-merge-refs/use-merge-refs.js');
9
+ require('@digdir/designsystemet-web');
8
10
 
9
11
  const RovingFocusContext = react.createContext({
10
12
  elements: { current: new Map() },
@@ -18,6 +20,7 @@ const RovingFocusContext = react.createContext({
18
20
  focusableValue: null,
19
21
  orientation: 'horizontal',
20
22
  });
23
+ /** @deprecated RovingFocusRoot is deprecated. */
21
24
  const RovingFocusRoot = react.forwardRef(({ activeValue, asChild, orientation = 'horizontal', onBlur, onFocus, ...rest }, ref) => {
22
25
  const Component = asChild ? reactSlot.Slot : 'div';
23
26
  const activeValueOrNull = activeValue ?? null;
@@ -37,6 +40,7 @@ const RovingFocusRoot = react.forwardRef(({ activeValue, asChild, orientation =
37
40
  react.useEffect(() => {
38
41
  setFocusableValue(activeValueOrNull);
39
42
  }, [activeValueOrNull]);
43
+ index.warn('RovingFocusRoot is deprecated.');
40
44
  return (jsxRuntime.jsx(RovingFocusContext.Provider, { value: {
41
45
  elements,
42
46
  getOrderedItems,
@@ -6,7 +6,9 @@ var rovingFocusRoot = require('./roving-focus-root.js');
6
6
 
7
7
  // Logic from: https://www.joshuawootonn.com/react-roving-tabindex
8
8
  // Inspired by: https://github.com/radix-ui/primitives/tree/main/packages/react/roving-focus/src
9
- /** Handles props for `RovingFocus` in context with `RovingFocusRoot` */
9
+ /**
10
+ @deprecated useRovingFocus is deprecated.
11
+ Handles props for `RovingFocus` in context with `RovingFocusRoot` */
10
12
  const useRovingFocus = (value) => {
11
13
  const { elements, getOrderedItems, setFocusableValue, focusableValue, onShiftTab, orientation, } = react.useContext(rovingFocusRoot.RovingFocusContext);
12
14
  return {
@@ -5,6 +5,7 @@ import { useVirtualizer } from '@tanstack/react-virtual';
5
5
  import cl from 'clsx/lite';
6
6
  import { forwardRef, useRef, useState, useEffect } from 'react';
7
7
  import { useDebounceCallback } from '../../utilities/hooks/deprecated/use-debounce-callback/use-debounce-callback.js';
8
+ import '@digdir/designsystemet-web';
8
9
  import '../../utilities/roving-focus/roving-focus-item.js';
9
10
  import '../../utilities/roving-focus/roving-focus-root.js';
10
11
  import { Spinner } from '../spinner/spinner.js';
@@ -2,6 +2,7 @@
2
2
  import { useMergeRefs } from '@floating-ui/react';
3
3
  import { useId, useContext, useMemo, useEffect } from 'react';
4
4
  import { useDebounceCallback } from '../../../utilities/hooks/deprecated/use-debounce-callback/use-debounce-callback.js';
5
+ import '@digdir/designsystemet-web';
5
6
  import '../../../utilities/roving-focus/roving-focus-item.js';
6
7
  import '../../../utilities/roving-focus/roving-focus-root.js';
7
8
  import { ComboboxContext } from '../ComboboxContext.js';
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { useDebounceCallback } from '../../utilities/hooks/deprecated/use-debounce-callback/use-debounce-callback.js';
3
3
  import 'react';
4
+ import '@digdir/designsystemet-web';
4
5
  import '../../utilities/roving-focus/roving-focus-item.js';
5
6
  import '../../utilities/roving-focus/roving-focus-root.js';
6
7
  import { useComboboxId } from './ComboboxIdContext.js';
@@ -20,12 +20,12 @@ import { forwardRef, Fragment } from 'react';
20
20
  * <Icon />
21
21
  * </Avatar>
22
22
  */
23
- const Avatar = forwardRef(function Avatar({ 'aria-label': ariaLabel, variant = 'circle', className, children, initials, asChild, ...rest }, ref) {
23
+ const Avatar = forwardRef(function Avatar({ 'aria-label': ariaLabel, 'data-tooltip': dataTooltip, variant = 'circle', className, children, initials, asChild, ...rest }, ref) {
24
24
  const OuterComponent = asChild ? Slot : 'span';
25
25
  const useSlot = children && typeof children !== 'string';
26
26
  const textChild = children && typeof children === 'string';
27
27
  const Component = useSlot ? Slot : Fragment;
28
- return (jsx(OuterComponent, { ref: ref, className: cl('ds-avatar', className), "data-variant": variant, "data-initials": initials, role: asChild ? undefined : 'img', "aria-label": ariaLabel, ...rest, children: jsx(Component, { ...(useSlot && !asChild ? { 'aria-hidden': true } : {}), children: textChild ? jsx("span", { children: children }) : children }) }));
28
+ return (jsx(OuterComponent, { ref: ref, className: cl('ds-avatar', className), "data-variant": variant, "data-initials": initials, role: asChild ? undefined : 'img', "aria-label": ariaLabel || dataTooltip, tabIndex: dataTooltip ? 0 : undefined, ...rest, children: jsx(Component, { ...(useSlot && !asChild ? { 'aria-hidden': true } : {}), children: textChild ? jsx("span", { children: children }) : children }) }));
29
29
  });
30
30
 
31
31
  export { Avatar };
@@ -4,7 +4,8 @@ import { forwardRef } from 'react';
4
4
  import { Link } from '../link/link.js';
5
5
 
6
6
  const BreadcrumbsLink = forwardRef(function BreadcrumbsLink(rest, ref) {
7
- return jsx(Link, { ref: ref, ...rest });
7
+ return (jsx(Link, { suppressHydrationWarning // Since <ds-breadcrumbs> adds aria-current="page"
8
+ : true, ref: ref, ...rest }));
8
9
  });
9
10
 
10
11
  export { BreadcrumbsLink };
@@ -1,19 +1,9 @@
1
1
  'use client';
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { forwardRef, useRef, useEffect } from 'react';
4
- import { useMergeRefs } from '../../utilities/hooks/use-merge-refs/use-merge-refs.js';
3
+ import { forwardRef } from 'react';
5
4
 
6
5
  const BreadcrumbsList = forwardRef(function BreadcrumbsList(rest, ref) {
7
- const innerRef = useRef(null);
8
- const mergedRefs = useMergeRefs([innerRef, ref]);
9
- // Set aria-current on last link
10
- useEffect(() => {
11
- const links = innerRef.current?.querySelectorAll(':scope > * > *') || [];
12
- const lastLink = links[links?.length - 1];
13
- lastLink?.setAttribute('aria-current', 'page');
14
- return () => lastLink?.removeAttribute('aria-current'); // Remove on re-render as React can re-use DOM elements
15
- });
16
- return jsx("ol", { ref: mergedRefs, ...rest });
6
+ return jsx("ol", { ref: ref, ...rest });
17
7
  });
18
8
 
19
9
  export { BreadcrumbsList };
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { jsx } from 'react/jsx-runtime';
3
+ import '@digdir/designsystemet-web';
3
4
  import cl from 'clsx/lite';
4
5
  import { forwardRef } from 'react';
5
6
 
@@ -21,6 +22,6 @@ import { forwardRef } from 'react';
21
22
  * </Breadcrumbs.List>
22
23
  * </Breadcrumbs>
23
24
  */
24
- const Breadcrumbs = forwardRef(({ 'aria-label': ariaLabel = 'Du er her:', className, ...rest }, ref) => (jsx("nav", { "aria-label": ariaLabel, className: cl('ds-breadcrumbs', className), ref: ref, ...rest })));
25
+ const Breadcrumbs = forwardRef(({ className, ...rest }, ref) => (jsx("ds-breadcrumbs", { suppressHydrationWarning: true, class: cl('ds-breadcrumbs', className), ref: ref, ...rest })));
25
26
 
26
27
  export { Breadcrumbs };
@@ -2,7 +2,7 @@
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { Slot, Slottable } from '@radix-ui/react-slot';
4
4
  import cl from 'clsx/lite';
5
- import { forwardRef } from 'react';
5
+ import { forwardRef, version } from 'react';
6
6
  import { Spinner } from '../spinner/spinner.js';
7
7
 
8
8
  /**
@@ -11,12 +11,17 @@ import { Spinner } from '../spinner/spinner.js';
11
11
  * @example
12
12
  * <Button>Click me</Button>
13
13
  */
14
- const Button = forwardRef(function Button({ asChild, className, children, icon = false, loading = false, variant = 'primary', ...rest }, ref) {
14
+ const Button = forwardRef(function Button({ asChild, className, children, icon = false, loading = false, variant = 'primary', popoverTarget, popovertarget, ...rest }, ref) {
15
15
  const Component = asChild ? Slot : 'button';
16
+ const popoverVal = popoverTarget ?? popovertarget;
17
+ const popoverKey = version.startsWith('19')
18
+ ? 'popoverTarget'
19
+ : 'popovertarget';
16
20
  // Fallbacks to undefined to prevent rendering attribute="false"
17
- return (jsxs(Component, { "aria-busy": Boolean(loading) || undefined, "aria-disabled": Boolean(loading) || undefined, className: cl('ds-button', className), "data-icon": icon || undefined, "data-variant": variant, ref: ref,
21
+ return (jsxs(Component, { suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup etc.
22
+ : true, "aria-busy": Boolean(loading) || undefined, "aria-disabled": Boolean(loading) || undefined, className: cl('ds-button', className), "data-icon": icon || undefined, "data-variant": variant, ref: ref,
18
23
  /* don't set type when we use `asChild` */
19
- type: asChild ? undefined : 'button', ...rest, children: [loading === true ? (jsx(Spinner, { "aria-hidden": 'true' })) : (loading // Allow custom loading spinner
24
+ type: asChild ? undefined : 'button', [popoverKey]: popoverVal, ...rest, children: [loading === true ? (jsx(Spinner, { "aria-hidden": 'true' })) : (loading // Allow custom loading spinner
20
25
  ), jsx(Slottable, { children: icon && loading ? null : children })] }));
21
26
  });
22
27
 
@@ -2,9 +2,13 @@
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { Slot } from '@radix-ui/react-slot';
4
4
  import cl from 'clsx/lite';
5
- import { forwardRef, useRef, useEffect } from 'react';
5
+ import { forwardRef, useRef, useId, useEffect } from 'react';
6
6
  import { useMergeRefs } from '../../utilities/hooks/use-merge-refs/use-merge-refs.js';
7
+ import '@digdir/designsystemet-web';
7
8
 
9
+ const ATTR_CLICKDELEGATE = 'data-clickdelegatefor';
10
+ const SELECTOR_LINK = `:is(h1,h2,h3,h4,h5,h6) a`;
11
+ const SELECTOR_SKIP = 'a,button,label,details,dialog,[role="button"],[popover],[contenteditable]';
8
12
  /**
9
13
  * Card component to present content in a structured way.
10
14
  *
@@ -18,22 +22,26 @@ import { useMergeRefs } from '../../utilities/hooks/use-merge-refs/use-merge-ref
18
22
  const Card = forwardRef(function Card({ asChild = false, variant = 'default', className, ...rest }, ref) {
19
23
  const Component = asChild ? Slot : 'div';
20
24
  const cardRef = useRef(null);
25
+ const linkGeneratedId = useId();
21
26
  const mergedRefs = useMergeRefs([cardRef, ref]);
22
27
  // Forward click on card to heading links for better accessibility
23
28
  // https://adrianroselli.com/2020/02/block-links-cards-clickable-regions-etc.html
24
29
  useEffect(() => {
25
30
  const card = cardRef.current;
26
- const handleClick = ({ ctrlKey, metaKey, target }) => {
27
- const link = card?.querySelector(':is(h1,h2,h3,h4,h5,h6) a');
28
- if (!link || link?.contains(target))
29
- return; // Let links handle their own clicks
30
- if (ctrlKey || metaKey)
31
- window.open(link.href, '', 'noreferrer');
31
+ const link = card?.querySelector(SELECTOR_LINK);
32
+ const skip = !link || link.parentElement?.closest(SELECTOR_SKIP); // Using parentElement as link variable will always match a selector
33
+ const id = link?.id;
34
+ if (card?.hasAttribute(ATTR_CLICKDELEGATE) || skip)
35
+ return; // Already delegated or skipped
36
+ link.id = id || linkGeneratedId;
37
+ card?.setAttribute(ATTR_CLICKDELEGATE, link.id);
38
+ return () => {
39
+ if (id && link)
40
+ link.id = id;
32
41
  else
33
- link.click(); // Using link.click instead of window.location.href as this will trigger the browser's handling of rel=, target=, etc.
42
+ link?.removeAttribute('id');
43
+ card?.removeAttribute(ATTR_CLICKDELEGATE);
34
44
  };
35
- card?.addEventListener('click', handleClick);
36
- return () => card?.removeEventListener('click', handleClick);
37
45
  }, []);
38
46
  return (jsx(Component, { className: cl(`ds-card`, className), "data-variant": variant, ref: mergedRefs, ...rest }));
39
47
  });
@@ -8,9 +8,9 @@ import { forwardRef } from 'react';
8
8
  * @example
9
9
  * <Details.Summary>Heading</Details.Summary>
10
10
  */
11
- const DetailsSummary = forwardRef(function DetailsSummary({ className, ...rest }, ref) {
12
- /* Set `className` as `class` so react is happy */
13
- return jsx("u-summary", { ref: ref, class: className, ...rest });
11
+ const DetailsSummary = forwardRef(function DetailsSummary(rest, ref) {
12
+ return (jsx("summary", { suppressHydrationWarning // Since <details> polyfill adds attributes
13
+ : true, ref: ref, ...rest }));
14
14
  });
15
15
 
16
16
  export { DetailsSummary };
@@ -3,7 +3,7 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import cl from 'clsx/lite';
4
4
  import { forwardRef, useRef, useEffect } from 'react';
5
5
  import { useMergeRefs } from '../../utilities/hooks/use-merge-refs/use-merge-refs.js';
6
- import '@u-elements/u-details';
6
+ import '@digdir/designsystemet-web';
7
7
 
8
8
  /**
9
9
  * Details component, contains `Details.Summary` and `Details.Content` components.
@@ -35,7 +35,7 @@ const Details = forwardRef(function Details({ className, open, defaultOpen = fal
35
35
  details?.addEventListener('toggle', handleToggle, true);
36
36
  return () => details?.removeEventListener('toggle', handleToggle, true);
37
37
  }, []);
38
- return (jsx("u-details", { class: cl('ds-details', className), open: (open ?? initialOpen.current) || undefined, "data-variant": variant, ref: mergedRefs, ...rest }));
38
+ return (jsx("details", { className: cl('ds-details', className), open: (open ?? initialOpen.current) || undefined, "data-variant": variant, ref: mergedRefs, ...rest }));
39
39
  });
40
40
 
41
41
  export { Details };
@@ -1,10 +1,8 @@
1
1
  'use client';
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { createContext, useRef } from 'react';
3
+ import { createContext, useState } from 'react';
4
4
 
5
- const Context = createContext({
6
- current: null,
7
- });
5
+ const Context = createContext({});
8
6
  /**
9
7
  * DialogTriggerContext component, used to provide a context for a dialog trigger.
10
8
  *
@@ -16,9 +14,10 @@ const Context = createContext({
16
14
  * </Dialog>
17
15
  * </Dialog.TriggerContext>
18
16
  */
19
- const DialogTriggerContext = ({ children, }) => {
20
- const contextRef = useRef(null);
21
- return jsx(Context.Provider, { value: contextRef, children: children });
17
+ const DialogTriggerContext = (rest) => {
18
+ const [state, setState] = useState({});
19
+ const setContext = (next) => setState({ ...state, ...next });
20
+ return jsx(Context.Provider, { value: { ...state, setContext }, ...rest });
22
21
  };
23
22
  DialogTriggerContext.displayName = 'DialogTriggerContext';
24
23
 
@@ -17,15 +17,10 @@ import { Context } from './dialog-trigger-context.js';
17
17
  * </Dialog.TriggerContext>
18
18
  */
19
19
  const DialogTrigger = forwardRef(function DialogTrigger({ asChild, ...rest }, ref) {
20
- const contextRef = useContext(Context);
20
+ const { id, modal } = useContext(Context);
21
21
  const Component = asChild ? Slot : Button;
22
- const openDialog = () => {
23
- /* check if element has `data-modal`, it it has, use `showModal` */
24
- contextRef.current?.getAttribute('data-modal') === 'true'
25
- ? contextRef.current?.showModal()
26
- : contextRef.current?.show();
27
- };
28
- return (jsx(Component, { "aria-haspopup": 'dialog', onClick: openDialog, ref: ref, ...rest }));
22
+ return (jsx(Component, { suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup
23
+ : true, command: modal ? 'show-modal' : 'show', commandfor: id, ref: ref, ...rest }));
29
24
  });
30
25
 
31
26
  export { DialogTrigger };