@obosbbl/grunnmuren-react 2.2.0 → 2.3.1
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.d.mts +40 -5
- package/dist/index.mjs +258 -42
- package/package.json +10 -9
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RouterProvider, ButtonProps as ButtonProps$1, LinkProps, CheckboxProps as CheckboxProps$1, CheckboxGroupProps as CheckboxGroupProps$1, ListBoxItemProps, ListBoxSectionProps, HeadingProps as HeadingProps$1, ComboBoxProps, RadioGroupProps as RadioGroupProps$1, RadioProps as RadioProps$1, SelectProps as SelectProps$1, TextFieldProps as TextFieldProps$1, NumberFieldProps as NumberFieldProps$1,
|
|
1
|
+
import { RouterProvider, ButtonProps as ButtonProps$1, LinkProps, ContextValue, CheckboxProps as CheckboxProps$1, CheckboxGroupProps as CheckboxGroupProps$1, ListBoxItemProps, ListBoxSectionProps, HeadingProps as HeadingProps$1, ComboBoxProps, RadioGroupProps as RadioGroupProps$1, RadioProps as RadioProps$1, SelectProps as SelectProps$1, TextFieldProps as TextFieldProps$1, NumberFieldProps as NumberFieldProps$1, BreadcrumbProps as BreadcrumbProps$1, BreadcrumbsProps as BreadcrumbsProps$1, DisclosureProps as DisclosureProps$1, FileTriggerProps as FileTriggerProps$1, TextProps, LabelProps, DialogTriggerProps as DialogTriggerProps$1, ModalOverlayProps, DialogProps as DialogProps$1, TagGroupProps as TagGroupProps$1, TagListProps as TagListProps$1, TagProps as TagProps$1 } from 'react-aria-components';
|
|
2
2
|
export { ListBoxItemProps as ComboboxItemProps, Form, Group, LabelProps, ListBoxItemProps as SelectItemProps, DisclosureGroup as UNSAFE_DisclosureGroup, DisclosureGroupProps as UNSAFE_DisclosureGroupProps } from 'react-aria-components';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import * as react from 'react';
|
|
@@ -105,7 +105,8 @@ type ButtonOrLinkProps$1 = VariantProps<typeof buttonVariants> & {
|
|
|
105
105
|
ref?: Ref<HTMLButtonElement | HTMLAnchorElement>;
|
|
106
106
|
};
|
|
107
107
|
type ButtonProps = (ButtonProps$1 | LinkProps) & ButtonOrLinkProps$1;
|
|
108
|
-
declare
|
|
108
|
+
declare const ButtonContext: react.Context<ContextValue<ButtonProps, HTMLButtonElement | HTMLAnchorElement>>;
|
|
109
|
+
declare function Button({ ref, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
|
|
109
110
|
|
|
110
111
|
type CheckboxProps = {
|
|
111
112
|
children: React.ReactNode;
|
|
@@ -390,10 +391,22 @@ type ContentProps = HTMLProps<HTMLDivElement> & {
|
|
|
390
391
|
ref?: Ref<HTMLDivElement>;
|
|
391
392
|
};
|
|
392
393
|
declare const Content: ({ ref, ...props }: ContentProps) => string | number | bigint | boolean | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
|
|
393
|
-
type MediaProps = HTMLProps<HTMLDivElement> & {
|
|
394
|
+
type MediaProps = HTMLProps<HTMLDivElement> & VariantProps<typeof mediaVariant> & {
|
|
394
395
|
children: React.ReactNode;
|
|
396
|
+
/** Ref for the element. */
|
|
397
|
+
ref?: Ref<HTMLDivElement>;
|
|
395
398
|
};
|
|
396
|
-
declare const
|
|
399
|
+
declare const mediaVariant: (props?: ({
|
|
400
|
+
fit?: "cover" | "contain" | undefined;
|
|
401
|
+
} & ({
|
|
402
|
+
class?: cva.ClassValue;
|
|
403
|
+
className?: never;
|
|
404
|
+
} | {
|
|
405
|
+
class?: never;
|
|
406
|
+
className?: cva.ClassValue;
|
|
407
|
+
})) | undefined) => string;
|
|
408
|
+
declare const MediaContext: react.Context<ContextValue<Partial<MediaProps>, HTMLDivElement>>;
|
|
409
|
+
declare const Media: ({ ref, ...props }: MediaProps) => react_jsx_runtime.JSX.Element;
|
|
397
410
|
type FooterProps = HTMLProps<HTMLDivElement> & {
|
|
398
411
|
children: React.ReactNode;
|
|
399
412
|
};
|
|
@@ -616,4 +629,26 @@ declare const variants: (props?: ({
|
|
|
616
629
|
})) | undefined) => string;
|
|
617
630
|
declare const Hero: ({ variant, className, children }: HeroProps) => react_jsx_runtime.JSX.Element;
|
|
618
631
|
|
|
619
|
-
|
|
632
|
+
type CarouselProps = {
|
|
633
|
+
/** The <CarouselItem/> components to be displayed within the carousel. */
|
|
634
|
+
children: React.ReactNode;
|
|
635
|
+
/** Additional CSS className for the element. */
|
|
636
|
+
className?: string;
|
|
637
|
+
};
|
|
638
|
+
declare const Carousel: ({ className, children }: CarouselProps) => react_jsx_runtime.JSX.Element;
|
|
639
|
+
type CarouselItemsProps = {
|
|
640
|
+
/** The <CarouselItem/> components to be displayed within the carousel. */
|
|
641
|
+
children: React.ReactNode;
|
|
642
|
+
/** Additional CSS className for the element. */
|
|
643
|
+
className?: string;
|
|
644
|
+
};
|
|
645
|
+
declare const CarouselItems: ({ className, children }: CarouselItemsProps) => react_jsx_runtime.JSX.Element;
|
|
646
|
+
type CarouselItemProps = {
|
|
647
|
+
/** The component/components to display as the <CarouselItem/>. */
|
|
648
|
+
children: React.ReactNode;
|
|
649
|
+
/** Additional CSS className for the element. */
|
|
650
|
+
className?: string;
|
|
651
|
+
};
|
|
652
|
+
declare const CarouselItem: ({ className, children }: CarouselItemProps) => react_jsx_runtime.JSX.Element;
|
|
653
|
+
|
|
654
|
+
export { Accordion, AccordionItem, type AccordionItemProps, type AccordionProps, Alertbox, type Props as AlertboxProps, Avatar, type AvatarProps, Backlink, type BacklinkProps, Badge, type BadgeProps, Breadcrumb, type BreadcrumbProps, Breadcrumbs, type BreadcrumbsProps, Button, ButtonContext, type ButtonProps, Caption, type CaptionProps, Card, CardLink, type CardLinkProps, type CardProps, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Combobox, ListBoxHeader as ComboboxHeader, ListBoxItem as ComboboxItem, type ComboboxProps, ListBoxSection as ComboboxSection, Content, ContentContext, type ContentProps, DateFormatter, type DateFormatterProps, Description, type DescriptionProps, DisclosureStateContext, ErrorMessage, type ErrorMessageProps, Footer, type FooterProps, GrunnmurenProvider, type GrunnmurenProviderProps, Heading, HeadingContext, type HeadingProps, Label, type Locale, Media, MediaContext, type MediaProps, NumberField, type NumberFieldProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Select, ListBoxHeader as SelectHeader, ListBoxItem as SelectItem, type SelectProps, ListBoxSection as SelectSection, type TagGroupProps, type TagListProps, type TagProps, TextArea, type TextAreaProps, TextField, type TextFieldProps, Carousel as UNSAFE_Carousel, CarouselItem as UNSAFE_CarouselItem, type CarouselItemProps as UNSAFE_CarouselItemProps, CarouselItems as UNSAFE_CarouselItems, type CarouselItemsProps as UNSAFE_CarouselItemsProps, type CarouselProps as UNSAFE_CarouselProps, Dialog as UNSAFE_Dialog, type DialogProps as UNSAFE_DialogProps, DialogTrigger as UNSAFE_DialogTrigger, type DialogTriggerProps as UNSAFE_DialogTriggerProps, Disclosure as UNSAFE_Disclosure, DisclosureButton as UNSAFE_DisclosureButton, type DisclosureButtonProps as UNSAFE_DisclosureButtonProps, DisclosurePanel as UNSAFE_DisclosurePanel, type DisclosurePanelProps as UNSAFE_DisclosurePanelProps, type DisclosureProps as UNSAFE_DisclosureProps, FileUpload as UNSAFE_FileUpload, type FileUploadProps as UNSAFE_FileUploadProps, Hero as UNSAFE_Hero, type HeroProps as UNSAFE_HeroProps, Modal as UNSAFE_Modal, type ModalProps as UNSAFE_ModalProps, Tag as UNSAFE_Tag, TagGroup as UNSAFE_TagGroup, TagList as UNSAFE_TagList, VideoLoop, _useLocale as useLocale };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { I18nProvider, RouterProvider, useLocale, useContextProps, Provider, Link, Button as Button$1, Text, CheckboxContext, Checkbox as Checkbox$1, FieldError, Label as Label$1, CheckboxGroup as CheckboxGroup$1, ListBoxItem as ListBoxItem$1, ListBoxSection as ListBoxSection$1, Header, ListBox as ListBox$1, ComboBox, Group, Input, 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, Breadcrumbs as Breadcrumbs$1, Breadcrumb as Breadcrumb$1, ButtonContext, DisclosureContext, DisclosureGroupStateContext, DEFAULT_SLOT, useSlottedContext, FormContext, FieldErrorContext, LabelContext, InputContext, DialogTrigger as DialogTrigger$1, Modal as Modal$1, Dialog as Dialog$1, ModalOverlay as ModalOverlay$1, TagGroup as TagGroup$1, TagList as TagList$1, Tag as Tag$1, GroupContext } from 'react-aria-components';
|
|
2
|
+
import { I18nProvider, RouterProvider, useLocale, useContextProps, Provider, Link, Button as Button$1, Text, CheckboxContext, Checkbox as Checkbox$1, FieldError, Label as Label$1, CheckboxGroup as CheckboxGroup$1, ListBoxItem as ListBoxItem$1, ListBoxSection as ListBoxSection$1, Header, ListBox as ListBox$1, ComboBox, Group, Input, 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, Breadcrumbs as Breadcrumbs$1, Breadcrumb as Breadcrumb$1, ButtonContext as ButtonContext$1, DisclosureContext, DisclosureGroupStateContext, DEFAULT_SLOT, useSlottedContext, FormContext, FieldErrorContext, LabelContext, InputContext, DialogTrigger as DialogTrigger$1, Modal as Modal$1, Dialog as Dialog$1, ModalOverlay as ModalOverlay$1, TagGroup as TagGroup$1, TagList as TagList$1, Tag as Tag$1, GroupContext } from 'react-aria-components';
|
|
3
3
|
export { Form, Group, DisclosureGroup as UNSAFE_DisclosureGroup } from 'react-aria-components';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { ChevronDown, LoadingSpinner, Check, Close, InfoCircle, CheckCircle, Warning, Error, ChevronRight, ChevronLeft, PlayerPause, PlayerPlay, Trash, User } from '@obosbbl/grunnmuren-icons-react';
|
|
@@ -12,6 +12,7 @@ import { useFormValidation } from '@react-aria/form';
|
|
|
12
12
|
import { useFormValidationState } from '@react-stately/form';
|
|
13
13
|
import { useControlledState } from '@react-stately/utils';
|
|
14
14
|
import { PressResponder } from '@react-aria/interactions';
|
|
15
|
+
import { useDebouncedCallback } from 'use-debounce';
|
|
15
16
|
|
|
16
17
|
function GrunnmurenProvider({ children, locale = 'nb', navigate, useHref }) {
|
|
17
18
|
return /*#__PURE__*/ jsx(I18nProvider, {
|
|
@@ -69,10 +70,35 @@ const Content = ({ ref = null, ...props })=>{
|
|
|
69
70
|
});
|
|
70
71
|
return outerWrapper ? outerWrapper(content) : content;
|
|
71
72
|
};
|
|
72
|
-
const
|
|
73
|
-
|
|
73
|
+
const mediaVariant = cva({
|
|
74
|
+
variants: {
|
|
75
|
+
/**
|
|
76
|
+
* Control how the content should be placed with the object-fit property
|
|
77
|
+
* You might for example want to use `fit="contain"` portrait images that should not be cropped
|
|
78
|
+
* @default cover
|
|
79
|
+
* */ fit: {
|
|
80
|
+
cover: '*:object-cover',
|
|
81
|
+
contain: '*:object-contain'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const MediaContext = /*#__PURE__*/ createContext({});
|
|
86
|
+
const Media = ({ ref = null, ...props })=>{
|
|
87
|
+
[props, ref] = useContextProps(props, ref, MediaContext);
|
|
88
|
+
const { className, fit, ...restProps } = props;
|
|
89
|
+
const _className = mediaVariant({
|
|
90
|
+
fit
|
|
91
|
+
});
|
|
92
|
+
return /*#__PURE__*/ jsx("div", {
|
|
93
|
+
ref: ref,
|
|
94
|
+
className: cx(className, _className),
|
|
95
|
+
// This can be used (internally) in other components
|
|
96
|
+
// to apply custom styles to the media element depending on the fit
|
|
97
|
+
"data-fit": fit,
|
|
98
|
+
...restProps,
|
|
74
99
|
"data-slot": "media"
|
|
75
100
|
});
|
|
101
|
+
};
|
|
76
102
|
const Caption = ({ className, ...restProps })=>/*#__PURE__*/ jsx("div", {
|
|
77
103
|
...restProps,
|
|
78
104
|
className: cx('description', className),
|
|
@@ -239,6 +265,16 @@ const translations$1 = {
|
|
|
239
265
|
nb: 'Vis mindre',
|
|
240
266
|
sv: 'Dölj',
|
|
241
267
|
en: 'Show less'
|
|
268
|
+
},
|
|
269
|
+
previous: {
|
|
270
|
+
nb: 'Forrige',
|
|
271
|
+
sv: 'Föregående',
|
|
272
|
+
en: 'Previous'
|
|
273
|
+
},
|
|
274
|
+
next: {
|
|
275
|
+
nb: 'Neste',
|
|
276
|
+
sv: 'Nästa',
|
|
277
|
+
en: 'Next'
|
|
242
278
|
}
|
|
243
279
|
};
|
|
244
280
|
|
|
@@ -335,11 +371,13 @@ const translations$1 = {
|
|
|
335
371
|
isPending: false
|
|
336
372
|
}
|
|
337
373
|
});
|
|
374
|
+
const ButtonContext = /*#__PURE__*/ createContext({});
|
|
338
375
|
function isLinkProps$1(props) {
|
|
339
376
|
return !!props.href;
|
|
340
377
|
}
|
|
341
|
-
function Button(props) {
|
|
342
|
-
|
|
378
|
+
function Button({ ref = null, ...props }) {
|
|
379
|
+
[props, ref] = useContextProps(props, ref, ButtonContext);
|
|
380
|
+
const { children: _children, color, isIconOnly, isLoading, variant, isPending: _isPending, ...restProps } = props;
|
|
343
381
|
const isPending = _isPending || isLoading;
|
|
344
382
|
const className = buttonVariants({
|
|
345
383
|
className: props.className,
|
|
@@ -364,6 +402,7 @@ function Button(props) {
|
|
|
364
402
|
}) : _children;
|
|
365
403
|
return isLinkProps$1(restProps) ? /*#__PURE__*/ jsx(Link, {
|
|
366
404
|
...restProps,
|
|
405
|
+
routerOptions: restProps.routerOptions,
|
|
367
406
|
className: className,
|
|
368
407
|
ref: ref,
|
|
369
408
|
children: children
|
|
@@ -1079,14 +1118,6 @@ const cardVariants = cva({
|
|
|
1079
1118
|
'rounded-2xl border p-3',
|
|
1080
1119
|
'flex gap-y-4',
|
|
1081
1120
|
'relative',
|
|
1082
|
-
// **** Heading ****
|
|
1083
|
-
'[&_[data-slot="heading"]]:inline',
|
|
1084
|
-
'[&_[data-slot="heading"]]:heading-s',
|
|
1085
|
-
'[&_[data-slot="heading"]]:leading-6',
|
|
1086
|
-
'[&_[data-slot="heading"]]:w-fit',
|
|
1087
|
-
'[&_[data-slot="heading"]]:text-pretty',
|
|
1088
|
-
'[&_[data-slot="heading"]]:hyphens-auto',
|
|
1089
|
-
'[&_[data-slot="heading"]]:[word-break:break-word]',
|
|
1090
1121
|
// **** Content ****
|
|
1091
1122
|
'[&_[data-slot="content"]]:flex [&_[data-slot="content"]]:flex-col [&_[data-slot="content"]]:gap-y-4',
|
|
1092
1123
|
// **** Media ****
|
|
@@ -1103,21 +1134,7 @@ const cardVariants = cva({
|
|
|
1103
1134
|
// **** Hover ****
|
|
1104
1135
|
// Enables the zoom hover effect on media (note that we can't use group-hover/card here, because there might be other clickable elements in the card aside from the heading)
|
|
1105
1136
|
'[&:has([data-slot="card-link"]_a:hover)_[data-slot="media"]>img]:scale-110',
|
|
1106
|
-
// **** Card link in Heading ****
|
|
1107
1137
|
'[&:has([data-slot="heading"]_[data-slot="card-link"]:hover)_[data-slot="media"]>img]:scale-110',
|
|
1108
|
-
// Border (bottom/top) is set to transparent to make sure the bottom underline is not visible when the card is hovered
|
|
1109
|
-
// Border top is set to even out the border bottom used for the underline
|
|
1110
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:no-underline',
|
|
1111
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:border-y-2',
|
|
1112
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:border-y-transparent',
|
|
1113
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:transition-colors',
|
|
1114
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]:hover]:border-b-current',
|
|
1115
|
-
// Mimic heading styles for the card link if placed in the heading slot. This is necessary to make the custom underline align with the link text
|
|
1116
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:heading-s',
|
|
1117
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:leading-6',
|
|
1118
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:text-pretty',
|
|
1119
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:hyphens-auto',
|
|
1120
|
-
'[&_[data-slot="heading"]_[data-slot="card-link"]]:[word-break:break-word]',
|
|
1121
1138
|
// **** Fail-safe for interactive elements ****
|
|
1122
1139
|
// Make interactive elements clickable by themselves, while the rest of the card is clickable as a whole
|
|
1123
1140
|
// The card is made clickable by a pseudo-element on the heading that covers the entire card
|
|
@@ -1220,7 +1237,37 @@ const Card = ({ children, className: _className, variant, layout, ...restProps }
|
|
|
1220
1237
|
return /*#__PURE__*/ jsx("div", {
|
|
1221
1238
|
className: className,
|
|
1222
1239
|
...restProps,
|
|
1223
|
-
children:
|
|
1240
|
+
children: /*#__PURE__*/ jsx(Provider, {
|
|
1241
|
+
values: [
|
|
1242
|
+
[
|
|
1243
|
+
HeadingContext,
|
|
1244
|
+
{
|
|
1245
|
+
size: 's',
|
|
1246
|
+
className: cx([
|
|
1247
|
+
'inline',
|
|
1248
|
+
'w-fit',
|
|
1249
|
+
'text-pretty',
|
|
1250
|
+
'hyphens-auto',
|
|
1251
|
+
'[word-break:break-word]',
|
|
1252
|
+
// **** Card link in Heading ****
|
|
1253
|
+
// Border (bottom/top) is set to transparent to make sure the bottom underline is not visible when the card is hovered
|
|
1254
|
+
// Border top is set to even out the border bottom used for the underline
|
|
1255
|
+
'*:data-[slot="card-link"]:no-underline',
|
|
1256
|
+
'*:data-[slot="card-link"]:border-y-2',
|
|
1257
|
+
'*:data-[slot="card-link"]:border-y-transparent',
|
|
1258
|
+
'*:data-[slot="card-link"]:transition-colors',
|
|
1259
|
+
'*:data-[slot="card-link"]:hover:border-b-current',
|
|
1260
|
+
// Mimic heading styles for the card link if placed in the heading slot. This is necessary to make the custom underline align with the link text
|
|
1261
|
+
'*:data-[slot="card-link"]:font-inherit',
|
|
1262
|
+
'*:data-[slot="card-link"]:text-pretty',
|
|
1263
|
+
'*:data-[slot="card-link"]:hyphens-auto',
|
|
1264
|
+
'*:data-[slot="card-link"]:[word-break:break-word]'
|
|
1265
|
+
])
|
|
1266
|
+
}
|
|
1267
|
+
]
|
|
1268
|
+
],
|
|
1269
|
+
children: children
|
|
1270
|
+
})
|
|
1224
1271
|
});
|
|
1225
1272
|
};
|
|
1226
1273
|
const cardLinkVariants = cva({
|
|
@@ -1354,6 +1401,7 @@ const VideoLoop = ({ src, format, alt, className })=>{
|
|
|
1354
1401
|
})
|
|
1355
1402
|
}),
|
|
1356
1403
|
userPrefersReducedMotion !== null && /*#__PURE__*/ jsx("button", {
|
|
1404
|
+
"data-slot": "video-loop-button",
|
|
1357
1405
|
"aria-hidden": true,
|
|
1358
1406
|
type: "button",
|
|
1359
1407
|
onClick: ()=>setShouldPlay((prevState)=>!prevState),
|
|
@@ -1402,7 +1450,7 @@ const disclosureButtonVariants = cva({
|
|
|
1402
1450
|
}
|
|
1403
1451
|
});
|
|
1404
1452
|
const DisclosureButton = ({ className, withChevron, isIconOnly, children, ref: _ref, ...restProps })=>{
|
|
1405
|
-
const [props, ref] = useContextProps(restProps, _ref, ButtonContext);
|
|
1453
|
+
const [props, ref] = useContextProps(restProps, _ref, ButtonContext$1);
|
|
1406
1454
|
return /*#__PURE__*/ jsxs(Button$1, {
|
|
1407
1455
|
...props,
|
|
1408
1456
|
ref: ref,
|
|
@@ -1457,7 +1505,7 @@ const Disclosure = ({ ref: _ref, children, ..._props })=>{
|
|
|
1457
1505
|
state
|
|
1458
1506
|
],
|
|
1459
1507
|
[
|
|
1460
|
-
ButtonContext,
|
|
1508
|
+
ButtonContext$1,
|
|
1461
1509
|
{
|
|
1462
1510
|
slots: {
|
|
1463
1511
|
[DEFAULT_SLOT]: {},
|
|
@@ -1527,7 +1575,7 @@ const DisclosurePanel = ({ ref, children, ...props })=>{
|
|
|
1527
1575
|
null
|
|
1528
1576
|
],
|
|
1529
1577
|
[
|
|
1530
|
-
ButtonContext,
|
|
1578
|
+
ButtonContext$1,
|
|
1531
1579
|
null
|
|
1532
1580
|
]
|
|
1533
1581
|
],
|
|
@@ -1719,7 +1767,7 @@ const FileUpload = ({ children, files: _files, onChange, validate, isInvalid: _i
|
|
|
1719
1767
|
}
|
|
1720
1768
|
],
|
|
1721
1769
|
[
|
|
1722
|
-
ButtonContext,
|
|
1770
|
+
ButtonContext$1,
|
|
1723
1771
|
{
|
|
1724
1772
|
// The button acts as the trigger for the file input, which is why we connect the label to the button id
|
|
1725
1773
|
id,
|
|
@@ -1875,7 +1923,7 @@ const Dialog = ({ className, children, ...restProps })=>{
|
|
|
1875
1923
|
}
|
|
1876
1924
|
],
|
|
1877
1925
|
[
|
|
1878
|
-
ButtonContext,
|
|
1926
|
+
ButtonContext$1,
|
|
1879
1927
|
{
|
|
1880
1928
|
// This is necessary to support multiple close buttons
|
|
1881
1929
|
slots: {
|
|
@@ -1968,15 +2016,16 @@ const oneColumnLayout = [
|
|
|
1968
2016
|
// Make sure other elements than <Content> and <Media> (i.e CTA) does not span the full width on small screens
|
|
1969
2017
|
'*:not-data-[slot="content"]:not-data-[slot="media"]:w-fit',
|
|
1970
2018
|
// Other elements than <Content> and <Media> (e.g. CTA, SVG logo or Badge) take up 3 columns on medium screens and above, and are right aligned
|
|
1971
|
-
'lg:*:not-data-[slot="content"]:not-data-[slot="media"]:col-span-3 lg:*:not-data-[slot="content"]:not-data-[slot="media"]:justify-self-end',
|
|
1972
|
-
// <Media> content takes up the full width on medium screens and above
|
|
2019
|
+
'lg:*:not-data-[slot="content"]:not-data-[slot="media"]:not-data-[slot="carousel"]:col-span-3 lg:*:not-data-[slot="content"]:not-data-[slot="media"]:justify-self-end',
|
|
2020
|
+
// <Media> and <Carousel> content takes up the full width on medium screens and above
|
|
1973
2021
|
'lg:*:data-[slot="media"]:col-span-full *:data-[slot="media"]:*:w-full',
|
|
2022
|
+
'lg:*:data-[slot="carousel"]:col-span-full *:data-[slot="carousel"]:*:w-full',
|
|
1974
2023
|
// Aligns <Content> and any element beside it (e.g. <Media>, <Badge>, <CTA> etc.) to the bottom of the <Content> container
|
|
1975
2024
|
'lg:items-end'
|
|
1976
2025
|
];
|
|
1977
2026
|
const variants = cva({
|
|
1978
2027
|
base: [
|
|
1979
|
-
'container',
|
|
2028
|
+
'container px-0',
|
|
1980
2029
|
// Grid variant to position the Hero's content
|
|
1981
2030
|
'grid lg:grid-cols-12 lg:gap-x-12 xl:gap-x-16',
|
|
1982
2031
|
'gap-y-10 lg:gap-y-12',
|
|
@@ -1998,13 +2047,18 @@ const variants = cva({
|
|
|
1998
2047
|
],
|
|
1999
2048
|
'full-bleed': [
|
|
2000
2049
|
oneColumnLayout,
|
|
2050
|
+
// Position the media and carousel content to fill the entire viewport width
|
|
2051
|
+
'*:data-[slot="media"]:*:absolute *:data-[slot="media"]:*:left-0',
|
|
2052
|
+
'*:data-[slot="carousel"]:*:absolute *:data-[slot="carousel"]:*:left-0',
|
|
2053
|
+
// Match the heights of the <Media> or <Carousel> wrapper for the Media content (e.g. image, VideoLoop, video etc.)
|
|
2054
|
+
// This is necessary due to the absolute positioning of the media and carousel containers in this variant
|
|
2001
2055
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
2002
|
-
'*:data-[slot="media"]
|
|
2003
|
-
// Match the heights of the <Media> wrapper for the Media content (e.g. image, VideoLoop, video etc.)
|
|
2056
|
+
'*:data-[slot="media"]:*:h-70 sm:*:data-[slot="media"]:*:h-[25rem] md:*:data-[slot="media"]:*:h-[30rem] lg:*:data-[slot="media"]:*:h-[35rem] xl:*:data-[slot="media"]:*:h-[40rem] 2xl:*:data-[slot="media"]:*:h-[42rem] 3xl:*:data-[slot="media"]:*:h-[48rem] 4xl:*:data-[slot="media"]:*:h-[53rem]',
|
|
2004
2057
|
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
2005
|
-
'*:data-[slot="
|
|
2006
|
-
|
|
2007
|
-
|
|
2058
|
+
'*:data-[slot="carousel"]:h-70 sm:*:data-[slot="carousel"]:h-[25rem] md:*:data-[slot="carousel"]:h-[30rem] lg:*:data-[slot="carousel"]:h-[35rem] xl:*:data-[slot="carousel"]:h-[40rem] 2xl:*:data-[slot="carousel"]:h-[42rem] 3xl:*:data-[slot="carousel"]:h-[48rem] 4xl:*:data-[slot="carousel"]:h-[53rem]',
|
|
2059
|
+
'**:data-[slot="carousel-controls"]:container **:data-[slot="carousel-controls"]:right-0 **:data-[slot="carousel-controls"]:bottom-4 **:data-[slot="carousel-controls"]:left-0 **:data-[slot="carousel-controls"]:justify-end',
|
|
2060
|
+
// Override rounded corners of Carousel slots
|
|
2061
|
+
'*:data-[slot="carousel"]:*:rounded-none'
|
|
2008
2062
|
],
|
|
2009
2063
|
'two-column': [
|
|
2010
2064
|
'lg:items-center lg:*:col-span-6',
|
|
@@ -2051,4 +2105,166 @@ const Hero = ({ variant, className, children })=>{
|
|
|
2051
2105
|
});
|
|
2052
2106
|
};
|
|
2053
2107
|
|
|
2054
|
-
|
|
2108
|
+
const Carousel = ({ className, children })=>{
|
|
2109
|
+
const ref = useRef(null);
|
|
2110
|
+
const locale = _useLocale();
|
|
2111
|
+
const { previous, next } = translations$1;
|
|
2112
|
+
const [scrollTargetIndex, setScrollTargetIndex] = useState(0);
|
|
2113
|
+
const [hasReachedScrollStart, setHasReachedScrollStart] = useState(scrollTargetIndex === 0);
|
|
2114
|
+
const [hasReachedScrollEnd, setHasReachedScrollEnd] = useState(!ref.current || ref.current.children.length - 1 === scrollTargetIndex);
|
|
2115
|
+
useEffect(()=>{
|
|
2116
|
+
setHasReachedScrollStart(scrollTargetIndex === 0);
|
|
2117
|
+
setHasReachedScrollEnd(!ref.current || ref.current.children.length - 1 === scrollTargetIndex);
|
|
2118
|
+
}, [
|
|
2119
|
+
scrollTargetIndex
|
|
2120
|
+
]);
|
|
2121
|
+
// Handle scrolling when user clicks the arrow icons
|
|
2122
|
+
useUpdateEffect(()=>{
|
|
2123
|
+
if (!ref.current) return;
|
|
2124
|
+
ref.current.children[scrollTargetIndex]?.scrollIntoView({
|
|
2125
|
+
behavior: 'smooth',
|
|
2126
|
+
inline: 'start',
|
|
2127
|
+
block: 'nearest'
|
|
2128
|
+
});
|
|
2129
|
+
}, [
|
|
2130
|
+
scrollTargetIndex
|
|
2131
|
+
]);
|
|
2132
|
+
const onScroll = useDebouncedCallback((event)=>{
|
|
2133
|
+
const target = event.target;
|
|
2134
|
+
// Calculate the index of the item that is currently in view
|
|
2135
|
+
const newScrollTargetIndex = Array.from(target.children).findIndex((child)=>{
|
|
2136
|
+
const rect = child.getBoundingClientRect();
|
|
2137
|
+
return rect.left >= 0 && rect.right <= window.innerWidth && rect.top >= 0;
|
|
2138
|
+
});
|
|
2139
|
+
if (newScrollTargetIndex !== -1) {
|
|
2140
|
+
setScrollTargetIndex(newScrollTargetIndex);
|
|
2141
|
+
}
|
|
2142
|
+
}, 100);
|
|
2143
|
+
return /*#__PURE__*/ jsx("div", {
|
|
2144
|
+
"data-slot": "carousel",
|
|
2145
|
+
children: /*#__PURE__*/ jsx(Provider, {
|
|
2146
|
+
values: [
|
|
2147
|
+
[
|
|
2148
|
+
CarouselItemsContext,
|
|
2149
|
+
{
|
|
2150
|
+
ref,
|
|
2151
|
+
onScroll
|
|
2152
|
+
}
|
|
2153
|
+
],
|
|
2154
|
+
[
|
|
2155
|
+
ButtonContext,
|
|
2156
|
+
{
|
|
2157
|
+
slots: {
|
|
2158
|
+
prev: {
|
|
2159
|
+
'aria-label': previous[locale],
|
|
2160
|
+
onPress: ()=>{
|
|
2161
|
+
if (scrollTargetIndex > 0) {
|
|
2162
|
+
setScrollTargetIndex((prev)=>prev - 1);
|
|
2163
|
+
}
|
|
2164
|
+
},
|
|
2165
|
+
isDisabled: hasReachedScrollStart
|
|
2166
|
+
},
|
|
2167
|
+
next: {
|
|
2168
|
+
isIconOnly: true,
|
|
2169
|
+
'aria-label': next[locale],
|
|
2170
|
+
onPress: ()=>{
|
|
2171
|
+
if (!ref.current) return;
|
|
2172
|
+
if (scrollTargetIndex < ref.current.children.length - 1) {
|
|
2173
|
+
setScrollTargetIndex((prev)=>prev + 1);
|
|
2174
|
+
}
|
|
2175
|
+
},
|
|
2176
|
+
isDisabled: hasReachedScrollEnd
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
]
|
|
2181
|
+
],
|
|
2182
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
2183
|
+
className: cx(className, 'relative rounded-3xl', // If any <CarouselItems/> (the scroll-snap container) or <VideoLoop/> component is focused, apply custom focus styles around the carousel, this makes ensures that the focus outline is visible around the carousel in all cases
|
|
2184
|
+
'[&:has([data-slot="carousel-items"]:focus-visible,[data-slot="video-loop-button"]:focus-visible)]:outline-focus', '[&:has([data-slot="carousel-items"]:focus-visible,[data-slot="video-loop-button"]:focus-visible)]:outline-focus-offset', // Unset the default focus outline for potential video loop buttons, as it interferes with the custom focus styles for the carousel
|
|
2185
|
+
'**:data-[slot="video-loop-button"]:focus-visible:outline-none'),
|
|
2186
|
+
children: [
|
|
2187
|
+
children,
|
|
2188
|
+
/*#__PURE__*/ jsxs(_CarouselControls, {
|
|
2189
|
+
children: [
|
|
2190
|
+
/*#__PURE__*/ jsx(Button, {
|
|
2191
|
+
isIconOnly: true,
|
|
2192
|
+
slot: "prev",
|
|
2193
|
+
variant: "primary",
|
|
2194
|
+
color: "white",
|
|
2195
|
+
className: cx('group/carousel-previous', hasReachedScrollStart && 'invisible'),
|
|
2196
|
+
children: /*#__PURE__*/ jsx(ChevronLeft, {
|
|
2197
|
+
className: "group-hover/carousel-previous:motion-safe:-translate-x-1 transition-transform"
|
|
2198
|
+
})
|
|
2199
|
+
}),
|
|
2200
|
+
/*#__PURE__*/ jsx(Button, {
|
|
2201
|
+
isIconOnly: true,
|
|
2202
|
+
slot: "next",
|
|
2203
|
+
variant: "primary",
|
|
2204
|
+
color: "white",
|
|
2205
|
+
className: cx('group/carousel-next', hasReachedScrollEnd && 'invisible'),
|
|
2206
|
+
children: /*#__PURE__*/ jsx(ChevronRight, {
|
|
2207
|
+
className: "transition-transform group-hover/carousel-next:motion-safe:translate-x-1"
|
|
2208
|
+
})
|
|
2209
|
+
})
|
|
2210
|
+
]
|
|
2211
|
+
})
|
|
2212
|
+
]
|
|
2213
|
+
})
|
|
2214
|
+
})
|
|
2215
|
+
});
|
|
2216
|
+
};
|
|
2217
|
+
/**
|
|
2218
|
+
* This is internal for now, but we will expose it in the future when we support more flexible positioning of prev/next and other actions.
|
|
2219
|
+
* It is used to render the prev/next buttons in the carousel for now.
|
|
2220
|
+
*/ const _CarouselControls = ({ children, className })=>/*#__PURE__*/ jsx("div", {
|
|
2221
|
+
className: cx(className, 'absolute right-6 bottom-6 flex gap-x-2', // Make it easier to position in full-bleed hero variants (these style have no other side effects)
|
|
2222
|
+
'items-end *:h-fit'),
|
|
2223
|
+
"data-slot": "carousel-controls",
|
|
2224
|
+
children: children
|
|
2225
|
+
});
|
|
2226
|
+
const CarouselItemsContext = /*#__PURE__*/ createContext({
|
|
2227
|
+
ref: null
|
|
2228
|
+
});
|
|
2229
|
+
const CarouselItems = ({ className, children })=>/*#__PURE__*/ jsx(CarouselItemsContext.Consumer, {
|
|
2230
|
+
children: ({ ref, onScroll })=>/*#__PURE__*/ jsx("div", {
|
|
2231
|
+
"data-slot": "carousel-items",
|
|
2232
|
+
className: cx(className, [
|
|
2233
|
+
'scrollbar-hidden',
|
|
2234
|
+
'flex',
|
|
2235
|
+
'snap-x',
|
|
2236
|
+
'snap-mandatory',
|
|
2237
|
+
'overflow-x-auto',
|
|
2238
|
+
'outline-none',
|
|
2239
|
+
'rounded-[inherit]'
|
|
2240
|
+
]),
|
|
2241
|
+
ref: ref,
|
|
2242
|
+
// When the SnapEvent is supported: https://developer.mozilla.org/en-US/docs/Web/API/SnapEvent
|
|
2243
|
+
// We can use the scrollsnapchange event to detect when the user has scrolled to a new item.
|
|
2244
|
+
// We can then use Array.from(event.target.children).indexOf(event.snapTargetInline) to calculate the index of the item that is currently in view.
|
|
2245
|
+
// Another option is to use the scrollEnd event, when Safiri supports it: https://developer.apple.com/documentation/webkitjs/snap_event/scrollend_event
|
|
2246
|
+
onScroll: onScroll,
|
|
2247
|
+
children: children
|
|
2248
|
+
})
|
|
2249
|
+
});
|
|
2250
|
+
const CarouselItem = ({ className, children })=>{
|
|
2251
|
+
return /*#__PURE__*/ jsx("div", {
|
|
2252
|
+
className: cx(className, 'shrink-0 basis-full snap-start'),
|
|
2253
|
+
"data-slot": "carousel-item",
|
|
2254
|
+
children: /*#__PURE__*/ jsx(Provider, {
|
|
2255
|
+
values: [
|
|
2256
|
+
[
|
|
2257
|
+
MediaContext,
|
|
2258
|
+
{
|
|
2259
|
+
fit: 'cover',
|
|
2260
|
+
className: cx('data-[fit="contain"]:bg-blue-dark', '*:w-full', // biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
|
|
2261
|
+
'*:h-70 sm:*:h-[25rem] lg:*:h-[35rem] xl:*:h-[40rem] 2xl:*:h-[42rem] 3xl:*:h-[48rem] 4xl:*:h-[53rem]')
|
|
2262
|
+
}
|
|
2263
|
+
]
|
|
2264
|
+
],
|
|
2265
|
+
children: children
|
|
2266
|
+
})
|
|
2267
|
+
});
|
|
2268
|
+
};
|
|
2269
|
+
|
|
2270
|
+
export { Accordion, AccordionItem, Alertbox, Avatar, Backlink, Badge, Breadcrumb, Breadcrumbs, Button, ButtonContext, Caption, Card, CardLink, Checkbox, CheckboxGroup, Combobox, ListBoxHeader as ComboboxHeader, ListBoxItem as ComboboxItem, ListBoxSection as ComboboxSection, Content, ContentContext, DateFormatter, Description, DisclosureStateContext, ErrorMessage, Footer, GrunnmurenProvider, Heading, HeadingContext, Label, Media, MediaContext, NumberField, Radio, RadioGroup, Select, ListBoxHeader as SelectHeader, ListBoxItem as SelectItem, ListBoxSection as SelectSection, TextArea, TextField, Carousel as UNSAFE_Carousel, CarouselItem as UNSAFE_CarouselItem, CarouselItems as UNSAFE_CarouselItems, Dialog as UNSAFE_Dialog, DialogTrigger as UNSAFE_DialogTrigger, Disclosure as UNSAFE_Disclosure, DisclosureButton as UNSAFE_DisclosureButton, DisclosurePanel as UNSAFE_DisclosurePanel, FileUpload as UNSAFE_FileUpload, Hero as UNSAFE_Hero, Modal as UNSAFE_Modal, Tag as UNSAFE_Tag, TagGroup as UNSAFE_TagGroup, TagList as UNSAFE_TagList, VideoLoop, _useLocale as useLocale };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obosbbl/grunnmuren-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Grunnmuren components in React",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/code-obos/grunnmuren"
|
|
@@ -19,16 +19,17 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@obosbbl/grunnmuren-icons-react": "^2.1.0",
|
|
22
|
-
"@react-aria/form": "^3.0.
|
|
23
|
-
"@react-aria/interactions": "^3.
|
|
24
|
-
"@react-aria/utils": "^3.
|
|
25
|
-
"@react-stately/form": "^3.1.
|
|
26
|
-
"@react-stately/utils": "^3.10.
|
|
22
|
+
"@react-aria/form": "^3.0.18",
|
|
23
|
+
"@react-aria/interactions": "^3.25.3",
|
|
24
|
+
"@react-aria/utils": "^3.29.1",
|
|
25
|
+
"@react-stately/form": "^3.1.5",
|
|
26
|
+
"@react-stately/utils": "^3.10.7",
|
|
27
27
|
"@types/node": "^22.0.0",
|
|
28
28
|
"cva": "^1.0.0-0",
|
|
29
|
-
"react-aria": "^3.
|
|
30
|
-
"react-aria-components": "^1.
|
|
31
|
-
"react-stately": "^3.
|
|
29
|
+
"react-aria": "^3.41.1",
|
|
30
|
+
"react-aria-components": "^1.10.1",
|
|
31
|
+
"react-stately": "^3.39.0",
|
|
32
|
+
"use-debounce": "^10.0.4"
|
|
32
33
|
},
|
|
33
34
|
"peerDependencies": {
|
|
34
35
|
"react": "^19"
|