@obosbbl/grunnmuren-react 2.0.0-canary.3 → 2.0.0-canary.5

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 CHANGED
@@ -50,6 +50,42 @@ export default function RootLayout({
50
50
 
51
51
  See the [RAC internationalization docs](https://react-spectrum.adobe.com/react-aria/internationalization.html) for more information.
52
52
 
53
+ ### Optimize bundle size by removing unused locales
54
+
55
+ React Aria Components has built in support for over 30 languages, most of which will be unused in your application. To optimize your applications bundle size, it is recommended to use React Aria's build plugin to remove all the unused locales. Here is a quick example for Next.js:
56
+
57
+ #### Install
58
+
59
+ ```sh
60
+ # npm
61
+ npm install @react-aria/optimize-locales-plugin --save-dev
62
+
63
+ # pnpm
64
+ pnpm add -D @react-aria/optimize-locales-plugin
65
+ ```
66
+
67
+ #### Configuration
68
+
69
+ ```js
70
+ // next.config.js
71
+ const optimizeLocales = require('@react-aria/optimize-locales-plugin');
72
+
73
+ module.exports = {
74
+ webpack(config) {
75
+ config.plugins.push(
76
+ optimizeLocales.webpack({
77
+ // If you have a multitenant app, include both Norwegian and Swedish
78
+ // If your app only serves one language, adjust accordingly
79
+ locales: ['nb-NO', 'sv-SE'],
80
+ }),
81
+ );
82
+ return config;
83
+ },
84
+ };
85
+ ```
86
+
87
+ The plugin works with several different bundlers. See [React Aria's bundle size optimization docs](https://react-spectrum.adobe.com/react-aria/internationalization.html#optimizing-bundle-size) for more information.
88
+
53
89
  ## Usage
54
90
 
55
91
  Before you start using the components you need to configure the [Tailwind preset](../tailwind/). Remember to add this package to the content scan.
@@ -0,0 +1,144 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { useLayoutEffect, forwardRef, useState, useRef } from 'react';
4
+ import { cva } from 'cva';
5
+ import { LoadingSpinner } from '@obosbbl/grunnmuren-icons-react';
6
+ import { mergeRefs } from '@react-aria/utils';
7
+
8
+ const canUseDOM = ()=>{
9
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
10
+ };
11
+ const useClientLayoutEffect = canUseDOM() ? useLayoutEffect : ()=>{};
12
+
13
+ /**
14
+ * Figma: https://www.figma.com/file/9OvSg0ZXI5E1eQYi7AWiWn/Grunnmuren-2.0-%E2%94%82-Designsystem?node-id=30%3A2574&mode=dev
15
+ */ const buttonVariants = cva({
16
+ base: [
17
+ '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'
18
+ ],
19
+ variants: {
20
+ /**
21
+ * The variant of the button
22
+ * @default primary
23
+ */ variant: {
24
+ primary: 'no-underline',
25
+ // 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
26
+ secondary: 'no-underline shadow-[inset_0_0_0_2px]',
27
+ tertiary: 'underline hover:no-underline'
28
+ },
29
+ /**
30
+ * Adjusts the color of the button for usage on different backgrounds.
31
+ * @default green
32
+ */ color: {
33
+ green: 'focus-visible:ring-black',
34
+ mint: 'focus-visible:ring-mint focus-visible:ring-offset-green-dark',
35
+ white: 'focus-visible:ring-white focus-visible:ring-offset-blue'
36
+ },
37
+ /**
38
+ * When the button is without text, but with a single icon.
39
+ * @default false
40
+ */ isIconOnly: {
41
+ true: 'p-2 [&>svg]:h-7 [&>svg]:w-7',
42
+ false: // The of-type classes takes care to add spacing when the button is used with icons
43
+ 'px-4 py-2 [&>svg]:first-of-type:mr-2.5 [&>svg]:last-of-type:ml-2.5'
44
+ }
45
+ },
46
+ compoundVariants: [
47
+ {
48
+ color: 'green',
49
+ variant: 'primary',
50
+ // Darken bg by 20% on hover. The color is manually crafted
51
+ className: 'bg-green text-white hover:bg-green-dark active:bg-[#007352]'
52
+ },
53
+ {
54
+ color: 'green',
55
+ variant: 'secondary',
56
+ className: 'bg-white text-black shadow-green hover:bg-green hover:text-white active:bg-green'
57
+ },
58
+ {
59
+ color: 'mint',
60
+ variant: 'primary',
61
+ // Darken bg by 20% on hover. The color is manually crafted
62
+ className: 'active:[#9ddac6] bg-mint text-black hover:bg-[#8dd4bd]'
63
+ },
64
+ {
65
+ color: 'mint',
66
+ variant: 'secondary',
67
+ className: 'text-mint shadow-mint hover:bg-mint hover:text-black'
68
+ },
69
+ {
70
+ color: 'mint',
71
+ variant: 'tertiary',
72
+ className: 'text-mint'
73
+ },
74
+ {
75
+ color: 'white',
76
+ variant: 'primary',
77
+ className: 'bg-white text-black hover:bg-sky active:bg-sky-light'
78
+ },
79
+ {
80
+ color: 'white',
81
+ variant: 'secondary',
82
+ className: 'text-white shadow-white hover:bg-white hover:text-black'
83
+ },
84
+ {
85
+ color: 'white',
86
+ variant: 'tertiary',
87
+ className: 'text-white'
88
+ }
89
+ ],
90
+ defaultVariants: {
91
+ variant: 'primary',
92
+ color: 'green',
93
+ isIconOnly: false
94
+ }
95
+ });
96
+ function Button(props, forwardedRef) {
97
+ const { children, className, color, isIconOnly, isLoading, variant, style, ...restProps } = props;
98
+ const [widthOverride, setWidthOverride] = useState();
99
+ const ownRef = useRef(null);
100
+ const ref = mergeRefs(ownRef, forwardedRef);
101
+ useClientLayoutEffect(()=>{
102
+ if (isLoading) {
103
+ const requestID = window.requestAnimationFrame(()=>{
104
+ setWidthOverride(ownRef.current?.getBoundingClientRect()?.width);
105
+ });
106
+ return ()=>{
107
+ setWidthOverride(undefined);
108
+ cancelAnimationFrame(requestID);
109
+ };
110
+ }
111
+ }, [
112
+ isLoading,
113
+ children
114
+ ]);
115
+ let Component = 'a';
116
+ if (props.href == null) {
117
+ // 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
118
+ Component = 'button';
119
+ restProps.type ??= 'button';
120
+ }
121
+ 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
122
+ /*#__PURE__*/ jsx(Component, {
123
+ "aria-busy": isLoading ? true : undefined,
124
+ className: buttonVariants({
125
+ className,
126
+ color,
127
+ isIconOnly,
128
+ variant
129
+ }),
130
+ ref: ref,
131
+ style: {
132
+ ...style,
133
+ width: widthOverride
134
+ },
135
+ ...restProps,
136
+ children: widthOverride ? // remove margin for icon alignment
137
+ /*#__PURE__*/ jsx(LoadingSpinner, {
138
+ className: "!m-0 mx-auto animate-spin"
139
+ }) : children
140
+ }));
141
+ }
142
+ const _Button = /*#__PURE__*/ forwardRef(Button);
143
+
144
+ export { _Button as _ };
package/dist/index.d.mts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { CheckboxProps as CheckboxProps$1, CheckboxGroupProps as CheckboxGroupProps$1, ComboBoxProps, ListBoxItemProps, RadioGroupProps as RadioGroupProps$1, RadioProps as RadioProps$1, SelectProps as SelectProps$1, TextFieldProps as TextFieldProps$1 } from 'react-aria-components';
2
2
  export { ListBoxItemProps as ComboboxItemProps, Form, I18nProvider, ListBoxItemProps as SelectItemProps } from 'react-aria-components';
3
- import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import * as react from 'react';
4
4
  import { VariantProps } from 'cva';
5
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
6
 
6
7
  /**
7
8
  * Figma: https://www.figma.com/file/9OvSg0ZXI5E1eQYi7AWiWn/Grunnmuren-2.0-%E2%94%82-Designsystem?node-id=30%3A2574&mode=dev
@@ -80,7 +81,7 @@ type ButtonProps = VariantProps<typeof buttonVariants> & {
80
81
  isLoading?: boolean;
81
82
  style?: React.CSSProperties;
82
83
  } & ButtonOrLinkProps;
83
- declare function Button(props: ButtonProps): react_jsx_runtime.JSX.Element;
84
+ declare const _Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
84
85
 
85
86
  type CheckboxProps = {
86
87
  children: React.ReactNode;
@@ -93,7 +94,7 @@ type CheckboxProps = {
93
94
  /** Additional style properties for the element. */
94
95
  style?: React.CSSProperties;
95
96
  } & Omit<CheckboxProps$1, 'isDisabled' | 'style' | 'children' | 'isIndeterminate' | 'isReadOnly'>;
96
- declare function Checkbox(props: CheckboxProps): react_jsx_runtime.JSX.Element;
97
+ declare const _Checkbox: react.ForwardRefExoticComponent<Omit<CheckboxProps, "ref"> & react.RefAttributes<HTMLLabelElement>>;
97
98
 
98
99
  type CheckboxGroupProps = {
99
100
  children: React.ReactNode;
@@ -108,7 +109,7 @@ type CheckboxGroupProps = {
108
109
  /** Additional style properties for the element. */
109
110
  style?: React.CSSProperties;
110
111
  } & Omit<CheckboxGroupProps$1, 'className' | 'isReadOnly' | 'isDisabled' | 'children' | 'style' | 'orientation'>;
111
- declare function CheckboxGroup(props: CheckboxGroupProps): react_jsx_runtime.JSX.Element;
112
+ declare const _CheckboxGroup: react.ForwardRefExoticComponent<Omit<CheckboxGroupProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
112
113
 
113
114
  type ComboboxProps<T extends object> = {
114
115
  children: React.ReactNode;
@@ -130,8 +131,8 @@ type ComboboxProps<T extends object> = {
130
131
  /** Additional style properties for the element. */
131
132
  style?: React.CSSProperties;
132
133
  } & Omit<ComboBoxProps<T>, 'className' | 'isReadOnly' | 'isDisabled' | 'children' | 'style'>;
133
- declare function Combobox<T extends object>(props: ComboboxProps<T>): react_jsx_runtime.JSX.Element;
134
134
  declare const ComboboxItem: (props: ListBoxItemProps) => react_jsx_runtime.JSX.Element;
135
+ declare const _Combobox: react.ForwardRefExoticComponent<Omit<ComboboxProps<object>, "ref"> & react.RefAttributes<HTMLInputElement>>;
135
136
 
136
137
  type RadioGroupProps = {
137
138
  children: React.ReactNode;
@@ -146,7 +147,7 @@ type RadioGroupProps = {
146
147
  /** Additional style properties for the element. */
147
148
  style?: React.CSSProperties;
148
149
  } & Omit<RadioGroupProps$1, 'className' | 'isReadOnly' | 'isDisabled' | 'children' | 'style' | 'orientation'>;
149
- declare function RadioGroup(props: RadioGroupProps): react_jsx_runtime.JSX.Element;
150
+ declare const _RadioGroup: react.ForwardRefExoticComponent<Omit<RadioGroupProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
150
151
 
151
152
  type RadioProps = {
152
153
  children: React.ReactNode;
@@ -157,7 +158,7 @@ type RadioProps = {
157
158
  /** Additional style properties for the element. */
158
159
  style?: React.CSSProperties;
159
160
  } & Omit<RadioProps$1, 'isDisabled' | 'children' | 'style'>;
160
- declare function Radio(props: RadioProps): react_jsx_runtime.JSX.Element;
161
+ declare const _Radio: react.ForwardRefExoticComponent<Omit<RadioProps, "ref"> & react.RefAttributes<HTMLLabelElement>>;
161
162
 
162
163
  type SelectProps<T extends object> = {
163
164
  children: React.ReactNode;
@@ -174,8 +175,8 @@ type SelectProps<T extends object> = {
174
175
  /** Additional style properties for the element. */
175
176
  style?: React.CSSProperties;
176
177
  } & Omit<SelectProps$1<T>, 'className' | 'isReadOnly' | 'isDisabled' | 'children' | 'style'>;
177
- declare function Select<T extends object>(props: SelectProps<T>): react_jsx_runtime.JSX.Element;
178
178
  declare const SelectItem: (props: ListBoxItemProps) => react_jsx_runtime.JSX.Element;
179
+ declare const _Select: react.ForwardRefExoticComponent<Omit<SelectProps<object>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
179
180
 
180
181
  type TextAreaProps = {
181
182
  /** Additional CSS className for the element. */
@@ -196,7 +197,7 @@ type TextAreaProps = {
196
197
  */
197
198
  rows?: number;
198
199
  } & Omit<TextFieldProps$1, 'className' | 'isReadOnly' | 'isDisabled' | 'children' | 'style'>;
199
- declare function TextArea(props: TextAreaProps): react_jsx_runtime.JSX.Element;
200
+ declare const _TextArea: react.ForwardRefExoticComponent<Omit<TextAreaProps, "ref"> & react.RefAttributes<HTMLTextAreaElement>>;
200
201
 
201
202
  type TextFieldProps = {
202
203
  /** Additional CSS className for the element. */
@@ -223,6 +224,6 @@ type TextFieldProps = {
223
224
  /** Add a divider between the left/right addons and the input */
224
225
  withAddonDivider?: boolean;
225
226
  } & Omit<TextFieldProps$1, 'className' | 'isReadOnly' | 'isDisabled' | 'children' | 'style'>;
226
- declare function TextField(props: TextFieldProps): react_jsx_runtime.JSX.Element;
227
+ declare const _TextField: react.ForwardRefExoticComponent<Omit<TextFieldProps, "ref"> & react.RefAttributes<HTMLInputElement>>;
227
228
 
228
- export { Button, type ButtonProps, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Combobox, ComboboxItem, type ComboboxProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Select, SelectItem, type SelectProps, TextArea, type TextAreaProps, TextField, type TextFieldProps };
229
+ export { _Button as Button, type ButtonProps, _Checkbox as Checkbox, _CheckboxGroup as CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, _Combobox as Combobox, ComboboxItem, type ComboboxProps, _Radio as Radio, _RadioGroup as RadioGroup, type RadioGroupProps, type RadioProps, _Select as Select, SelectItem, type SelectProps, _TextArea as TextArea, type TextAreaProps, _TextField as TextField, type TextFieldProps };
package/dist/index.mjs CHANGED
@@ -1,140 +1,10 @@
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';
1
+ import { Text, CheckboxContext, Checkbox as Checkbox$1, Label as Label$1, CheckboxGroup as CheckboxGroup$1, FieldError, ListBoxItem, ComboBox, Group, Input, Button, Popover, ListBox, 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
2
  export { Form, I18nProvider } from 'react-aria-components';
3
+ export { _ as Button } from './Button-client-wuoyidfi.js';
3
4
  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, isLoading, 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 (isLoading) {
99
- const requestID = window.requestAnimationFrame(()=>{
100
- setWidthOverride(buttonRef?.current?.getBoundingClientRect()?.width);
101
- });
102
- return ()=>{
103
- setWidthOverride(undefined);
104
- cancelAnimationFrame(requestID);
105
- };
106
- }
107
- }, [
108
- isLoading,
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": isLoading ? 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
- }
5
+ import { forwardRef, useId } from 'react';
6
+ import { cx, cva, compose } from 'cva';
7
+ import { Check, LoadingSpinner, ChevronDown } from '@obosbbl/grunnmuren-icons-react';
138
8
 
139
9
  const formField = cx('group flex flex-col gap-2');
140
10
  const formFieldError = cx('w-fit rounded-sm bg-red-light px-2 py-1 text-sm leading-6 text-red');
@@ -216,7 +86,7 @@ function CheckmarkBox() {
216
86
  })
217
87
  });
218
88
  }
219
- function Checkbox(props) {
89
+ function Checkbox(props, ref) {
220
90
  const { children, className, description, errorMessage, isInvalid: _isInvalid, ...restProps } = props;
221
91
  const id = useId();
222
92
  const descriptionId = 'desc' + id;
@@ -233,6 +103,7 @@ function Checkbox(props) {
233
103
  ...restProps,
234
104
  className: cx(className, defaultClasses$1),
235
105
  isInvalid: isInvalid,
106
+ ref: ref,
236
107
  children: [
237
108
  /*#__PURE__*/ jsx("div", {
238
109
  className: "absolute -left-2.5 top-0 z-10 h-11 w-11"
@@ -255,6 +126,7 @@ function Checkbox(props) {
255
126
  })
256
127
  });
257
128
  }
129
+ const _Checkbox = /*#__PURE__*/ forwardRef(Checkbox);
258
130
 
259
131
  function Label(props) {
260
132
  const { children, className, ...restProps } = props;
@@ -265,7 +137,7 @@ function Label(props) {
265
137
  });
266
138
  }
267
139
 
268
- function CheckboxGroup(props) {
140
+ function CheckboxGroup(props, ref) {
269
141
  const { children, className, description, errorMessage, label, isRequired, isInvalid: _isInvalid, ...restProps } = props;
270
142
  const isInvalid = _isInvalid || errorMessage != null;
271
143
  return /*#__PURE__*/ jsxs(CheckboxGroup$1, {
@@ -273,6 +145,7 @@ function CheckboxGroup(props) {
273
145
  className: cx(className, 'flex flex-col gap-2'),
274
146
  isInvalid: isInvalid,
275
147
  isRequired: isRequired,
148
+ ref: ref,
276
149
  children: [
277
150
  label && /*#__PURE__*/ jsx(Label, {
278
151
  children: label
@@ -287,6 +160,7 @@ function CheckboxGroup(props) {
287
160
  ]
288
161
  });
289
162
  }
163
+ const _CheckboxGroup = /*#__PURE__*/ forwardRef(CheckboxGroup);
290
164
 
291
165
  /**
292
166
  * This component handles renders a custom error message (if provided), otherwise it falls back to the browser's native validation.
@@ -299,7 +173,7 @@ function CheckboxGroup(props) {
299
173
  });
300
174
  }
301
175
 
302
- function Combobox(props) {
176
+ function Combobox(props, ref) {
303
177
  const { className, children, description, errorMessage, isLoading, label, isInvalid: _isInvalid, ...restProps } = props;
304
178
  const isInvalid = _isInvalid || errorMessage != null;
305
179
  return /*#__PURE__*/ jsxs(ComboBox, {
@@ -319,9 +193,10 @@ function Combobox(props) {
319
193
  /*#__PURE__*/ jsx(Input, {
320
194
  className: input({
321
195
  isGrouped: true
322
- })
196
+ }),
197
+ ref: ref
323
198
  }),
324
- /*#__PURE__*/ jsx(Button$1, {
199
+ /*#__PURE__*/ jsx(Button, {
325
200
  children: isLoading ? /*#__PURE__*/ jsx(LoadingSpinner, {
326
201
  className: "animate-spin"
327
202
  }) : /*#__PURE__*/ jsx(ChevronDown, {
@@ -370,8 +245,9 @@ const ComboboxItem = (props)=>{
370
245
  })
371
246
  });
372
247
  };
248
+ const _Combobox = /*#__PURE__*/ forwardRef(Combobox);
373
249
 
374
- function RadioGroup(props) {
250
+ function RadioGroup(props, ref) {
375
251
  const { children, className, description, errorMessage, label, isRequired, isInvalid: _isInvalid, ...restProps } = props;
376
252
  const isInvalid = _isInvalid || errorMessage != null;
377
253
  return /*#__PURE__*/ jsxs(RadioGroup$1, {
@@ -379,6 +255,7 @@ function RadioGroup(props) {
379
255
  className: cx(className, 'flex flex-col gap-2'),
380
256
  isInvalid: isInvalid,
381
257
  isRequired: isRequired,
258
+ ref: ref,
382
259
  children: [
383
260
  label && /*#__PURE__*/ jsx(Label, {
384
261
  children: label
@@ -393,6 +270,7 @@ function RadioGroup(props) {
393
270
  ]
394
271
  });
395
272
  }
273
+ const _RadioGroup = /*#__PURE__*/ forwardRef(RadioGroup);
396
274
 
397
275
  const defaultClasses = cx([
398
276
  'relative inline-flex max-w-fit cursor-pointer items-start gap-4 py-2 leading-7',
@@ -413,11 +291,12 @@ const defaultClasses = cx([
413
291
  // so we use an inner outline to artifically pad the border
414
292
  '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
293
  ]);
416
- function Radio(props) {
294
+ function Radio(props, ref) {
417
295
  const { children, className, description, ...restProps } = props;
418
296
  return /*#__PURE__*/ jsxs(Radio$1, {
419
297
  ...restProps,
420
298
  className: cx(className, defaultClasses),
299
+ ref: ref,
421
300
  children: [
422
301
  /*#__PURE__*/ jsx("div", {
423
302
  className: "absolute -left-2.5 top-0 z-10 h-11 w-11 "
@@ -434,8 +313,9 @@ function Radio(props) {
434
313
  ]
435
314
  });
436
315
  }
316
+ const _Radio = /*#__PURE__*/ forwardRef(Radio);
437
317
 
438
- function Select(props) {
318
+ function Select(props, ref) {
439
319
  const { className, children, description, errorMessage, label, isInvalid: _isInvalid, ...restProps } = props;
440
320
  const isInvalid = _isInvalid || errorMessage != null;
441
321
  return /*#__PURE__*/ jsxs(Select$1, {
@@ -449,11 +329,13 @@ function Select(props) {
449
329
  description && /*#__PURE__*/ jsx(Description, {
450
330
  children: description
451
331
  }),
452
- /*#__PURE__*/ jsxs(Button$1, {
332
+ /*#__PURE__*/ jsxs(Button, {
453
333
  className: cx(input({
454
334
  focusModifier: 'visible'
455
335
  }), // How to reuse placeholder text?
456
336
  'inline-flex cursor-default items-center gap-2'),
337
+ // See https://github.com/adobe/react-spectrum/discussions/4792#discussioncomment-6492305
338
+ ref: ref,
457
339
  children: [
458
340
  /*#__PURE__*/ jsx(SelectValue, {
459
341
  className: "flex-1 truncate text-left data-[placeholder]:text-[#727070]"
@@ -498,8 +380,9 @@ const SelectItem = (props)=>{
498
380
  })
499
381
  });
500
382
  };
383
+ const _Select = /*#__PURE__*/ forwardRef(Select);
501
384
 
502
- function TextArea(props) {
385
+ function TextArea(props, ref) {
503
386
  const { className, description, errorMessage, label, isInvalid: _isInvalid, rows, ...restProps } = props;
504
387
  const isInvalid = _isInvalid || errorMessage != null;
505
388
  return /*#__PURE__*/ jsxs(TextField$1, {
@@ -515,7 +398,8 @@ function TextArea(props) {
515
398
  }),
516
399
  /*#__PURE__*/ jsx(TextArea$1, {
517
400
  className: input(),
518
- rows: rows
401
+ rows: rows,
402
+ ref: ref
519
403
  }),
520
404
  /*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
521
405
  errorMessage: errorMessage
@@ -523,6 +407,7 @@ function TextArea(props) {
523
407
  ]
524
408
  });
525
409
  }
410
+ const _TextArea = /*#__PURE__*/ forwardRef(TextArea);
526
411
 
527
412
  const inputWithAlignment = compose(input, cva({
528
413
  base: '',
@@ -533,7 +418,7 @@ const inputWithAlignment = compose(input, cva({
533
418
  }
534
419
  }
535
420
  }));
536
- function TextField(props) {
421
+ function TextField(props, ref) {
537
422
  const { className, description, errorMessage, label, leftAddon, isInvalid: _isInvalid, textAlign, rightAddon, withAddonDivider, ...restProps } = props;
538
423
  const isInvalid = _isInvalid || errorMessage != null;
539
424
  return /*#__PURE__*/ jsxs(TextField$1, {
@@ -558,7 +443,8 @@ function TextField(props) {
558
443
  className: inputWithAlignment({
559
444
  textAlign,
560
445
  isGrouped: true
561
- })
446
+ }),
447
+ ref: ref
562
448
  }),
563
449
  withAddonDivider && rightAddon && /*#__PURE__*/ jsx(Divider, {
564
450
  className: "mr-3"
@@ -568,7 +454,8 @@ function TextField(props) {
568
454
  }) : /*#__PURE__*/ jsx(Input, {
569
455
  className: inputWithAlignment({
570
456
  textAlign
571
- })
457
+ }),
458
+ ref: ref
572
459
  }),
573
460
  /*#__PURE__*/ jsx(ErrorMessageOrFieldError, {
574
461
  errorMessage: errorMessage
@@ -581,5 +468,6 @@ function Divider({ className }) {
581
468
  className: cx(className, 'block h-6 w-px flex-none bg-black')
582
469
  });
583
470
  }
471
+ const _TextField = /*#__PURE__*/ forwardRef(TextField);
584
472
 
585
- export { Button, Checkbox, CheckboxGroup, Combobox, ComboboxItem, Radio, RadioGroup, Select, SelectItem, TextArea, TextField };
473
+ export { _Checkbox as Checkbox, _CheckboxGroup as CheckboxGroup, _Combobox as Combobox, ComboboxItem, _Radio as Radio, _RadioGroup as RadioGroup, _Select as Select, SelectItem, _TextArea as TextArea, _TextField as TextField };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obosbbl/grunnmuren-react",
3
- "version": "2.0.0-canary.3",
3
+ "version": "2.0.0-canary.5",
4
4
  "description": "Grunnmuren components in React",
5
5
  "repository": {
6
6
  "url": "https://github.com/code-obos/grunnmuren"
@@ -19,6 +19,7 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "@obosbbl/grunnmuren-icons-react": "^2.0.0-canary.1",
22
+ "@react-aria/utils": "^3.23.0",
22
23
  "cva": "1.0.0-beta.1",
23
24
  "react-aria-components": "^1.0.0"
24
25
  },
@@ -1,9 +0,0 @@
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 };