@obosbbl/grunnmuren-react 2.0.0-canary.2 → 2.0.0-canary.21
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/README.md +138 -0
- package/dist/index.d.mts +388 -14
- package/dist/index.mjs +459 -93
- package/package.json +4 -2
- package/dist/useClientLayoutEffect-client-2_5nawgR.js +0 -9
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,156 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { I18nProvider, RouterProvider, useContextProps, Provider, Text, CheckboxContext, Checkbox as Checkbox$1, Label as Label$1, CheckboxGroup as CheckboxGroup$1, FieldError, ListBoxItem as ListBoxItem$1, ListBox as ListBox$1, ComboBox, Group, Input, Button as Button$1, Popover, RadioGroup as RadioGroup$1, Radio as Radio$1, Select as Select$1, SelectValue, TextField as TextField$1, TextArea as TextArea$1, NumberField as NumberField$1, useLocale, Breadcrumbs as Breadcrumbs$1, Breadcrumb as Breadcrumb$1, Link } from 'react-aria-components';
|
|
2
3
|
export { Form } from 'react-aria-components';
|
|
3
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { LoadingSpinner, Check,
|
|
7
|
-
import {
|
|
5
|
+
import { useLayoutEffect, createContext, forwardRef, Children, useId, useState, useRef } from 'react';
|
|
6
|
+
import { cx, cva, compose } from 'cva';
|
|
7
|
+
import { ChevronDown, LoadingSpinner, Check, Close, InfoCircle, CheckCircle, Warning, CloseCircle, ChevronRight, ChevronLeft } from '@obosbbl/grunnmuren-icons-react';
|
|
8
|
+
import { mergeRefs } from '@react-aria/utils';
|
|
9
|
+
|
|
10
|
+
function GrunnmurenProvider({ children, locale = 'nb', navigate }) {
|
|
11
|
+
return /*#__PURE__*/ jsx(I18nProvider, {
|
|
12
|
+
locale: locale,
|
|
13
|
+
children: navigate ? /*#__PURE__*/ jsx(RouterProvider, {
|
|
14
|
+
navigate: navigate,
|
|
15
|
+
children: children
|
|
16
|
+
}) : children
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const canUseDOM = ()=>{
|
|
21
|
+
return typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
22
|
+
};
|
|
23
|
+
const useClientLayoutEffect = canUseDOM() ? useLayoutEffect : ()=>{};
|
|
24
|
+
|
|
25
|
+
const HeadingContext = /*#__PURE__*/ createContext({});
|
|
26
|
+
const Heading = (props, ref)=>{
|
|
27
|
+
[props, ref] = useContextProps(props, ref, HeadingContext);
|
|
28
|
+
const { children, level, className, _innerWrapper: innerWrapper, ...restProps } = props;
|
|
29
|
+
const Element = `h${level}`;
|
|
30
|
+
return /*#__PURE__*/ jsx(Element, {
|
|
31
|
+
...restProps,
|
|
32
|
+
className: className,
|
|
33
|
+
"data-slot": "heading",
|
|
34
|
+
children: innerWrapper ? innerWrapper(children) : children
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
const ContentContext = /*#__PURE__*/ createContext({});
|
|
38
|
+
const Content = (props, ref)=>{
|
|
39
|
+
[props, ref] = useContextProps(props, ref, ContentContext);
|
|
40
|
+
const { _outerWrapper: outerWrapper, ...restProps } = props;
|
|
41
|
+
const content = /*#__PURE__*/ jsx("div", {
|
|
42
|
+
...restProps,
|
|
43
|
+
"data-slot": "content"
|
|
44
|
+
});
|
|
45
|
+
return outerWrapper ? outerWrapper(content) : content;
|
|
46
|
+
};
|
|
47
|
+
const Footer = (props)=>/*#__PURE__*/ jsx("div", {
|
|
48
|
+
...props,
|
|
49
|
+
"data-slot": "footer"
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function Accordion(props, ref) {
|
|
53
|
+
const { children, className, ...restProps } = props;
|
|
54
|
+
const childCount = Children.count(children);
|
|
55
|
+
return /*#__PURE__*/ jsx("div", {
|
|
56
|
+
...restProps,
|
|
57
|
+
ref: ref,
|
|
58
|
+
className: cx('rounded-lg bg-white', className),
|
|
59
|
+
children: Children.map(children, (child, index)=>/*#__PURE__*/ jsxs(Fragment, {
|
|
60
|
+
children: [
|
|
61
|
+
child,
|
|
62
|
+
index < childCount - 1 && // Margin is added to enable support for containers with a background color
|
|
63
|
+
/*#__PURE__*/ jsx("hr", {
|
|
64
|
+
className: "mx-2 border-gray-light",
|
|
65
|
+
"aria-hidden": true
|
|
66
|
+
})
|
|
67
|
+
]
|
|
68
|
+
}))
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function AccordionItem(props, ref) {
|
|
72
|
+
const { className, children, defaultOpen = false, isOpen: controlledIsOpen, onOpenChange, ...restProps } = props;
|
|
73
|
+
const contentId = useId();
|
|
74
|
+
const buttonId = useId();
|
|
75
|
+
const isControlled = controlledIsOpen != null;
|
|
76
|
+
// This component has internal state that controls whether it is open or not,
|
|
77
|
+
// regardless if we are controlled or uncontrolled.
|
|
78
|
+
// If we are controlled, we use a layout effect to sync the controlled state
|
|
79
|
+
// with the internal state.
|
|
80
|
+
//
|
|
81
|
+
const [isOpen, setIsOpen] = useState(// If we are controlled, use that open state, otherwise use the uncontrolled
|
|
82
|
+
isControlled ? controlledIsOpen : defaultOpen);
|
|
83
|
+
useClientLayoutEffect(()=>{
|
|
84
|
+
if (isControlled) {
|
|
85
|
+
setIsOpen(controlledIsOpen);
|
|
86
|
+
}
|
|
87
|
+
}, [
|
|
88
|
+
controlledIsOpen,
|
|
89
|
+
isControlled
|
|
90
|
+
]);
|
|
91
|
+
const handleOpenChange = ()=>{
|
|
92
|
+
const newOpenState = !isOpen;
|
|
93
|
+
if (!isControlled) {
|
|
94
|
+
setIsOpen(newOpenState);
|
|
95
|
+
}
|
|
96
|
+
// Always call the change handler, even if we're uncontrolled.
|
|
97
|
+
// Easier to add stuff such as tracking etc.
|
|
98
|
+
if (onOpenChange) {
|
|
99
|
+
onOpenChange(newOpenState);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return /*#__PURE__*/ jsx("div", {
|
|
103
|
+
...restProps,
|
|
104
|
+
className: cx('group relative px-2', className),
|
|
105
|
+
ref: ref,
|
|
106
|
+
"data-open": isOpen,
|
|
107
|
+
children: /*#__PURE__*/ jsx(Provider, {
|
|
108
|
+
values: [
|
|
109
|
+
[
|
|
110
|
+
HeadingContext,
|
|
111
|
+
{
|
|
112
|
+
// Negative margin to strech the button to the entire with of the accordion (to support containers with a background color)
|
|
113
|
+
className: 'font-semibold leading-7 -mx-2',
|
|
114
|
+
// Supply a default level here to make this typecheck ok. Will be overwritten with the consumers set heading level anyways
|
|
115
|
+
level: 3,
|
|
116
|
+
_innerWrapper: (children)=>/*#__PURE__*/ jsxs("button", {
|
|
117
|
+
"aria-controls": contentId,
|
|
118
|
+
"aria-expanded": isOpen,
|
|
119
|
+
// Use outline with offset as focus indicator, this does not cover the left mint border on the expanded content and works with or without a background color on the accordion container
|
|
120
|
+
className: "flex min-h-[44px] w-full items-center justify-between gap-1.5 rounded-lg px-2 py-3.5 text-left focus-visible:outline focus-visible:outline-4 focus-visible:outline-offset-[-6px] focus-visible:outline-black",
|
|
121
|
+
id: buttonId,
|
|
122
|
+
onClick: handleOpenChange,
|
|
123
|
+
children: [
|
|
124
|
+
children,
|
|
125
|
+
/*#__PURE__*/ jsx(ChevronDown, {
|
|
126
|
+
className: cx('transition-transform duration-300 motion-reduce:transition-none', isOpen && 'rotate-180')
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
[
|
|
133
|
+
ContentContext,
|
|
134
|
+
{
|
|
135
|
+
className: // Uses pseudo element for vertical padding, since that doesn't affect the height when the accordion is closed
|
|
136
|
+
'text-sm font-light leading-6 px-3.5 relative overflow-hidden border-mint border-l-[3px] before:relative before:block before:h-1.5 after:relative after:block after:h-1.5',
|
|
137
|
+
role: 'region',
|
|
138
|
+
// @ts-expect-error TODO: remove this expect-error when we're on React 19 https://github.com/facebook/react/issues/17157#issuecomment-2003750544
|
|
139
|
+
inert: isOpen ? undefined : 'true',
|
|
140
|
+
'aria-labelledby': buttonId,
|
|
141
|
+
_outerWrapper: (children)=>/*#__PURE__*/ jsx("div", {
|
|
142
|
+
className: cx('grid transition-all duration-300 after:relative after:block after:h-0 after:transition-all after:duration-300 motion-reduce:transition-none', isOpen ? 'grid-rows-[1fr] after:h-3.5' : 'grid-rows-[0fr] '),
|
|
143
|
+
children: children
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
],
|
|
148
|
+
children: children
|
|
149
|
+
})
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const _Accordion = /*#__PURE__*/ forwardRef(Accordion);
|
|
153
|
+
const _AccordionItem = /*#__PURE__*/ forwardRef(AccordionItem);
|
|
8
154
|
|
|
9
155
|
/**
|
|
10
156
|
* Figma: https://www.figma.com/file/9OvSg0ZXI5E1eQYi7AWiWn/Grunnmuren-2.0-%E2%94%82-Designsystem?node-id=30%3A2574&mode=dev
|
|
@@ -35,8 +181,7 @@ import { u as useClientLayoutEffect } from './useClientLayoutEffect-client-2_5na
|
|
|
35
181
|
* @default false
|
|
36
182
|
*/ isIconOnly: {
|
|
37
183
|
true: 'p-2 [&>svg]:h-7 [&>svg]:w-7',
|
|
38
|
-
false:
|
|
39
|
-
'px-4 py-2 [&>svg]:first-of-type:mr-2.5 [&>svg]:last-of-type:ml-2.5'
|
|
184
|
+
false: 'gap-2.5 px-4 py-2'
|
|
40
185
|
}
|
|
41
186
|
},
|
|
42
187
|
compoundVariants: [
|
|
@@ -89,15 +234,15 @@ import { u as useClientLayoutEffect } from './useClientLayoutEffect-client-2_5na
|
|
|
89
234
|
isIconOnly: false
|
|
90
235
|
}
|
|
91
236
|
});
|
|
92
|
-
function Button(props) {
|
|
93
|
-
const { children, className, color, isIconOnly,
|
|
94
|
-
// TODO: Merge refs when we use RAC
|
|
95
|
-
const buttonRef = useRef(null);
|
|
237
|
+
function Button(props, forwardedRef) {
|
|
238
|
+
const { children, className, color, isIconOnly, isLoading, variant, style, ...restProps } = props;
|
|
96
239
|
const [widthOverride, setWidthOverride] = useState();
|
|
240
|
+
const ownRef = useRef(null);
|
|
241
|
+
const ref = mergeRefs(ownRef, forwardedRef);
|
|
97
242
|
useClientLayoutEffect(()=>{
|
|
98
|
-
if (
|
|
243
|
+
if (isLoading) {
|
|
99
244
|
const requestID = window.requestAnimationFrame(()=>{
|
|
100
|
-
setWidthOverride(
|
|
245
|
+
setWidthOverride(ownRef.current?.getBoundingClientRect()?.width);
|
|
101
246
|
});
|
|
102
247
|
return ()=>{
|
|
103
248
|
setWidthOverride(undefined);
|
|
@@ -105,7 +250,7 @@ function Button(props) {
|
|
|
105
250
|
};
|
|
106
251
|
}
|
|
107
252
|
}, [
|
|
108
|
-
|
|
253
|
+
isLoading,
|
|
109
254
|
children
|
|
110
255
|
]);
|
|
111
256
|
let Component = 'a';
|
|
@@ -116,14 +261,14 @@ function Button(props) {
|
|
|
116
261
|
}
|
|
117
262
|
return(// @ts-expect-error TS doesn't agree here taht restProps is safe to spread, because restProps for anchors aren't type compatible with restProps for buttons, but that should be okay here
|
|
118
263
|
/*#__PURE__*/ jsx(Component, {
|
|
119
|
-
"aria-busy":
|
|
264
|
+
"aria-busy": isLoading ? true : undefined,
|
|
120
265
|
className: buttonVariants({
|
|
121
266
|
className,
|
|
122
267
|
color,
|
|
123
268
|
isIconOnly,
|
|
124
269
|
variant
|
|
125
270
|
}),
|
|
126
|
-
ref:
|
|
271
|
+
ref: ref,
|
|
127
272
|
style: {
|
|
128
273
|
...style,
|
|
129
274
|
width: widthOverride
|
|
@@ -135,14 +280,17 @@ function Button(props) {
|
|
|
135
280
|
}) : children
|
|
136
281
|
}));
|
|
137
282
|
}
|
|
283
|
+
const _Button = /*#__PURE__*/ forwardRef(Button);
|
|
138
284
|
|
|
139
285
|
const formField = cx('group flex flex-col gap-2');
|
|
140
286
|
const formFieldError = cx('w-fit rounded-sm bg-red-light px-2 py-1 text-sm leading-6 text-red');
|
|
141
287
|
const input = cva({
|
|
142
288
|
base: [
|
|
143
|
-
'rounded-md
|
|
289
|
+
'rounded-md py-2.5 text-sm font-normal leading-6 placeholder-[#727070] outline-none ring-1 ring-black',
|
|
144
290
|
// invalid styles
|
|
145
|
-
'group-data-[invalid]:ring-2 group-data-[invalid]:ring-red'
|
|
291
|
+
'group-data-[invalid]:ring-2 group-data-[invalid]:ring-red',
|
|
292
|
+
// Fix invisible ring on safari: https://github.com/tailwindlabs/tailwindcss.com/issues/1135
|
|
293
|
+
'appearance-none'
|
|
146
294
|
],
|
|
147
295
|
variants: {
|
|
148
296
|
// Focus rings. Can either be :focus or :focus-visible based on the needs of the particular component.
|
|
@@ -151,9 +299,8 @@ const input = cva({
|
|
|
151
299
|
visible: 'data-[focus-visible]:ring-2 group-data-[invalid]:data-[focus-visible]:ring'
|
|
152
300
|
},
|
|
153
301
|
isGrouped: {
|
|
154
|
-
false: '',
|
|
155
|
-
|
|
156
|
-
true: 'flex-1 !ring-0 first:pl-0 last:pr-0'
|
|
302
|
+
false: 'px-3',
|
|
303
|
+
true: 'flex-1 !ring-0'
|
|
157
304
|
}
|
|
158
305
|
},
|
|
159
306
|
defaultVariants: {
|
|
@@ -161,7 +308,12 @@ const input = cva({
|
|
|
161
308
|
isGrouped: false
|
|
162
309
|
}
|
|
163
310
|
});
|
|
164
|
-
const inputGroup = cx(
|
|
311
|
+
const inputGroup = cx([
|
|
312
|
+
'inline-flex items-center gap-3 overflow-hidden rounded-md bg-white px-3 text-sm ring-1 ring-black focus-within:ring-2',
|
|
313
|
+
'group-data-[invalid]:ring-2 group-data-[invalid]:ring-red group-data-[invalid]:focus-within:ring',
|
|
314
|
+
// Make sure icons are the correct size
|
|
315
|
+
'[&_svg]:text-base'
|
|
316
|
+
]);
|
|
165
317
|
const dropdown = {
|
|
166
318
|
popover: cx('min-w-[--trigger-width] overflow-auto rounded-md border border-black bg-white shadow data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in data-[exiting]:fade-out'),
|
|
167
319
|
listbox: cx('text-sm outline-none'),
|
|
@@ -193,7 +345,7 @@ const defaultClasses$1 = cx([
|
|
|
193
345
|
// Pulling this out into it's own component. Will probably export it in the future
|
|
194
346
|
// so it can be used in other views, outside of an input of type checkbox, like in table rows.
|
|
195
347
|
function CheckmarkBox() {
|
|
196
|
-
return /*#__PURE__*/ jsx("
|
|
348
|
+
return /*#__PURE__*/ jsx("span", {
|
|
197
349
|
className: cx([
|
|
198
350
|
'relative left-0 grid flex-none place-content-center rounded-sm border-2 border-black text-white',
|
|
199
351
|
// to vertically align the radio we need to calculate the label's height, which is equal to it's font size multiplied by the line height.
|
|
@@ -216,7 +368,7 @@ function CheckmarkBox() {
|
|
|
216
368
|
})
|
|
217
369
|
});
|
|
218
370
|
}
|
|
219
|
-
function Checkbox(props) {
|
|
371
|
+
function Checkbox(props, ref) {
|
|
220
372
|
const { children, className, description, errorMessage, isInvalid: _isInvalid, ...restProps } = props;
|
|
221
373
|
const id = useId();
|
|
222
374
|
const descriptionId = 'desc' + id;
|
|
@@ -233,8 +385,9 @@ function Checkbox(props) {
|
|
|
233
385
|
...restProps,
|
|
234
386
|
className: cx(className, defaultClasses$1),
|
|
235
387
|
isInvalid: isInvalid,
|
|
388
|
+
ref: ref,
|
|
236
389
|
children: [
|
|
237
|
-
/*#__PURE__*/ jsx("
|
|
390
|
+
/*#__PURE__*/ jsx("span", {
|
|
238
391
|
className: "absolute -left-2.5 top-0 z-10 h-11 w-11"
|
|
239
392
|
}),
|
|
240
393
|
/*#__PURE__*/ jsx(CheckmarkBox, {}),
|
|
@@ -255,6 +408,7 @@ function Checkbox(props) {
|
|
|
255
408
|
})
|
|
256
409
|
});
|
|
257
410
|
}
|
|
411
|
+
const _Checkbox = /*#__PURE__*/ forwardRef(Checkbox);
|
|
258
412
|
|
|
259
413
|
function Label(props) {
|
|
260
414
|
const { children, className, ...restProps } = props;
|
|
@@ -265,7 +419,7 @@ function Label(props) {
|
|
|
265
419
|
});
|
|
266
420
|
}
|
|
267
421
|
|
|
268
|
-
function CheckboxGroup(props) {
|
|
422
|
+
function CheckboxGroup(props, ref) {
|
|
269
423
|
const { children, className, description, errorMessage, label, isRequired, isInvalid: _isInvalid, ...restProps } = props;
|
|
270
424
|
const isInvalid = _isInvalid || errorMessage != null;
|
|
271
425
|
return /*#__PURE__*/ jsxs(CheckboxGroup$1, {
|
|
@@ -273,6 +427,7 @@ function CheckboxGroup(props) {
|
|
|
273
427
|
className: cx(className, 'flex flex-col gap-2'),
|
|
274
428
|
isInvalid: isInvalid,
|
|
275
429
|
isRequired: isRequired,
|
|
430
|
+
ref: ref,
|
|
276
431
|
children: [
|
|
277
432
|
label && /*#__PURE__*/ jsx(Label, {
|
|
278
433
|
children: label
|
|
@@ -287,6 +442,7 @@ function CheckboxGroup(props) {
|
|
|
287
442
|
]
|
|
288
443
|
});
|
|
289
444
|
}
|
|
445
|
+
const _CheckboxGroup = /*#__PURE__*/ forwardRef(CheckboxGroup);
|
|
290
446
|
|
|
291
447
|
/**
|
|
292
448
|
* This component handles renders a custom error message (if provided), otherwise it falls back to the browser's native validation.
|
|
@@ -299,7 +455,40 @@ function CheckboxGroup(props) {
|
|
|
299
455
|
});
|
|
300
456
|
}
|
|
301
457
|
|
|
302
|
-
|
|
458
|
+
const ListBox = ({ className, ...restProps })=>/*#__PURE__*/ jsx(ListBox$1, {
|
|
459
|
+
...restProps,
|
|
460
|
+
className: cx(dropdown.listbox, className)
|
|
461
|
+
});
|
|
462
|
+
const ListBoxItem = (props)=>{
|
|
463
|
+
let textValue = props.textValue;
|
|
464
|
+
// When the ListBoxItem child isn't a string we have to set textValue for keyboard completion to work.
|
|
465
|
+
// Since we use a render function (to handle the selected state) the child is never a string.
|
|
466
|
+
// This condition adds back that behaviour
|
|
467
|
+
if (textValue == null && typeof props.children === 'string') {
|
|
468
|
+
textValue = props.children;
|
|
469
|
+
}
|
|
470
|
+
return /*#__PURE__*/ jsx(ListBoxItem$1, {
|
|
471
|
+
...props,
|
|
472
|
+
className: cx(props.className, 'flex cursor-pointer px-6 py-3 leading-6 outline-none data-[focused]:bg-sky-lightest'),
|
|
473
|
+
textValue: textValue,
|
|
474
|
+
children: ({ isSelected })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
475
|
+
children: [
|
|
476
|
+
isSelected && /*#__PURE__*/ jsx(Check, {
|
|
477
|
+
className: "-ml-6 text-base"
|
|
478
|
+
}),
|
|
479
|
+
props.children
|
|
480
|
+
]
|
|
481
|
+
})
|
|
482
|
+
});
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
function InputAddonDivider() {
|
|
486
|
+
return /*#__PURE__*/ jsx("span", {
|
|
487
|
+
className: "block h-6 w-px flex-none bg-black"
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function Combobox(props, ref) {
|
|
303
492
|
const { className, children, description, errorMessage, isLoading, label, isInvalid: _isInvalid, ...restProps } = props;
|
|
304
493
|
const isInvalid = _isInvalid || errorMessage != null;
|
|
305
494
|
return /*#__PURE__*/ jsxs(ComboBox, {
|
|
@@ -319,7 +508,8 @@ function Combobox(props) {
|
|
|
319
508
|
/*#__PURE__*/ jsx(Input, {
|
|
320
509
|
className: input({
|
|
321
510
|
isGrouped: true
|
|
322
|
-
})
|
|
511
|
+
}),
|
|
512
|
+
ref: ref
|
|
323
513
|
}),
|
|
324
514
|
/*#__PURE__*/ jsx(Button$1, {
|
|
325
515
|
children: isLoading ? /*#__PURE__*/ jsx(LoadingSpinner, {
|
|
@@ -341,37 +531,15 @@ function Combobox(props) {
|
|
|
341
531
|
className: cx(dropdown.popover, 'min-w-[calc(var(--trigger-width)+26px)]'),
|
|
342
532
|
crossOffset: -13,
|
|
343
533
|
children: /*#__PURE__*/ jsx(ListBox, {
|
|
344
|
-
className: dropdown.listbox,
|
|
345
534
|
children: children
|
|
346
535
|
})
|
|
347
536
|
})
|
|
348
537
|
]
|
|
349
538
|
});
|
|
350
539
|
}
|
|
351
|
-
const
|
|
352
|
-
let textValue = props.textValue;
|
|
353
|
-
// When the ListBoxItem child isn't a string we have to set textValue for keyboard completion to work.
|
|
354
|
-
// Since we use a render function (to handle the selected state) the child is never a string.
|
|
355
|
-
// This condition adds back that behaviour
|
|
356
|
-
if (textValue == null && typeof props.children === 'string') {
|
|
357
|
-
textValue = props.children;
|
|
358
|
-
}
|
|
359
|
-
return /*#__PURE__*/ jsx(ListBoxItem, {
|
|
360
|
-
...props,
|
|
361
|
-
className: cx(props.className, 'flex cursor-default px-6 py-2 leading-6 outline-none data-[focused]:bg-sky-lightest'),
|
|
362
|
-
textValue: textValue,
|
|
363
|
-
children: ({ isSelected })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
364
|
-
children: [
|
|
365
|
-
isSelected && /*#__PURE__*/ jsx(Check, {
|
|
366
|
-
className: "-ml-6 text-base"
|
|
367
|
-
}),
|
|
368
|
-
props.children
|
|
369
|
-
]
|
|
370
|
-
})
|
|
371
|
-
});
|
|
372
|
-
};
|
|
540
|
+
const _Combobox = /*#__PURE__*/ forwardRef(Combobox);
|
|
373
541
|
|
|
374
|
-
function RadioGroup(props) {
|
|
542
|
+
function RadioGroup(props, ref) {
|
|
375
543
|
const { children, className, description, errorMessage, label, isRequired, isInvalid: _isInvalid, ...restProps } = props;
|
|
376
544
|
const isInvalid = _isInvalid || errorMessage != null;
|
|
377
545
|
return /*#__PURE__*/ jsxs(RadioGroup$1, {
|
|
@@ -379,6 +547,7 @@ function RadioGroup(props) {
|
|
|
379
547
|
className: cx(className, 'flex flex-col gap-2'),
|
|
380
548
|
isInvalid: isInvalid,
|
|
381
549
|
isRequired: isRequired,
|
|
550
|
+
ref: ref,
|
|
382
551
|
children: [
|
|
383
552
|
label && /*#__PURE__*/ jsx(Label, {
|
|
384
553
|
children: label
|
|
@@ -393,6 +562,7 @@ function RadioGroup(props) {
|
|
|
393
562
|
]
|
|
394
563
|
});
|
|
395
564
|
}
|
|
565
|
+
const _RadioGroup = /*#__PURE__*/ forwardRef(RadioGroup);
|
|
396
566
|
|
|
397
567
|
const defaultClasses = cx([
|
|
398
568
|
'relative inline-flex max-w-fit cursor-pointer items-start gap-4 py-2 leading-7',
|
|
@@ -413,13 +583,14 @@ const defaultClasses = cx([
|
|
|
413
583
|
// so we use an inner outline to artifically pad the border
|
|
414
584
|
'data-[invalid]:before:outline-solid data-[invalid]:before:border-red data-[invalid]:data-[selected]:before:!bg-red data-[invalid]:before:outline data-[invalid]:before:outline-[3px] data-[invalid]:before:outline-offset-[-3px] data-[invalid]:before:outline-red'
|
|
415
585
|
]);
|
|
416
|
-
function Radio(props) {
|
|
586
|
+
function Radio(props, ref) {
|
|
417
587
|
const { children, className, description, ...restProps } = props;
|
|
418
588
|
return /*#__PURE__*/ jsxs(Radio$1, {
|
|
419
589
|
...restProps,
|
|
420
590
|
className: cx(className, defaultClasses),
|
|
591
|
+
ref: ref,
|
|
421
592
|
children: [
|
|
422
|
-
/*#__PURE__*/ jsx("
|
|
593
|
+
/*#__PURE__*/ jsx("span", {
|
|
423
594
|
className: "absolute -left-2.5 top-0 z-10 h-11 w-11 "
|
|
424
595
|
}),
|
|
425
596
|
/*#__PURE__*/ jsxs("div", {
|
|
@@ -434,8 +605,9 @@ function Radio(props) {
|
|
|
434
605
|
]
|
|
435
606
|
});
|
|
436
607
|
}
|
|
608
|
+
const _Radio = /*#__PURE__*/ forwardRef(Radio);
|
|
437
609
|
|
|
438
|
-
function Select(props) {
|
|
610
|
+
function Select(props, ref) {
|
|
439
611
|
const { className, children, description, errorMessage, label, isInvalid: _isInvalid, ...restProps } = props;
|
|
440
612
|
const isInvalid = _isInvalid || errorMessage != null;
|
|
441
613
|
return /*#__PURE__*/ jsxs(Select$1, {
|
|
@@ -454,6 +626,8 @@ function Select(props) {
|
|
|
454
626
|
focusModifier: 'visible'
|
|
455
627
|
}), // How to reuse placeholder text?
|
|
456
628
|
'inline-flex cursor-default items-center gap-2'),
|
|
629
|
+
// See https://github.com/adobe/react-spectrum/discussions/4792#discussioncomment-6492305
|
|
630
|
+
ref: ref,
|
|
457
631
|
children: [
|
|
458
632
|
/*#__PURE__*/ jsx(SelectValue, {
|
|
459
633
|
className: "flex-1 truncate text-left data-[placeholder]:text-[#727070]"
|
|
@@ -469,37 +643,15 @@ function Select(props) {
|
|
|
469
643
|
/*#__PURE__*/ jsx(Popover, {
|
|
470
644
|
className: dropdown.popover,
|
|
471
645
|
children: /*#__PURE__*/ jsx(ListBox, {
|
|
472
|
-
className: dropdown.listbox,
|
|
473
646
|
children: children
|
|
474
647
|
})
|
|
475
648
|
})
|
|
476
649
|
]
|
|
477
650
|
});
|
|
478
651
|
}
|
|
479
|
-
const
|
|
480
|
-
let textValue = props.textValue;
|
|
481
|
-
// When the ListBoxItem child isn't a string we have to set textValue for keyboard completion to work.
|
|
482
|
-
// Since we use a render function (to handle the selected state) the child is never a string.
|
|
483
|
-
// This condition adds back that behaviour
|
|
484
|
-
if (textValue == null && typeof props.children === 'string') {
|
|
485
|
-
textValue = props.children;
|
|
486
|
-
}
|
|
487
|
-
return /*#__PURE__*/ jsx(ListBoxItem, {
|
|
488
|
-
...props,
|
|
489
|
-
className: cx(props.className, 'flex cursor-default px-6 py-2 leading-6 outline-none data-[focused]:bg-sky-lightest'),
|
|
490
|
-
textValue: textValue,
|
|
491
|
-
children: ({ isSelected })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
492
|
-
children: [
|
|
493
|
-
isSelected && /*#__PURE__*/ jsx(Check, {
|
|
494
|
-
className: "-ml-6 text-base"
|
|
495
|
-
}),
|
|
496
|
-
props.children
|
|
497
|
-
]
|
|
498
|
-
})
|
|
499
|
-
});
|
|
500
|
-
};
|
|
652
|
+
const _Select = /*#__PURE__*/ forwardRef(Select);
|
|
501
653
|
|
|
502
|
-
function TextArea(props) {
|
|
654
|
+
function TextArea(props, ref) {
|
|
503
655
|
const { className, description, errorMessage, label, isInvalid: _isInvalid, rows, ...restProps } = props;
|
|
504
656
|
const isInvalid = _isInvalid || errorMessage != null;
|
|
505
657
|
return /*#__PURE__*/ jsxs(TextField$1, {
|
|
@@ -515,7 +667,8 @@ function TextArea(props) {
|
|
|
515
667
|
}),
|
|
516
668
|
/*#__PURE__*/ jsx(TextArea$1, {
|
|
517
669
|
className: input(),
|
|
518
|
-
rows: rows
|
|
670
|
+
rows: rows,
|
|
671
|
+
ref: ref
|
|
519
672
|
}),
|
|
520
673
|
/*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
|
|
521
674
|
errorMessage: errorMessage
|
|
@@ -523,8 +676,9 @@ function TextArea(props) {
|
|
|
523
676
|
]
|
|
524
677
|
});
|
|
525
678
|
}
|
|
679
|
+
const _TextArea = /*#__PURE__*/ forwardRef(TextArea);
|
|
526
680
|
|
|
527
|
-
const inputWithAlignment = compose(input, cva({
|
|
681
|
+
const inputWithAlignment$1 = compose(input, cva({
|
|
528
682
|
base: '',
|
|
529
683
|
variants: {
|
|
530
684
|
textAlign: {
|
|
@@ -533,7 +687,7 @@ const inputWithAlignment = compose(input, cva({
|
|
|
533
687
|
}
|
|
534
688
|
}
|
|
535
689
|
}));
|
|
536
|
-
function TextField(props) {
|
|
690
|
+
function TextField(props, ref) {
|
|
537
691
|
const { className, description, errorMessage, label, leftAddon, isInvalid: _isInvalid, textAlign, rightAddon, withAddonDivider, ...restProps } = props;
|
|
538
692
|
const isInvalid = _isInvalid || errorMessage != null;
|
|
539
693
|
return /*#__PURE__*/ jsxs(TextField$1, {
|
|
@@ -551,24 +705,75 @@ function TextField(props) {
|
|
|
551
705
|
className: inputGroup,
|
|
552
706
|
children: [
|
|
553
707
|
leftAddon,
|
|
554
|
-
withAddonDivider && leftAddon && /*#__PURE__*/ jsx(
|
|
555
|
-
|
|
708
|
+
withAddonDivider && leftAddon && /*#__PURE__*/ jsx(InputAddonDivider, {}),
|
|
709
|
+
/*#__PURE__*/ jsx(Input, {
|
|
710
|
+
className: inputWithAlignment$1({
|
|
711
|
+
textAlign,
|
|
712
|
+
isGrouped: true
|
|
713
|
+
}),
|
|
714
|
+
ref: ref
|
|
556
715
|
}),
|
|
716
|
+
withAddonDivider && rightAddon && /*#__PURE__*/ jsx(InputAddonDivider, {}),
|
|
717
|
+
rightAddon
|
|
718
|
+
]
|
|
719
|
+
}) : /*#__PURE__*/ jsx(Input, {
|
|
720
|
+
className: inputWithAlignment$1({
|
|
721
|
+
textAlign
|
|
722
|
+
}),
|
|
723
|
+
ref: ref
|
|
724
|
+
}),
|
|
725
|
+
/*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
|
|
726
|
+
errorMessage: errorMessage
|
|
727
|
+
})
|
|
728
|
+
]
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
const _TextField = /*#__PURE__*/ forwardRef(TextField);
|
|
732
|
+
|
|
733
|
+
// This component is based on a copy of ../textfield/TextField, refactoring is TBD: https://github.com/code-obos/grunnmuren/pull/722#issuecomment-1931478786
|
|
734
|
+
const inputWithAlignment = compose(input, cva({
|
|
735
|
+
base: '',
|
|
736
|
+
variants: {
|
|
737
|
+
textAlign: {
|
|
738
|
+
right: 'text-right',
|
|
739
|
+
left: ''
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}));
|
|
743
|
+
function NumberField(props, ref) {
|
|
744
|
+
const { className, description, errorMessage, label, leftAddon, isInvalid: _isInvalid, textAlign, rightAddon, withAddonDivider, ...restProps } = props;
|
|
745
|
+
const isInvalid = _isInvalid || errorMessage != null;
|
|
746
|
+
return /*#__PURE__*/ jsxs(NumberField$1, {
|
|
747
|
+
...restProps,
|
|
748
|
+
className: cx(className, formField),
|
|
749
|
+
isInvalid: isInvalid,
|
|
750
|
+
children: [
|
|
751
|
+
label && /*#__PURE__*/ jsx(Label, {
|
|
752
|
+
children: label
|
|
753
|
+
}),
|
|
754
|
+
description && /*#__PURE__*/ jsx(Description, {
|
|
755
|
+
children: description
|
|
756
|
+
}),
|
|
757
|
+
leftAddon || rightAddon ? /*#__PURE__*/ jsxs(Group, {
|
|
758
|
+
className: inputGroup,
|
|
759
|
+
children: [
|
|
760
|
+
leftAddon,
|
|
761
|
+
withAddonDivider && leftAddon && /*#__PURE__*/ jsx(InputAddonDivider, {}),
|
|
557
762
|
/*#__PURE__*/ jsx(Input, {
|
|
558
763
|
className: inputWithAlignment({
|
|
559
764
|
textAlign,
|
|
560
765
|
isGrouped: true
|
|
561
|
-
})
|
|
562
|
-
|
|
563
|
-
withAddonDivider && rightAddon && /*#__PURE__*/ jsx(Divider, {
|
|
564
|
-
className: "mr-3"
|
|
766
|
+
}),
|
|
767
|
+
ref: ref
|
|
565
768
|
}),
|
|
769
|
+
withAddonDivider && rightAddon && /*#__PURE__*/ jsx(InputAddonDivider, {}),
|
|
566
770
|
rightAddon
|
|
567
771
|
]
|
|
568
772
|
}) : /*#__PURE__*/ jsx(Input, {
|
|
569
773
|
className: inputWithAlignment({
|
|
570
774
|
textAlign
|
|
571
|
-
})
|
|
775
|
+
}),
|
|
776
|
+
ref: ref
|
|
572
777
|
}),
|
|
573
778
|
/*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
|
|
574
779
|
errorMessage: errorMessage
|
|
@@ -576,10 +781,171 @@ function TextField(props) {
|
|
|
576
781
|
]
|
|
577
782
|
});
|
|
578
783
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
784
|
+
const _NumberField = /*#__PURE__*/ forwardRef(NumberField);
|
|
785
|
+
|
|
786
|
+
// TODO: add new icons
|
|
787
|
+
const iconMap = {
|
|
788
|
+
info: InfoCircle,
|
|
789
|
+
success: CheckCircle,
|
|
790
|
+
warning: Warning,
|
|
791
|
+
danger: CloseCircle
|
|
792
|
+
};
|
|
793
|
+
const alertVariants = cva({
|
|
794
|
+
base: [
|
|
795
|
+
'grid grid-cols-[auto_1fr_auto] items-center gap-2 rounded-md border-2 px-3 py-2',
|
|
796
|
+
// Heading styles:
|
|
797
|
+
'[&_[data-slot="heading"]]:text-base [&_[data-slot="heading"]]:font-medium [&_[data-slot="heading"]]:leading-7',
|
|
798
|
+
// Content styles:
|
|
799
|
+
'[&:has([data-slot="heading"])_[data-slot="content"]]:col-span-full [&_[data-slot="content"]]:text-sm [&_[data-slot="content"]]:leading-6',
|
|
800
|
+
// Footer styles:
|
|
801
|
+
'[&_[data-slot="footer"]]:col-span-full [&_[data-slot="footer"]]:text-xs [&_[data-slot="footer"]]:font-light [&_[data-slot="footer"]]:leading-6'
|
|
802
|
+
],
|
|
803
|
+
variants: {
|
|
804
|
+
/**
|
|
805
|
+
* The variant of the alert
|
|
806
|
+
* @default info
|
|
807
|
+
*/ variant: {
|
|
808
|
+
info: 'border-[#1A7FA7] bg-sky-light',
|
|
809
|
+
success: 'border-[#0F9B6E] bg-mint-light',
|
|
810
|
+
warning: 'border-[#C57C13] bg-[#FFF2DE]',
|
|
811
|
+
danger: 'border-[#C0385D] bg-red-light'
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
defaultVariants: {
|
|
815
|
+
variant: 'info'
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
const translations = {
|
|
819
|
+
close: {
|
|
820
|
+
nb: 'Lukk',
|
|
821
|
+
sv: 'Stäng',
|
|
822
|
+
en: 'Close'
|
|
823
|
+
},
|
|
824
|
+
showMore: {
|
|
825
|
+
nb: 'Les mer',
|
|
826
|
+
sv: 'Läs mer',
|
|
827
|
+
en: 'Read more'
|
|
828
|
+
},
|
|
829
|
+
showLess: {
|
|
830
|
+
nb: 'Vis mindre',
|
|
831
|
+
sv: 'Dölj',
|
|
832
|
+
en: 'Show less'
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
const Alertbox = ({ children, role, className, variant = 'info', isDismissable = false, isDismissed, onDismiss, isExpandable })=>{
|
|
836
|
+
const Icon = iconMap[variant];
|
|
837
|
+
const { locale } = useLocale();
|
|
838
|
+
const id = useId();
|
|
839
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
840
|
+
const isCollapsed = isExpandable && !isExpanded;
|
|
841
|
+
const [isUncontrolledVisible, setIsUncontrolledVisible] = useState(true);
|
|
842
|
+
const isVisible = isDismissed !== undefined ? !isDismissed : isUncontrolledVisible;
|
|
843
|
+
if (!isVisible) return;
|
|
844
|
+
const close = ()=>{
|
|
845
|
+
setIsUncontrolledVisible(false);
|
|
846
|
+
if (onDismiss) onDismiss();
|
|
847
|
+
};
|
|
848
|
+
const isInDevMode = process.env.NODE_ENV !== 'production';
|
|
849
|
+
if (isInDevMode && onDismiss && !isDismissable) {
|
|
850
|
+
console.warn('Passing an `onDismiss` callback without setting the `isDismissable` prop to `true` will not have any effect.');
|
|
851
|
+
}
|
|
852
|
+
if (isInDevMode && !children) {
|
|
853
|
+
console.error('`No children was passed to the <AlertBox/>` component.');
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
const [firstChild, ...restChildren] = Children.toArray(children);
|
|
857
|
+
const lastChild = restChildren.pop();
|
|
858
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
859
|
+
className: alertVariants({
|
|
860
|
+
className,
|
|
861
|
+
variant
|
|
862
|
+
}),
|
|
863
|
+
// The role prop is required to force consumers to consider and choose the appropriate alertbox role.
|
|
864
|
+
// role="none" will not have any effect on a div, so it can be omitted.
|
|
865
|
+
role: role === 'none' ? undefined : role,
|
|
866
|
+
children: [
|
|
867
|
+
/*#__PURE__*/ jsx(Icon, {}),
|
|
868
|
+
firstChild,
|
|
869
|
+
isDismissable && /*#__PURE__*/ jsx("button", {
|
|
870
|
+
className: cx('-m-2 grid h-11 w-11 place-items-center rounded-xl', 'focus:outline-none focus:-outline-offset-8 focus:outline-black'),
|
|
871
|
+
onClick: close,
|
|
872
|
+
"aria-label": translations.close[locale],
|
|
873
|
+
children: /*#__PURE__*/ jsx(Close, {})
|
|
874
|
+
}),
|
|
875
|
+
isExpandable && /*#__PURE__*/ jsxs("button", {
|
|
876
|
+
className: cx('relative col-span-full row-start-2 -my-3 inline-flex max-w-fit cursor-pointer items-center gap-1 py-3 text-sm leading-6', // Focus styles:
|
|
877
|
+
'outline-none after:absolute after:bottom-3 after:left-0 after:right-0 after:h-0 after:bg-transparent after:transition-all after:duration-200', 'focus:after:h-[1px] focus:after:bg-black'),
|
|
878
|
+
onClick: ()=>setIsExpanded((prevState)=>!prevState),
|
|
879
|
+
"aria-expanded": isExpanded,
|
|
880
|
+
"aria-controls": id,
|
|
881
|
+
children: [
|
|
882
|
+
isExpanded ? translations.showLess[locale] : translations.showMore[locale],
|
|
883
|
+
/*#__PURE__*/ jsx(ChevronDown, {
|
|
884
|
+
className: cx('transition-transform duration-150 motion-reduce:transition-none', isExpanded && 'rotate-180')
|
|
885
|
+
})
|
|
886
|
+
]
|
|
887
|
+
}),
|
|
888
|
+
!isCollapsed && restChildren.length > 0 && /*#__PURE__*/ jsx("div", {
|
|
889
|
+
className: "col-span-full grid gap-y-4",
|
|
890
|
+
id: id,
|
|
891
|
+
children: restChildren
|
|
892
|
+
}),
|
|
893
|
+
lastChild
|
|
894
|
+
]
|
|
895
|
+
});
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
function Breadcrumbs(props, ref) {
|
|
899
|
+
const { className, children, ...restProps } = props;
|
|
900
|
+
return /*#__PURE__*/ jsx(Breadcrumbs$1, {
|
|
901
|
+
...restProps,
|
|
902
|
+
className: cx(className, 'flex flex-wrap text-sm leading-6'),
|
|
903
|
+
ref: ref,
|
|
904
|
+
children: children
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
const _Breadcrumbs = /*#__PURE__*/ forwardRef(Breadcrumbs);
|
|
908
|
+
|
|
909
|
+
function Breadcrumb(props, ref) {
|
|
910
|
+
const { className, children, href, ...restProps } = props;
|
|
911
|
+
return /*#__PURE__*/ jsxs(Breadcrumb$1, {
|
|
912
|
+
className: cx(className, 'group flex items-center'),
|
|
913
|
+
...restProps,
|
|
914
|
+
ref: ref,
|
|
915
|
+
children: [
|
|
916
|
+
href ? /*#__PURE__*/ jsx(Link, {
|
|
917
|
+
href: href,
|
|
918
|
+
className: "group-last:no-underline",
|
|
919
|
+
children: children
|
|
920
|
+
}) : children,
|
|
921
|
+
/*#__PURE__*/ jsx(ChevronRight, {
|
|
922
|
+
className: "px-1 group-last:hidden"
|
|
923
|
+
})
|
|
924
|
+
]
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
const _Breadcrumb = /*#__PURE__*/ forwardRef(Breadcrumb);
|
|
928
|
+
|
|
929
|
+
function Backlink(props, ref) {
|
|
930
|
+
const { className, children, href, withUnderline, ...restProps } = props;
|
|
931
|
+
return /*#__PURE__*/ jsxs(Link, {
|
|
932
|
+
className: cx(className, 'group flex max-w-fit items-center gap-3 rounded-md p-2.5 no-underline focus:outline-none focus-visible:ring focus-visible:ring-black'),
|
|
933
|
+
...restProps,
|
|
934
|
+
ref: ref,
|
|
935
|
+
href: href,
|
|
936
|
+
children: [
|
|
937
|
+
/*#__PURE__*/ jsx(ChevronLeft, {
|
|
938
|
+
className: cx('-ml-[0.5em] flex-shrink-0 transition-transform duration-300 group-hover:-translate-x-1')
|
|
939
|
+
}),
|
|
940
|
+
/*#__PURE__*/ jsx("span", {
|
|
941
|
+
children: /*#__PURE__*/ jsx("span", {
|
|
942
|
+
className: cx('border-b-[1px] border-t-[1px] border-transparent transition-colors duration-300', withUnderline ? 'border-b-black' : 'group-hover:border-b-black'),
|
|
943
|
+
children: children
|
|
944
|
+
})
|
|
945
|
+
})
|
|
946
|
+
]
|
|
582
947
|
});
|
|
583
948
|
}
|
|
949
|
+
const _Backlink = /*#__PURE__*/ forwardRef(Backlink);
|
|
584
950
|
|
|
585
|
-
export { Button, Checkbox, CheckboxGroup, Combobox, ComboboxItem, Radio, RadioGroup, Select, SelectItem, TextArea, TextField };
|
|
951
|
+
export { _Accordion as Accordion, _AccordionItem as AccordionItem, Alertbox, _Backlink as Backlink, _Breadcrumb as Breadcrumb, _Breadcrumbs as Breadcrumbs, _Button as Button, _Checkbox as Checkbox, _CheckboxGroup as CheckboxGroup, _Combobox as Combobox, ListBoxItem as ComboboxItem, Content, ContentContext, Footer, GrunnmurenProvider, Heading, HeadingContext, _NumberField as NumberField, _Radio as Radio, _RadioGroup as RadioGroup, _Select as Select, ListBoxItem as SelectItem, _TextArea as TextArea, _TextField as TextField };
|