@obosbbl/grunnmuren-react 2.0.0-canary.1 → 2.0.0-canary.2

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/dist/index.mjs ADDED
@@ -0,0 +1,585 @@
1
+ import { Text, CheckboxContext, Checkbox as Checkbox$1, Label as Label$1, CheckboxGroup as CheckboxGroup$1, FieldError, ComboBox, Group, Input, Button as Button$1, Popover, ListBox, ListBoxItem, RadioGroup as RadioGroup$1, Radio as Radio$1, Select as Select$1, SelectValue, TextField as TextField$1, TextArea as TextArea$1 } from 'react-aria-components';
2
+ export { Form } from 'react-aria-components';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+ import { useRef, useState, useId } from 'react';
5
+ import { cva, cx, compose } from 'cva';
6
+ import { LoadingSpinner, Check, ChevronDown } from '@obosbbl/grunnmuren-icons-react';
7
+ import { u as useClientLayoutEffect } from './useClientLayoutEffect-client-2_5nawgR.js';
8
+
9
+ /**
10
+ * Figma: https://www.figma.com/file/9OvSg0ZXI5E1eQYi7AWiWn/Grunnmuren-2.0-%E2%94%82-Designsystem?node-id=30%3A2574&mode=dev
11
+ */ const buttonVariants = cva({
12
+ base: [
13
+ 'inline-flex min-h-[44px] cursor-pointer items-center justify-center whitespace-nowrap rounded-lg font-medium transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2'
14
+ ],
15
+ variants: {
16
+ /**
17
+ * The variant of the button
18
+ * @default primary
19
+ */ variant: {
20
+ primary: 'no-underline',
21
+ // by using an inset box-shadow to emulate a border instead of an actual border, the button size will be equal regardless of the variant
22
+ secondary: 'no-underline shadow-[inset_0_0_0_2px]',
23
+ tertiary: 'underline hover:no-underline'
24
+ },
25
+ /**
26
+ * Adjusts the color of the button for usage on different backgrounds.
27
+ * @default green
28
+ */ color: {
29
+ green: 'focus-visible:ring-black',
30
+ mint: 'focus-visible:ring-mint focus-visible:ring-offset-green-dark',
31
+ white: 'focus-visible:ring-white focus-visible:ring-offset-blue'
32
+ },
33
+ /**
34
+ * When the button is without text, but with a single icon.
35
+ * @default false
36
+ */ isIconOnly: {
37
+ true: 'p-2 [&>svg]:h-7 [&>svg]:w-7',
38
+ false: // The of-type classes takes care to add spacing when the button is used with icons
39
+ 'px-4 py-2 [&>svg]:first-of-type:mr-2.5 [&>svg]:last-of-type:ml-2.5'
40
+ }
41
+ },
42
+ compoundVariants: [
43
+ {
44
+ color: 'green',
45
+ variant: 'primary',
46
+ // Darken bg by 20% on hover. The color is manually crafted
47
+ className: 'bg-green text-white hover:bg-green-dark active:bg-[#007352]'
48
+ },
49
+ {
50
+ color: 'green',
51
+ variant: 'secondary',
52
+ className: 'bg-white text-black shadow-green hover:bg-green hover:text-white active:bg-green'
53
+ },
54
+ {
55
+ color: 'mint',
56
+ variant: 'primary',
57
+ // Darken bg by 20% on hover. The color is manually crafted
58
+ className: 'active:[#9ddac6] bg-mint text-black hover:bg-[#8dd4bd]'
59
+ },
60
+ {
61
+ color: 'mint',
62
+ variant: 'secondary',
63
+ className: 'text-mint shadow-mint hover:bg-mint hover:text-black'
64
+ },
65
+ {
66
+ color: 'mint',
67
+ variant: 'tertiary',
68
+ className: 'text-mint'
69
+ },
70
+ {
71
+ color: 'white',
72
+ variant: 'primary',
73
+ className: 'bg-white text-black hover:bg-sky active:bg-sky-light'
74
+ },
75
+ {
76
+ color: 'white',
77
+ variant: 'secondary',
78
+ className: 'text-white shadow-white hover:bg-white hover:text-black'
79
+ },
80
+ {
81
+ color: 'white',
82
+ variant: 'tertiary',
83
+ className: 'text-white'
84
+ }
85
+ ],
86
+ defaultVariants: {
87
+ variant: 'primary',
88
+ color: 'green',
89
+ isIconOnly: false
90
+ }
91
+ });
92
+ function Button(props) {
93
+ const { children, className, color, isIconOnly, loading, variant, style, ...restProps } = props;
94
+ // TODO: Merge refs when we use RAC
95
+ const buttonRef = useRef(null);
96
+ const [widthOverride, setWidthOverride] = useState();
97
+ useClientLayoutEffect(()=>{
98
+ if (loading) {
99
+ const requestID = window.requestAnimationFrame(()=>{
100
+ setWidthOverride(buttonRef?.current?.getBoundingClientRect()?.width);
101
+ });
102
+ return ()=>{
103
+ setWidthOverride(undefined);
104
+ cancelAnimationFrame(requestID);
105
+ };
106
+ }
107
+ }, [
108
+ loading,
109
+ children
110
+ ]);
111
+ let Component = 'a';
112
+ if (props.href == null) {
113
+ // If we don't have a href, it's a button, and we add a fallback type button to prevent the button from accidentally submitting when in a form
114
+ Component = 'button';
115
+ restProps.type ??= 'button';
116
+ }
117
+ 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
+ /*#__PURE__*/ jsx(Component, {
119
+ "aria-busy": loading ? true : undefined,
120
+ className: buttonVariants({
121
+ className,
122
+ color,
123
+ isIconOnly,
124
+ variant
125
+ }),
126
+ ref: buttonRef,
127
+ style: {
128
+ ...style,
129
+ width: widthOverride
130
+ },
131
+ ...restProps,
132
+ children: widthOverride ? // remove margin for icon alignment
133
+ /*#__PURE__*/ jsx(LoadingSpinner, {
134
+ className: "!m-0 mx-auto animate-spin"
135
+ }) : children
136
+ }));
137
+ }
138
+
139
+ const formField = cx('group flex flex-col gap-2');
140
+ const formFieldError = cx('w-fit rounded-sm bg-red-light px-2 py-1 text-sm leading-6 text-red');
141
+ const input = cva({
142
+ base: [
143
+ 'rounded-md px-3 py-2.5 text-sm font-normal leading-6 placeholder-[#727070] outline-none ring-1 ring-black',
144
+ // invalid styles
145
+ 'group-data-[invalid]:ring-2 group-data-[invalid]:ring-red'
146
+ ],
147
+ variants: {
148
+ // Focus rings. Can either be :focus or :focus-visible based on the needs of the particular component.
149
+ focusModifier: {
150
+ focus: 'focus:ring-2 group-data-[invalid]:focus:ring',
151
+ visible: 'data-[focus-visible]:ring-2 group-data-[invalid]:data-[focus-visible]:ring'
152
+ },
153
+ isGrouped: {
154
+ false: '',
155
+ //
156
+ true: 'flex-1 !ring-0 first:pl-0 last:pr-0'
157
+ }
158
+ },
159
+ defaultVariants: {
160
+ focusModifier: 'focus',
161
+ isGrouped: false
162
+ }
163
+ });
164
+ const inputGroup = cx('inline-flex items-center overflow-hidden rounded-md px-3 ring-1 ring-black focus-within:ring-2 group-data-[invalid]:ring-2 group-data-[invalid]:ring-red group-data-[invalid]:focus-within:ring');
165
+ const dropdown = {
166
+ 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
+ listbox: cx('text-sm outline-none'),
168
+ chevronIcon: cx('text-base transition-transform duration-150 group-data-[open]:rotate-180 motion-reduce:transition-none')
169
+ };
170
+
171
+ function ErrorMessage(props) {
172
+ const { children, className, ...restProps } = props;
173
+ return /*#__PURE__*/ jsx(Text, {
174
+ ...restProps,
175
+ className: cx(className, formFieldError),
176
+ slot: "errorMessage",
177
+ children: children
178
+ });
179
+ }
180
+
181
+ function Description(props) {
182
+ const { className, ...restProps } = props;
183
+ return /*#__PURE__*/ jsx(Text, {
184
+ ...restProps,
185
+ className: cx(className, 'text-sm font-light leading-6'),
186
+ slot: "description"
187
+ });
188
+ }
189
+
190
+ const defaultClasses$1 = cx([
191
+ 'group relative left-0 inline-flex max-w-fit cursor-pointer items-start gap-4 py-2 leading-7'
192
+ ]);
193
+ // Pulling this out into it's own component. Will probably export it in the future
194
+ // so it can be used in other views, outside of an input of type checkbox, like in table rows.
195
+ function CheckmarkBox() {
196
+ return /*#__PURE__*/ jsx("div", {
197
+ className: cx([
198
+ 'relative left-0 grid flex-none place-content-center rounded-sm border-2 border-black text-white',
199
+ // 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.
200
+ // For the ::before psuedo element the line height of the label is always 1em.
201
+ // When we know the height of the label we use the height of the radio to push it down to align with the label's first line
202
+ // TODO: 1.75 here is the unit less lineheight, altough we use 1.75rem as the line height, so there is a mismatch here. Revisit this when we've worked on typography in v2. Should this be a CSS custom property instead?
203
+ 'mt-[calc((1em_*_1.75_-_24px)_/_2)] h-[24px] w-[24px]',
204
+ // selected
205
+ 'group-data-[selected]:!border-green group-data-[selected]:!bg-green',
206
+ // focus
207
+ 'group-data-[focus-visible]:ring-2 group-data-[focus-visible]:ring-black group-data-[focus-visible]:ring-offset-[9px]',
208
+ // hovered
209
+ 'group-data-[hovered]:border-green group-data-[hovered]:group-data-[invalid]:border-red group-data-[hovered]:bg-green-lightest group-data-[hovered]:group-data-[invalid]:bg-red-light',
210
+ // invalid - The border is 1 px thicker when invalid. We don't actually want to change the border width, as that causes the element's size to change
211
+ // so we use an inner shadow of 1 px instead to pad the actual border
212
+ 'group-data-[invalid]:border-red group-data-[invalid]:group-data-[selected]:shadow-none group-data-[invalid]:shadow-[inset_0_0_0_1px] group-data-[invalid]:shadow-red'
213
+ ]),
214
+ children: /*#__PURE__*/ jsx(Check, {
215
+ className: "h-full w-full opacity-0 group-data-[selected]:opacity-100"
216
+ })
217
+ });
218
+ }
219
+ function Checkbox(props) {
220
+ const { children, className, description, errorMessage, isInvalid: _isInvalid, ...restProps } = props;
221
+ const id = useId();
222
+ const descriptionId = 'desc' + id;
223
+ const errorMessageId = 'error' + id;
224
+ const isInvalid = _isInvalid || errorMessage != null;
225
+ return /*#__PURE__*/ jsx("div", {
226
+ children: /*#__PURE__*/ jsxs(CheckboxContext.Provider, {
227
+ value: {
228
+ 'aria-describedby': description ? descriptionId : undefined,
229
+ 'aria-errormessage': errorMessage ? errorMessageId : undefined
230
+ },
231
+ children: [
232
+ /*#__PURE__*/ jsxs(Checkbox$1, {
233
+ ...restProps,
234
+ className: cx(className, defaultClasses$1),
235
+ isInvalid: isInvalid,
236
+ children: [
237
+ /*#__PURE__*/ jsx("div", {
238
+ className: "absolute -left-2.5 top-0 z-10 h-11 w-11"
239
+ }),
240
+ /*#__PURE__*/ jsx(CheckmarkBox, {}),
241
+ children
242
+ ]
243
+ }),
244
+ description && /*#__PURE__*/ jsx(Description, {
245
+ className: "block",
246
+ id: descriptionId,
247
+ children: description
248
+ }),
249
+ errorMessage && /*#__PURE__*/ jsx(ErrorMessage, {
250
+ className: "mt-2 block",
251
+ id: errorMessageId,
252
+ children: errorMessage
253
+ })
254
+ ]
255
+ })
256
+ });
257
+ }
258
+
259
+ function Label(props) {
260
+ const { children, className, ...restProps } = props;
261
+ return /*#__PURE__*/ jsx(Label$1, {
262
+ className: cx(className, 'font-semibold leading-7'),
263
+ ...restProps,
264
+ children: children
265
+ });
266
+ }
267
+
268
+ function CheckboxGroup(props) {
269
+ const { children, className, description, errorMessage, label, isRequired, isInvalid: _isInvalid, ...restProps } = props;
270
+ const isInvalid = _isInvalid || errorMessage != null;
271
+ return /*#__PURE__*/ jsxs(CheckboxGroup$1, {
272
+ ...restProps,
273
+ className: cx(className, 'flex flex-col gap-2'),
274
+ isInvalid: isInvalid,
275
+ isRequired: isRequired,
276
+ children: [
277
+ label && /*#__PURE__*/ jsx(Label, {
278
+ children: label
279
+ }),
280
+ description && /*#__PURE__*/ jsx(Description, {
281
+ children: description
282
+ }),
283
+ children,
284
+ errorMessage && /*#__PURE__*/ jsx(ErrorMessage, {
285
+ children: errorMessage
286
+ })
287
+ ]
288
+ });
289
+ }
290
+
291
+ /**
292
+ * This component handles renders a custom error message (if provided), otherwise it falls back to the browser's native validation.
293
+ * In other words, this handles controlled and uncontrolled form errors.
294
+ */ function ErrorMessageOrFieldError({ errorMessage }) {
295
+ return errorMessage ? /*#__PURE__*/ jsx(ErrorMessage, {
296
+ children: errorMessage
297
+ }) : /*#__PURE__*/ jsx(FieldError, {
298
+ className: formFieldError
299
+ });
300
+ }
301
+
302
+ function Combobox(props) {
303
+ const { className, children, description, errorMessage, isLoading, label, isInvalid: _isInvalid, ...restProps } = props;
304
+ const isInvalid = _isInvalid || errorMessage != null;
305
+ return /*#__PURE__*/ jsxs(ComboBox, {
306
+ ...restProps,
307
+ className: cx(className, formField),
308
+ isInvalid: isInvalid,
309
+ children: [
310
+ label && /*#__PURE__*/ jsx(Label, {
311
+ children: label
312
+ }),
313
+ description && /*#__PURE__*/ jsx(Description, {
314
+ children: description
315
+ }),
316
+ /*#__PURE__*/ jsxs(Group, {
317
+ className: inputGroup,
318
+ children: [
319
+ /*#__PURE__*/ jsx(Input, {
320
+ className: input({
321
+ isGrouped: true
322
+ })
323
+ }),
324
+ /*#__PURE__*/ jsx(Button$1, {
325
+ children: isLoading ? /*#__PURE__*/ jsx(LoadingSpinner, {
326
+ className: "animate-spin"
327
+ }) : /*#__PURE__*/ jsx(ChevronDown, {
328
+ className: dropdown.chevronIcon
329
+ })
330
+ })
331
+ ]
332
+ }),
333
+ /*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
334
+ errorMessage: errorMessage
335
+ }),
336
+ /*#__PURE__*/ jsx(Popover, {
337
+ // FIXME: The trigger width doesn't include the padding of the group, so for now we have to apply this workaround.
338
+ // Also... the combobox border gets a pixel wider when focused, so we account for that as well when calculating the width
339
+ // and the offset.
340
+ // The input gutter should probably be moved to a theme variable instead of using the hardcoded value as here.
341
+ className: cx(dropdown.popover, 'min-w-[calc(var(--trigger-width)+26px)]'),
342
+ crossOffset: -13,
343
+ children: /*#__PURE__*/ jsx(ListBox, {
344
+ className: dropdown.listbox,
345
+ children: children
346
+ })
347
+ })
348
+ ]
349
+ });
350
+ }
351
+ const ComboboxItem = (props)=>{
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
+ };
373
+
374
+ function RadioGroup(props) {
375
+ const { children, className, description, errorMessage, label, isRequired, isInvalid: _isInvalid, ...restProps } = props;
376
+ const isInvalid = _isInvalid || errorMessage != null;
377
+ return /*#__PURE__*/ jsxs(RadioGroup$1, {
378
+ ...restProps,
379
+ className: cx(className, 'flex flex-col gap-2'),
380
+ isInvalid: isInvalid,
381
+ isRequired: isRequired,
382
+ children: [
383
+ label && /*#__PURE__*/ jsx(Label, {
384
+ children: label
385
+ }),
386
+ description && /*#__PURE__*/ jsx(Description, {
387
+ children: description
388
+ }),
389
+ children,
390
+ errorMessage && /*#__PURE__*/ jsx(ErrorMessage, {
391
+ children: errorMessage
392
+ })
393
+ ]
394
+ });
395
+ }
396
+
397
+ const defaultClasses = cx([
398
+ 'relative inline-flex max-w-fit cursor-pointer items-start gap-4 py-2 leading-7',
399
+ // the radio button itself
400
+ 'before:flex-none before:rounded-full before:border-2 before:border-black',
401
+ // 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.
402
+ // For the ::before psuedo element the line height of the label is always 1em.
403
+ // When we know the height of the label we use the height of the radio to push it down to align with the label's first line
404
+ // TODO: 1.75 here is the unit less lineheight, altough we use 1.75rem as the line height, so there is a mismatch here. Revisit this when we've worked on typography in v2. Should this be a CSS custom property instead?
405
+ 'before:mt-[calc((1em_*_1.75_-_24px)_/_2)] before:h-[24px] before:w-[24px]',
406
+ // selected
407
+ 'data-[selected]:before:border-black data-[selected]:before:bg-green data-[selected]:before:shadow-[inset_0_0_0_4px_rgb(255,255,255)]',
408
+ // hover
409
+ 'data-[hovered]:before:border-green data-[hovered]:before:bg-green-lightest data-[hovered]:data-[invalid]:before:bg-red-light',
410
+ // focus
411
+ 'data-[focus-visible]:before:ring data-[focus-visible]:before:ring-black data-[focus-visible]:before:ring-offset-[9px]',
412
+ // invalid - The border is 1 px thicker when invalid. We don't actually want to change the border width, as that causes the element's size to change
413
+ // so we use an inner outline to artifically pad the border
414
+ '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
+ ]);
416
+ function Radio(props) {
417
+ const { children, className, description, ...restProps } = props;
418
+ return /*#__PURE__*/ jsxs(Radio$1, {
419
+ ...restProps,
420
+ className: cx(className, defaultClasses),
421
+ children: [
422
+ /*#__PURE__*/ jsx("div", {
423
+ className: "absolute -left-2.5 top-0 z-10 h-11 w-11 "
424
+ }),
425
+ /*#__PURE__*/ jsxs("div", {
426
+ children: [
427
+ children,
428
+ description && /*#__PURE__*/ jsx(Description, {
429
+ className: "mt-2 block",
430
+ children: description
431
+ })
432
+ ]
433
+ })
434
+ ]
435
+ });
436
+ }
437
+
438
+ function Select(props) {
439
+ const { className, children, description, errorMessage, label, isInvalid: _isInvalid, ...restProps } = props;
440
+ const isInvalid = _isInvalid || errorMessage != null;
441
+ return /*#__PURE__*/ jsxs(Select$1, {
442
+ ...restProps,
443
+ className: cx(className, formField),
444
+ isInvalid: isInvalid,
445
+ children: [
446
+ label && /*#__PURE__*/ jsx(Label, {
447
+ children: label
448
+ }),
449
+ description && /*#__PURE__*/ jsx(Description, {
450
+ children: description
451
+ }),
452
+ /*#__PURE__*/ jsxs(Button$1, {
453
+ className: cx(input({
454
+ focusModifier: 'visible'
455
+ }), // How to reuse placeholder text?
456
+ 'inline-flex cursor-default items-center gap-2'),
457
+ children: [
458
+ /*#__PURE__*/ jsx(SelectValue, {
459
+ className: "flex-1 truncate text-left data-[placeholder]:text-[#727070]"
460
+ }),
461
+ /*#__PURE__*/ jsx(ChevronDown, {
462
+ className: dropdown.chevronIcon
463
+ })
464
+ ]
465
+ }),
466
+ /*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
467
+ errorMessage: errorMessage
468
+ }),
469
+ /*#__PURE__*/ jsx(Popover, {
470
+ className: dropdown.popover,
471
+ children: /*#__PURE__*/ jsx(ListBox, {
472
+ className: dropdown.listbox,
473
+ children: children
474
+ })
475
+ })
476
+ ]
477
+ });
478
+ }
479
+ const SelectItem = (props)=>{
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
+ };
501
+
502
+ function TextArea(props) {
503
+ const { className, description, errorMessage, label, isInvalid: _isInvalid, rows, ...restProps } = props;
504
+ const isInvalid = _isInvalid || errorMessage != null;
505
+ return /*#__PURE__*/ jsxs(TextField$1, {
506
+ ...restProps,
507
+ className: cx(className, formField),
508
+ isInvalid: isInvalid,
509
+ children: [
510
+ label && /*#__PURE__*/ jsx(Label, {
511
+ children: label
512
+ }),
513
+ description && /*#__PURE__*/ jsx(Description, {
514
+ children: description
515
+ }),
516
+ /*#__PURE__*/ jsx(TextArea$1, {
517
+ className: input(),
518
+ rows: rows
519
+ }),
520
+ /*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
521
+ errorMessage: errorMessage
522
+ })
523
+ ]
524
+ });
525
+ }
526
+
527
+ const inputWithAlignment = compose(input, cva({
528
+ base: '',
529
+ variants: {
530
+ textAlign: {
531
+ right: 'text-right',
532
+ left: ''
533
+ }
534
+ }
535
+ }));
536
+ function TextField(props) {
537
+ const { className, description, errorMessage, label, leftAddon, isInvalid: _isInvalid, textAlign, rightAddon, withAddonDivider, ...restProps } = props;
538
+ const isInvalid = _isInvalid || errorMessage != null;
539
+ return /*#__PURE__*/ jsxs(TextField$1, {
540
+ ...restProps,
541
+ className: cx(className, formField),
542
+ isInvalid: isInvalid,
543
+ children: [
544
+ label && /*#__PURE__*/ jsx(Label, {
545
+ children: label
546
+ }),
547
+ description && /*#__PURE__*/ jsx(Description, {
548
+ children: description
549
+ }),
550
+ leftAddon || rightAddon ? /*#__PURE__*/ jsxs(Group, {
551
+ className: inputGroup,
552
+ children: [
553
+ leftAddon,
554
+ withAddonDivider && leftAddon && /*#__PURE__*/ jsx(Divider, {
555
+ className: "ml-3"
556
+ }),
557
+ /*#__PURE__*/ jsx(Input, {
558
+ className: inputWithAlignment({
559
+ textAlign,
560
+ isGrouped: true
561
+ })
562
+ }),
563
+ withAddonDivider && rightAddon && /*#__PURE__*/ jsx(Divider, {
564
+ className: "mr-3"
565
+ }),
566
+ rightAddon
567
+ ]
568
+ }) : /*#__PURE__*/ jsx(Input, {
569
+ className: inputWithAlignment({
570
+ textAlign
571
+ })
572
+ }),
573
+ /*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
574
+ errorMessage: errorMessage
575
+ })
576
+ ]
577
+ });
578
+ }
579
+ function Divider({ className }) {
580
+ return /*#__PURE__*/ jsx("span", {
581
+ className: cx(className, 'block h-6 w-px flex-none bg-black')
582
+ });
583
+ }
584
+
585
+ export { Button, Checkbox, CheckboxGroup, Combobox, ComboboxItem, Radio, RadioGroup, Select, SelectItem, TextArea, TextField };
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ import { useLayoutEffect } from 'react';
3
+
4
+ const canUseDOM = ()=>{
5
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
6
+ };
7
+ const useClientLayoutEffect = canUseDOM() ? useLayoutEffect : ()=>{};
8
+
9
+ export { useClientLayoutEffect as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obosbbl/grunnmuren-react",
3
- "version": "2.0.0-canary.1",
3
+ "version": "2.0.0-canary.2",
4
4
  "description": "Grunnmuren components in React",
5
5
  "repository": {
6
6
  "url": "https://github.com/code-obos/grunnmuren"
@@ -9,54 +9,23 @@
9
9
  "sideEffects": false,
10
10
  "type": "module",
11
11
  "exports": {
12
- "./button": {
13
- "types": "./dist/button/Button.d.ts",
14
- "default": "./dist/button/Button.mjs"
15
- },
16
- "./checkbox": {
17
- "types": "./dist/checkbox/index.d.ts",
18
- "default": "./dist/checkbox/index.mjs"
19
- },
20
- "./label": {
21
- "types": "./dist/label/index.d.ts",
22
- "default": "./dist/label/index.mjs"
23
- },
24
- "./radiogroup": {
25
- "types": "./dist/radiogroup/index.d.ts",
26
- "default": "./dist/radiogroup/index.mjs"
27
- },
28
- "./textfield": {
29
- "types": "./dist/textfield/index.d.ts",
30
- "default": "./dist/textfield/index.mjs"
12
+ ".": {
13
+ "types": "./dist/index.d.mts",
14
+ "default": "./dist/index.mjs"
31
15
  }
32
16
  },
33
17
  "files": [
34
18
  "dist"
35
19
  ],
36
20
  "dependencies": {
37
- "@obosbbl/grunnmuren-icons-react": "^2.0.0-canary.0",
21
+ "@obosbbl/grunnmuren-icons-react": "^2.0.0-canary.1",
38
22
  "cva": "1.0.0-beta.1",
39
- "react-aria-components": "1.0.0-rc.0"
23
+ "react-aria-components": "^1.0.0"
40
24
  },
41
25
  "peerDependencies": {
42
26
  "react": "^18"
43
27
  },
44
- "unbuild": {
45
- "entries": [
46
- "./src/button/Button.tsx",
47
- "./src/checkbox/index.ts",
48
- "./src/label/index.ts",
49
- "./src/radiogroup/index.ts",
50
- "./src/textfield/index.ts"
51
- ],
52
- "declaration": true,
53
- "rollup": {
54
- "esbuild": {
55
- "jsx": "automatic"
56
- }
57
- }
58
- },
59
28
  "scripts": {
60
- "build": "unbuild"
29
+ "build": "bunchee"
61
30
  }
62
31
  }